diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e88eb8eb88b..2c51c2730297 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,8 @@ ### Fixes -- `[expect]` Display expectedDiff more carefully in toBeCloseTo ([#8389](https://github.com/facebook/jest/pull/8389)) +- `[expect]` Display `expectedDiff` more carefully in `toBeCloseTo` ([#8389](https://github.com/facebook/jest/pull/8389)) +- `[expect]` Avoid incorrect difference for subset when `toMatchObject` fails ([#9005](https://github.com/facebook/jest/pull/9005)) - `[jest-core]` Don't include unref'd timers in --detectOpenHandles results ([#8941](https://github.com/facebook/jest/pull/8941)) - `[jest-diff]` Do not inverse format if line consists of one change ([#8903](https://github.com/facebook/jest/pull/8903)) - `[jest-fake-timers]` `getTimerCount` will not include cancelled immediates ([#8764](https://github.com/facebook/jest/pull/8764)) diff --git a/packages/expect/src/__tests__/utils.test.js b/packages/expect/src/__tests__/utils.test.js index b20b3db68700..e78c4e597313 100644 --- a/packages/expect/src/__tests__/utils.test.js +++ b/packages/expect/src/__tests__/utils.test.js @@ -147,7 +147,7 @@ describe('hasOwnProperty', () => { }); }); -describe('getObjectSubset()', () => { +describe('getObjectSubset', () => { [ [{a: 'b', c: 'd'}, {a: 'd'}, {a: 'b'}], [{a: [1, 2], b: 'b'}, {a: [3, 4]}, {a: [1, 2]}], @@ -165,6 +165,43 @@ describe('getObjectSubset()', () => { ); }); + describe('returns the object instance if the subset has no extra properties', () => { + test('Date', () => { + const object = new Date('2015-11-30'); + const subset = new Date('2016-12-30'); + + expect(getObjectSubset(object, subset)).toBe(object); + }); + }); + + describe('returns the subset instance if its property values are equal', () => { + test('Object', () => { + const object = {key0: 'zero', key1: 'one', key2: 'two'}; + const subset = {key0: 'zero', key2: 'two'}; + + expect(getObjectSubset(object, subset)).toBe(subset); + }); + + describe('Uint8Array', () => { + const equalObject = {'0': 0, '1': 0, '2': 0}; + const typedArray = new Uint8Array(3); + + test('expected', () => { + const object = equalObject; + const subset = typedArray; + + expect(getObjectSubset(object, subset)).toBe(subset); + }); + + test('received', () => { + const object = typedArray; + const subset = equalObject; + + expect(getObjectSubset(object, subset)).toBe(subset); + }); + }); + }); + describe('calculating subsets of objects with circular references', () => { test('simple circular references', () => { const nonCircularObj = {a: 'world', b: 'something'}; diff --git a/packages/expect/src/utils.ts b/packages/expect/src/utils.ts index 6e77197bf219..a642e56b22ee 100644 --- a/packages/expect/src/utils.ts +++ b/packages/expect/src/utils.ts @@ -111,6 +111,7 @@ export const getObjectSubset = ( ): any => { if (Array.isArray(object)) { if (Array.isArray(subset) && subset.length === object.length) { + // The map method returns correct subclass of subset. return subset.map((sub: any, i: number) => getObjectSubset(object[i], sub), ); @@ -118,6 +119,11 @@ export const getObjectSubset = ( } else if (object instanceof Date) { return object; } else if (isObject(object) && isObject(subset)) { + if (equals(object, subset, [iterableEquality, subsetEquality])) { + // Avoid unnecessary copy which might return Object instead of subclass. + return subset; + } + const trimmed: any = {}; seenReferences.set(object, trimmed);