-
Notifications
You must be signed in to change notification settings - Fork 669
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add scoped slots option (#507)
- Loading branch information
1 parent
fa45baf
commit e6a54b2
Showing
14 changed files
with
208 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ Options for `mount` and `shallow`. The options object can contain both Vue Test | |
|
||
- [`context`](#context) | ||
- [`slots`](#slots) | ||
- [`scopedSlots`](#scopedslots) | ||
- [`stubs`](#stubs) | ||
- [`mocks`](#mocks) | ||
- [`localVue`](#localvue) | ||
|
@@ -66,7 +67,33 @@ You can pass text to `slots`. | |
There is a limitation to this. | ||
|
||
This does not support PhantomJS. | ||
Please use [Puppeteer](https://github.com/karma-runner/karma-chrome-launcher#headless-chromium-with-puppeteer). | ||
You can use [Puppeteer](https://github.com/karma-runner/karma-chrome-launcher#headless-chromium-with-puppeteer) as an alternative. | ||
|
||
### `scopedSlots` | ||
|
||
- type: `{ [name: string]: string }` | ||
|
||
Provide an object of scoped slots contents to the component. The key corresponds to the slot name. The value can be a template string. | ||
|
||
There are three limitations. | ||
|
||
* This option is only supported in [email protected]+. | ||
|
||
* You can not use `<template>` tag as the root element in the `scopedSlots` option. | ||
|
||
* This does not support PhantomJS. | ||
You can use [Puppeteer](https://github.com/karma-runner/karma-chrome-launcher#headless-chromium-with-puppeteer) as an alternative. | ||
|
||
Example: | ||
|
||
```js | ||
const wrapper = shallow(Component, { | ||
scopedSlots: { | ||
foo: '<p slot-scope="props">{{props.index}},{{props.text}}</p>' | ||
} | ||
}) | ||
expect(wrapper.find('#fooWrapper').html()).toBe('<div id="fooWrapper"><p>0,text1</p><p>1,text2</p><p>2,text3</p></div>') | ||
``` | ||
|
||
### `stubs` | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// @flow | ||
|
||
import { compileToFunctions } from 'vue-template-compiler' | ||
import { throwError } from 'shared/util' | ||
|
||
export function addScopedSlots (vm: Component, scopedSlots: Object): void { | ||
Object.keys(scopedSlots).forEach((key) => { | ||
const template = scopedSlots[key].trim() | ||
if (template.substr(0, 9) === '<template') { | ||
throwError('the scopedSlots option does not support a template tag as the root element.') | ||
} | ||
const domParser = new window.DOMParser() | ||
const _document = domParser.parseFromString(template, 'text/html') | ||
vm.$_vueTestUtils_scopedSlots[key] = compileToFunctions(template).render | ||
vm.$_vueTestUtils_slotScopes[key] = _document.body.firstChild.getAttribute('slot-scope') | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
// @flow | ||
|
||
import Vue from 'vue' | ||
import { addSlots } from './add-slots' | ||
import { addScopedSlots } from './add-scoped-slots' | ||
import addMocks from './add-mocks' | ||
import addAttrs from './add-attrs' | ||
import addListeners from './add-listeners' | ||
|
@@ -57,6 +59,40 @@ export default function createInstance ( | |
addAttrs(vm, options.attrs) | ||
addListeners(vm, options.listeners) | ||
|
||
if (options.scopedSlots) { | ||
if (window.navigator.userAgent.match(/PhantomJS/i)) { | ||
throwError('the scopedSlots option does not support PhantomJS. Please use Puppeteer, or pass a component.') | ||
} | ||
const vueVersion = Number(`${Vue.version.split('.')[0]}.${Vue.version.split('.')[1]}`) | ||
if (vueVersion >= 2.5) { | ||
vm.$_vueTestUtils_scopedSlots = {} | ||
vm.$_vueTestUtils_slotScopes = {} | ||
const renderSlot = vm._renderProxy._t | ||
|
||
vm._renderProxy._t = function (name, feedback, props, bindObject) { | ||
const scopedSlotFn = vm.$_vueTestUtils_scopedSlots[name] | ||
const slotScope = vm.$_vueTestUtils_slotScopes[name] | ||
if (scopedSlotFn) { | ||
props = { ...bindObject, ...props } | ||
const proxy = {} | ||
const helpers = ['_c', '_o', '_n', '_s', '_l', '_t', '_q', '_i', '_m', '_f', '_k', '_b', '_v', '_e', '_u', '_g'] | ||
helpers.forEach((key) => { | ||
proxy[key] = vm._renderProxy[key] | ||
}) | ||
proxy[slotScope] = props | ||
return scopedSlotFn.call(proxy) | ||
} else { | ||
return renderSlot.call(vm._renderProxy, name, feedback, props, bindObject) | ||
} | ||
} | ||
|
||
// $FlowIgnore | ||
addScopedSlots(vm, options.scopedSlots) | ||
} else { | ||
throwError('the scopedSlots option is only supported in [email protected]+.') | ||
} | ||
} | ||
|
||
if (options.slots) { | ||
addSlots(vm, options.slots) | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<template> | ||
<div> | ||
<div id="foo"> | ||
<slot name="foo" | ||
v-for="(item, index) in foo" | ||
:text="item.text" | ||
:index="index"> | ||
</slot> | ||
</div> | ||
<div id="bar"> | ||
<slot name="bar" | ||
v-for="(item, index) in bar" | ||
:text="item.text" | ||
:index="index"> | ||
</slot> | ||
</div> | ||
<div id="slots"> | ||
<slot></slot> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script> | ||
export default { | ||
name: 'component-with-scoped-slots', | ||
data () { | ||
return { | ||
foo: [{ text: 'a1' }, { text: 'a2' }, { text: 'a3' }], | ||
bar: [{ text: 'A1' }, { text: 'A2' }, { text: 'A3' }] | ||
} | ||
} | ||
} | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { describeWithShallowAndMount, vueVersion, itDoNotRunIf } from '~resources/utils' | ||
import ComponentWithScopedSlots from '~resources/components/component-with-scoped-slots.vue' | ||
|
||
describeWithShallowAndMount('scopedSlots', (mountingMethod) => { | ||
let _window | ||
|
||
beforeEach(() => { | ||
_window = window | ||
}) | ||
|
||
afterEach(() => { | ||
if (!window.navigator.userAgent.match(/Chrome/i)) { | ||
window = _window // eslint-disable-line no-native-reassign | ||
} | ||
}) | ||
|
||
itDoNotRunIf(vueVersion < 2.5, | ||
'mounts component scoped slots', () => { | ||
const wrapper = mountingMethod(ComponentWithScopedSlots, { | ||
slots: { default: '<span>123</span>' }, | ||
scopedSlots: { | ||
'foo': '<p slot-scope="foo">{{foo.index}},{{foo.text}}</p>', | ||
'bar': '<p slot-scope="bar">{{bar.text}},{{bar.index}}</p>' | ||
} | ||
}) | ||
expect(wrapper.find('#slots').html()).to.equal('<div id="slots"><span>123</span></div>') | ||
expect(wrapper.find('#foo').html()).to.equal('<div id="foo"><p>0,a1</p><p>1,a2</p><p>2,a3</p></div>') | ||
expect(wrapper.find('#bar').html()).to.equal('<div id="bar"><p>A1,0</p><p>A2,1</p><p>A3,2</p></div>') | ||
wrapper.vm.foo = [{ text: 'b1' }, { text: 'b2' }, { text: 'b3' }] | ||
wrapper.vm.bar = [{ text: 'B1' }, { text: 'B2' }, { text: 'B3' }] | ||
expect(wrapper.find('#foo').html()).to.equal('<div id="foo"><p>0,b1</p><p>1,b2</p><p>2,b3</p></div>') | ||
expect(wrapper.find('#bar').html()).to.equal('<div id="bar"><p>B1,0</p><p>B2,1</p><p>B3,2</p></div>') | ||
} | ||
) | ||
|
||
itDoNotRunIf(vueVersion < 2.5, | ||
'throws exception when it is seted to a template tag at top', () => { | ||
const fn = () => { | ||
mountingMethod(ComponentWithScopedSlots, { | ||
scopedSlots: { | ||
'foo': '<template></template>' | ||
} | ||
}) | ||
} | ||
const message = '[vue-test-utils]: the scopedSlots option does not support a template tag as the root element.' | ||
expect(fn).to.throw().with.property('message', message) | ||
} | ||
) | ||
|
||
itDoNotRunIf(vueVersion >= 2.5, | ||
'throws exception when vue version < 2.5', () => { | ||
const fn = () => { | ||
mountingMethod(ComponentWithScopedSlots, { | ||
scopedSlots: { | ||
'foo': '<p slot-scope="foo">{{foo.index}},{{foo.text}}</p>' | ||
} | ||
}) | ||
} | ||
const message = '[vue-test-utils]: the scopedSlots option is only supported in [email protected]+.' | ||
expect(fn).to.throw().with.property('message', message) | ||
} | ||
) | ||
|
||
itDoNotRunIf(vueVersion < 2.5, | ||
'throws exception when using PhantomJS', () => { | ||
if (window.navigator.userAgent.match(/Chrome/i)) { | ||
return | ||
} | ||
window = { navigator: { userAgent: 'PhantomJS' }} // eslint-disable-line no-native-reassign | ||
const fn = () => { | ||
mountingMethod(ComponentWithScopedSlots, { | ||
scopedSlots: { | ||
'foo': '<p slot-scope="foo">{{foo.index}},{{foo.text}}</p>' | ||
} | ||
}) | ||
} | ||
const message = '[vue-test-utils]: the scopedSlots option does not support PhantomJS. Please use Puppeteer, or pass a component.' | ||
expect(fn).to.throw().with.property('message', message) | ||
} | ||
) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters