1
1
// @flow
2
2
3
3
import Vue from 'vue'
4
- import { addSlots } from './add-slots'
5
- import { addScopedSlots } from './add-scoped-slots'
4
+ import { createSlotVNodes } from './add-slots'
6
5
import addMocks from './add-mocks'
7
- import addAttrs from './add-attrs'
8
- import addListeners from './add-listeners'
9
- import addProvide from './add-provide'
10
6
import { addEventLogger } from './log-events'
11
7
import { createComponentStubs } from 'shared/stub-components'
12
- import { throwError , warn } from 'shared/util'
8
+ import { throwError , warn , vueVersion } from 'shared/util'
13
9
import { compileTemplate } from 'shared/compile-template'
14
- import deleteoptions from './delete-mounting-options'
10
+ import deleteMountingOptions from './delete-mounting-options'
15
11
import createFunctionalComponent from './create-functional-component'
16
12
import { componentNeedsCompiling } from 'shared/validators'
17
-
18
- function isDestructuringSlotScope ( slotScope : string ) : boolean {
19
- return slotScope [ 0 ] === '{' && slotScope [ slotScope . length - 1 ] === '}'
20
- }
21
-
22
- function getVueTemplateCompilerHelpers ( proxy : Object ) : Object {
23
- const helpers = { }
24
- const names = [ '_c' , '_o' , '_n' , '_s' , '_l' , '_t' , '_q' , '_i' , '_m' , '_f' , '_k' , '_b' , '_v' , '_e' , '_u' , '_g' ]
25
- names . forEach ( ( name ) => {
26
- helpers [ name ] = proxy [ name ]
27
- } )
28
- return helpers
29
- }
13
+ import { validateSlots } from './validate-slots'
30
14
31
15
export default function createInstance (
32
16
component : Component ,
33
17
options : Options ,
34
- vue : Component
18
+ _Vue : Component ,
19
+ elm ?: Element
35
20
) : Component {
21
+ // Remove cached constructor
22
+ delete component . _Ctor
23
+
36
24
if ( options . mocks ) {
37
- addMocks ( options . mocks , vue )
25
+ addMocks ( options . mocks , _Vue )
38
26
}
39
-
40
27
if ( ( component . options && component . options . functional ) || component . functional ) {
41
28
component = createFunctionalComponent ( component , options )
42
29
} else if ( options . context ) {
@@ -45,23 +32,23 @@ export default function createInstance (
45
32
)
46
33
}
47
34
48
- if ( options . provide ) {
49
- addProvide ( component , options . provide , options )
50
- }
51
-
52
35
if ( componentNeedsCompiling ( component ) ) {
53
36
compileTemplate ( component )
54
37
}
55
38
56
- addEventLogger ( vue )
39
+ addEventLogger ( _Vue )
40
+
41
+ const instanceOptions = {
42
+ ...options ,
43
+ propsData : {
44
+ ...options . propsData
45
+ }
46
+ }
57
47
58
- const Constructor = ( typeof component === 'function' && component . prototype instanceof Vue ) ? component : vue . extend ( component )
48
+ deleteMountingOptions ( instanceOptions )
59
49
60
- const instanceOptions = { ...options , propsData : { ...options . propsData } }
61
- deleteoptions ( instanceOptions )
62
50
// $FlowIgnore
63
51
const stubComponents = createComponentStubs ( component . components , options . stubs )
64
-
65
52
if ( options . stubs ) {
66
53
instanceOptions . components = {
67
54
...instanceOptions . components ,
@@ -76,60 +63,53 @@ export default function createInstance (
76
63
if ( options . logModifiedComponents ) {
77
64
warn ( `an extended child component ${ c } has been modified to ensure it has the correct instance properties. This means it is not possible to find the component with a component selector. To find the component, you must stub it manually using the stubs mounting option.` )
78
65
}
79
- instanceOptions . components [ c ] = vue . extend ( component . components [ c ] )
66
+ instanceOptions . components [ c ] = _Vue . extend ( component . components [ c ] )
80
67
}
81
68
} )
82
69
83
70
Object . keys ( stubComponents ) . forEach ( c => {
84
- vue . component ( c , stubComponents [ c ] )
71
+ _Vue . component ( c , stubComponents [ c ] )
85
72
} )
86
73
87
- const vm = new Constructor ( instanceOptions )
88
-
89
- // Workaround for Vue < 2.5
90
- vm . _staticTrees = [ ]
74
+ const Constructor = ( typeof component === 'function' && component . prototype instanceof Vue )
75
+ ? component . extend ( instanceOptions )
76
+ : _Vue . extend ( component ) . extend ( instanceOptions )
91
77
92
- addAttrs ( vm , options . attrs )
93
- addListeners ( vm , options . listeners )
78
+ // const Constructor = _Vue.extend(component).extend(instanceOptions)
94
79
95
- if ( options . scopedSlots ) {
96
- if ( window . navigator . userAgent . match ( / P h a n t o m J S / i) ) {
97
- throwError ( 'the scopedSlots option does not support PhantomJS. Please use Puppeteer, or pass a component.' )
98
- }
99
- const vueVersion = Number ( `${ Vue . version . split ( '.' ) [ 0 ] } .${ Vue . version . split ( '.' ) [ 1 ] } ` )
100
- if ( vueVersion >= 2.5 ) {
101
- vm . $_vueTestUtils_scopedSlots = { }
102
- vm . $_vueTestUtils_slotScopes = { }
103
- const renderSlot = vm . _renderProxy . _t
104
-
105
- vm . _renderProxy . _t = function ( name , feedback , props , bindObject ) {
106
- const scopedSlotFn = vm . $_vueTestUtils_scopedSlots [ name ]
107
- const slotScope = vm . $_vueTestUtils_slotScopes [ name ]
108
- if ( scopedSlotFn ) {
109
- props = { ...bindObject , ...props }
110
- const helpers = getVueTemplateCompilerHelpers ( vm . _renderProxy )
111
- let proxy = { ...helpers }
112
- if ( isDestructuringSlotScope ( slotScope ) ) {
113
- proxy = { ...helpers , ...props }
114
- } else {
115
- proxy [ slotScope ] = props
116
- }
117
- return scopedSlotFn . call ( proxy )
118
- } else {
119
- return renderSlot . call ( vm . _renderProxy , name , feedback , props , bindObject )
120
- }
121
- }
80
+ Object . keys ( instanceOptions . components || { } ) . forEach ( key => {
81
+ Constructor . component ( key , instanceOptions . components [ key ] )
82
+ _Vue . component ( key , instanceOptions . components [ key ] )
83
+ } )
122
84
123
- // $FlowIgnore
124
- addScopedSlots ( vm , options . scopedSlots )
125
- } else {
126
- throwError ( 'the scopedSlots option is only supported in [email protected] +.' )
127
- }
85
+ if ( options . slots ) {
86
+ validateSlots ( options . slots )
128
87
}
129
88
130
- if ( options . slots ) {
131
- addSlots ( vm , options . slots )
89
+ // Objects are not resolved in extended components in Vue < 2.5
90
+ // https://github.com/vuejs/vue/issues/6436
91
+ if ( options . provide &&
92
+ typeof options . provide === 'object' &&
93
+ vueVersion < 2.5
94
+ ) {
95
+ const obj = { ...options . provide }
96
+ options . provide = ( ) => obj
132
97
}
133
98
134
- return vm
99
+ const Parent = _Vue . extend ( {
100
+ provide: options . provide ,
101
+ render ( h ) {
102
+ const slots = options . slots
103
+ ? createSlotVNodes ( h , options . slots )
104
+ : undefined
105
+ return h ( Constructor , {
106
+ ref : 'vm' ,
107
+ props : options . propsData ,
108
+ on : options . listeners ,
109
+ attrs : options . attrs
110
+ } , slots )
111
+ }
112
+ } )
113
+
114
+ return new Parent ( )
135
115
}
0 commit comments