Skip to content

Commit b461900

Browse files
authored
refactor: use validator functions (#1107)
1 parent efab983 commit b461900

File tree

7 files changed

+90
-65
lines changed

7 files changed

+90
-65
lines changed

Diff for: packages/create-instance/create-component-stubs.js

+11-11
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import {
1010
import {
1111
componentNeedsCompiling,
1212
templateContainsComponent,
13-
isVueComponent
13+
isVueComponent,
14+
isDynamicComponent,
15+
isConstructor
1416
} from '../shared/validators'
1517
import {
1618
compileTemplate,
@@ -65,11 +67,11 @@ function createClassString (staticClass, dynamicClass) {
6567
}
6668

6769
function resolveOptions (component, _Vue) {
68-
if (typeof component === 'function' && !component.cid) {
70+
if (isDynamicComponent(component)) {
6971
return {}
7072
}
7173

72-
return typeof component === 'function'
74+
return isConstructor(component)
7375
? component.options
7476
: _Vue.extend(component).options
7577
}
@@ -112,19 +114,16 @@ export function createStubFromComponent (
112114
}
113115
}
114116

115-
export function createStubFromString (
117+
function createStubFromString (
116118
templateString: string,
117119
originalComponent: Component = {},
118-
name: string
120+
name: string,
121+
_Vue: Component
119122
): Component {
120123
if (templateContainsComponent(templateString, name)) {
121124
throwError('options.stub cannot contain a circular reference')
122125
}
123-
124-
const componentOptions =
125-
typeof originalComponent === 'function' && originalComponent.cid
126-
? originalComponent.extendOptions
127-
: originalComponent
126+
const componentOptions = resolveOptions(originalComponent, _Vue)
128127

129128
return {
130129
...getCoreProperties(componentOptions),
@@ -167,7 +166,8 @@ export function createStubsFromStubsObject (
167166
acc[stubName] = createStubFromString(
168167
stub,
169168
component,
170-
stubName
169+
stubName,
170+
_Vue
171171
)
172172
return acc
173173
}

Diff for: packages/create-instance/create-instance.js

+19-24
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { validateSlots } from './validate-slots'
1717
import createScopedSlots from './create-scoped-slots'
1818
import { createStubsFromStubsObject } from './create-component-stubs'
1919
import { patchCreateElement } from './patch-create-element'
20+
import { isConstructor } from 'shared/validators'
2021

2122
function vueExtendUnsupportedOption (option: string) {
2223
return `options.${option} is not supported for ` +
@@ -39,13 +40,8 @@ export default function createInstance (
3940
options: Options,
4041
_Vue: Component
4142
): Component {
42-
// make sure all extends are based on this instance
43-
_Vue.options._base = _Vue
44-
4543
if (
46-
VUE_VERSION < 2.3 &&
47-
typeof component === 'function' &&
48-
component.options
44+
VUE_VERSION < 2.3 && isConstructor(component)
4945
) {
5046
UNSUPPORTED_VERSION_OPTIONS.forEach((option) => {
5147
if (options[option]) {
@@ -54,11 +50,15 @@ export default function createInstance (
5450
})
5551
}
5652

53+
let componentOptions = isConstructor(component)
54+
? component.options
55+
: component
56+
5757
// instance options are options that are passed to the
5858
// root instance when it's instantiated
5959
const instanceOptions = extractInstanceOptions(options)
6060
const stubComponentsObject = createStubsFromStubsObject(
61-
component.components,
61+
componentOptions.components,
6262
// $FlowIgnore
6363
options.stubs,
6464
_Vue
@@ -69,31 +69,27 @@ export default function createInstance (
6969
addStubs(_Vue, stubComponentsObject)
7070
patchCreateElement(_Vue, stubComponentsObject, options.shouldProxy)
7171

72-
if (
73-
(component.options && component.options.functional) ||
74-
component.functional
75-
) {
76-
component = createFunctionalComponent(component, options, _Vue)
72+
if (componentOptions.functional) {
73+
componentOptions = createFunctionalComponent(
74+
componentOptions,
75+
options,
76+
_Vue
77+
)
7778
} else if (options.context) {
7879
throwError(
7980
`mount.context can only be used when mounting a ` +
8081
`functional component`
8182
)
8283
}
8384

84-
if (componentNeedsCompiling(component)) {
85-
compileTemplate(component)
85+
if (componentNeedsCompiling(componentOptions)) {
86+
compileTemplate(componentOptions)
8687
}
8788

88-
if (component.options) {
89-
component.options._base = _Vue
90-
}
89+
// make sure all extends are based on this instance
90+
componentOptions._base = _Vue
9191

92-
// extend component from _Vue to add properties and mixins
93-
// extend does not work correctly for sub class components in Vue < 2.2
94-
const Constructor = typeof component === 'function'
95-
? _Vue.extend(component.options).extend(instanceOptions)
96-
: _Vue.extend(component).extend(instanceOptions)
92+
const Constructor = _Vue.extend(componentOptions).extend(instanceOptions)
9793

9894
// used to identify extended component using constructor
9995
Constructor.options.$_vueTestUtils_original = component
@@ -122,8 +118,7 @@ export default function createInstance (
122118

123119
if (options.parentComponent && !isPlainObject(options.parentComponent)) {
124120
throwError(
125-
`options.parentComponent should be a valid Vue component ` +
126-
`options object`
121+
`options.parentComponent should be a valid Vue component options object`
127122
)
128123
}
129124

Diff for: packages/create-instance/patch-create-element.js

+9-18
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
import { createStubFromComponent } from './create-component-stubs'
22
import { resolveComponent } from 'shared/util'
3-
import { isReservedTag } from 'shared/validators'
3+
import {
4+
isReservedTag,
5+
isConstructor,
6+
isDynamicComponent,
7+
isComponentOptions
8+
} from 'shared/validators'
49
import {
510
BEFORE_RENDER_LIFECYCLE_HOOK,
611
CREATE_ELEMENT_ALIAS
712
} from 'shared/consts'
813

914
const isWhitelisted = (el, whitelist) => resolveComponent(el, whitelist)
1015
const isAlreadyStubbed = (el, stubs) => stubs.has(el)
11-
const isDynamicComponent = cmp => typeof cmp === 'function' && !cmp.cid
1216

1317
function shouldExtend (component, _Vue) {
1418
return (
15-
(typeof component === 'function' && !isDynamicComponent(component)) ||
19+
isConstructor(component) ||
1620
(component && component.extends)
1721
)
1822
}
@@ -21,6 +25,7 @@ function extend (component, _Vue) {
2125
const componentOptions = component.options ? component.options : component
2226
const stub = _Vue.extend(componentOptions)
2327
stub.options.$_vueTestUtils_original = component
28+
stub.options._base = _Vue
2429
return stub
2530
}
2631

@@ -42,14 +47,6 @@ function shouldNotBeStubbed (el, whitelist, modifiedComponents) {
4247
)
4348
}
4449

45-
function isConstructor (el) {
46-
return typeof el === 'function'
47-
}
48-
49-
function isComponentOptions (el) {
50-
return typeof el === 'object' && (el.template || el.render)
51-
}
52-
5350
export function patchCreateElement (_Vue, stubs, stubAllComponents) {
5451
// This mixin patches vm.$createElement so that we can stub all components
5552
// before they are rendered in shallow mode. We also need to ensure that
@@ -87,7 +84,7 @@ export function patchCreateElement (_Vue, stubs, stubAllComponents) {
8784
}
8885

8986
if (typeof el === 'string') {
90-
let original = resolveComponent(el, originalComponents)
87+
const original = resolveComponent(el, originalComponents)
9188

9289
if (!original) {
9390
return originalCreateElement(el, ...args)
@@ -97,12 +94,6 @@ export function patchCreateElement (_Vue, stubs, stubAllComponents) {
9794
return originalCreateElement(el, ...args)
9895
}
9996

100-
if (
101-
original.options &&
102-
original.options.$_vueTestUtils_original
103-
) {
104-
original = original.options.$_vueTestUtils_original
105-
}
10697
const stub = createStubIfNeeded(stubAllComponents, original, _Vue, el)
10798

10899
if (stub) {

Diff for: packages/shared/validators.js

+20-8
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,24 @@ export function isDomSelector (selector: any): boolean {
2828
}
2929
}
3030

31-
export function isVueComponent (component: any): boolean {
32-
if (typeof component === 'function' && component.options) {
31+
export function isVueComponent (c: any): boolean {
32+
if (isConstructor(c)) {
3333
return true
3434
}
3535

36-
if (component === null || typeof component !== 'object') {
36+
if (c === null || typeof c !== 'object') {
3737
return false
3838
}
3939

40-
if (component.extends || component._Ctor) {
40+
if (c.extends || c._Ctor) {
4141
return true
4242
}
4343

44-
if (typeof component.template === 'string') {
44+
if (typeof c.template === 'string') {
4545
return true
4646
}
4747

48-
return typeof component.render === 'function'
48+
return typeof c.render === 'function'
4949
}
5050

5151
export function componentNeedsCompiling (component: Component): boolean {
@@ -76,6 +76,18 @@ export function isNameSelector (nameOptionsObject: any): boolean {
7676
return !!nameOptionsObject.name
7777
}
7878

79+
export function isConstructor (c: any) {
80+
return typeof c === 'function' && c.cid
81+
}
82+
83+
export function isDynamicComponent (c: any) {
84+
return typeof c === 'function' && !c.cid
85+
}
86+
87+
export function isComponentOptions (c: any) {
88+
return typeof c === 'object' && (c.template || c.render)
89+
}
90+
7991
export function templateContainsComponent (
8092
template: string,
8193
name: string
@@ -86,8 +98,8 @@ export function templateContainsComponent (
8698
})
8799
}
88100

89-
export function isPlainObject (obj: any): boolean {
90-
return Object.prototype.toString.call(obj) === '[object Object]'
101+
export function isPlainObject (c: any): boolean {
102+
return Object.prototype.toString.call(c) === '[object Object]'
91103
}
92104

93105
export function isRequiredComponent (name: string): boolean {

Diff for: packages/test-utils/src/matches.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
COMPONENT_SELECTOR,
44
FUNCTIONAL_OPTIONS
55
} from 'shared/consts'
6+
import { isConstructor } from 'shared/validators'
67

78
export function vmMatchesName (vm, name) {
89
return !!name && (
@@ -19,7 +20,7 @@ function vmCtorMatches (vm, component) {
1920
return true
2021
}
2122

22-
const Ctor = typeof component === 'function'
23+
const Ctor = isConstructor(component)
2324
? component.options._Ctor
2425
: component._Ctor
2526

@@ -46,7 +47,7 @@ export function matches (node, selector) {
4647
return element && element.matches && element.matches(selector.value)
4748
}
4849

49-
const isFunctionalSelector = typeof selector.value === 'function'
50+
const isFunctionalSelector = isConstructor(selector.value)
5051
? selector.value.options.functional
5152
: selector.value.functional
5253

@@ -66,7 +67,7 @@ export function matches (node, selector) {
6667

6768
// Fallback to name selector for COMPONENT_SELECTOR for Vue < 2.1
6869
const nameSelector =
69-
typeof selector.value === 'function'
70+
isConstructor(selector.value)
7071
? selector.value.extendOptions.name
7172
: selector.value.name
7273
return vmMatchesName(componentInstance, nameSelector)

Diff for: test/specs/mount.spec.js

+26
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,32 @@ describeRunIf(process.env.TEST_ENV !== 'node', 'mount', () => {
384384
expect(wrapper.findAll(ChildComponent).length).to.equal(1)
385385
})
386386

387+
it('handles nested components with extends', () => {
388+
const GrandChildComponent = {
389+
template: '<div />',
390+
created () {
391+
this.$route.params
392+
}
393+
}
394+
const ChildComponent = Vue.extend({
395+
template: '<grand-child-component />',
396+
components: {
397+
GrandChildComponent
398+
}
399+
})
400+
const TestComponent = {
401+
template: '<child-component />',
402+
components: {
403+
ChildComponent
404+
}
405+
}
406+
const localVue = createLocalVue()
407+
localVue.prototype.$route = {}
408+
mount(TestComponent, {
409+
localVue
410+
})
411+
})
412+
387413
it('throws if component throws during update', () => {
388414
const TestComponent = {
389415
template: '<div :p="a" />',

Diff for: test/specs/mounting-options/stubs.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ describeWithMountingMethods('options.stub', mountingMethod => {
216216
components: { GrandChildComponent }
217217
}
218218
const TestComponent = {
219-
template: '<div><child-component /></div>',
219+
template: '<child-component />',
220220
components: { ChildComponent }
221221
}
222222
const wrapper = mountingMethod(Vue.extend(TestComponent), {

0 commit comments

Comments
 (0)