diff --git a/src/utils.ts b/src/utils.ts index 7b65a7ec7..e70a673e1 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -72,6 +72,25 @@ export function mergeGlobalProperties( export const isObject = (obj: unknown): obj is Record => !!obj && typeof obj === 'object' +function isClass(obj: unknown) { + if (!(obj instanceof Object)) return + + const isCtorClass = + obj.constructor && obj.constructor.toString().substring(0, 5) === 'class' + + if (!('prototype' in obj)) { + return isCtorClass + } + + const prototype = obj.prototype as any + const isPrototypeCtorClass = + prototype.constructor && + prototype.constructor.toString && + prototype.constructor.toString().substring(0, 5) === 'class' + + return isCtorClass || isPrototypeCtorClass +} + // https://stackoverflow.com/a/48218209 export const mergeDeep = ( target: Record, @@ -80,8 +99,13 @@ export const mergeDeep = ( if (!isObject(target) || !isObject(source)) { return source } + Object.keys(source) - .concat(Object.getOwnPropertyNames(Object.getPrototypeOf(source) ?? {})) + .concat( + isClass(source) + ? Object.getOwnPropertyNames(Object.getPrototypeOf(source) ?? {}) + : Object.getOwnPropertyNames(source) + ) .forEach((key) => { const targetValue = target[key] const sourceValue = source[key] diff --git a/tests/setData.spec.ts b/tests/setData.spec.ts index 6e0edb35b..ba4255b6d 100644 --- a/tests/setData.spec.ts +++ b/tests/setData.spec.ts @@ -246,4 +246,29 @@ describe('setData', () => { expect(wrapper.vm.getResult()).toStrictEqual(`test2: ${expectedResult}`) }) + + // https://github.com/vuejs/test-utils/issues/2257 + it('should ignore prototype methods when using setData on objects', async () => { + const wrapper = mount( + defineComponent({ + template: '
', + data() { + return { + firstArray: [], + secondArray: [] + } + } + }) + ) + + await wrapper.setData({ + firstArray: [1, 2], + secondArray: [3, 4] + }) + + expect(wrapper.vm.$data).toStrictEqual({ + firstArray: [1, 2], + secondArray: [3, 4] + }) + }) })