From 10490d711ba462856a4efb7390730b004d4e2eec Mon Sep 17 00:00:00 2001 From: 38elements Date: Fri, 4 May 2018 17:21:42 +0900 Subject: [PATCH 01/11] Revert "refactor: refactor stub-components.js (#544)" This reverts commit db5e07edc31f0a77280e435b492bbd3ddcbf73f4. --- packages/shared/compile-template.js | 15 +- packages/shared/stub-components-validate.js | 44 ----- packages/shared/stub-components.js | 183 +++++++++++++++----- packages/test-utils/src/shallow.js | 10 +- 4 files changed, 154 insertions(+), 98 deletions(-) delete mode 100644 packages/shared/stub-components-validate.js diff --git a/packages/shared/compile-template.js b/packages/shared/compile-template.js index 530a24dde..b449bffbc 100644 --- a/packages/shared/compile-template.js +++ b/packages/shared/compile-template.js @@ -3,13 +3,14 @@ import { compileToFunctions } from 'vue-template-compiler' export function compileTemplate (component: Component) { - Object.keys(component.components || {}).forEach((c) => { - const cmp = component.components[c] - if (!cmp.render) { - compileTemplate(cmp) - } - }) - + if (component.components) { + Object.keys(component.components).forEach((c) => { + const cmp = component.components[c] + if (!cmp.render) { + compileTemplate(cmp) + } + }) + } if (component.extends) { compileTemplate(component.extends) } diff --git a/packages/shared/stub-components-validate.js b/packages/shared/stub-components-validate.js deleted file mode 100644 index 81d49b6de..000000000 --- a/packages/shared/stub-components-validate.js +++ /dev/null @@ -1,44 +0,0 @@ -// @flow - -import { throwError } from './util' -import { compileToFunctions } from 'vue-template-compiler' - -export function validateStubOptions (stubOptions: Array | Object) { - if (Array.isArray(stubOptions)) { - if (containsNonStringItem(stubOptions)) { - throwError('each item in an options.stubs array must be a string') - } - } else { - if (containsInvalidOptions(stubOptions)) { - throwError('options.stub values must be passed a string or component') - } - - if (necessaryCompileToFunctionsMissed(stubOptions)) { - throwError('vueTemplateCompiler is undefined, you must pass components explicitly if vue-template-compiler is undefined') - } - } -} - -function containsNonStringItem (array: Array): boolean { - return array.some(name => typeof name !== 'string') -} - -function necessaryCompileToFunctionsMissed (stubOptions: Object): boolean { - return Object.keys(stubOptions) - .map(key => stubOptions[key]) - .some(stub => typeof stub === 'string') && !compileToFunctions -} - -function containsInvalidOptions (stubOptions: Object): boolean { - return Object.keys(stubOptions) - .map(key => stubOptions[key]) - .some(isInvalidStubOption) -} - -function isInvalidStubOption (stub): boolean { - return !['string', 'boolean'].includes(typeof stub) && !isVueComponent(stub) -} - -function isVueComponent (cmp) { - return cmp && (cmp.render || cmp.template || cmp.options) -} diff --git a/packages/shared/stub-components.js b/packages/shared/stub-components.js index ebf305f14..fda90dc37 100644 --- a/packages/shared/stub-components.js +++ b/packages/shared/stub-components.js @@ -1,12 +1,28 @@ // @flow +import Vue from 'vue' import { compileToFunctions } from 'vue-template-compiler' -import { validateStubOptions } from 'shared/stub-components-validate' -import { componentNeedsCompiling } from 'shared/validators' -import { compileTemplate } from 'shared/compile-template' +import { throwError } from './util' +import { componentNeedsCompiling } from './validators' +import { compileTemplate } from './compile-template' +import { capitalize, camelize, hyphenate } from './util' + +function isVueComponent (comp) { + return comp && (comp.render || comp.template || comp.options) +} + +function isValidStub (stub: any) { + return !!stub && + typeof stub === 'string' || + (stub === true) || + (isVueComponent(stub)) +} + +function isRequiredComponent (name) { + return name === 'KeepAlive' || name === 'Transition' || name === 'TransitionGroup' +} function getCoreProperties (component: Component): Object { - if (!component) return {} return { attrs: component.attrs, name: component.name, @@ -24,68 +40,147 @@ function getCoreProperties (component: Component): Object { functional: component.functional } } +function createStubFromString (templateString: string, originalComponent: Component): Object { + if (!compileToFunctions) { + throwError('vueTemplateCompiler is undefined, you must pass components explicitly if vue-template-compiler is undefined') + } + + if (templateString.indexOf(hyphenate(originalComponent.name)) !== -1 || + templateString.indexOf(capitalize(originalComponent.name)) !== -1 || + templateString.indexOf(camelize(originalComponent.name)) !== -1) { + throwError('options.stub cannot contain a circular reference') + } -function createStubFromString (originalComponent: Component, template: string): Object { return { ...getCoreProperties(originalComponent), - ...compileToFunctions(template) + ...compileToFunctions(templateString) } } -function createBlankStub (originalComponent: Component): Object { +function createBlankStub (originalComponent: Component) { return { ...getCoreProperties(originalComponent), render: h => h('') } } -function createStubFromComponent (component: Component, name: string): Object { - if (componentNeedsCompiling(component)) compileTemplate(component) - return name ? { ...component, name } : component -} +export function createComponentStubs (originalComponents: Object = {}, stubs: Object): Object { + const components = {} + if (!stubs) { + return components + } + if (Array.isArray(stubs)) { + stubs.forEach(stub => { + if (stub === false) { + return + } -function createStub (originalComponent: Component, stubValue): Object { - if (stubValue === true) { - return createBlankStub(originalComponent) - } else if (typeof stubValue === 'string') { - return createStubFromString(originalComponent, stubValue) + if (typeof stub !== 'string') { + throwError('each item in an options.stubs array must be a string') + } + components[stub] = createBlankStub({}) + }) } else { - return createStubFromComponent(stubValue, originalComponent && originalComponent.name) + Object.keys(stubs).forEach(stub => { + if (stubs[stub] === false) { + return + } + if (!isValidStub(stubs[stub])) { + throwError('options.stub values must be passed a string or component') + } + if (stubs[stub] === true) { + components[stub] = createBlankStub({}) + return + } + + if (componentNeedsCompiling(stubs[stub])) { + compileTemplate(stubs[stub]) + } + + if (originalComponents[stub]) { + // Remove cached constructor + delete originalComponents[stub]._Ctor + if (typeof stubs[stub] === 'string') { + components[stub] = createStubFromString(stubs[stub], originalComponents[stub]) + } else { + components[stub] = { + ...stubs[stub], + name: originalComponents[stub].name + } + } + } else { + if (typeof stubs[stub] === 'string') { + if (!compileToFunctions) { + throwError('vueTemplateCompiler is undefined, you must pass components explicitly if vue-template-compiler is undefined') + } + components[stub] = { + ...compileToFunctions(stubs[stub]) + } + } else { + components[stub] = { + ...stubs[stub] + } + } + } + // ignoreElements does not exist in Vue 2.0.x + if (Vue.config.ignoredElements) { + Vue.config.ignoredElements.push(stub) + } + }) } + return components +} + +function stubComponents (components: Object, stubbedComponents: Object) { + Object.keys(components).forEach(component => { + // Remove cached constructor + delete components[component]._Ctor + if (!components[component].name) { + components[component].name = component + } + stubbedComponents[component] = createBlankStub(components[component]) + + // ignoreElements does not exist in Vue 2.0.x + if (Vue.config.ignoredElements) { + Vue.config.ignoredElements.push(component) + } + }) } -function normalizeStubOptions (components: ?Object, stubOptions: ?Object | Array): Object { - if (!stubOptions) { - stubOptions = Object.keys(components || {}) +export function createComponentStubsForAll (component: Component): Object { + const stubbedComponents = {} + + if (component.components) { + stubComponents(component.components, stubbedComponents) } - if (Array.isArray(stubOptions)) { - stubOptions = stubOptions.reduce((object, name) => { - object[name] = true - return object - }, {}) + + let extended = component.extends + + // Loop through extended component chains to stub all child components + while (extended) { + if (extended.components) { + stubComponents(extended.components, stubbedComponents) + } + extended = extended.extends } - return stubOptions -} -export function createComponentStubs (components: Object = {}, stubOptions: Object): Object { - validateStubOptions(stubOptions) - return createStubs(components, stubOptions) -} + if (component.extendOptions && component.extendOptions.components) { + stubComponents(component.extendOptions.components, stubbedComponents) + } -export function createComponentStubsForAll (component: Component, stubs: Object = {}): Object { - if (!component) return stubs - Object.assign(stubs, createStubs(component.components)) - return createComponentStubsForAll(component.extends || component.extendOptions, stubs) + return stubbedComponents } -export function createStubs (components: Object, stubOptions: ?Object | Array): Object { - const options: Object = normalizeStubOptions(components, stubOptions) +export function createComponentStubsForGlobals (instance: Component): Object { + const components = {} + Object.keys(instance.options.components).forEach((c) => { + if (isRequiredComponent(c)) { + return + } - return Object.keys(options) - .filter(name => !['KeepAlive', 'Transition', 'TransitionGroup'].includes(name)) - .filter(name => options[name] !== false) - .reduce((stubs, name) => { - stubs[name] = createStub(components[name], options[name]) - return stubs - }, {}) + components[c] = createBlankStub(instance.options.components[c]) + delete instance.options.components[c]._Ctor // eslint-disable-line no-param-reassign + delete components[c]._Ctor // eslint-disable-line no-param-reassign + }) + return components } diff --git a/packages/test-utils/src/shallow.js b/packages/test-utils/src/shallow.js index 706782d72..dbbd6cb95 100644 --- a/packages/test-utils/src/shallow.js +++ b/packages/test-utils/src/shallow.js @@ -6,7 +6,7 @@ import mount from './mount' import type VueWrapper from './vue-wrapper' import { createComponentStubsForAll, - createStubs + createComponentStubsForGlobals } from 'shared/stub-components' import { camelize, capitalize, @@ -26,11 +26,15 @@ export default function shallow ( delete component.components[hyphenate(component.name)] } + const stubbedComponents = createComponentStubsForAll(component) + const stubbedGlobalComponents = createComponentStubsForGlobals(vue) + return mount(component, { ...options, components: { - ...createStubs(vue.options.components), - ...createComponentStubsForAll(component) + // stubbed components are used instead of original components components + ...stubbedGlobalComponents, + ...stubbedComponents } }) } From 9b08032ecb729548f6b3571a84fd9e9fcc9ce000 Mon Sep 17 00:00:00 2001 From: 38elements Date: Fri, 4 May 2018 17:22:33 +0900 Subject: [PATCH 02/11] Revert "refactor: refactor add-slots.js (#556)" This reverts commit ce9e1bf81383995d4338e7e5c3ed6ed840a3ba6f. --- packages/create-instance/add-slots.js | 71 ++++++++++++++-------- packages/create-instance/validate-slots.js | 33 +++++----- packages/shared/util.js | 8 --- 3 files changed, 59 insertions(+), 53 deletions(-) diff --git a/packages/create-instance/add-slots.js b/packages/create-instance/add-slots.js index 82a1c4391..ff6ea3f47 100644 --- a/packages/create-instance/add-slots.js +++ b/packages/create-instance/add-slots.js @@ -1,43 +1,60 @@ // @flow import { compileToFunctions } from 'vue-template-compiler' +import { throwError } from 'shared/util' import { validateSlots } from './validate-slots' -import { toArray } from 'shared/util' -function isSingleHTMLTag (template: string) { - if (!template.startsWith('<') || !template.endsWith('>')) { - return false - } - const _document = new window.DOMParser().parseFromString(template, 'text/html') - return _document.body.childElementCount === 1 -} - -function createElementFromAdvancedString (slotValue, vm) { - const compiledResult = compileToFunctions(`
${slotValue}{{ }}
`) - const _staticRenderFns = vm._renderProxy.$options.staticRenderFns - vm._renderProxy.$options.staticRenderFns = compiledResult.staticRenderFns - const elem = compiledResult.render.call(vm._renderProxy, vm.$createElement).children - vm._renderProxy.$options.staticRenderFns = _staticRenderFns - return elem -} - -function createElement (slotValue: string | Object, vm) { +function addSlotToVm (vm: Component, slotName: string, slotValue: Component | string | Array | Array): void { + let elem if (typeof slotValue === 'string') { - slotValue = slotValue.trim() - if (isSingleHTMLTag(slotValue)) { - return vm.$createElement(compileToFunctions(slotValue)) + if (!compileToFunctions) { + throwError('vueTemplateCompiler is undefined, you must pass components explicitly if vue-template-compiler is undefined') + } + if (typeof window === 'undefined') { + throwError('the slots string option does not support strings in server-test-uitls.') + } + if (window.navigator.userAgent.match(/PhantomJS/i)) { + throwError('the slots option 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 { - return createElementFromAdvancedString(slotValue, vm) + 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 { - return vm.$createElement(slotValue) + elem = vm.$createElement(slotValue) + } + if (Array.isArray(elem)) { + if (Array.isArray(vm.$slots[slotName])) { + vm.$slots[slotName] = [...vm.$slots[slotName], ...elem] + } else { + vm.$slots[slotName] = [...elem] + } + } else { + if (Array.isArray(vm.$slots[slotName])) { + vm.$slots[slotName].push(elem) + } else { + vm.$slots[slotName] = [elem] + } } } export function addSlots (vm: Component, slots: Object): void { validateSlots(slots) - Object.keys(slots).forEach(name => { - vm.$slots[name] = toArray(slots[name]) - .map(slotValue => createElement(slotValue, vm)) + Object.keys(slots).forEach((key) => { + if (Array.isArray(slots[key])) { + slots[key].forEach((slotValue) => { + addSlotToVm(vm, key, slotValue) + }) + } else { + addSlotToVm(vm, key, slots[key]) + } }) } diff --git a/packages/create-instance/validate-slots.js b/packages/create-instance/validate-slots.js index 0e69ca20e..1c1d7dd9d 100644 --- a/packages/create-instance/validate-slots.js +++ b/packages/create-instance/validate-slots.js @@ -1,26 +1,23 @@ // @flow -import { throwError, toArray, isObject } from 'shared/util' -import { compileToFunctions } from 'vue-template-compiler' +import { throwError } from 'shared/util' + +function isValidSlot (slot: any): boolean { + return Array.isArray(slot) || (slot !== null && typeof slot === 'object') || typeof slot === 'string' +} export function validateSlots (slots: Object): void { - Object.keys(slots).forEach(key => { - toArray(slots[key]).forEach(slotValue => { - if (!isObject(slotValue) && typeof slotValue !== 'string') { - throwError('slots[key] must be a Component, string or an array of Components') - } + slots && Object.keys(slots).forEach((key) => { + if (!isValidSlot(slots[key])) { + throwError('slots[key] must be a Component, string or an array of Components') + } - if (typeof slotValue === 'string') { - if (!compileToFunctions) { - throwError('vueTemplateCompiler is undefined, you must pass components explicitly if vue-template-compiler is undefined') - } - if (typeof window === 'undefined') { - throwError('the slots string option does not support strings in server-test-uitls.') - } - if (window.navigator.userAgent.match(/PhantomJS/i)) { - throwError('the slots option does not support strings in PhantomJS. Please use Puppeteer, or pass a component.') + if (Array.isArray(slots[key])) { + slots[key].forEach((slotValue) => { + if (!isValidSlot(slotValue)) { + throwError('slots[key] must be a Component, string or an array of Components') } - } - }) + }) + } }) } diff --git a/packages/shared/util.js b/packages/shared/util.js index 6da2418b8..c68044467 100644 --- a/packages/shared/util.js +++ b/packages/shared/util.js @@ -21,11 +21,3 @@ export const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.sli */ const hyphenateRE = /\B([A-Z])/g export const hyphenate = (str: string) => str.replace(hyphenateRE, '-$1').toLowerCase() - -export function toArray (value: any) { - return Array.isArray(value) ? value : [value] -} - -export function isObject (obj: mixed): boolean %checks { - return obj !== null && typeof obj === 'object' -} From e17937ae6619ed0911817a130004dfc260b9c834 Mon Sep 17 00:00:00 2001 From: 38elements Date: Fri, 4 May 2018 18:17:51 +0900 Subject: [PATCH 03/11] delete packages/test-utils/src/shallow.js --- packages/test-utils/src/shallow-mount.js | 4 +-- packages/test-utils/src/shallow.js | 40 ------------------------ 2 files changed, 2 insertions(+), 42 deletions(-) delete mode 100644 packages/test-utils/src/shallow.js diff --git a/packages/test-utils/src/shallow-mount.js b/packages/test-utils/src/shallow-mount.js index 55d878bad..037fd0720 100644 --- a/packages/test-utils/src/shallow-mount.js +++ b/packages/test-utils/src/shallow-mount.js @@ -6,7 +6,7 @@ import mount from './mount' import type VueWrapper from './vue-wrapper' import { createComponentStubsForAll, - createStubs + createComponentStubsForGlobals } from 'shared/stub-components' import { camelize, capitalize, @@ -29,7 +29,7 @@ export default function shallowMount ( return mount(component, { ...options, components: { - ...createStubs(vue.options.components), + ...createComponentStubsForGlobals(vue), ...createComponentStubsForAll(component) } }) diff --git a/packages/test-utils/src/shallow.js b/packages/test-utils/src/shallow.js deleted file mode 100644 index dbbd6cb95..000000000 --- a/packages/test-utils/src/shallow.js +++ /dev/null @@ -1,40 +0,0 @@ -// @flow - -import './warn-if-no-window' -import Vue from 'vue' -import mount from './mount' -import type VueWrapper from './vue-wrapper' -import { - createComponentStubsForAll, - createComponentStubsForGlobals -} from 'shared/stub-components' -import { camelize, - capitalize, - hyphenate -} from 'shared/util' - -export default function shallow ( - component: Component, - options: Options = {} -): VueWrapper { - const vue = options.localVue || Vue - - // remove any recursive components added to the constructor - // in vm._init from previous tests - if (component.name && component.components) { - delete component.components[capitalize(camelize(component.name))] - delete component.components[hyphenate(component.name)] - } - - const stubbedComponents = createComponentStubsForAll(component) - const stubbedGlobalComponents = createComponentStubsForGlobals(vue) - - return mount(component, { - ...options, - components: { - // stubbed components are used instead of original components components - ...stubbedGlobalComponents, - ...stubbedComponents - } - }) -} From 425d01da477f273ad8bd8ecfbf36e7fab03ab264 Mon Sep 17 00:00:00 2001 From: 38elements Date: Fri, 4 May 2018 19:13:55 +0900 Subject: [PATCH 04/11] add functions --- packages/create-instance/add-slots.js | 52 +++++++++++++++++---------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/packages/create-instance/add-slots.js b/packages/create-instance/add-slots.js index ff6ea3f47..3565b35a8 100644 --- a/packages/create-instance/add-slots.js +++ b/packages/create-instance/add-slots.js @@ -4,29 +4,45 @@ import { compileToFunctions } from 'vue-template-compiler' import { throwError } from 'shared/util' import { validateSlots } from './validate-slots' +function isSingleElement (slotValue: string): boolean { + const _slotValue = slotValue.trim() + if (_slotValue[0] !== '<' || _slotValue[_slotValue.length - 1] !== '>') { + return false + } + const domParser = new window.DOMParser() + const _document = domParser.parseFromString(slotValue, 'text/html') + return _document.body.childElementCount === 1 +} + +function createVNodesFromText (vm: Component, slotValue: string) { + const compiledResult = compileToFunctions(`
${slotValue}{{ }}
`) + const _staticRenderFns = vm._renderProxy.$options.staticRenderFns + vm._renderProxy.$options.staticRenderFns = compiledResult.staticRenderFns + const elem = compiledResult.render.call(vm._renderProxy, vm.$createElement).children + vm._renderProxy.$options.staticRenderFns = _staticRenderFns + return elem +} + +function validateEnvironment (_window, compileToFunctions): void { + if (!compileToFunctions) { + throwError('vueTemplateCompiler is undefined, you must pass components explicitly if vue-template-compiler is undefined') + } + if (typeof _window === 'undefined') { + throwError('the slots string option does not support strings in server-test-uitls.') + } + if (_window.navigator.userAgent.match(/PhantomJS/i)) { + throwError('the slots option does not support strings in PhantomJS. Please use Puppeteer, or pass a component.') + } +} + function addSlotToVm (vm: Component, slotName: string, slotValue: Component | string | Array | Array): void { let elem + validateEnvironment(window, compileToFunctions) if (typeof slotValue === 'string') { - if (!compileToFunctions) { - throwError('vueTemplateCompiler is undefined, you must pass components explicitly if vue-template-compiler is undefined') - } - if (typeof window === 'undefined') { - throwError('the slots string option does not support strings in server-test-uitls.') - } - if (window.navigator.userAgent.match(/PhantomJS/i)) { - throwError('the slots option 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) { + if (isSingleElement(slotValue)) { elem = vm.$createElement(compileToFunctions(slotValue)) } else { - 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 + elem = createVNodesFromText(vm, slotValue) } } else { elem = vm.$createElement(slotValue) From 135fd281d42d176d247fce11f231b9982307b7ba Mon Sep 17 00:00:00 2001 From: 38elements Date: Fri, 4 May 2018 22:10:45 +0900 Subject: [PATCH 05/11] add type SlotValue --- flow/vue.flow.js | 1 + packages/create-instance/add-slots.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/flow/vue.flow.js b/flow/vue.flow.js index d84644092..d7a51d41f 100644 --- a/flow/vue.flow.js +++ b/flow/vue.flow.js @@ -4,3 +4,4 @@ declare type Component = Object // eslint-disable-line no-undef declare type VNode = Object // eslint-disable-line no-undef +declare type SlotValue = Component | string | Array | Array diff --git a/packages/create-instance/add-slots.js b/packages/create-instance/add-slots.js index 3565b35a8..f09201506 100644 --- a/packages/create-instance/add-slots.js +++ b/packages/create-instance/add-slots.js @@ -35,7 +35,7 @@ function validateEnvironment (_window, compileToFunctions): void { } } -function addSlotToVm (vm: Component, slotName: string, slotValue: Component | string | Array | Array): void { +function addSlotToVm (vm: Component, slotName: string, slotValue: SlotValue): void { let elem validateEnvironment(window, compileToFunctions) if (typeof slotValue === 'string') { From b36e0923e7f0b24ce380c6a1929d8c21874cda0d Mon Sep 17 00:00:00 2001 From: 38elements Date: Sat, 5 May 2018 10:12:00 +0900 Subject: [PATCH 06/11] add test --- packages/create-instance/add-slots.js | 5 +++-- test/specs/mounting-options/slots.spec.js | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/create-instance/add-slots.js b/packages/create-instance/add-slots.js index f09201506..939572aa4 100644 --- a/packages/create-instance/add-slots.js +++ b/packages/create-instance/add-slots.js @@ -14,7 +14,8 @@ function isSingleElement (slotValue: string): boolean { return _document.body.childElementCount === 1 } -function createVNodesFromText (vm: Component, slotValue: string) { +// see https://github.com/vuejs/vue-test-utils/pull/274 +function createVNodes (vm: Component, slotValue: string) { const compiledResult = compileToFunctions(`
${slotValue}{{ }}
`) const _staticRenderFns = vm._renderProxy.$options.staticRenderFns vm._renderProxy.$options.staticRenderFns = compiledResult.staticRenderFns @@ -42,7 +43,7 @@ function addSlotToVm (vm: Component, slotName: string, slotValue: SlotValue): vo if (isSingleElement(slotValue)) { elem = vm.$createElement(compileToFunctions(slotValue)) } else { - elem = createVNodesFromText(vm, slotValue) + elem = createVNodes(vm, slotValue) } } else { elem = vm.$createElement(slotValue) diff --git a/test/specs/mounting-options/slots.spec.js b/test/specs/mounting-options/slots.spec.js index 9b4803395..458d72575 100644 --- a/test/specs/mounting-options/slots.spec.js +++ b/test/specs/mounting-options/slots.spec.js @@ -109,10 +109,13 @@ describeWithMountingMethods('options.slots', (mountingMethod) => { const wrapper5 = mountingMethod(ComponentWithSlots, { slots: { default: '1{{ foo }}2' }}) expect(wrapper5.find('main').html()).to.equal('
1bar2
') wrapper5.trigger('keydown') + // expect(wrapper5.find('main').html()).to.equal('
1BAR2
') const wrapper6 = mountingMethod(ComponentWithSlots, { slots: { default: '

1

2

' }}) expect(wrapper6.find('main').html()).to.equal('

1

2

') const wrapper7 = mountingMethod(ComponentWithSlots, { slots: { default: '1

2

3' }}) expect(wrapper7.find('main').html()).to.equal('
1

2

3
') + const wrapper8 = mountingMethod(ComponentWithSlots, { slots: { default: ' space ' }}) + expect(wrapper8.find('main').html()).to.equal('
space
') }) itSkipIf(mountingMethod.name === 'renderToString', From b26b81d9b95b0d5e2608d55dd7112a54e91d4322 Mon Sep 17 00:00:00 2001 From: 38elements Date: Sat, 5 May 2018 10:41:19 +0900 Subject: [PATCH 07/11] fix slotValue --- packages/create-instance/add-slots.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/create-instance/add-slots.js b/packages/create-instance/add-slots.js index 939572aa4..af0553ad2 100644 --- a/packages/create-instance/add-slots.js +++ b/packages/create-instance/add-slots.js @@ -38,8 +38,8 @@ function validateEnvironment (_window, compileToFunctions): void { function addSlotToVm (vm: Component, slotName: string, slotValue: SlotValue): void { let elem - validateEnvironment(window, compileToFunctions) if (typeof slotValue === 'string') { + validateEnvironment(window, compileToFunctions) if (isSingleElement(slotValue)) { elem = vm.$createElement(compileToFunctions(slotValue)) } else { From 82624d3d41836f4f795cf9e9ac7947cf8c333055 Mon Sep 17 00:00:00 2001 From: 38elements Date: Sat, 5 May 2018 11:08:14 +0900 Subject: [PATCH 08/11] fix validateEnvironment --- packages/create-instance/add-slots.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/create-instance/add-slots.js b/packages/create-instance/add-slots.js index af0553ad2..9b802ceaf 100644 --- a/packages/create-instance/add-slots.js +++ b/packages/create-instance/add-slots.js @@ -24,14 +24,14 @@ function createVNodes (vm: Component, slotValue: string) { return elem } -function validateEnvironment (_window, compileToFunctions): void { +function validateEnvironment (): void { if (!compileToFunctions) { throwError('vueTemplateCompiler is undefined, you must pass components explicitly if vue-template-compiler is undefined') } - if (typeof _window === 'undefined') { + if (typeof window === 'undefined') { throwError('the slots string option does not support strings in server-test-uitls.') } - if (_window.navigator.userAgent.match(/PhantomJS/i)) { + if (window.navigator.userAgent.match(/PhantomJS/i)) { throwError('the slots option does not support strings in PhantomJS. Please use Puppeteer, or pass a component.') } } @@ -39,7 +39,7 @@ function validateEnvironment (_window, compileToFunctions): void { function addSlotToVm (vm: Component, slotName: string, slotValue: SlotValue): void { let elem if (typeof slotValue === 'string') { - validateEnvironment(window, compileToFunctions) + validateEnvironment() if (isSingleElement(slotValue)) { elem = vm.$createElement(compileToFunctions(slotValue)) } else { From 5a4fa7a763a10326bdd8691d6479e1c8e54b062b Mon Sep 17 00:00:00 2001 From: 38elements Date: Sat, 5 May 2018 11:54:49 +0900 Subject: [PATCH 09/11] add test --- test/specs/mounting-options/slots.spec.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/specs/mounting-options/slots.spec.js b/test/specs/mounting-options/slots.spec.js index 458d72575..6e8402fd7 100644 --- a/test/specs/mounting-options/slots.spec.js +++ b/test/specs/mounting-options/slots.spec.js @@ -75,6 +75,18 @@ describeWithMountingMethods('options.slots', (mountingMethod) => { } }) + itDoNotRunIf( + typeof window === 'undefined' || window.navigator.userAgent.match(/Chrome/i), + 'works if the UserAgent is PhantomJS when passed Component is in slot object', () => { + window = { navigator: { userAgent: 'PhantomJS' }} // eslint-disable-line no-native-reassign + const wrapper = mountingMethod(ComponentWithSlots, { slots: { default: [Component] }}) + if (mountingMethod.name === 'renderToString') { + expect(wrapper).contains('
') + } else { + expect(wrapper.contains(Component)).to.equal(true) + } + }) + itDoNotRunIf( typeof window === 'undefined' || window.navigator.userAgent.match(/Chrome/i), 'throws error if the UserAgent is PhantomJS when passed string is in slot object', () => { From 6d78850bb6b82c791140f74d598741631d44359a Mon Sep 17 00:00:00 2001 From: 38elements Date: Sat, 5 May 2018 12:03:15 +0900 Subject: [PATCH 10/11] fix lint --- test/specs/mounting-options/slots.spec.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/specs/mounting-options/slots.spec.js b/test/specs/mounting-options/slots.spec.js index 6e8402fd7..2fd5486a5 100644 --- a/test/specs/mounting-options/slots.spec.js +++ b/test/specs/mounting-options/slots.spec.js @@ -78,14 +78,14 @@ describeWithMountingMethods('options.slots', (mountingMethod) => { itDoNotRunIf( typeof window === 'undefined' || window.navigator.userAgent.match(/Chrome/i), 'works if the UserAgent is PhantomJS when passed Component is in slot object', () => { - window = { navigator: { userAgent: 'PhantomJS' }} // eslint-disable-line no-native-reassign - const wrapper = mountingMethod(ComponentWithSlots, { slots: { default: [Component] }}) - if (mountingMethod.name === 'renderToString') { - expect(wrapper).contains('
') - } else { - expect(wrapper.contains(Component)).to.equal(true) - } - }) + window = { navigator: { userAgent: 'PhantomJS' }} // eslint-disable-line no-native-reassign + const wrapper = mountingMethod(ComponentWithSlots, { slots: { default: [Component] }}) + if (mountingMethod.name === 'renderToString') { + expect(wrapper).contains('
') + } else { + expect(wrapper.contains(Component)).to.equal(true) + } + }) itDoNotRunIf( typeof window === 'undefined' || window.navigator.userAgent.match(/Chrome/i), From 6288affec8a7ec182f18624823ab7311271db74b Mon Sep 17 00:00:00 2001 From: 38elements <38elements@users.noreply.github.com> Date: Sat, 5 May 2018 13:55:56 +0900 Subject: [PATCH 11/11] Update slots.spec.js --- test/specs/mounting-options/slots.spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/specs/mounting-options/slots.spec.js b/test/specs/mounting-options/slots.spec.js index 2fd5486a5..5bdf898c4 100644 --- a/test/specs/mounting-options/slots.spec.js +++ b/test/specs/mounting-options/slots.spec.js @@ -121,7 +121,6 @@ describeWithMountingMethods('options.slots', (mountingMethod) => { const wrapper5 = mountingMethod(ComponentWithSlots, { slots: { default: '1{{ foo }}2' }}) expect(wrapper5.find('main').html()).to.equal('
1bar2
') wrapper5.trigger('keydown') - // expect(wrapper5.find('main').html()).to.equal('
1BAR2
') const wrapper6 = mountingMethod(ComponentWithSlots, { slots: { default: '

1

2

' }}) expect(wrapper6.find('main').html()).to.equal('

1

2

') const wrapper7 = mountingMethod(ComponentWithSlots, { slots: { default: '1

2

3' }})