diff --git a/packages/expect/src/jest-expect.ts b/packages/expect/src/jest-expect.ts index 7252888c5631..e925e3c3316e 100644 --- a/packages/expect/src/jest-expect.ts +++ b/packages/expect/src/jest-expect.ts @@ -195,6 +195,7 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => { const { subset: actualSubset, stripped } = getObjectSubset( actual, expected, + customTesters, ) if ((pass && isNot) || (!pass && !isNot)) { const msg = utils.getMessage(this, [ diff --git a/packages/expect/src/jest-utils.ts b/packages/expect/src/jest-utils.ts index 08d5687dfb27..e0bb88e65e69 100644 --- a/packages/expect/src/jest-utils.ts +++ b/packages/expect/src/jest-utils.ts @@ -676,7 +676,7 @@ export function getObjectKeys(object: object): Array { export function getObjectSubset( object: any, subset: any, - customTesters: Array = [], + customTesters: Array, ): { subset: any; stripped: number } { let stripped = 0 @@ -702,13 +702,21 @@ export function getObjectSubset( subsetEquality, ]) ) { - // Avoid unnecessary copy which might return Object instead of subclass. + // return "expected" subset to avoid showing irrelavant toMatchObject diff return subset } const trimmed: any = {} seenReferences.set(object, trimmed) + // preserve constructor for toMatchObject diff + if (typeof object.constructor === 'function' && typeof object.constructor.name === 'string') { + Object.defineProperty(trimmed, 'constructor', { + enumerable: false, + value: object.constructor, + }) + } + for (const key of getObjectKeys(object)) { if (hasPropertyInObject(subset, key)) { trimmed[key] = seenReferences.has(object[key]) diff --git a/test/core/test/jest-expect.test.ts b/test/core/test/jest-expect.test.ts index 9f9bc6a7e112..b97d1a7c6297 100644 --- a/test/core/test/jest-expect.test.ts +++ b/test/core/test/jest-expect.test.ts @@ -927,12 +927,12 @@ function trim(s: string): string { function getError(f: () => unknown) { try { f() - return expect.unreachable() } catch (error) { const processed = processError(error) return [stripVTControlCharacters(processed.message), stripVTControlCharacters(trim(processed.diff))] } + return expect.unreachable() } it('toMatchObject error diff', () => { @@ -1059,6 +1059,126 @@ it('toMatchObject error diff', () => { }", ] `) + + // https://github.com/vitest-dev/vitest/issues/6543 + class Foo { + constructor(public value: any) {} + } + + class Bar { + constructor(public value: any) {} + } + + expect(new Foo(0)).toMatchObject(new Bar(0)) + expect(new Foo(0)).toMatchObject({ value: 0 }) + expect({ value: 0 }).toMatchObject(new Bar(0)) + + expect(getError(() => expect(new Foo(0)).toMatchObject(new Bar(1)))).toMatchInlineSnapshot(` + [ + "expected Foo{ value: +0 } to match object Bar{ value: 1 }", + "- Expected + + Received + + - Bar { + - "value": 1, + + Foo { + + "value": 0, + }", + ] + `) + + expect(getError(() => expect(new Foo(0)).toMatchObject({ value: 1 }))).toMatchInlineSnapshot(` + [ + "expected Foo{ value: +0 } to match object { value: 1 }", + "- Expected + + Received + + - Object { + - "value": 1, + + Foo { + + "value": 0, + }", + ] + `) + + expect(getError(() => expect({ value: 0 }).toMatchObject(new Bar(1)))).toMatchInlineSnapshot(` + [ + "expected { value: +0 } to match object Bar{ value: 1 }", + "- Expected + + Received + + - Bar { + - "value": 1, + + Object { + + "value": 0, + }", + ] + `) + + expect(getError(() => + expect({ + bad: new Foo(1), + good: new Foo(0), + }).toMatchObject({ + bad: new Bar(2), + good: new Bar(0), + }), + )).toMatchInlineSnapshot(` + [ + "expected { bad: Foo{ value: 1 }, …(1) } to match object { bad: Bar{ value: 2 }, …(1) }", + "- Expected + + Received + + Object { + - "bad": Bar { + - "value": 2, + + "bad": Foo { + + "value": 1, + }, + "good": Bar { + "value": 0, + }, + }", + ] + `) + + expect(getError(() => + expect(new Foo(new Foo(1))).toMatchObject(new Bar(new Bar(0))), + )).toMatchInlineSnapshot(` + [ + "expected Foo{ value: Foo{ value: 1 } } to match object Bar{ value: Bar{ value: +0 } }", + "- Expected + + Received + + - Bar { + - "value": Bar { + - "value": 0, + + Foo { + + "value": Foo { + + "value": 1, + }, + }", + ] + `) + + expect(new Foo(new Foo(1))).toMatchObject(new Bar(new Foo(1))) + expect(getError(() => + expect(new Foo(new Foo(1))).toMatchObject(new Bar(new Foo(2))), + )).toMatchInlineSnapshot(` + [ + "expected Foo{ value: Foo{ value: 1 } } to match object Bar{ value: Foo{ value: 2 } }", + "- Expected + + Received + + - Bar { + + Foo { + "value": Foo { + - "value": 2, + + "value": 1, + }, + }", + ] + `) }) it('toHaveProperty error diff', () => {