From 7a27e77e0819f63b416ac66c3b8a96639fee47f2 Mon Sep 17 00:00:00 2001 From: Gianfranco Date: Wed, 18 Dec 2019 18:00:14 +0800 Subject: [PATCH 1/2] Fix subsetEquality: same referenced object on same level node of tree is regarded as circular reference --- CHANGELOG.md | 1 + packages/expect/src/__tests__/utils.test.js | 13 +++++++++++++ packages/expect/src/utils.ts | 16 ++++++++++------ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 053ebb3bcbe0..497660acc406 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,7 @@ - `[jest-utils]` Allow querying process.domain ([#9136](https://github.com/facebook/jest/pull/9136)) - `[pretty-format]` Correctly detect memoized elements ([#9196](https://github.com/facebook/jest/pull/9196)) - `[jest-fake-timers]` Support `util.promisify` on `setTimeout` ([#9180](https://github.com/facebook/jest/pull/9180)) +- `[expect]` Fix subsetEquality: fix circular reference handling logic ([#9322](https://github.com/facebook/jest/pull/9322)) ### Chore & Maintenance diff --git a/packages/expect/src/__tests__/utils.test.js b/packages/expect/src/__tests__/utils.test.js index a8c539eb90dc..0eb4bdca4659 100644 --- a/packages/expect/src/__tests__/utils.test.js +++ b/packages/expect/src/__tests__/utils.test.js @@ -333,6 +333,19 @@ describe('subsetEquality()', () => { expect(subsetEquality(primitiveInsteadOfRef, circularObjA1)).toBe(false); }); + test('referenced object on same level should not regarded as circular reference', () => { + const referencedObj = {abc: 'def'}; + const object = { + a: {abc: 'def'}, + b: {abc: 'def', zzz: 'zzz'}, + }; + const thisIsNotCircular = { + a: referencedObj, + b: referencedObj, + }; + expect(subsetEquality(object, thisIsNotCircular)).toBeTruthy(); + }); + test('transitive circular references', () => { const transitiveCircularObjA1 = {a: 'hello'}; transitiveCircularObjA1.nestedObj = {parentObj: transitiveCircularObjA1}; diff --git a/packages/expect/src/utils.ts b/packages/expect/src/utils.ts index a642e56b22ee..d4763e9f4056 100644 --- a/packages/expect/src/utils.ts +++ b/packages/expect/src/utils.ts @@ -166,7 +166,6 @@ export const iterableEquality = ( if (a.constructor !== b.constructor) { return false; } - let length = aStack.length; while (length--) { // Linear search. Performance is inversely proportional to the number of @@ -290,20 +289,25 @@ export const subsetEquality = ( return Object.keys(subset).every(key => { if (isObjectWithKeys(subset[key])) { - if (seenReferences.get(subset[key])) { + if (seenReferences.has(subset[key])) { return equals(object[key], subset[key], [iterableEquality]); } seenReferences.set(subset[key], true); } - - return ( + const result = object != null && hasOwnProperty(object, key) && equals(object[key], subset[key], [ iterableEquality, subsetEqualityWithContext(seenReferences), - ]) - ); + ]); + // The main goal of using seenReference is to avoid circular node on tree. + // It will only happen within a parent and its child, not a node and nodes next to it (same level) + // We should keep the reference for a parent and its child only + // Thus we should delete the reference immediately so that it doesn't interfere + // other nodes within the same level on tree. + seenReferences.delete(subset[key]); + return result; }); }; From cb4e2eabc681f0dc3d9af40dd7d4f0a76bccddfa Mon Sep 17 00:00:00 2001 From: Tim Seckinger Date: Wed, 18 Dec 2019 14:47:56 +0000 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 497660acc406..34dd103e6227 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ - `[expect]` Avoid incorrect difference for subset when `toMatchObject` fails ([#9005](https://github.com/facebook/jest/pull/9005)) - `[expect]` Consider all RegExp flags for equality ([#9167](https://github.com/facebook/jest/pull/9167)) - `[expect]` [**BREAKING**] Consider primitives different from wrappers instantiated with `new` ([#9167](https://github.com/facebook/jest/pull/9167)) +- `[expect]` Fix subsetEquality false circular reference detection ([#9322](https://github.com/facebook/jest/pull/9322)) - `[jest-config]` Use half of the available cores when `watchAll` mode is enabled ([#9117](https://github.com/facebook/jest/pull/9117)) - `[jest-config]` Fix Jest multi project runner still cannot handle exactly one project ([#8894](https://github.com/facebook/jest/pull/8894)) - `[jest-console]` Add missing `console.group` calls to `NullConsole` ([#9024](https://github.com/facebook/jest/pull/9024)) @@ -73,7 +74,6 @@ - `[jest-utils]` Allow querying process.domain ([#9136](https://github.com/facebook/jest/pull/9136)) - `[pretty-format]` Correctly detect memoized elements ([#9196](https://github.com/facebook/jest/pull/9196)) - `[jest-fake-timers]` Support `util.promisify` on `setTimeout` ([#9180](https://github.com/facebook/jest/pull/9180)) -- `[expect]` Fix subsetEquality: fix circular reference handling logic ([#9322](https://github.com/facebook/jest/pull/9322)) ### Chore & Maintenance