Skip to content

Commit

Permalink
fix(expect): preserve prototype in toMatchObject diff (#6620)
Browse files Browse the repository at this point in the history
  • Loading branch information
hi-ogawa authored Oct 3, 2024
1 parent 0ce26a4 commit d289e7e
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 3 deletions.
1 change: 1 addition & 0 deletions packages/expect/src/jest-expect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, [
Expand Down
12 changes: 10 additions & 2 deletions packages/expect/src/jest-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ export function getObjectKeys(object: object): Array<string | symbol> {
export function getObjectSubset(
object: any,
subset: any,
customTesters: Array<Tester> = [],
customTesters: Array<Tester>,
): { subset: any; stripped: number } {
let stripped = 0

Expand All @@ -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])
Expand Down
122 changes: 121 additions & 1 deletion test/core/test/jest-expect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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', () => {
Expand Down

0 comments on commit d289e7e

Please sign in to comment.