-
Notifications
You must be signed in to change notification settings - Fork 668
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
Changes from 13 commits
e397ef2
76f14f6
99c0f7a
dec437c
912fbe1
3bd9da6
3c3abf8
c3750a8
66ecd96
3b99090
a07c622
192c5ac
2302443
d2a5d65
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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' | ||
|
||
|
@@ -10,27 +9,40 @@ 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] === '<') { | ||
if (window.navigator.userAgent.match(/PhantomJS/i)) { | ||
throwError('option.slots does not support strings PhantomJS. Please use Puppeteer, or pass a component') | ||
} | ||
const domParser = new window.DOMParser() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for reviewing. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for reply. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you change the error message to— There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am sorry. |
||
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) | ||
} | ||
if (Array.isArray(vm.$slots[slotName])) { | ||
vm.$slots[slotName].push(elem) | ||
if (Array.isArray(elem)) { | ||
if (Array.isArray(vm.$slots[slotName])) { | ||
vm.$slots[slotName] = [...vm.$slots[slotName], ...elem] | ||
} else { | ||
vm.$slots[slotName] = [...elem] | ||
} | ||
} else { | ||
vm.$slots[slotName] = [elem] | ||
if (Array.isArray(vm.$slots[slotName])) { | ||
vm.$slots[slotName].push(elem) | ||
} else { | ||
vm.$slots[slotName] = [elem] | ||
} | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,9 +2,20 @@ 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', () => { | ||
let _window | ||
|
||
beforeEach(() => { | ||
_window = window | ||
}) | ||
|
||
afterEach(() => { | ||
if (!window.navigator.userAgent.match(/Chrome/i)) { | ||
window = _window // eslint-disable-line no-native-reassign | ||
} | ||
}) | ||
|
||
it('mounts component with default slot if passed component in slot object', () => { | ||
const wrapper = mount(ComponentWithSlots, { slots: { default: Component }}) | ||
expect(wrapper.contains(Component)).to.equal(true) | ||
|
@@ -26,15 +37,33 @@ describe('mount.slots', () => { | |
expect(wrapper.contains('span')).to.equal(true) | ||
}) | ||
|
||
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) | ||
it('throws error if the UserAgent is PhantomJS when passed string is in slot object', () => { | ||
if (window.navigator.userAgent.match(/Chrome/i)) { | ||
return | ||
} | ||
window = { navigator: { userAgent: 'PhantomJS' }} // eslint-disable-line no-native-reassign | ||
const message = '[vue-test-utils]: option.slots does not support strings PhantomJS. Please use Puppeteer, or pass a component' | ||
const fn = () => mount(ComponentWithSlots, { slots: { default: 'foo' }}) | ||
expect(fn).to.throw().with.property('message', message) | ||
}) | ||
|
||
it('mounts component with default slot if passed string in slot object', () => { | ||
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>') | ||
wrapper5.trigger('keydown') | ||
expect(wrapper5.find('main').html()).to.equal('<main>1BAR2</main>') | ||
const wrapper6 = mount(ComponentWithSlots, { slots: { default: '<p>1</p><p>2</p>' }}) | ||
expect(wrapper6.find('main').html()).to.equal('<main><p>1</p><p>2</p></main>') | ||
const wrapper7 = mount(ComponentWithSlots, { slots: { default: '1<p>2</p>3' }}) | ||
expect(wrapper7.find('main').html()).to.equal('<main>1<p>2</p>3</main>') | ||
}) | ||
|
||
it('throws error if passed string in default slot object and vue-template-compiler is undefined', () => { | ||
|
@@ -59,14 +88,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', () => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed it.