Skip to content

Improve passing text to slots #274

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Dec 19, 2017
19 changes: 11 additions & 8 deletions docs/en/api/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,24 @@ expect(wrapper.find('div')).toBe(true)
#### Passing text

You can pass text to `slots`.
There are two limitations to this.
There is a limitation to this.

This works with Vue 2.2+.

This works for the text below.
The text works below.

```js
const wrapper = mount(ComponentWithSlots, { slots: { default: 'foobar' }})
const wrapper1 = mount(ComponentWithSlots, { slots: { default: '1{{ foo }}2' }})
const wrapper2 = mount(ComponentWithSlots, { slots: { default: '<p>1</p>{{ foo }}<p>2</p>' }})
const wrapper3 = mount(ComponentWithSlots, { slots: { default: '<p>1</p>{{ foo }}' }})
const wrapper4 = mount(ComponentWithSlots, { slots: { default: '123' }})
const wrapper5 = mount(ComponentWithSlots, { slots: { default: '1<p>2</p>{{ foo }}3' }})
```

This does not work for the text below.
This does not work for the text below.
When there are some elements, `{{ }}` is required.

```js
const wrapper1 = mount(ComponentWithSlots, { slots: { default: 'foo<span>bar</span>' }})
const wrapper2 = mount(FooComponent, { slots: { default: 'foo {{ bar }}' }})
const wrapper1 = mount(ComponentWithSlots, { slots: { default: '<p>1</p><p>2</p>' }})
const wrapper2 = mount(ComponentWithSlots, { slots: { default: '1<p>2</p>3' }})
```

### `stubs`
Expand Down
17 changes: 9 additions & 8 deletions src/lib/add-slots.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// @flow

import Vue from 'vue'
import { compileToFunctions } from 'vue-template-compiler'
import { throwError } from './util'

Expand All @@ -10,19 +9,21 @@ function isValidSlot (slot: any): boolean {

function addSlotToVm (vm: Component, slotName: string, slotValue: Component | string | Array<Component> | Array<string>): void {
let elem
const vueVersion = Number(`${Vue.version.split('.')[0]}.${Vue.version.split('.')[1]}`)
if (typeof slotValue === 'string') {
if (!compileToFunctions) {
throwError('vueTemplateCompiler is undefined, you must pass components explicitly if vue-template-compiler is undefined')
}
if (slotValue.trim()[0] === '<') {
const domParser = new window.DOMParser()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DOMParser isn't supported in phantomJs, so we need an alternative that will work in phantom

Copy link
Contributor Author

@38elements 38elements Dec 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for reviewing.
Is there a choice not to support PhantomJS ?
IMHO, I think it is better to use Puppeteer.
It is better to introduce Puppeteer at document.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of users still use phantom. We could throw an error, or a warning that phantom doesn't support markup in slots, and handle it gracefully

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for reply.
I will look for other ways.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you change the error message to—option.slots does not support strings PhantomJS. Please use Puppeteer, or pass a component

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am sorry.
I did not notice your comment.
I fixed the error message.

const document = domParser.parseFromString(slotValue, 'text/html')
const _slotValue = slotValue.trim()
if (_slotValue[0] === '<' && _slotValue[_slotValue.length - 1] === '>' && document.body.childElementCount === 1) {
elem = vm.$createElement(compileToFunctions(slotValue))
} else {
if (vueVersion >= 2.2) {
elem = vm._v(slotValue)
} else {
throwError('vue-test-utils support for passing text to slots at [email protected]+')
}
const compiledResult = compileToFunctions(`<div>${slotValue}</div>`)
const _staticRenderFns = vm._renderProxy.$options.staticRenderFns
vm._renderProxy.$options.staticRenderFns = compiledResult.staticRenderFns
elem = compiledResult.render.call(vm._renderProxy, vm.$createElement).children
vm._renderProxy.$options.staticRenderFns = _staticRenderFns
}
} else {
elem = vm.$createElement(slotValue)
Expand Down
7 changes: 6 additions & 1 deletion test/resources/components/component-with-slots.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@

<script>
export default {
name: 'component-with-slots'
name: 'component-with-slots',
data () {
return {
'foo': 'bar'
}
}
}
</script>
29 changes: 12 additions & 17 deletions test/unit/specs/mount/options/slots.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { compileToFunctions } from 'vue-template-compiler'
import { mount } from '~vue-test-utils'
import Component from '~resources/components/component.vue'
import ComponentWithSlots from '~resources/components/component-with-slots.vue'
import { vueVersion } from '~resources/test-utils'

describe('mount.slots', () => {
it('mounts component with default slot if passed component in slot object', () => {
Expand All @@ -27,14 +26,16 @@ describe('mount.slots', () => {
})

it('mounts component with default slot if passed string in slot object', () => {
if (vueVersion >= 2.2) {
const wrapper = mount(ComponentWithSlots, { slots: { default: 'foo' }})
expect(wrapper.find('main').text()).to.equal('foo')
} else {
const message = '[vue-test-utils]: vue-test-utils support for passing text to slots at [email protected]+'
const fn = () => mount(ComponentWithSlots, { slots: { default: 'foo' }})
expect(fn).to.throw().with.property('message', message)
}
const wrapper1 = mount(ComponentWithSlots, { slots: { default: 'foo<span>123</span>{{ foo }}' }})
expect(wrapper1.find('main').html()).to.equal('<main>foo<span>123</span>bar</main>')
const wrapper2 = mount(ComponentWithSlots, { slots: { default: '<p>1</p>{{ foo }}2' }})
expect(wrapper2.find('main').html()).to.equal('<main><p>1</p>bar2</main>')
const wrapper3 = mount(ComponentWithSlots, { slots: { default: '<p>1</p>{{ foo }}<p>2</p>' }})
expect(wrapper3.find('main').html()).to.equal('<main><p>1</p>bar<p>2</p></main>')
const wrapper4 = mount(ComponentWithSlots, { slots: { default: '123' }})
expect(wrapper4.find('main').html()).to.equal('<main>123</main>')
const wrapper5 = mount(ComponentWithSlots, { slots: { default: '1{{ foo }}2' }})
expect(wrapper5.find('main').html()).to.equal('<main>1bar2</main>')
})

it('throws error if passed string in default slot object and vue-template-compiler is undefined', () => {
Expand All @@ -59,14 +60,8 @@ describe('mount.slots', () => {
})

it('mounts component with default slot if passed string in slot text array object', () => {
if (vueVersion >= 2.2) {
const wrapper = mount(ComponentWithSlots, { slots: { default: ['foo', 'bar'] }})
expect(wrapper.find('main').text()).to.equal('foobar')
} else {
const message = '[vue-test-utils]: vue-test-utils support for passing text to slots at [email protected]+'
const fn = () => mount(ComponentWithSlots, { slots: { default: ['foo', 'bar'] }})
expect(fn).to.throw().with.property('message', message)
}
const wrapper = mount(ComponentWithSlots, { slots: { default: ['{{ foo }}<span>1</span>', 'bar'] }})
expect(wrapper.find('main').html()).to.equal('<main>bar<span>1</span>bar</main>')
})

it('throws error if passed string in default slot array vue-template-compiler is undefined', () => {
Expand Down