forked from vuejs/vue-test-utils
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcreate-instance.js
136 lines (116 loc) · 4.15 KB
/
create-instance.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// @flow
import { createSlotVNodes } from './create-slot-vnodes'
import addMocks from './add-mocks'
import { addEventLogger } from './log-events'
import { addStubs } from './add-stubs'
import { compileTemplate } from 'shared/compile-template'
import extractInstanceOptions from './extract-instance-options'
import { componentNeedsCompiling, isConstructor } from 'shared/validators'
import createScopedSlots from './create-scoped-slots'
import { createStubsFromStubsObject } from './create-component-stubs'
import { patchCreateElement } from './patch-create-element'
function createContext(options, scopedSlots) {
const on = {
...(options.context && options.context.on),
...options.listeners
}
return {
attrs: {
...options.attrs,
// pass as attrs so that inheritAttrs works correctly
// propsData should take precedence over attrs
...options.propsData
},
...(options.context || {}),
on,
scopedSlots
}
}
function createChildren(vm, h, { slots, context }) {
const slotVNodes = slots ? createSlotVNodes(vm, slots) : undefined
return (
(context &&
context.children &&
context.children.map(x => (typeof x === 'function' ? x(h) : x))) ||
slotVNodes
)
}
function getValuesFromCallableOption(optionValue) {
if (typeof optionValue === 'function') {
return optionValue.call(this)
}
return optionValue
}
export default function createInstance(
component: Component,
options: NormalizedOptions,
_Vue: Component
): Component {
const componentOptions = isConstructor(component)
? component.options
: component
// instance options are options that are passed to the
// root instance when it's instantiated
const instanceOptions = extractInstanceOptions(options)
const globalComponents = _Vue.options.components || {}
const componentsToStub = Object.assign(
Object.create(globalComponents),
componentOptions.components
)
const stubComponentsObject = createStubsFromStubsObject(
componentsToStub,
// $FlowIgnore
options.stubs,
_Vue
)
addEventLogger(_Vue)
addMocks(_Vue, options.mocks)
addStubs(_Vue, stubComponentsObject)
patchCreateElement(_Vue, stubComponentsObject, options.shouldProxy)
if (componentNeedsCompiling(componentOptions)) {
compileTemplate(componentOptions)
}
// used to identify extended component using constructor
componentOptions.$_vueTestUtils_original = component
// watchers provided in mounting options should override preexisting ones
if (componentOptions.watch && instanceOptions.watch) {
const componentWatchers = Object.keys(componentOptions.watch)
const instanceWatchers = Object.keys(instanceOptions.watch)
for (let i = 0; i < instanceWatchers.length; i++) {
const k = instanceWatchers[i]
// override the componentOptions with the one provided in mounting options
if (componentWatchers.includes(k)) {
componentOptions.watch[k] = instanceOptions.watch[k]
}
}
}
// make sure all extends are based on this instance
const Constructor = _Vue.extend(componentOptions).extend(instanceOptions)
Constructor.options._base = _Vue
const scopedSlots = createScopedSlots(options.scopedSlots, _Vue)
const parentComponentOptions = options.parentComponent || {}
const originalParentComponentProvide = parentComponentOptions.provide
parentComponentOptions.provide = function() {
return {
...getValuesFromCallableOption.call(this, originalParentComponentProvide),
...getValuesFromCallableOption.call(this, options.provide)
}
}
parentComponentOptions.$_doNotStubChildren = true
parentComponentOptions._isFunctionalContainer = componentOptions.functional
parentComponentOptions.render = function(h) {
return h(
Constructor,
createContext(options, scopedSlots),
createChildren(this, h, options)
)
}
// options "propsData" can only be used during instance creation with the `new` keyword
// "data" should be set only on component under test to avoid reactivity issues
const { propsData, data, ...rest } = options // eslint-disable-line
const Parent = _Vue.extend({
...rest,
...parentComponentOptions
})
return new Parent()
}