11// @flow
22
33import Vue from 'vue'
4- import { addSlots } from './add-slots'
5- import { addScopedSlots } from './add-scoped-slots'
4+ import { createSlotVNodes } from './add-slots'
65import addMocks from './add-mocks'
7- import addAttrs from './add-attrs'
8- import addListeners from './add-listeners'
9- import addProvide from './add-provide'
106import { addEventLogger } from './log-events'
117import { createComponentStubs } from 'shared/stub-components'
12- import { throwError , warn } from 'shared/util'
8+ import { throwError , warn , vueVersion } from 'shared/util'
139import { compileTemplate } from 'shared/compile-template'
14- import deleteoptions from './delete-mounting-options'
10+ import deleteMountingOptions from './delete-mounting-options'
1511import createFunctionalComponent from './create-functional-component'
1612import { 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'
3014
3115export default function createInstance (
3216 component : Component ,
3317 options : Options ,
34- vue : Component
18+ _Vue : Component ,
19+ elm ?: Element
3520) : Component {
21+ // Remove cached constructor
22+ delete component . _Ctor
23+
3624 if ( options . mocks ) {
37- addMocks ( options . mocks , vue )
25+ addMocks ( options . mocks , _Vue )
3826 }
39-
4027 if ( ( component . options && component . options . functional ) || component . functional ) {
4128 component = createFunctionalComponent ( component , options )
4229 } else if ( options . context ) {
@@ -45,23 +32,23 @@ export default function createInstance (
4532 )
4633 }
4734
48- if ( options . provide ) {
49- addProvide ( component , options . provide , options )
50- }
51-
5235 if ( componentNeedsCompiling ( component ) ) {
5336 compileTemplate ( component )
5437 }
5538
56- addEventLogger ( vue )
39+ addEventLogger ( _Vue )
40+
41+ const instanceOptions = {
42+ ...options ,
43+ propsData : {
44+ ...options . propsData
45+ }
46+ }
5747
58- const Constructor = ( typeof component === 'function' && component . prototype instanceof Vue ) ? component : vue . extend ( component )
48+ deleteMountingOptions ( instanceOptions )
5949
60- const instanceOptions = { ...options , propsData : { ...options . propsData } }
61- deleteoptions ( instanceOptions )
6250 // $FlowIgnore
6351 const stubComponents = createComponentStubs ( component . components , options . stubs )
64-
6552 if ( options . stubs ) {
6653 instanceOptions . components = {
6754 ...instanceOptions . components ,
@@ -76,60 +63,53 @@ export default function createInstance (
7663 if ( options . logModifiedComponents ) {
7764 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.` )
7865 }
79- instanceOptions . components [ c ] = vue . extend ( component . components [ c ] )
66+ instanceOptions . components [ c ] = _Vue . extend ( component . components [ c ] )
8067 }
8168 } )
8269
8370 Object . keys ( stubComponents ) . forEach ( c => {
84- vue . component ( c , stubComponents [ c ] )
71+ _Vue . component ( c , stubComponents [ c ] )
8572 } )
8673
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 )
9177
92- addAttrs ( vm , options . attrs )
93- addListeners ( vm , options . listeners )
78+ // const Constructor = _Vue.extend(component).extend(instanceOptions)
9479
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+ } )
12284
123- // $FlowIgnore
124- addScopedSlots ( vm , options . scopedSlots )
125- } else {
126- throwError ( 'the scopedSlots option is only supported in vue@2.5+.' )
127- }
85+ if ( options . slots ) {
86+ validateSlots ( options . slots )
12887 }
12988
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
13297 }
13398
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 ( )
135115}
0 commit comments