diff --git a/flow/options.flow.js b/flow/options.flow.js index 6056e6ddc..94b0c4a6a 100644 --- a/flow/options.flow.js +++ b/flow/options.flow.js @@ -18,6 +18,25 @@ declare type Options = { shouldProxy?: boolean } +declare type NormalizedOptions = { + attachToDocument?: boolean, + propsData?: Object, + mocks: Object, + methods: { [key: string]: Function }, + slots?: SlotsObject, + scopedSlots?: { [key: string]: string | Function }, + localVue?: Component, + provide?: Object | Function, + stubs: { [name: string]: Component | true | string } | boolean, + context?: Object, + attrs?: { [key: string]: string }, + listeners?: { [key: string]: Function | Array }, + parentComponent?: Object, + logModifiedComponents?: boolean, + sync: boolean, + shouldProxy?: boolean +} + declare type SlotValue = Component | string | Array declare type SlotsObject = { [name: string]: SlotValue } diff --git a/package.json b/package.json index 6c501aaa2..540112fd7 100644 --- a/package.json +++ b/package.json @@ -68,12 +68,12 @@ "sinon-chai": "^2.10.0", "typescript": "^3.0.1", "vee-validate": "^2.1.3", - "vue": "2.5.21", + "vue": "^2.5.22", "vue-class-component": "^6.1.2", "vue-loader": "^13.6.2", "vue-router": "^3.0.1", - "vue-server-renderer": "2.5.21", - "vue-template-compiler": "2.5.21", + "vue-server-renderer": "^2.5.22", + "vue-template-compiler": "^2.5.22", "vuepress": "^0.14.2", "vuepress-theme-vue": "^1.0.3", "vuex": "^3.0.1", diff --git a/packages/create-instance/create-instance.js b/packages/create-instance/create-instance.js index b0869002b..bc859ce9f 100644 --- a/packages/create-instance/create-instance.js +++ b/packages/create-instance/create-instance.js @@ -41,7 +41,7 @@ function createChildren(vm, h, { slots, context }) { export default function createInstance( component: Component, - options: Options, + options: NormalizedOptions, _Vue: Component ): Component { const componentOptions = isConstructor(component) diff --git a/packages/shared/merge-options.js b/packages/shared/merge-options.js index 6ad19f2aa..b9f0eb507 100644 --- a/packages/shared/merge-options.js +++ b/packages/shared/merge-options.js @@ -19,16 +19,27 @@ function getOption(option, config?: Object): any { } } -export function mergeOptions(options: Options, config: Config): Options { +function getStubs(stubs, configStubs): Object { + const normalizedStubs = normalizeStubs(stubs) + const normalizedConfigStubs = normalizeStubs(configStubs) + return getOption(normalizedStubs, normalizedConfigStubs) +} + +export function mergeOptions( + options: Options, + config: Config +): NormalizedOptions { const mocks = (getOption(options.mocks, config.mocks): Object) const methods = (getOption(options.methods, config.methods): { [key: string]: Function }) const provide = (getOption(options.provide, config.provide): Object) + const stubs = (getStubs(options.stubs, config.stubs): Object) + // $FlowIgnore return { ...options, provide: normalizeProvide(provide), - stubs: getOption(normalizeStubs(options.stubs), config.stubs), + stubs, mocks, methods, sync: !!(options.sync || options.sync === undefined) diff --git a/packages/test-utils/src/config.js b/packages/test-utils/src/config.js index 70734d99c..fbd002dbd 100644 --- a/packages/test-utils/src/config.js +++ b/packages/test-utils/src/config.js @@ -1,11 +1,5 @@ -import TransitionStub from './components/TransitionStub' -import TransitionGroupStub from './components/TransitionGroupStub' - export default { - stubs: { - transition: TransitionStub, - 'transition-group': TransitionGroupStub - }, + stubs: {}, mocks: {}, methods: {}, provide: {}, diff --git a/packages/test-utils/src/mount.js b/packages/test-utils/src/mount.js index 458aead11..3ef6a5625 100644 --- a/packages/test-utils/src/mount.js +++ b/packages/test-utils/src/mount.js @@ -1,7 +1,4 @@ -// @flow - import Vue from 'vue' -import VueWrapper from './vue-wrapper' import createInstance from 'create-instance' import createElement from './create-element' import { throwIfInstancesThrew, addGlobalErrorHandler } from './error' @@ -14,6 +11,8 @@ import { warn } from 'shared/util' import semver from 'semver' import { COMPAT_SYNC_MODE } from 'shared/consts' import { validateOptions } from 'shared/validate-options' +import TransitionGroupStub from './components/TransitionGroupStub' +import TransitionStub from './components/TransitionStub' Vue.config.productionTip = false Vue.config.devtools = false @@ -45,10 +44,27 @@ function getSyncOption(syncOption) { return true } -export default function mount( - component: Component, - options: Options = {} -): VueWrapper | Wrapper { +function addTransitionStubs(options) { + if (config.stubs === false) { + return + } + if ( + options.stubs && + options.stubs.transition !== false && + !options.stubs.transition + ) { + options.stubs.transition = TransitionStub + } + if ( + options.stubs && + options.stubs['transition-group'] !== false && + !options.stubs['transition-group'] + ) { + options.stubs['transition-group'] = TransitionGroupStub + } +} + +export default function mount(component, options = {}) { warnIfNoWindow() addGlobalErrorHandler(Vue) @@ -56,9 +72,17 @@ export default function mount( const _Vue = createLocalVue(options.localVue) const mergedOptions = mergeOptions(options, config) + const sync = getSyncOption(mergedOptions.sync) validateOptions(mergedOptions, component) + // Stub transition and transition-group if in compat sync mode to keep old + // behavior + // TODO: Remove when compat sync mode is removed + if (sync === COMPAT_SYNC_MODE) { + addTransitionStubs(mergedOptions) + } + const parentVm = createInstance(component, mergedOptions, _Vue) const el = options.attachToDocument ? createElement() : undefined @@ -67,7 +91,6 @@ export default function mount( component._Ctor = {} throwIfInstancesThrew(vm) - const sync = getSyncOption(mergedOptions.sync) const wrapperOptions = { attachedToDocument: !!mergedOptions.attachToDocument, diff --git a/test/resources/components/component-with-transition-group.vue b/test/resources/components/component-with-transition-group.vue index 932aeef6e..0c1163b4e 100644 --- a/test/resources/components/component-with-transition-group.vue +++ b/test/resources/components/component-with-transition-group.vue @@ -1,7 +1,7 @@ diff --git a/test/specs/components/TransitionGroupStub.spec.js b/test/specs/components/TransitionGroupStub.spec.js index 36097c2df..e3fb3f673 100644 --- a/test/specs/components/TransitionGroupStub.spec.js +++ b/test/specs/components/TransitionGroupStub.spec.js @@ -1,6 +1,7 @@ import ComponentWithTransitionGroup from '~resources/components/component-with-transition-group.vue' import { TransitionGroupStub } from '~vue/test-utils' -import { describeWithShallowAndMount } from '~resources/utils' +import { describeWithShallowAndMount, vueVersion } from '~resources/utils' +import { itDoNotRunIf } from 'conditional-specs' describeWithShallowAndMount('TransitionGroupStub', mountingMethod => { it('update synchronously when used as stubs for Transition', () => { @@ -14,6 +15,18 @@ describeWithShallowAndMount('TransitionGroupStub', mountingMethod => { expect(wrapper.text()).contains('b') }) + itDoNotRunIf( + vueVersion < 2.5, + 'does not stub TransitionGroup, but applies synchronously in Vue > 2.5.18', + () => { + const wrapper = mountingMethod(ComponentWithTransitionGroup) + expect(wrapper.find(TransitionGroupStub).exists()).to.equal(false) + expect(wrapper.text()).contains('a') + wrapper.setData({ a: 'b' }) + expect(wrapper.text()).contains('b') + } + ) + it('updates watchers', () => { const TestComponent = { data: () => ({ diff --git a/test/specs/components/TransitionStub.spec.js b/test/specs/components/TransitionStub.spec.js index 17594edab..ced8a6514 100644 --- a/test/specs/components/TransitionStub.spec.js +++ b/test/specs/components/TransitionStub.spec.js @@ -1,6 +1,7 @@ import ComponentWithTransition from '~resources/components/component-with-transition.vue' -import { describeWithShallowAndMount } from '~resources/utils' +import { describeWithShallowAndMount, vueVersion } from '~resources/utils' import { TransitionStub } from '~vue/test-utils' +import { itDoNotRunIf } from 'conditional-specs' describeWithShallowAndMount('TransitionStub', mountingMethod => { let consoleError @@ -24,6 +25,18 @@ describeWithShallowAndMount('TransitionStub', mountingMethod => { expect(wrapper.text()).contains('b') }) + itDoNotRunIf( + vueVersion < 2.5, + 'does not stub Transition, but applies synchronously in Vue > 2.5.18', + () => { + const wrapper = mountingMethod(ComponentWithTransition) + expect(wrapper.find(TransitionStub).exists()).to.equal(false) + expect(wrapper.text()).contains('a') + wrapper.setData({ a: 'b' }) + expect(wrapper.text()).contains('b') + } + ) + it('does not add v-leave class to children', () => { const TestComponent = { template: ` diff --git a/test/specs/config.spec.js b/test/specs/config.spec.js index 4261aa198..9f66a28a7 100644 --- a/test/specs/config.spec.js +++ b/test/specs/config.spec.js @@ -122,20 +122,6 @@ describeWithShallowAndMount('config', mountingMethod => { expect(wrapper.contains(TransitionStub)).to.equal(false) }) - it("doesn't stub transition when config.stubs is set to a string", () => { - config.stubs = 'a string' - const testComponent = { - template: ` -
-

-

- ` - } - const wrapper = mountingMethod(testComponent) - expect(wrapper.contains(TransitionGroupStub)).to.equal(false) - expect(wrapper.contains(TransitionStub)).to.equal(false) - }) - it("doesn't throw Vue warning when silent is set to true", () => { config.silent = true const localVue = createLocalVue() diff --git a/yarn.lock b/yarn.lock index c6b21eee1..bfc6a85d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9823,10 +9823,9 @@ vue-router@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.1.tgz#d9b05ad9c7420ba0f626d6500d693e60092cc1e9" -vue-server-renderer@2.5.21: - version "2.5.21" - resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.5.21.tgz#7c2b611d2e8558359cdb84dcd3080845c07121b4" - integrity sha512-bAkOYZ5DnmQKv3RboNbmCB4LReF2tIE20EgUeWrz/87aVkpMihf3FVK+8DT45nyN4k9iSQOhsyem49fq++cF8w== +vue-server-renderer@^2.5.16: + version "2.5.16" + resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.5.16.tgz#279ef8e37e502a0de3a9ae30758cc04a472eaac0" dependencies: chalk "^1.1.3" hash-sum "^1.0.2" @@ -9837,9 +9836,10 @@ vue-server-renderer@2.5.21: serialize-javascript "^1.3.0" source-map "0.5.6" -vue-server-renderer@^2.5.16: - version "2.5.16" - resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.5.16.tgz#279ef8e37e502a0de3a9ae30758cc04a472eaac0" +vue-server-renderer@^2.5.22: + version "2.5.22" + resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.5.22.tgz#f119efef289c865adc22fda0ae7595299bedbdcf" + integrity sha512-PQ0PubA6b2MyZud/gepWeiUuDFSbRfa6h1qYINcbwXRr4Z3yLTHprEQuFnWikdkTkZpeLFYUqZrDxPbDcJ71mA== dependencies: chalk "^1.1.3" hash-sum "^1.0.2" @@ -9864,17 +9864,17 @@ vue-style-loader@^4.1.0: hash-sum "^1.0.2" loader-utils "^1.0.2" -vue-template-compiler@2.5.21: - version "2.5.21" - resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.5.21.tgz#a57ceb903177e8f643560a8d639a0f8db647054a" - integrity sha512-Vmk5Cv7UcmI99B9nXJEkaK262IQNnHp5rJYo+EwYpe2epTAXqcVyExhV6pk8jTkxQK2vRc8v8KmZBAwdmUZvvw== +vue-template-compiler@^2.5.16: + version "2.5.16" + resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.5.16.tgz#93b48570e56c720cdf3f051cc15287c26fbd04cb" dependencies: de-indent "^1.0.2" he "^1.1.0" -vue-template-compiler@^2.5.16: - version "2.5.16" - resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.5.16.tgz#93b48570e56c720cdf3f051cc15287c26fbd04cb" +vue-template-compiler@^2.5.22: + version "2.5.22" + resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.5.22.tgz#c3d3c02c65f1908205c4fbd3b0ef579e51239955" + integrity sha512-1VTw/NPTUeHNiwhkq6NkFzO7gYLjFCueBN0FX8NEiQIemd5EUMQ5hxrF7O0zCPo5tae+U9S/scETPea+hIz8Eg== dependencies: de-indent "^1.0.2" he "^1.1.0" @@ -9883,15 +9883,15 @@ vue-template-es2015-compiler@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.6.0.tgz#dc42697133302ce3017524356a6c61b7b69b4a18" -vue@2.5.21: - version "2.5.21" - resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.21.tgz#3d33dcd03bb813912ce894a8303ab553699c4a85" - integrity sha512-Aejvyyfhn0zjVeLvXd70h4hrE4zZDx1wfZqia6ekkobLmUZ+vNFQer53B4fu0EjWBSiqApxPejzkO1Znt3joxQ== - vue@^2.5.16: version "2.5.16" resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.16.tgz#07edb75e8412aaeed871ebafa99f4672584a0085" +vue@^2.5.22: + version "2.5.22" + resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.22.tgz#3bf88041af08b8539c37b268b70ca79245e9cc30" + integrity sha512-pxY3ZHlXNJMFQbkjEgGVMaMMkSV1ONpz+4qB55kZuJzyJOhn6MSy/YZdzhdnumegNzVTL/Dn3Pp4UrVBYt1j/g== + vuepress-html-webpack-plugin@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/vuepress-html-webpack-plugin/-/vuepress-html-webpack-plugin-3.2.0.tgz#219be272ad510faa8750d2d4e70fd028bfd1c16e"