diff --git a/docs/en/api/options.md b/docs/en/api/options.md index d93a0ee2b..67739ca07 100644 --- a/docs/en/api/options.md +++ b/docs/en/api/options.md @@ -64,22 +64,10 @@ 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. - -```js -const wrapper = mount(ComponentWithSlots, { slots: { default: 'foobar' }}) -``` - -This does not work for the text below. - -```js -const wrapper1 = mount(ComponentWithSlots, { slots: { default: 'foobar' }}) -const wrapper2 = mount(FooComponent, { slots: { default: 'foo {{ bar }}' }}) -``` +This does not support PhantomJS. +Please use [Puppeteer](https://github.com/karma-runner/karma-chrome-launcher#headless-chromium-with-puppeteer). ### `stubs` diff --git a/src/lib/add-slots.js b/src/lib/add-slots.js index 536b8de02..d0583d640 100644 --- a/src/lib/add-slots.js +++ b/src/lib/add-slots.js @@ -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 | Array): 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 in PhantomJS. Please use Puppeteer, or pass a component') + } + const domParser = new window.DOMParser() + 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 vue@2.2+') - } + const compiledResult = compileToFunctions(`
${slotValue}{{ }}
`) + 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] + } } } diff --git a/src/lib/create-instance.js b/src/lib/create-instance.js index 993b7b921..03a316424 100644 --- a/src/lib/create-instance.js +++ b/src/lib/create-instance.js @@ -13,6 +13,7 @@ import createLocalVue from '../create-local-vue' import extractOptions from '../options/extract-options' import deleteMountingOptions from '../options/delete-mounting-options' import createFunctionalComponent from './create-functional-component' +import cloneDeep from 'lodash/cloneDeep' export default function createConstructor ( component: Component, @@ -58,6 +59,9 @@ export default function createConstructor ( addAttrs(vm, mountingOptions.attrs) addListeners(vm, mountingOptions.listeners) + vm.$_mountingOptionsSlots = mountingOptions.slots + vm.$_originalSlots = cloneDeep(vm.$slots) + if (mountingOptions.slots) { addSlots(vm, mountingOptions.slots) } diff --git a/src/wrappers/vue-wrapper.js b/src/wrappers/vue-wrapper.js index 8e853bf4b..7c7b14af5 100644 --- a/src/wrappers/vue-wrapper.js +++ b/src/wrappers/vue-wrapper.js @@ -1,9 +1,19 @@ // @flow import Wrapper from './wrapper' +import addSlots from '../lib/add-slots' +import cloneDeep from 'lodash/cloneDeep' function update () { - this._update(this._render()) + // the only component made by mount() + if (this.$_originalSlots) { + this.$slots = cloneDeep(this.$_originalSlots) + } + if (this.$_mountingOptionsSlots) { + addSlots(this, this.$_mountingOptionsSlots) + } + const vnodes = this._render() + this._update(vnodes) this.$children.forEach(child => update.call(child)) } diff --git a/test/resources/components/component-with-slots.vue b/test/resources/components/component-with-slots.vue index c2134d3a3..ec2585bd0 100644 --- a/test/resources/components/component-with-slots.vue +++ b/test/resources/components/component-with-slots.vue @@ -1,5 +1,5 @@