From ff6ac3d16f38a26bd6f45b8d7beb5e1a70c64024 Mon Sep 17 00:00:00 2001 From: Mitch Lillie Date: Wed, 28 Apr 2021 14:51:30 -0700 Subject: [PATCH] feat(stubs): render function props deterministically --- .../create-instance/create-component-stubs.js | 27 +++++++- test/specs/mounting-options/stubs.spec.js | 65 +++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/packages/create-instance/create-component-stubs.js b/packages/create-instance/create-component-stubs.js index 8ffd002a7..7185ab648 100644 --- a/packages/create-instance/create-component-stubs.js +++ b/packages/create-instance/create-component-stubs.js @@ -18,6 +18,8 @@ import { } from '../shared/validators' import { compileTemplate } from '../shared/compile-template' +const FUNCTION_PLACEHOLDER = '[Function]' + function isVueComponentStub(comp): boolean { return (comp && comp.template) || isVueComponent(comp) } @@ -116,13 +118,13 @@ export function createStubFromComponent( ? { ...context.data, attrs: { - ...context.props, + ...shapeStubProps(context.props), ...context.data.attrs } } : { attrs: { - ...this.$props + ...shapeStubProps(this.$props) } }, context @@ -136,6 +138,27 @@ export function createStubFromComponent( } } +function shapeStubProps(props) { + const shapedProps: Object = {} + for (const propName in props) { + if (typeof props[propName] === 'function') { + shapedProps[propName] = FUNCTION_PLACEHOLDER + continue + } + + if (Array.isArray(props[propName])) { + shapedProps[propName] = props[propName].map(value => { + return typeof value === 'function' ? FUNCTION_PLACEHOLDER : value + }) + continue + } + + shapedProps[propName] = props[propName] + } + + return shapedProps +} + // DEPRECATED: converts string stub to template stub. function createStubFromString(templateString: string, name: string): Component { warnDeprecated('Using a string for stubs') diff --git a/test/specs/mounting-options/stubs.spec.js b/test/specs/mounting-options/stubs.spec.js index 91741d93d..fa926c278 100644 --- a/test/specs/mounting-options/stubs.spec.js +++ b/test/specs/mounting-options/stubs.spec.js @@ -639,4 +639,69 @@ describeWithShallowAndMount('options.stub', mountingMethod => { ) config.showDeprecationWarnings = false }) + + it('should render functions in props as a deterministic string', () => { + const ChildComponent = { + name: 'child-component', + props: { + foo: { + type: Function, + required: true + }, + bar: { + type: Array, + required: true + }, + qux: { + type: String, + required: true + } + }, + template: '
' + } + + const FunctionalChildComponent = { + ...ChildComponent, + name: 'functional-child-component', + functional: true + } + + const ParentComponent = { + components: { + ChildComponent, + FunctionalChildComponent + }, + name: 'parent-component', + template: ` +
+ + +
+ `, + data() { + return { + foo: () => 42, + bar: [1, 'string', () => true], + qux: 'qux' + } + } + } + + const wrapper = mountingMethod(ParentComponent, { + stubs: ['child-component', 'functional-child-component'] + }) + + expect(wrapper.html()).toEqual( + `
\n` + + ` \n` + + ` \n` + + `
` + ) + }) })