Skip to content

Commit

Permalink
fix(expect): toMatchObject with inherited getters
Browse files Browse the repository at this point in the history
- It also works with `defineProperty`
- There's still a bit of work to be done on
  improving the reporting of this
  • Loading branch information
souldzin committed Aug 9, 2020
1 parent 7723ae2 commit 3a88c29
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -7,6 +7,7 @@

### Fixes

- `[expect]` Fix `toMatchObject` to work with inherited class getters ([#10381](https://github.com/facebook/jest/pull/10381))
- `[jest-leak-detector]` Wait properly for GC runs due to changes in Node 14.7 ([#10366](https://github.com/facebook/jest/pull/10366))
- `[jest-worker]` Downgrade minimum node version to 10.13 ([#10352](https://github.com/facebook/jest/pull/10352))

Expand Down
14 changes: 14 additions & 0 deletions packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap
Expand Up @@ -4314,13 +4314,27 @@ exports[`toMatchObject() {pass: true} expect({"a": undefined}).toMatchObject({"a
Expected: not <g>{"a": undefined}</>
`;

exports[`toMatchObject() {pass: true} expect({}).toMatchObject({"a": undefined, "b": "b", "c": "c"}) 1`] = `
<d>expect(</><r>received</><d>).</>not<d>.</>toMatchObject<d>(</><g>expected</><d>)</>

Expected: not <g>{"a": undefined, "b": "b", "c": "c"}</>
Received: <r>{}</>
`;

exports[`toMatchObject() {pass: true} expect({}).toMatchObject({"a": undefined, "b": "b"}) 1`] = `
<d>expect(</><r>received</><d>).</>not<d>.</>toMatchObject<d>(</><g>expected</><d>)</>

Expected: not <g>{"a": undefined, "b": "b"}</>
Received: <r>{}</>
`;

exports[`toMatchObject() {pass: true} expect({}).toMatchObject({"d": 4}) 1`] = `
<d>expect(</><r>received</><d>).</>not<d>.</>toMatchObject<d>(</><g>expected</><d>)</>

Expected: not <g>{"d": 4}</>
Received: <r>{}</>
`;

exports[`toMatchObject() {pass: true} expect(2015-11-30T00:00:00.000Z).toMatchObject(2015-11-30T00:00:00.000Z) 1`] = `
<d>expect(</><r>received</><d>).</>not<d>.</>toMatchObject<d>(</><g>expected</><d>)</>

Expand Down
21 changes: 21 additions & 0 deletions packages/expect/src/__tests__/matchers.test.js
Expand Up @@ -1958,6 +1958,22 @@ describe('toMatchObject()', () => {
}
}

class Sub extends Foo {
get c() {
return 'c';
}
}

const withDefineProperty = (obj, key, val) => {
Object.defineProperty(obj, key, {
get() {
return val;
},
});

return obj;
};

const testNotToMatchSnapshots = tuples => {
tuples.forEach(([n1, n2]) => {
it(`{pass: true} expect(${stringify(n1)}).toMatchObject(${stringify(
Expand Down Expand Up @@ -2082,6 +2098,11 @@ describe('toMatchObject()', () => {
{a: 'b', c: 'd', [Symbol.for('jest')]: 'jest'},
{a: 'b', c: 'd', [Symbol.for('jest')]: 'jest'},
],
// These snapshots will show {} as the object because the properties
// are not enumerable. We will need to somehow make the serialization of
// these keys a little smarter before reporting accurately.
[new Sub(), {a: undefined, b: 'b', c: 'c'}],
[withDefineProperty(new Sub(), 'd', 4), {d: 4}],
]);

testToMatchSnapshots([
Expand Down
5 changes: 4 additions & 1 deletion packages/expect/src/utils.ts
Expand Up @@ -21,6 +21,9 @@ type GetPath = {
value?: unknown;
};

const hasPropertyInObject = (object: object, key: string) =>
typeof object === 'object' && key in object;

// Return whether object instance inherits getter from its class.
const hasGetterFromConstructor = (object: object, key: string) => {
const constructor = object.constructor;
Expand Down Expand Up @@ -299,7 +302,7 @@ export const subsetEquality = (
}
const result =
object != null &&
hasOwnProperty(object, key) &&
hasPropertyInObject(object, key) &&
equals(object[key], subset[key], [
iterableEquality,
subsetEqualityWithContext(seenReferences),
Expand Down

0 comments on commit 3a88c29

Please sign in to comment.