From 49af781bf791999b97eb81fd27c60b9a0fbd0389 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Thu, 2 Nov 2023 23:28:00 +1100 Subject: [PATCH 1/2] fix(@jest/expect-utils): exclude non-enumerable symbol in object matching (#14670) --- CHANGELOG.md | 1 + .../expect-utils/src/__tests__/utils.test.ts | 45 +++++++++++++++++++ packages/expect-utils/src/utils.ts | 24 +++++++--- 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a66604ccaa6e..dc4bc7cd6bd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - `[jest-circus, jest-expect, jest-snapshot]` Pass `test.failing` tests when containing failing snapshot matchers ([#14313](https://github.com/jestjs/jest/pull/14313)) - `[jest-config]` Make sure to respect `runInBand` option ([#14578](https://github.com/facebook/jest/pull/14578)) - `[@jest/expect-utils]` Fix comparison of `DataView` ([#14408](https://github.com/jestjs/jest/pull/14408)) +- `[@jest/expect-utils]` [**BREAKING**] exclude non-enumerable in object matching ([#14670](https://github.com/jestjs/jest/pull/14670)) - `[jest-leak-detector]` Make leak-detector more aggressive when running GC ([#14526](https://github.com/jestjs/jest/pull/14526)) - `[jest-runtime]` Properly handle re-exported native modules in ESM via CJS ([#14589](https://github.com/jestjs/jest/pull/14589)) - `[jest-util]` Make sure `isInteractive` works in a browser ([#14552](https://github.com/jestjs/jest/pull/14552)) diff --git a/packages/expect-utils/src/__tests__/utils.test.ts b/packages/expect-utils/src/__tests__/utils.test.ts index c4d7893e4298..a563e9d9a860 100644 --- a/packages/expect-utils/src/__tests__/utils.test.ts +++ b/packages/expect-utils/src/__tests__/utils.test.ts @@ -355,6 +355,51 @@ describe('subsetEquality()', () => { ).toBe(false); }); }); + + describe('matching subsets with symbols', () => { + describe('same symbol', () => { + test('objects to not match with value diff', () => { + const symbol = Symbol('foo'); + expect(subsetEquality({[symbol]: 1}, {[symbol]: 2})).toBe(false); + }); + + test('objects to match with non-enumerable symbols', () => { + const symbol = Symbol('foo'); + const foo = {}; + Object.defineProperty(foo, symbol, { + enumerable: false, + value: 1, + }); + const bar = {}; + Object.defineProperty(bar, symbol, { + enumerable: false, + value: 2, + }); + expect(subsetEquality(foo, bar)).toBe(true); + }); + }); + + describe('different symbol', () => { + test('objects to not match with same value', () => { + expect(subsetEquality({[Symbol('foo')]: 1}, {[Symbol('foo')]: 2})).toBe( + false, + ); + }); + test('objects to match with non-enumerable symbols', () => { + const foo = {}; + Object.defineProperty(foo, Symbol('foo'), { + enumerable: false, + value: 1, + }); + const bar = {}; + Object.defineProperty(bar, Symbol('foo'), { + enumerable: false, + value: 2, + }); + expect(subsetEquality(foo, bar)).toBe(true); + }); + }); + }); }); describe('iterableEquality', () => { diff --git a/packages/expect-utils/src/utils.ts b/packages/expect-utils/src/utils.ts index c666e6697d9b..45d341bfdd78 100644 --- a/packages/expect-utils/src/utils.ts +++ b/packages/expect-utils/src/utils.ts @@ -44,13 +44,23 @@ const hasPropertyInObject = (object: object, key: string | symbol): boolean => { }; // Retrieves an object's keys for evaluation by getObjectSubset. This evaluates -// the prototype chain for string keys but not for symbols. (Otherwise, it -// could find values such as a Set or Map's Symbol.toStringTag, with unexpected -// results.) -export const getObjectKeys = (object: object): Array => [ - ...Object.keys(object), - ...Object.getOwnPropertySymbols(object), -]; +// the prototype chain for string keys but not for non-enumerable symbols. +// (Otherwise, it could find values such as a Set or Map's Symbol.toStringTag, +// with unexpected results.) +// export const getObjectKeys = (object: object): Array => [ +// ...Object.keys(object), +// ...Object.getOwnPropertySymbols(object).filter( +// s => Object.getOwnPropertyDescriptor(object, s)?.enumerable, +// ), +// ]; +export const getObjectKeys = (object: object): Array => { + return [ + ...Object.keys(object), + ...Object.getOwnPropertySymbols(object).filter( + s => Object.getOwnPropertyDescriptor(object, s)?.enumerable, + ), + ]; +}; export const getPath = ( object: Record, From 544a4b8b2f5bffbac2192b0f75c024a434d49b79 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Thu, 2 Nov 2023 23:50:13 +1100 Subject: [PATCH 2/2] chore: remove mis-added comments in expect-utils (#14673) --- packages/expect-utils/src/utils.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/expect-utils/src/utils.ts b/packages/expect-utils/src/utils.ts index 45d341bfdd78..0afc8fb23086 100644 --- a/packages/expect-utils/src/utils.ts +++ b/packages/expect-utils/src/utils.ts @@ -47,12 +47,6 @@ const hasPropertyInObject = (object: object, key: string | symbol): boolean => { // the prototype chain for string keys but not for non-enumerable symbols. // (Otherwise, it could find values such as a Set or Map's Symbol.toStringTag, // with unexpected results.) -// export const getObjectKeys = (object: object): Array => [ -// ...Object.keys(object), -// ...Object.getOwnPropertySymbols(object).filter( -// s => Object.getOwnPropertyDescriptor(object, s)?.enumerable, -// ), -// ]; export const getObjectKeys = (object: object): Array => { return [ ...Object.keys(object),