Skip to content

Commit 032513c

Browse files
committed
fix props
1 parent 4678bfb commit 032513c

File tree

7 files changed

+76
-15
lines changed

7 files changed

+76
-15
lines changed

docs/en/api/options.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,15 @@ Please use [Puppeteer](https://github.com/karma-runner/karma-chrome-launcher#hea
7575

7676
Provide an object of scoped slots contents to the component. The key corresponds to the slot name. The value can be a template string.
7777

78-
There are two limitations.
78+
There are three limitations.
7979

8080
* This option is only supported in [email protected]+.
8181

8282
* You can not use `<template>` tag as the root element in the `scopedSlots` option.
8383

84+
* This does not support PhantomJS.
85+
Please use [Puppeteer](https://github.com/karma-runner/karma-chrome-launcher#headless-chromium-with-puppeteer).
86+
8487
Example:
8588

8689
```js

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ export function addScopedSlots (vm: Component, scopedSlots: Object): void {
99
if (template.substr(0, 9) === '<template') {
1010
throwError('the scopedSlots option does not support a template tag as the root element.')
1111
}
12+
const domParser = new window.DOMParser()
13+
const document = domParser.parseFromString(template, 'text/html')
1214
vm.$_vueTestUtils_scopedSlots[key] = compileToFunctions(template).render
15+
vm.$_vueTestUtils_slotScopes[key] = document.body.firstChild.getAttribute('slot-scope')
1316
})
1417
}

packages/create-instance/add-slots.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ function addSlotToVm (vm: Component, slotName: string, slotValue: Component | st
1111
throwError('vueTemplateCompiler is undefined, you must pass components explicitly if vue-template-compiler is undefined')
1212
}
1313
if (window.navigator.userAgent.match(/PhantomJS/i)) {
14-
throwError('option.slots does not support strings in PhantomJS. Please use Puppeteer, or pass a component')
14+
throwError('the slots option does not support strings in PhantomJS. Please use Puppeteer, or pass a component.')
1515
}
1616
const domParser = new window.DOMParser()
1717
const document = domParser.parseFromString(slotValue, 'text/html')

packages/create-instance/create-instance.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,20 +60,33 @@ export default function createInstance (
6060
addListeners(vm, options.listeners)
6161

6262
if (options.scopedSlots) {
63+
if (window.navigator.userAgent.match(/PhantomJS/i)) {
64+
throwError('the scopedSlots option does not support strings in PhantomJS. Please use Puppeteer, or pass a component.')
65+
}
6366
const vueVersion = Number(`${Vue.version.split('.')[0]}.${Vue.version.split('.')[1]}`)
6467
if (vueVersion >= 2.5) {
6568
vm.$_vueTestUtils_scopedSlots = {}
69+
vm.$_vueTestUtils_slotScopes = {}
6670
const renderSlot = vm._renderProxy._t
71+
6772
vm._renderProxy._t = function (name, feedback, props, bindObject) {
6873
const scopedSlotFn = vm.$_vueTestUtils_scopedSlots[name]
74+
const slotScope = vm.$_vueTestUtils_slotScopes[name]
6975
if (scopedSlotFn) {
7076
props = { ...bindObject, ...props }
71-
vm._renderProxy.props = props
72-
return scopedSlotFn.call(vm._renderProxy)
77+
const proxy = {}
78+
Object.keys(vm._renderProxy).concat(Object.keys(Vue.prototype)).forEach((key) => {
79+
if (key[0] === '_') {
80+
proxy[key] = vm._renderProxy[key]
81+
}
82+
})
83+
proxy[slotScope] = props
84+
return scopedSlotFn.call(proxy)
7385
} else {
7486
return renderSlot.call(vm._renderProxy, name, feedback, props, bindObject)
7587
}
7688
}
89+
7790
// $FlowIgnore
7891
addScopedSlots(vm, options.scopedSlots)
7992
} else {

test/resources/components/component-with-scoped-slots.vue

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
<template>
22
<div>
3-
<div id="scopedSlots">
4-
<slot name="item"
5-
v-for="(item, index) in items"
3+
<div id="foo">
4+
<slot name="foo"
5+
v-for="(item, index) in foo"
6+
:text="item.text"
7+
:index="index">
8+
</slot>
9+
</div>
10+
<div id="bar">
11+
<slot name="bar"
12+
v-for="(item, index) in bar"
613
:text="item.text"
714
:index="index">
815
</slot>
@@ -18,7 +25,8 @@
1825
name: 'component-with-scoped-slots',
1926
data () {
2027
return {
21-
items: [{ text: 'a1' }, { text: 'a2' }, { text: 'a3' }]
28+
foo: [{ text: 'a1' }, { text: 'a2' }, { text: 'a3' }],
29+
bar: [{ text: 'A1' }, { text: 'A2' }, { text: 'A3' }]
2230
}
2331
}
2432
}

test/specs/mounting-options/scopedSlots.spec.js

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,34 @@ import { describeWithShallowAndMount, vueVersion, itDoNotRunIf } from '~resource
22
import ComponentWithScopedSlots from '~resources/components/component-with-scoped-slots.vue'
33

44
describeWithShallowAndMount('scopedSlots', (mountingMethod) => {
5+
let _window
6+
7+
beforeEach(() => {
8+
_window = window
9+
})
10+
11+
afterEach(() => {
12+
if (!window.navigator.userAgent.match(/Chrome/i)) {
13+
window = _window // eslint-disable-line no-native-reassign
14+
}
15+
})
16+
517
itDoNotRunIf(vueVersion < 2.5,
618
'mounts component scoped slots', () => {
719
const wrapper = mountingMethod(ComponentWithScopedSlots, {
820
slots: { default: '<span>123</span>' },
921
scopedSlots: {
10-
'item': '<p slot-scope="props">{{props.index}},{{props.text}}</p>'
22+
'foo': '<p slot-scope="foo">{{foo.index}},{{foo.text}}</p>',
23+
'bar': '<p slot-scope="bar">{{bar.text}},{{bar.index}}</p>'
1124
}
1225
})
1326
expect(wrapper.find('#slots').html()).to.equal('<div id="slots"><span>123</span></div>')
14-
expect(wrapper.find('#scopedSlots').html()).to.equal('<div id="scopedSlots"><p>0,a1</p><p>1,a2</p><p>2,a3</p></div>')
15-
wrapper.vm.items = [{ text: 'b1' }, { text: 'b2' }, { text: 'b3' }]
16-
expect(wrapper.find('#scopedSlots').html()).to.equal('<div id="scopedSlots"><p>0,b1</p><p>1,b2</p><p>2,b3</p></div>')
27+
expect(wrapper.find('#foo').html()).to.equal('<div id="foo"><p>0,a1</p><p>1,a2</p><p>2,a3</p></div>')
28+
expect(wrapper.find('#bar').html()).to.equal('<div id="bar"><p>A1,0</p><p>A2,1</p><p>A3,2</p></div>')
29+
wrapper.vm.foo = [{ text: 'b1' }, { text: 'b2' }, { text: 'b3' }]
30+
wrapper.vm.bar = [{ text: 'B1' }, { text: 'B2' }, { text: 'B3' }]
31+
expect(wrapper.find('#foo').html()).to.equal('<div id="foo"><p>0,b1</p><p>1,b2</p><p>2,b3</p></div>')
32+
expect(wrapper.find('#bar').html()).to.equal('<div id="bar"><p>B1,0</p><p>B2,1</p><p>B3,2</p></div>')
1733
}
1834
)
1935

@@ -22,7 +38,7 @@ describeWithShallowAndMount('scopedSlots', (mountingMethod) => {
2238
const fn = () => {
2339
mountingMethod(ComponentWithScopedSlots, {
2440
scopedSlots: {
25-
'item': '<template></template>'
41+
'foo': '<template></template>'
2642
}
2743
})
2844
}
@@ -36,12 +52,30 @@ describeWithShallowAndMount('scopedSlots', (mountingMethod) => {
3652
const fn = () => {
3753
mountingMethod(ComponentWithScopedSlots, {
3854
scopedSlots: {
39-
'item': '<p slot="item" slot-scope="props">{{props.index}},{{props.text}}</p>'
55+
'foo': '<p slot-scope="foo">{{foo.index}},{{foo.text}}</p>'
4056
}
4157
})
4258
}
4359
const message = '[vue-test-utils]: the scopedSlots option is only supported in [email protected]+.'
4460
expect(fn).to.throw().with.property('message', message)
4561
}
4662
)
63+
64+
itDoNotRunIf(!window.navigator.userAgent.match(/PhantomJS/i),
65+
'throws exception when using PhantomJS', () => {
66+
if (window.navigator.userAgent.match(/Chrome/i)) {
67+
return
68+
}
69+
window = { navigator: { userAgent: 'PhantomJS' }} // eslint-disable-line no-native-reassign
70+
const fn = () => {
71+
mountingMethod(ComponentWithScopedSlots, {
72+
scopedSlots: {
73+
'foo': '<p slot-scope="foo">{{foo.index}},{{foo.text}}</p>'
74+
}
75+
})
76+
}
77+
const message = '[vue-test-utils]: the scopedSlots option does not support strings in PhantomJS. Please use Puppeteer, or pass a component.'
78+
expect(fn).to.throw().with.property('message', message)
79+
}
80+
)
4781
})

test/specs/mounting-options/slots.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ describeWithMountingMethods('options.slots', (mountingMethod) => {
7676
return
7777
}
7878
window = { navigator: { userAgent: 'PhantomJS' }} // eslint-disable-line no-native-reassign
79-
const message = '[vue-test-utils]: option.slots does not support strings in PhantomJS. Please use Puppeteer, or pass a component'
79+
const message = '[vue-test-utils]: the slots option does not support strings in PhantomJS. Please use Puppeteer, or pass a component.'
8080
const fn = () => mountingMethod(ComponentWithSlots, { slots: { default: 'foo' }})
8181
expect(fn).to.throw().with.property('message', message)
8282
})

0 commit comments

Comments
 (0)