Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0ab5a75

Browse filesBrowse files
authored
feat: add parent in create-instance (vuejs#586)
breaking change: removes templates from slots
1 parent 6a40f8a commit 0ab5a75
Copy full SHA for 0ab5a75
Expand file treeCollapse file tree

38 files changed

+290
-550
lines changed

‎flow/options.flow.js

Copy file name to clipboardExpand all lines: flow/options.flow.js
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,10 @@ declare type Options = { // eslint-disable-line no-undef
1111
context?: Object,
1212
attrs?: Object,
1313
listeners?: Object,
14-
logModifiedComponents?: Boolean
14+
logModifiedComponents?: boolean,
15+
sync?: boolean
1516
}
17+
18+
declare type SlotValue = Component | string | Array<Component | string>
19+
20+
declare type SlotsObject = {[name: string]: SlotValue}

‎flow/vue.flow.js

Copy file name to clipboardExpand all lines: flow/vue.flow.js
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,3 @@
44

55
declare type Component = Object | Function // eslint-disable-line no-undef
66
declare type VNode = Object // eslint-disable-line no-undef
7-
declare type SlotValue = Component | string | Array<Component> | Array<string>

‎flow/wrapper.flow.js

Copy file name to clipboardExpand all lines: flow/wrapper.flow.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,5 @@ declare interface BaseWrapper { // eslint-disable-line no-undef
3939

4040
declare type WrapperOptions = { // eslint-disable-line no-undef
4141
attachedToDocument: boolean,
42-
sync: boolean
42+
sync?: boolean
4343
}

‎package.json

Copy file name to clipboardExpand all lines: package.json
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@
6363
"rollup": "^0.58.2",
6464
"sinon": "^2.3.2",
6565
"sinon-chai": "^2.10.0",
66-
"vue": "2.5.13",
66+
"vue": "^2.5.16",
6767
"vue-class-component": "^6.1.2",
6868
"vue-loader": "^13.6.2",
6969
"vue-router": "^3.0.1",
70-
"vue-server-renderer": "2.5.13",
71-
"vue-template-compiler": "2.5.13",
70+
"vue-server-renderer": "^2.5.16",
71+
"vue-template-compiler": "^2.5.16",
7272
"vuepress": "^0.10.0",
7373
"vuepress-theme-vue": "^1.0.3",
7474
"vuetify": "^0.16.9",

‎packages/create-instance/add-attrs.js

Copy file name to clipboardExpand all lines: packages/create-instance/add-attrs.js
-12Lines changed: 0 additions & 12 deletions
This file was deleted.

‎packages/create-instance/add-listeners.js

Copy file name to clipboardExpand all lines: packages/create-instance/add-listeners.js
-12Lines changed: 0 additions & 12 deletions
This file was deleted.

‎packages/create-instance/add-provide.js

Copy file name to clipboardExpand all lines: packages/create-instance/add-provide.js
-13Lines changed: 0 additions & 13 deletions
This file was deleted.

‎packages/create-instance/add-scoped-slots.js

Copy file name to clipboardExpand all lines: packages/create-instance/add-scoped-slots.js
-17Lines changed: 0 additions & 17 deletions
This file was deleted.

‎packages/create-instance/add-slots.js

Copy file name to clipboard
+24-50Lines changed: 24 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,34 @@
11
// @flow
22

33
import { compileToFunctions } from 'vue-template-compiler'
4-
import { throwError } from 'shared/util'
5-
import { validateSlots } from './validate-slots'
64

7-
// see https://github.com/vuejs/vue-test-utils/pull/274
8-
function createVNodes (vm: Component, slotValue: string) {
9-
const compiledResult = compileToFunctions(`<div>${slotValue}{{ }}</div>`)
10-
const _staticRenderFns = vm._renderProxy.$options.staticRenderFns
11-
vm._renderProxy.$options.staticRenderFns = compiledResult.staticRenderFns
12-
const elem = compiledResult.render.call(vm._renderProxy, vm.$createElement).children
13-
vm._renderProxy.$options.staticRenderFns = _staticRenderFns
14-
return elem
15-
}
16-
17-
function validateEnvironment (): void {
18-
if (!compileToFunctions) {
19-
throwError('vueTemplateCompiler is undefined, you must pass components explicitly if vue-template-compiler is undefined')
20-
}
21-
if (typeof window === 'undefined') {
22-
throwError('the slots string option does not support strings in server-test-uitls.')
23-
}
24-
}
5+
function createVNodesForSlot (
6+
h: Function,
7+
slotValue: SlotValue,
8+
name: string
9+
): Array<VNode> {
10+
const el = typeof slotValue === 'string'
11+
? compileToFunctions(slotValue)
12+
: slotValue
2513

26-
function addSlotToVm (vm: Component, slotName: string, slotValue: SlotValue): void {
27-
let elem
28-
if (typeof slotValue === 'string') {
29-
validateEnvironment()
30-
elem = createVNodes(vm, slotValue)
31-
} else {
32-
elem = vm.$createElement(slotValue)
33-
}
34-
if (Array.isArray(elem)) {
35-
if (Array.isArray(vm.$slots[slotName])) {
36-
vm.$slots[slotName] = [...vm.$slots[slotName], ...elem]
37-
} else {
38-
vm.$slots[slotName] = [...elem]
39-
}
40-
} else {
41-
if (Array.isArray(vm.$slots[slotName])) {
42-
vm.$slots[slotName].push(elem)
43-
} else {
44-
vm.$slots[slotName] = [elem]
45-
}
46-
}
14+
const vnode = h(el)
15+
vnode.data.slot = name
16+
return vnode
4717
}
4818

49-
export function addSlots (vm: Component, slots: Object): void {
50-
validateSlots(slots)
51-
Object.keys(slots).forEach((key) => {
52-
if (Array.isArray(slots[key])) {
53-
slots[key].forEach((slotValue) => {
54-
addSlotToVm(vm, key, slotValue)
55-
})
19+
export function createSlotVNodes (
20+
h: Function,
21+
slots: SlotsObject
22+
): Array<VNode> {
23+
return Object.keys(slots).reduce((acc, key) => {
24+
const content = slots[key]
25+
if (Array.isArray(content)) {
26+
const nodes = content.reduce((accInner, slotDef) => {
27+
return accInner.concat(createVNodesForSlot(h, slotDef, key))
28+
}, [])
29+
return acc.concat(nodes)
5630
} else {
57-
addSlotToVm(vm, key, slots[key])
31+
return acc.concat(createVNodesForSlot(h, content, key))
5832
}
59-
})
33+
}, [])
6034
}
+55-75Lines changed: 55 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,29 @@
11
// @flow
22

33
import Vue from 'vue'
4-
import { addSlots } from './add-slots'
5-
import { addScopedSlots } from './add-scoped-slots'
4+
import { createSlotVNodes } from './add-slots'
65
import addMocks from './add-mocks'
7-
import addAttrs from './add-attrs'
8-
import addListeners from './add-listeners'
9-
import addProvide from './add-provide'
106
import { addEventLogger } from './log-events'
117
import { createComponentStubs } from 'shared/stub-components'
12-
import { throwError, warn } from 'shared/util'
8+
import { throwError, warn, vueVersion } from 'shared/util'
139
import { compileTemplate } from 'shared/compile-template'
14-
import deleteoptions from './delete-mounting-options'
10+
import deleteMountingOptions from './delete-mounting-options'
1511
import createFunctionalComponent from './create-functional-component'
1612
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'
3014

3115
export 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(/PhantomJS/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
}

‎packages/create-instance/delete-mounting-options.js

Copy file name to clipboardExpand all lines: packages/create-instance/delete-mounting-options.js
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export default function deleteMountingOptions (options) {
88
delete options.clone
99
delete options.attrs
1010
delete options.listeners
11+
delete options.propsData
1112
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.