From 76841a658eea25f14ebb6648b3567bd9c781e554 Mon Sep 17 00:00:00 2001 From: eddyerburgh Date: Sun, 22 Jul 2018 18:59:24 +0100 Subject: [PATCH 1/2] feat: add parent option --- packages/create-instance/create-instance.js | 44 ++++++++++--------- packages/shared/util.js | 4 -- packages/shared/validators.js | 8 ++++ .../test-utils/src/recursively-set-data.js | 2 +- 4 files changed, 33 insertions(+), 25 deletions(-) diff --git a/packages/create-instance/create-instance.js b/packages/create-instance/create-instance.js index 515ddeff9..070b9a7e1 100644 --- a/packages/create-instance/create-instance.js +++ b/packages/create-instance/create-instance.js @@ -8,7 +8,7 @@ import { throwError, warn, vueVersion } from 'shared/util' import { compileTemplate } from 'shared/compile-template' import extractInstanceOptions from './extract-instance-options' import createFunctionalComponent from './create-functional-component' -import { componentNeedsCompiling } from 'shared/validators' +import { componentNeedsCompiling, isPlainObject } from 'shared/validators' import { validateSlots } from './validate-slots' import createScopedSlots from './create-scoped-slots' @@ -125,25 +125,29 @@ export default function createInstance ( const scopedSlots = createScopedSlots(options.scopedSlots) - const Parent = _Vue.extend({ - provide: options.provide, - render (h) { - const slots = options.slots - ? createSlotVNodes(h, options.slots) - : undefined - return h( - Constructor, - { - ref: 'vm', - props: options.propsData, - on: options.listeners, - attrs: options.attrs, - scopedSlots - }, - slots - ) - } - }) + if (options.parent && !isPlainObject(options.parent)) { + throwError('options.parent should be a valid Vue component options object') + } + + const parentComponentOptions = options.parent || {} + parentComponentOptions.provide = options.provide + parentComponentOptions.render = function (h) { + const slots = options.slots + ? createSlotVNodes(h, options.slots) + : undefined + return h( + Constructor, + { + ref: 'vm', + props: options.propsData, + on: options.listeners, + attrs: options.attrs, + scopedSlots + }, + slots + ) + } + const Parent = _Vue.extend(parentComponentOptions) return new Parent() } diff --git a/packages/shared/util.js b/packages/shared/util.js index 730cf8b27..1b78c8506 100644 --- a/packages/shared/util.js +++ b/packages/shared/util.js @@ -34,7 +34,3 @@ export const hyphenate = (str: string): string => export const vueVersion = Number( `${Vue.version.split('.')[0]}.${Vue.version.split('.')[1]}` ) - -export function isPlainObject (obj: any): boolean { - return Object.prototype.toString.call(obj) === '[object Object]' -} diff --git a/packages/shared/validators.js b/packages/shared/validators.js index 2ba725dec..6116596d8 100644 --- a/packages/shared/validators.js +++ b/packages/shared/validators.js @@ -41,6 +41,10 @@ export function isVueComponent (component: any): boolean { return true } + if (typeof component.template === 'string') { + return true + } + return typeof component.render === 'function' } @@ -81,3 +85,7 @@ export function templateContainsComponent ( return re.test(template) }) } + +export function isPlainObject (obj: any): boolean { + return Object.prototype.toString.call(obj) === '[object Object]' +} diff --git a/packages/test-utils/src/recursively-set-data.js b/packages/test-utils/src/recursively-set-data.js index bd75f35ae..e76a54612 100644 --- a/packages/test-utils/src/recursively-set-data.js +++ b/packages/test-utils/src/recursively-set-data.js @@ -1,4 +1,4 @@ -import { isPlainObject } from 'shared/util' +import { isPlainObject } from 'shared/validators' export function recursivelySetData (vm, target, obj) { Object.keys(obj).forEach(key => { From 8f3da275b800531d84fd24ad3c98a12e0040bcd0 Mon Sep 17 00:00:00 2001 From: eddyerburgh Date: Sun, 22 Jul 2018 18:59:40 +0100 Subject: [PATCH 2/2] test: add test for parent option --- test/specs/mounting-options/parent.spec.js | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 test/specs/mounting-options/parent.spec.js diff --git a/test/specs/mounting-options/parent.spec.js b/test/specs/mounting-options/parent.spec.js new file mode 100644 index 000000000..d3331d1dc --- /dev/null +++ b/test/specs/mounting-options/parent.spec.js @@ -0,0 +1,32 @@ +import { describeWithMountingMethods } from '~resources/utils' + +describeWithMountingMethods('options.parent', mountingMethod => { + it('mounts component with $parent set to options.parent', () => { + const Parent = { + data: () => ({ + customName: 'Parent Name' + }) + } + const TestComponent = { + template: '
{{$parent.customName}}
' + } + const wrapper = mountingMethod(TestComponent, { + parent: Parent + }) + expect(wrapper.html()).to.contain('Parent Name') + }) + + it('validates parent option', () => { + ;['str', 123, [], () => {}].forEach(invalidParent => { + const TestComponent = { + template: '
{{$parent.customName}}
' + } + const fn = () => mountingMethod(TestComponent, { + parent: invalidParent + }) + const message = '[vue-test-utils]: options.parent should be a valid Vue component options object' + expect(fn).to.throw() + .with.property('message', message) + }) + }) +})