From cf4875422e50a1cd5dfa68df394f1afa7d95348c Mon Sep 17 00:00:00 2001 From: eddyerburgh Date: Sat, 28 Jul 2018 07:32:10 +0100 Subject: [PATCH 1/3] fix: stub globally registered components Fixes #830 --- packages/create-instance/create-instance.js | 18 ++++++-- packages/shared/stub-components.js | 9 +--- packages/shared/validators.js | 6 +++ .../test-utils/src/find-vue-components.js | 2 +- test/specs/mounting-options/stubs.spec.js | 46 +++++++++++++++---- test/specs/wrapper/find.spec.js | 2 +- 6 files changed, 62 insertions(+), 21 deletions(-) diff --git a/packages/create-instance/create-instance.js b/packages/create-instance/create-instance.js index cc82ea95a..d5ee7881e 100644 --- a/packages/create-instance/create-instance.js +++ b/packages/create-instance/create-instance.js @@ -6,6 +6,7 @@ import { addEventLogger } from './log-events' import { createComponentStubs } from 'shared/stub-components' import { throwError, warn, vueVersion } from 'shared/util' import { compileTemplate } from 'shared/compile-template' +import { isRequiredComponent } from 'shared/validators' import extractInstanceOptions from './extract-instance-options' import createFunctionalComponent from './create-functional-component' import { componentNeedsCompiling, isPlainObject } from 'shared/validators' @@ -64,8 +65,20 @@ export default function createInstance ( addEventLogger(_Vue) + // Replace globally registered components with components extended + // from localVue. This makes sure the beforeMount mixins to add stubs + // is applied to globally registered components. + // Vue version must be 2.3 or greater, because of a bug resolving + // extended constructor options (https://github.com/vuejs/vue/issues/4976) + if (vueVersion > 2.2) { + for (const c in _Vue.options.components) { + if (!isRequiredComponent(c)) { + _Vue.component(c, _Vue.extend(_Vue.options.components[c])) + } + } + } + const stubComponents = createComponentStubs( - // $FlowIgnore component.components, // $FlowIgnore options.stubs @@ -73,12 +86,11 @@ export default function createInstance ( if (options.stubs) { instanceOptions.components = { ...instanceOptions.components, - // $FlowIgnore ...stubComponents } } _Vue.mixin({ - created () { + beforeMount () { Object.assign( this.$options.components, stubComponents diff --git a/packages/shared/stub-components.js b/packages/shared/stub-components.js index 8fe7d3339..cd27a4f4a 100644 --- a/packages/shared/stub-components.js +++ b/packages/shared/stub-components.js @@ -11,7 +11,8 @@ import { import { componentNeedsCompiling, templateContainsComponent, - isVueComponent + isVueComponent, + isRequiredComponent } from './validators' import { compileTemplate } from './compile-template' @@ -36,12 +37,6 @@ function resolveComponent (obj: Object, component: string): Object { {} } -function isRequiredComponent (name): boolean { - return ( - name === 'KeepAlive' || name === 'Transition' || name === 'TransitionGroup' - ) -} - function getCoreProperties (componentOptions: Component): Object { return { attrs: componentOptions.attrs, diff --git a/packages/shared/validators.js b/packages/shared/validators.js index 6116596d8..8259e753f 100644 --- a/packages/shared/validators.js +++ b/packages/shared/validators.js @@ -89,3 +89,9 @@ export function templateContainsComponent ( export function isPlainObject (obj: any): boolean { return Object.prototype.toString.call(obj) === '[object Object]' } + +export function isRequiredComponent (name: string): boolean { + return ( + name === 'KeepAlive' || name === 'Transition' || name === 'TransitionGroup' + ) +} diff --git a/packages/test-utils/src/find-vue-components.js b/packages/test-utils/src/find-vue-components.js index ff6b5d8f7..d9858c49b 100644 --- a/packages/test-utils/src/find-vue-components.js +++ b/packages/test-utils/src/find-vue-components.js @@ -76,7 +76,7 @@ export function vmFunctionalCtorMatchesSelector ( ): boolean { if (VUE_VERSION < 2.3) { throwError( - `find for functional components is not support in ` + `Vue < 2.3` + `find for functional components is not supported in ` + `Vue < 2.3` ) } diff --git a/test/specs/mounting-options/stubs.spec.js b/test/specs/mounting-options/stubs.spec.js index 24a86cad8..7aa4b75d4 100644 --- a/test/specs/mounting-options/stubs.spec.js +++ b/test/specs/mounting-options/stubs.spec.js @@ -5,7 +5,7 @@ import ComponentAsAClass from '~resources/components/component-as-a-class.vue' import { createLocalVue, config } from '~vue/test-utils' import { config as serverConfig } from '~vue/server-test-utils' import Vue from 'vue' -import { describeWithMountingMethods } from '~resources/utils' +import { describeWithMountingMethods, vueVersion } from '~resources/utils' import { itDoNotRunIf } from 'conditional-specs' describeWithMountingMethods('options.stub', mountingMethod => { @@ -133,19 +133,19 @@ describeWithMountingMethods('options.stub', mountingMethod => { itDoNotRunIf( mountingMethod.name === 'shallowMount', 'stubs nested components', () => { - const GrandchildComponent = { + const GrandChildComponent = { template: '' } const ChildComponent = { - template: '', - components: { GrandchildComponent } + template: '', + components: { GrandChildComponent } } const TestComponent = { template: '', components: { ChildComponent } } const wrapper = mountingMethod(TestComponent, { - stubs: ['grandchild-component'] + stubs: ['grand-child-component'] }) const HTML = mountingMethod.name === 'renderToString' ? wrapper @@ -153,22 +153,50 @@ describeWithMountingMethods('options.stub', mountingMethod => { expect(HTML).not.to.contain('') }) + itDoNotRunIf( + mountingMethod.name === 'shallowMount' || vueVersion < 2.3, + 'stubs nested components registered globally', () => { + const GrandChildComponent = { + render: h => h('span', ['hello']) + } + const ChildComponent = { + render: h => h('grand-child-component') + } + const TestComponent = { + render: h => h('child-component') + } + Vue.component('child-component', ChildComponent) + Vue.component('grand-child-component', GrandChildComponent) + + const wrapper = mountingMethod(TestComponent, { + stubs: { + 'grand-child-component': true + } + }) + const HTML = mountingMethod.name === 'renderToString' + ? wrapper + : wrapper.html() + expect(HTML).not.to.contain('') + delete Vue.options.components['child-component'] + delete Vue.options.components['grand-child-component'] + }) + itDoNotRunIf( mountingMethod.name === 'shallowMount', 'stubs nested components on extended components', () => { - const GrandchildComponent = { + const GrandChildComponent = { template: '' } const ChildComponent = { - template: '', - components: { GrandchildComponent } + template: '', + components: { GrandChildComponent } } const TestComponent = { template: '
', components: { ChildComponent } } const wrapper = mountingMethod(Vue.extend(TestComponent), { - stubs: ['grandchild-component'] + stubs: ['grand-child-component'] }) const HTML = mountingMethod.name === 'renderToString' ? wrapper diff --git a/test/specs/wrapper/find.spec.js b/test/specs/wrapper/find.spec.js index 717b34821..a45e8fc53 100644 --- a/test/specs/wrapper/find.spec.js +++ b/test/specs/wrapper/find.spec.js @@ -186,7 +186,7 @@ describeWithShallowAndMount('find', mountingMethod => { const wrapper = mountingMethod(TestComponent) if (vueVersion < 2.3) { const message = - '[vue-test-utils]: find for functional components is not support in Vue < 2.3' + '[vue-test-utils]: find for functional components is not supported in Vue < 2.3' const fn = () => wrapper.find(TestFunctionalComponent) expect(fn) .to.throw() From 67135ccfdf6df37f9c6cd3d029eaccd0012f3a6f Mon Sep 17 00:00:00 2001 From: eddyerburgh Date: Sat, 28 Jul 2018 07:52:38 +0100 Subject: [PATCH 2/3] fix: add stubs for components created in node --- packages/create-instance/create-instance.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/create-instance/create-instance.js b/packages/create-instance/create-instance.js index d5ee7881e..e931ec0bc 100644 --- a/packages/create-instance/create-instance.js +++ b/packages/create-instance/create-instance.js @@ -89,13 +89,17 @@ export default function createInstance ( ...stubComponents } } + function addStubComponentsMixin(){ + Object.assign( + this.$options.components, + stubComponents + ) + } _Vue.mixin({ - beforeMount () { - Object.assign( - this.$options.components, - stubComponents - ) - } + beforeMount: addStubComponentsMixin, + // beforeCreate is for components created in node, which + // never mount + beforeCreate: addStubComponentsMixin }) Object.keys(componentOptions.components || {}).forEach(c => { if ( From ec184707efa75c00585517c955f0af6a8e0c8f86 Mon Sep 17 00:00:00 2001 From: eddyerburgh Date: Sat, 28 Jul 2018 08:01:44 +0100 Subject: [PATCH 3/3] test: fix lint errors: --- packages/create-instance/create-instance.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/create-instance/create-instance.js b/packages/create-instance/create-instance.js index e931ec0bc..2b964a548 100644 --- a/packages/create-instance/create-instance.js +++ b/packages/create-instance/create-instance.js @@ -89,7 +89,7 @@ export default function createInstance ( ...stubComponents } } - function addStubComponentsMixin(){ + function addStubComponentsMixin () { Object.assign( this.$options.components, stubComponents