Skip to content

Commit

Permalink
fix: stub globally registered components (#859)
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyerburgh authored Jul 28, 2018
1 parent 1c8109d commit 5af3677
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 26 deletions.
32 changes: 24 additions & 8 deletions packages/create-instance/create-instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -64,26 +65,41 @@ 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
)
if (options.stubs) {
instanceOptions.components = {
...instanceOptions.components,
// $FlowIgnore
...stubComponents
}
}
function addStubComponentsMixin () {
Object.assign(
this.$options.components,
stubComponents
)
}
_Vue.mixin({
created () {
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 (
Expand Down
9 changes: 2 additions & 7 deletions packages/shared/stub-components.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
import {
componentNeedsCompiling,
templateContainsComponent,
isVueComponent
isVueComponent,
isRequiredComponent
} from './validators'
import { compileTemplate } from './compile-template'

Expand All @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions packages/shared/validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
)
}
2 changes: 1 addition & 1 deletion packages/test-utils/src/find-vue-components.js
Original file line number Diff line number Diff line change
Expand Up @@ -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`
)
}

Expand Down
46 changes: 37 additions & 9 deletions test/specs/mounting-options/stubs.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down Expand Up @@ -133,42 +133,70 @@ describeWithMountingMethods('options.stub', mountingMethod => {
itDoNotRunIf(
mountingMethod.name === 'shallowMount',
'stubs nested components', () => {
const GrandchildComponent = {
const GrandChildComponent = {
template: '<span />'
}
const ChildComponent = {
template: '<grandchild-component />',
components: { GrandchildComponent }
template: '<grand-child-component />',
components: { GrandChildComponent }
}
const TestComponent = {
template: '<child-component />',
components: { ChildComponent }
}
const wrapper = mountingMethod(TestComponent, {
stubs: ['grandchild-component']
stubs: ['grand-child-component']
})
const HTML = mountingMethod.name === 'renderToString'
? wrapper
: wrapper.html()
expect(HTML).not.to.contain('<span>')
})

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('<span>')
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: '<span />'
}
const ChildComponent = {
template: '<grandchild-component />',
components: { GrandchildComponent }
template: '<grand-child-component />',
components: { GrandChildComponent }
}
const TestComponent = {
template: '<div><child-component /></div>',
components: { ChildComponent }
}
const wrapper = mountingMethod(Vue.extend(TestComponent), {
stubs: ['grandchild-component']
stubs: ['grand-child-component']
})
const HTML = mountingMethod.name === 'renderToString'
? wrapper
Expand Down
2 changes: 1 addition & 1 deletion test/specs/wrapper/find.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit 5af3677

Please sign in to comment.