From efca188cf62bea1f0e4ed07c9cd4766016c1c71c Mon Sep 17 00:00:00 2001 From: freakzlike Date: Thu, 23 Dec 2021 16:54:32 +0100 Subject: [PATCH 1/4] feat: Hide props with default values within snapshot --- src/stubs.ts | 48 +++++++++++++++++-- tests/components/ScriptSetupDefineProps.vue | 17 +++++++ tests/components/WithProps.vue | 13 +++++ tests/features/teleport.spec.ts | 6 ++- tests/mountingOptions/global.stubs.spec.ts | 53 ++++++++++++++++++++- tests/props.spec.ts | 23 ++++++++- 6 files changed, 154 insertions(+), 6 deletions(-) create mode 100644 tests/components/ScriptSetupDefineProps.vue diff --git a/src/stubs.ts b/src/stubs.ts index 1948f5158..2dfea559d 100644 --- a/src/stubs.ts +++ b/src/stubs.ts @@ -13,8 +13,8 @@ import { } from 'vue' import { hyphenate } from './utils/vueShared' import { matchName } from './utils/matchName' -import { isComponent, isFunctionalComponent, isObjectComponent } from './utils' -import { ComponentInternalInstance } from '@vue/runtime-core' +import { hasOwnProperty, isComponent, isFunctionalComponent, isObjectComponent } from './utils' +import { ComponentInternalInstance, Prop } from '@vue/runtime-core' import { isLegacyExtendedComponent, unwrapLegacyVueExtendComponent @@ -84,9 +84,51 @@ export const createStub = ({ // props that will be passed and stringify any that are symbols. const propsWithoutSymbols = stringifySymbols(ctx.$props) + // Filter default value of props + const props = Object.entries(propsWithoutSymbols).reduce((props, [propName, propValue]) => { + const skipProp = (() => { + if (propValue === undefined) return true + + // Prop declaration in array style will be skipped here + const propDeclaration = (propsDeclaration as any)?.[propName] as Prop | undefined + if (propDeclaration) { + // Boolean prop declaration: myProp: Boolean + if (propDeclaration === Boolean) return !propValue + + // Prop declaration with object style + // myProp: { type: String, default: 'default-value' } + if (typeof propDeclaration === 'object' && hasOwnProperty(propDeclaration, 'default')) { + let defaultValue = propDeclaration.default + + // Default value factory? + // myProp: { type: Array, default: () => ['one'] } + if (typeof defaultValue === 'function') { + defaultValue = defaultValue() + } + + // Compare primitive value + if (typeof defaultValue !== 'object' || typeof propValue !== 'object') { + return defaultValue === propValue + } + + // Compare objects + // TODO: use some different object comparison + return JSON.stringify(defaultValue) === JSON.stringify(propValue) + } + } + + return false + })() + + if (!skipProp) { + props[propName] = propValue + } + return props + }, {} as Record) + return h( tag, - propsWithoutSymbols, + props, renderStubDefaultSlot ? ctx.$slots : undefined ) } diff --git a/tests/components/ScriptSetupDefineProps.vue b/tests/components/ScriptSetupDefineProps.vue new file mode 100644 index 000000000..4449d7b9d --- /dev/null +++ b/tests/components/ScriptSetupDefineProps.vue @@ -0,0 +1,17 @@ + + + diff --git a/tests/components/WithProps.vue b/tests/components/WithProps.vue index 36aa30a1e..d78492f0c 100644 --- a/tests/components/WithProps.vue +++ b/tests/components/WithProps.vue @@ -14,6 +14,19 @@ export default defineComponent({ msg: { type: String, required: false + }, + withDefaultString: { + type: String, + default: 'default-value' + }, + withDefaultBool: Boolean, + withDefaultArray: { + type: Array, + default: () => ['default-value'] + }, + withDefaultObject: { + type: Object, + default: () => ({ obj: 'default' }) } } }) diff --git a/tests/features/teleport.spec.ts b/tests/features/teleport.spec.ts index be6f09976..7ad855bb6 100644 --- a/tests/features/teleport.spec.ts +++ b/tests/features/teleport.spec.ts @@ -127,7 +127,11 @@ describe('teleport', () => { const withProps = wrapper.getComponent(WithProps) expect(withProps.props()).toEqual({ - msg: 'hi there' + msg: 'hi there', + withDefaultString: 'default-value', + withDefaultBool: false, + withDefaultArray: ['default-value'], + withDefaultObject: { obj: 'default' } }) }) diff --git a/tests/mountingOptions/global.stubs.spec.ts b/tests/mountingOptions/global.stubs.spec.ts index 8a0558060..6fb28e4c4 100644 --- a/tests/mountingOptions/global.stubs.spec.ts +++ b/tests/mountingOptions/global.stubs.spec.ts @@ -1,9 +1,11 @@ import { h, defineComponent, defineAsyncComponent } from 'vue' -import { config, flushPromises, mount, RouterLinkStub } from '../../src' +import { config, flushPromises, mount, RouterLinkStub, shallowMount } from '../../src' import Hello from '../components/Hello.vue' import ComponentWithoutName from '../components/ComponentWithoutName.vue' import ComponentWithSlots from '../components/ComponentWithSlots.vue' +import ScriptSetupDefineProps from '../components/ScriptSetupDefineProps.vue' +import WithProps from '../components/WithProps.vue' describe('mounting options: stubs', () => { let configStubsSave = config.global.stubs @@ -698,6 +700,55 @@ describe('mounting options: stubs', () => { }) }) + describe('stub props', () => { + it('stubs component props', () => { + const wrapper = shallowMount(defineComponent({ + render: () => h(WithProps, { + withDefaultString: 'other-value', + withDefaultBool: true, + withDefaultArray: ['one', 'two'], + withDefaultObject: {key: 'value'} + }) + })) + expect(wrapper.html()).toEqual( + '' + ) + }) + + it('stubs component props default values', () => { + const wrapper = shallowMount(defineComponent({ + render: () => h(WithProps) + })) + expect(wrapper.html()).toEqual( + '' + ) + }) + + it('stubs component props default values', () => { + const wrapper = shallowMount(defineComponent({ + render: () => h(WithProps, { + withDefaultString: 'default-value', + withDefaultBool: false, + withDefaultArray: ['default-value'], + withDefaultObject: { obj: 'default' } + }) + })) + expect(wrapper.html()).toEqual( + '' + ) + }) + + it('stubs script setup component with define props default values', () => { + const wrapper = shallowMount(defineComponent({ + components: { ScriptSetupDefineProps }, + render: () => h(ScriptSetupDefineProps) + })) + expect(wrapper.html()).toEqual( + '' + ) + }) + }) + it('renders stub for anonymous component when using shallow mount', () => { const AnonymousComponent = defineComponent({ template: `
` diff --git a/tests/props.spec.ts b/tests/props.spec.ts index f4788c3e1..f4f0fa39c 100644 --- a/tests/props.spec.ts +++ b/tests/props.spec.ts @@ -12,7 +12,28 @@ describe('props', () => { it('returns all props applied to a component', () => { const wrapper = mount(WithProps, { props: { msg: 'ABC' } }) - expect(wrapper.props()).toEqual({ msg: 'ABC' }) + expect(wrapper.props()).toEqual({ + msg: 'ABC', + withDefaultString: 'default-value', + withDefaultBool: false, + withDefaultArray: ['default-value'], + withDefaultObject: { obj: 'default' } + }) + }) + + it('return default value of string prop', () => { + const wrapper = mount(WithProps, { props: { msg: 'ABC' } }) + expect(wrapper.props('withDefaultString')).toBe('default-value') + }) + + it('return default value of boolean prop', () => { + const wrapper = mount(WithProps, { props: { msg: 'ABC' } }) + expect(wrapper.props('withDefaultBool')).toBe(false) + }) + + it('return default value of object prop', () => { + const wrapper = mount(WithProps, { props: { msg: 'ABC' } }) + expect(wrapper.props('withDefaultObject')).toEqual({ obj: 'default' }) }) it('returns undefined if props does not exist', () => { From 782fb60aff1977dc72e95b8694d793d131e989c0 Mon Sep 17 00:00:00 2001 From: freakzlike Date: Thu, 23 Dec 2021 17:08:43 +0100 Subject: [PATCH 2/4] chore: fix lint errors --- src/stubs.ts | 96 ++++++++++++--------- tests/components/ScriptSetupDefineProps.vue | 27 +++--- tests/mountingOptions/global.stubs.spec.ts | 64 ++++++++------ 3 files changed, 107 insertions(+), 80 deletions(-) diff --git a/src/stubs.ts b/src/stubs.ts index 2dfea559d..a49bb56b4 100644 --- a/src/stubs.ts +++ b/src/stubs.ts @@ -13,7 +13,12 @@ import { } from 'vue' import { hyphenate } from './utils/vueShared' import { matchName } from './utils/matchName' -import { hasOwnProperty, isComponent, isFunctionalComponent, isObjectComponent } from './utils' +import { + hasOwnProperty, + isComponent, + isFunctionalComponent, + isObjectComponent +} from './utils' import { ComponentInternalInstance, Prop } from '@vue/runtime-core' import { isLegacyExtendedComponent, @@ -85,52 +90,59 @@ export const createStub = ({ const propsWithoutSymbols = stringifySymbols(ctx.$props) // Filter default value of props - const props = Object.entries(propsWithoutSymbols).reduce((props, [propName, propValue]) => { - const skipProp = (() => { - if (propValue === undefined) return true - - // Prop declaration in array style will be skipped here - const propDeclaration = (propsDeclaration as any)?.[propName] as Prop | undefined - if (propDeclaration) { - // Boolean prop declaration: myProp: Boolean - if (propDeclaration === Boolean) return !propValue - - // Prop declaration with object style - // myProp: { type: String, default: 'default-value' } - if (typeof propDeclaration === 'object' && hasOwnProperty(propDeclaration, 'default')) { - let defaultValue = propDeclaration.default - - // Default value factory? - // myProp: { type: Array, default: () => ['one'] } - if (typeof defaultValue === 'function') { - defaultValue = defaultValue() - } - - // Compare primitive value - if (typeof defaultValue !== 'object' || typeof propValue !== 'object') { - return defaultValue === propValue + const props = Object.entries(propsWithoutSymbols).reduce( + (props, [propName, propValue]) => { + const skipProp = (() => { + if (propValue === undefined) return true + + // Prop declaration in array style will be skipped here + const propDeclaration = (propsDeclaration as any)?.[propName] as + | Prop + | undefined + if (propDeclaration) { + // Boolean prop declaration: myProp: Boolean + if (propDeclaration === Boolean) return !propValue + + // Prop declaration with object style + // myProp: { type: String, default: 'default-value' } + if ( + typeof propDeclaration === 'object' && + hasOwnProperty(propDeclaration, 'default') + ) { + let defaultValue = propDeclaration.default + + // Default value factory? + // myProp: { type: Array, default: () => ['one'] } + if (typeof defaultValue === 'function') { + defaultValue = defaultValue() + } + + // Compare primitive value + if ( + typeof defaultValue !== 'object' || + typeof propValue !== 'object' + ) { + return defaultValue === propValue + } + + // Compare objects + // TODO: use some different object comparison + return JSON.stringify(defaultValue) === JSON.stringify(propValue) } - - // Compare objects - // TODO: use some different object comparison - return JSON.stringify(defaultValue) === JSON.stringify(propValue) } - } - return false - })() + return false + })() - if (!skipProp) { - props[propName] = propValue - } - return props - }, {} as Record) - - return h( - tag, - props, - renderStubDefaultSlot ? ctx.$slots : undefined + if (!skipProp) { + props[propName] = propValue + } + return props + }, + {} as Record ) + + return h(tag, props, renderStubDefaultSlot ? ctx.$slots : undefined) } return defineComponent({ diff --git a/tests/components/ScriptSetupDefineProps.vue b/tests/components/ScriptSetupDefineProps.vue index 4449d7b9d..d9521a7d5 100644 --- a/tests/components/ScriptSetupDefineProps.vue +++ b/tests/components/ScriptSetupDefineProps.vue @@ -1,17 +1,20 @@ diff --git a/tests/mountingOptions/global.stubs.spec.ts b/tests/mountingOptions/global.stubs.spec.ts index 6fb28e4c4..918f6d066 100644 --- a/tests/mountingOptions/global.stubs.spec.ts +++ b/tests/mountingOptions/global.stubs.spec.ts @@ -1,6 +1,12 @@ import { h, defineComponent, defineAsyncComponent } from 'vue' -import { config, flushPromises, mount, RouterLinkStub, shallowMount } from '../../src' +import { + config, + flushPromises, + mount, + RouterLinkStub, + shallowMount +} from '../../src' import Hello from '../components/Hello.vue' import ComponentWithoutName from '../components/ComponentWithoutName.vue' import ComponentWithSlots from '../components/ComponentWithSlots.vue' @@ -702,47 +708,53 @@ describe('mounting options: stubs', () => { describe('stub props', () => { it('stubs component props', () => { - const wrapper = shallowMount(defineComponent({ - render: () => h(WithProps, { - withDefaultString: 'other-value', - withDefaultBool: true, - withDefaultArray: ['one', 'two'], - withDefaultObject: {key: 'value'} + const wrapper = shallowMount( + defineComponent({ + render: () => + h(WithProps, { + withDefaultString: 'other-value', + withDefaultBool: true, + withDefaultArray: ['one', 'two'], + withDefaultObject: { key: 'value' } + }) }) - })) + ) expect(wrapper.html()).toEqual( '' ) }) it('stubs component props default values', () => { - const wrapper = shallowMount(defineComponent({ - render: () => h(WithProps) - })) - expect(wrapper.html()).toEqual( - '' + const wrapper = shallowMount( + defineComponent({ + render: () => h(WithProps) + }) ) + expect(wrapper.html()).toEqual('') }) it('stubs component props default values', () => { - const wrapper = shallowMount(defineComponent({ - render: () => h(WithProps, { - withDefaultString: 'default-value', - withDefaultBool: false, - withDefaultArray: ['default-value'], - withDefaultObject: { obj: 'default' } + const wrapper = shallowMount( + defineComponent({ + render: () => + h(WithProps, { + withDefaultString: 'default-value', + withDefaultBool: false, + withDefaultArray: ['default-value'], + withDefaultObject: { obj: 'default' } + }) }) - })) - expect(wrapper.html()).toEqual( - '' ) + expect(wrapper.html()).toEqual('') }) it('stubs script setup component with define props default values', () => { - const wrapper = shallowMount(defineComponent({ - components: { ScriptSetupDefineProps }, - render: () => h(ScriptSetupDefineProps) - })) + const wrapper = shallowMount( + defineComponent({ + components: { ScriptSetupDefineProps }, + render: () => h(ScriptSetupDefineProps) + }) + ) expect(wrapper.html()).toEqual( '' ) From 5f49b61f23dc85f077453f024aa45621e2d96fb8 Mon Sep 17 00:00:00 2001 From: freakzlike Date: Wed, 29 Dec 2021 16:13:53 +0100 Subject: [PATCH 3/4] chore: Add deepCompare for stub prop compare and refactor default props --- src/stubs.ts | 135 ++++++++------ src/utils.ts | 38 ++++ tests/mountingOptions/global.stubs.spec.ts | 198 ++++++++++++++++----- tests/utils.jest.spec.ts | 64 +++++++ 4 files changed, 336 insertions(+), 99 deletions(-) create mode 100644 tests/utils.jest.spec.ts diff --git a/src/stubs.ts b/src/stubs.ts index 008a79a65..dd57ef03f 100644 --- a/src/stubs.ts +++ b/src/stubs.ts @@ -14,17 +14,18 @@ import { import { hyphenate } from './utils/vueShared' import { matchName } from './utils/matchName' import { + deepCompare, hasOwnProperty, isComponent, - isFunctionalComponent, - isObjectComponent + isFunctionalComponent } from './utils' -import { ComponentInternalInstance, Prop } from '@vue/runtime-core' -import { - isLegacyExtendedComponent, - unwrapLegacyVueExtendComponent -} from './utils/vueCompatSupport' +import { ComponentInternalInstance } from '@vue/runtime-core' +import { unwrapLegacyVueExtendComponent } from './utils/vueCompatSupport' import { Stub, Stubs } from './types' +import { + getComponentName, + getComponentRegisteredName +} from './utils/componentName' interface StubOptions { name: string @@ -80,6 +81,64 @@ export const createStub = ({ const anonName = 'anonymous-stub' const tag = name ? `${hyphenate(name)}-stub` : anonName + // Object with default values for component props + const defaultProps = (() => { + // Array-style prop declaration + if (!propsDeclaration || Array.isArray(propsDeclaration)) return {} + + return Object.entries(propsDeclaration).reduce( + (defaultProps, [propName, propDeclaration]) => { + let defaultValue = undefined + + if (propDeclaration) { + // Specific default value set + // myProp: { type: String, default: 'default-value' } + if ( + typeof propDeclaration === 'object' && + hasOwnProperty(propDeclaration, 'default') + ) { + defaultValue = propDeclaration.default + + // Default value factory? + // myProp: { type: Array, default: () => ['one'] } + if (typeof defaultValue === 'function') { + defaultValue = defaultValue() + } + } else { + const propType = (() => { + if ( + typeof propDeclaration === 'function' || + Array.isArray(propDeclaration) + ) + return propDeclaration + return typeof propDeclaration === 'object' && + hasOwnProperty(propDeclaration, 'type') + ? propDeclaration.type + : null + })() + + // Boolean prop declaration + // myProp: Boolean + // or + // myProp: [Boolean, String] + if ( + propType === Boolean || + (Array.isArray(propType) && propType.includes(Boolean)) + ) { + defaultValue = false + } + } + } + + if (defaultValue !== undefined) { + defaultProps[propName] = defaultValue + } + return defaultProps + }, + {} as Record + ) + })() + const render = (ctx: ComponentPublicInstance) => { // https://github.com/vuejs/vue-test-utils-next/issues/1076 // Passing a symbol as a static prop is not legal, since Vue will try to do @@ -87,60 +146,24 @@ export const createStub = ({ // causes an error. // Only a problem when shallow mounting. For this reason we iterate of the // props that will be passed and stringify any that are symbols. - const propsWithoutSymbols = stringifySymbols(ctx.$props) + const propsWithoutSymbols: Record = stringifySymbols( + ctx.$props + ) // Filter default value of props - const props = Object.entries(propsWithoutSymbols).reduce( - (props, [propName, propValue]) => { - const skipProp = (() => { - if (propValue === undefined) return true - - // Prop declaration in array style will be skipped here - const propDeclaration = (propsDeclaration as any)?.[propName] as - | Prop - | undefined - if (propDeclaration) { - // Boolean prop declaration: myProp: Boolean - if (propDeclaration === Boolean) return !propValue - - // Prop declaration with object style - // myProp: { type: String, default: 'default-value' } - if ( - typeof propDeclaration === 'object' && - hasOwnProperty(propDeclaration, 'default') - ) { - let defaultValue = propDeclaration.default - - // Default value factory? - // myProp: { type: Array, default: () => ['one'] } - if (typeof defaultValue === 'function') { - defaultValue = defaultValue() - } - - // Compare primitive value - if ( - typeof defaultValue !== 'object' || - typeof propValue !== 'object' - ) { - return defaultValue === propValue - } - - // Compare objects - // TODO: use some different object comparison - return JSON.stringify(defaultValue) === JSON.stringify(propValue) - } - } - - return false - })() - - if (!skipProp) { + const props = Object.keys(propsWithoutSymbols) + .sort() + .reduce((props, propName) => { + const propValue = propsWithoutSymbols[propName] + + if ( + propValue !== undefined && + !deepCompare(propValue, defaultProps[propName]) + ) { props[propName] = propValue } return props - }, - {} as Record - ) + }, {} as Record) return h(tag, props, renderStubDefaultSlot ? ctx.$slots : undefined) } diff --git a/src/utils.ts b/src/utils.ts index 2748805c7..32b367b19 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -68,6 +68,44 @@ export const mergeDeep = ( return target } +/** + * Deep compare two objects + * Does not work with circular objects and only compares method names + */ +export const deepCompare = (a: unknown, b: unknown): boolean => { + if (a === b) return true + if (!a || !b) return false + if (Array.isArray(a) !== Array.isArray(b)) return false + // Primitive objects! -> Simple compare with: === + if (!isObject(a) || !isObject(b)) return a === b + + if (Object.keys(a).length !== Object.keys(b).length) return false + + for (const p of Object.keys(a)) { + if (!hasOwnProperty(b, p)) return false + + if (typeof a[p] !== typeof b[p]) return false + + switch (typeof a[p]) { + case 'object': + if (!deepCompare(a[p], b[p])) return false + break + case 'function': + type callable = () => void + if ((a[p] as callable).toString() !== (b[p] as callable).toString()) { + return false + } + break + default: + if (a[p] !== b[p]) { + return false + } + } + } + + return true +} + export function isClassComponent(component: unknown) { return typeof component === 'function' && '__vccOpts' in component } diff --git a/tests/mountingOptions/global.stubs.spec.ts b/tests/mountingOptions/global.stubs.spec.ts index 340489fa0..7a42dd707 100644 --- a/tests/mountingOptions/global.stubs.spec.ts +++ b/tests/mountingOptions/global.stubs.spec.ts @@ -1,18 +1,11 @@ import { h, defineComponent, defineAsyncComponent } from 'vue' -import { - config, - flushPromises, - mount, - RouterLinkStub, - shallowMount -} from '../../src' +import { config, flushPromises, mount, RouterLinkStub } from '../../src' import Hello from '../components/Hello.vue' import ComponentWithoutName from '../components/ComponentWithoutName.vue' import ComponentWithSlots from '../components/ComponentWithSlots.vue' import ScriptSetupWithChildren from '../components/ScriptSetupWithChildren.vue' import ScriptSetupDefineProps from '../components/ScriptSetupDefineProps.vue' -import WithProps from '../components/WithProps.vue' describe('mounting options: stubs', () => { let configStubsSave = config.global.stubs @@ -735,55 +728,174 @@ describe('mounting options: stubs', () => { }) describe('stub props', () => { - it('stubs component props', () => { - const wrapper = shallowMount( - defineComponent({ - render: () => - h(WithProps, { - withDefaultString: 'other-value', - withDefaultBool: true, - withDefaultArray: ['one', 'two'], - withDefaultObject: { key: 'value' } - }) - }) + const PropsComponent = defineComponent({ + name: 'PropsComponent', + props: { + boolShort: Boolean, + boolAndStringShort: [String, Boolean], + boolWithoutDefault: { + type: Boolean + }, + boolWithDefault: { + type: Boolean, + default: true + }, + string: { + type: String, + default: 'default-value' + }, + number: { + type: Number, + default: 47 + }, + array: { + type: Array, + default: () => ['one', 'two'] + }, + obj: { + type: Object, + default: () => ({ obj1: 7 }) + }, + nestedObj: { + type: Object, + default: () => ({ nested: { obj1: 1 } }) + } + }, + template: '
' + }) + + const ParentPropsComponent = defineComponent({ + props: { + childProps: { + type: Object, + default: undefined + } + }, + setup(props) { + return () => h(PropsComponent, props.childProps) + } + }) + + it('stubs with default props', () => { + const wrapper = mount(ParentPropsComponent, { + global: { + stubs: { + PropsComponent: true + } + } + }) + + expect(wrapper.html()).toBe( + '' ) - expect(wrapper.html()).toEqual( - '' + }) + + it('stubs with given default props', () => { + const wrapper = mount(ParentPropsComponent, { + props: { + childProps: { + boolShort: false, + boolAndStringShort: false, + boolWithoutDefault: false, + boolWithDefault: true, + string: 'default-value', + number: 47, + array: ['one', 'two'], + obj: { obj1: 7 }, + nestedObj: { nested: { obj1: 1 } } + } + }, + global: { + stubs: { + PropsComponent: true + } + } + }) + + expect(wrapper.html()).toBe( + '' ) }) - it('stubs component props default values', () => { - const wrapper = shallowMount( - defineComponent({ - render: () => h(WithProps) - }) + it('stubs with given props', () => { + const wrapper = mount(ParentPropsComponent, { + props: { + childProps: { + boolShort: true, + boolAndStringShort: 'test', + boolWithoutDefault: true, + boolWithDefault: false, + string: 'test', + number: 5, + array: ['three', 'four'], + obj: { obj1: 5 }, + nestedObj: { nested: { obj1: 2 } } + } + }, + global: { + stubs: { + PropsComponent: true + } + } + }) + + expect(wrapper.html()).toBe( + '' ) - expect(wrapper.html()).toEqual('') }) - it('stubs component props default values', () => { - const wrapper = shallowMount( - defineComponent({ - render: () => - h(WithProps, { - withDefaultString: 'default-value', - withDefaultBool: false, - withDefaultArray: ['default-value'], - withDefaultObject: { obj: 'default' } - }) - }) + it('stubs with array style props', () => { + const ChildComponent = defineComponent({ + name: 'ChildComponent', + props: ['var1', 'var2', 'var3'], + template: '
' + }) + + const ParentComponent = defineComponent({ + render: () => + h(ChildComponent, { + var1: 'test' + }) + }) + + const wrapper = mount(ParentComponent, { + global: { + stubs: { + ChildComponent: true + } + } + }) + + expect(wrapper.html()).toBe( + '' ) - expect(wrapper.html()).toEqual('') }) - it('stubs script setup component with define props default values', () => { - const wrapper = shallowMount( + it('stubs with script setup define props', () => { + const wrapper = mount( defineComponent({ components: { ScriptSetupDefineProps }, render: () => h(ScriptSetupDefineProps) - }) + }), + { + global: { + stubs: { + ScriptSetupDefineProps: true + } + } + } ) - expect(wrapper.html()).toEqual( + expect(wrapper.html()).toBe( '' ) }) diff --git a/tests/utils.jest.spec.ts b/tests/utils.jest.spec.ts new file mode 100644 index 000000000..9e6f2f9b9 --- /dev/null +++ b/tests/utils.jest.spec.ts @@ -0,0 +1,64 @@ +/** + * deepCompare + */ +import { deepCompare } from '../src/utils' + +describe('deepCompare', () => { + it('should be equal', () => { + expect(deepCompare(1, 1)).toBe(true) + expect(deepCompare('1', '1')).toBe(true) + expect(deepCompare(true, true)).toBe(true) + expect(deepCompare(false, false)).toBe(true) + expect(deepCompare({}, {})).toBe(true) + expect(deepCompare([], [])).toBe(true) + expect(deepCompare({ a: 1 }, { a: 1 })).toBe(true) + expect(deepCompare({ a: '1' }, { a: '1' })).toBe(true) + expect(deepCompare({ a: '1', b: 2 }, { a: '1', b: 2 })).toBe(true) + expect(deepCompare({ a: '1', b: [] }, { a: '1', b: [] })).toBe(true) + expect(deepCompare({ a: '1', b: [1, 2] }, { a: '1', b: [1, 2] })).toBe(true) + expect(deepCompare([1], [1])).toBe(true) + expect(deepCompare([1, 1], [1, 1])).toBe(true) + expect(deepCompare([1, '1'], [1, '1'])).toBe(true) + expect(deepCompare(['1', 1], ['1', 1])).toBe(true) + expect(deepCompare([{}], [{}])).toBe(true) + expect(deepCompare([{ a: 1 }], [{ a: 1 }])).toBe(true) + expect(deepCompare({ + method () { + } + }, { + method () { + } + })).toBe(true) + }) + + it('should not be equal', () => { + expect(deepCompare(1, 2)).toBe(false) + expect(deepCompare(1, null)).toBe(false) + expect(deepCompare('1', '2')).toBe(false) + expect(deepCompare({}, { a: 1 })).toBe(false) + expect(deepCompare({ a: 1 }, {})).toBe(false) + expect(deepCompare({ a: 1 }, { a: 2 })).toBe(false) + expect(deepCompare({ a: 2 }, { a: 1 })).toBe(false) + expect(deepCompare({ a: 2 }, { b: 2 })).toBe(false) + expect(deepCompare({ a: { b: 1 } }, { a: { c: 1 } })).toBe(false) + expect(deepCompare([], [1])).toBe(false) + expect(deepCompare([1], [])).toBe(false) + expect(deepCompare([], ['1'])).toBe(false) + expect(deepCompare(['1'], [])).toBe(false) + expect(deepCompare(1, {})).toBe(false) + expect(deepCompare({}, 1)).toBe(false) + expect(deepCompare(1, { a: 1 })).toBe(false) + expect(deepCompare({ a: 1 }, 1)).toBe(false) + expect(deepCompare({}, [])).toBe(false) + expect(deepCompare([], {})).toBe(false) + expect(deepCompare({ a: 1 }, [1])).toBe(false) + expect(deepCompare([1], { a: 1 })).toBe(false) + expect(deepCompare({ + method: function x () { + } + }, { + method: function y () { + } + })).toBe(false) + }) +}) From 777749941ef1b3cd4186661b50d10132d2cc5a52 Mon Sep 17 00:00:00 2001 From: freakzlike Date: Wed, 29 Dec 2021 16:15:12 +0100 Subject: [PATCH 4/4] chore: fix lint errors --- tests/utils.jest.spec.ts | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/tests/utils.jest.spec.ts b/tests/utils.jest.spec.ts index 9e6f2f9b9..4782fe793 100644 --- a/tests/utils.jest.spec.ts +++ b/tests/utils.jest.spec.ts @@ -22,13 +22,16 @@ describe('deepCompare', () => { expect(deepCompare(['1', 1], ['1', 1])).toBe(true) expect(deepCompare([{}], [{}])).toBe(true) expect(deepCompare([{ a: 1 }], [{ a: 1 }])).toBe(true) - expect(deepCompare({ - method () { - } - }, { - method () { - } - })).toBe(true) + expect( + deepCompare( + { + method() {} + }, + { + method() {} + } + ) + ).toBe(true) }) it('should not be equal', () => { @@ -53,12 +56,15 @@ describe('deepCompare', () => { expect(deepCompare([], {})).toBe(false) expect(deepCompare({ a: 1 }, [1])).toBe(false) expect(deepCompare([1], { a: 1 })).toBe(false) - expect(deepCompare({ - method: function x () { - } - }, { - method: function y () { - } - })).toBe(false) + expect( + deepCompare( + { + method: function x() {} + }, + { + method: function y() {} + } + ) + ).toBe(false) }) })