Skip to content

Commit 49af781

Browse files
authored
fix(@jest/expect-utils): exclude non-enumerable symbol in object matching (#14670)
1 parent 728f112 commit 49af781

File tree

3 files changed

+63
-7
lines changed

3 files changed

+63
-7
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
- `[jest-circus, jest-expect, jest-snapshot]` Pass `test.failing` tests when containing failing snapshot matchers ([#14313](https://github.com/jestjs/jest/pull/14313))
2525
- `[jest-config]` Make sure to respect `runInBand` option ([#14578](https://github.com/facebook/jest/pull/14578))
2626
- `[@jest/expect-utils]` Fix comparison of `DataView` ([#14408](https://github.com/jestjs/jest/pull/14408))
27+
- `[@jest/expect-utils]` [**BREAKING**] exclude non-enumerable in object matching ([#14670](https://github.com/jestjs/jest/pull/14670))
2728
- `[jest-leak-detector]` Make leak-detector more aggressive when running GC ([#14526](https://github.com/jestjs/jest/pull/14526))
2829
- `[jest-runtime]` Properly handle re-exported native modules in ESM via CJS ([#14589](https://github.com/jestjs/jest/pull/14589))
2930
- `[jest-util]` Make sure `isInteractive` works in a browser ([#14552](https://github.com/jestjs/jest/pull/14552))

packages/expect-utils/src/__tests__/utils.test.ts

+45
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,51 @@ describe('subsetEquality()', () => {
355355
).toBe(false);
356356
});
357357
});
358+
359+
describe('matching subsets with symbols', () => {
360+
describe('same symbol', () => {
361+
test('objects to not match with value diff', () => {
362+
const symbol = Symbol('foo');
363+
expect(subsetEquality({[symbol]: 1}, {[symbol]: 2})).toBe(false);
364+
});
365+
366+
test('objects to match with non-enumerable symbols', () => {
367+
const symbol = Symbol('foo');
368+
const foo = {};
369+
Object.defineProperty(foo, symbol, {
370+
enumerable: false,
371+
value: 1,
372+
});
373+
const bar = {};
374+
Object.defineProperty(bar, symbol, {
375+
enumerable: false,
376+
value: 2,
377+
});
378+
expect(subsetEquality(foo, bar)).toBe(true);
379+
});
380+
});
381+
382+
describe('different symbol', () => {
383+
test('objects to not match with same value', () => {
384+
expect(subsetEquality({[Symbol('foo')]: 1}, {[Symbol('foo')]: 2})).toBe(
385+
false,
386+
);
387+
});
388+
test('objects to match with non-enumerable symbols', () => {
389+
const foo = {};
390+
Object.defineProperty(foo, Symbol('foo'), {
391+
enumerable: false,
392+
value: 1,
393+
});
394+
const bar = {};
395+
Object.defineProperty(bar, Symbol('foo'), {
396+
enumerable: false,
397+
value: 2,
398+
});
399+
expect(subsetEquality(foo, bar)).toBe(true);
400+
});
401+
});
402+
});
358403
});
359404

360405
describe('iterableEquality', () => {

packages/expect-utils/src/utils.ts

+17-7
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,23 @@ const hasPropertyInObject = (object: object, key: string | symbol): boolean => {
4444
};
4545

4646
// Retrieves an object's keys for evaluation by getObjectSubset. This evaluates
47-
// the prototype chain for string keys but not for symbols. (Otherwise, it
48-
// could find values such as a Set or Map's Symbol.toStringTag, with unexpected
49-
// results.)
50-
export const getObjectKeys = (object: object): Array<string | symbol> => [
51-
...Object.keys(object),
52-
...Object.getOwnPropertySymbols(object),
53-
];
47+
// the prototype chain for string keys but not for non-enumerable symbols.
48+
// (Otherwise, it could find values such as a Set or Map's Symbol.toStringTag,
49+
// with unexpected results.)
50+
// export const getObjectKeys = (object: object): Array<string | symbol> => [
51+
// ...Object.keys(object),
52+
// ...Object.getOwnPropertySymbols(object).filter(
53+
// s => Object.getOwnPropertyDescriptor(object, s)?.enumerable,
54+
// ),
55+
// ];
56+
export const getObjectKeys = (object: object): Array<string | symbol> => {
57+
return [
58+
...Object.keys(object),
59+
...Object.getOwnPropertySymbols(object).filter(
60+
s => Object.getOwnPropertyDescriptor(object, s)?.enumerable,
61+
),
62+
];
63+
};
5464

5565
export const getPath = (
5666
object: Record<string, any>,

0 commit comments

Comments
 (0)