Skip to content

Commit

Permalink
fix: symbol key could not be enum (#14414)
Browse files Browse the repository at this point in the history
  • Loading branch information
eryue0220 authored Aug 17, 2023
1 parent a5cdc86 commit 9c8fdbb
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Fixes

- `[expect, @jest/expect-utils]` `ObjectContaining` support `sumbol` as key ([#14414](https://github.com/jestjs/jest/pull/14414))
- `[expect]` Remove `@types/node` from dependencies ([#14385](https://github.com/jestjs/jest/pull/14385))
- `[jest-core]` Use workers in watch mode by default to avoid crashes ([#14059](https://github.com/facebook/jest/pull/14059) & [#14085](https://github.com/facebook/jest/pull/14085)).
- `[jest-reporters]` Update `istanbul-lib-instrument` dependency to v6. ([#14401](https://github.com/jestjs/jest/pull/14401))
Expand Down
2 changes: 1 addition & 1 deletion packages/expect-utils/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const hasPropertyInObject = (object: object, key: string | symbol): boolean => {
// 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.)
const getObjectKeys = (object: object) => [
export const getObjectKeys = (object: object): Array<string | symbol> => [
...Object.keys(object),
...Object.getOwnPropertySymbols(object),
];
Expand Down
8 changes: 8 additions & 0 deletions packages/expect/src/__tests__/asymmetricMatchers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ test('ArrayNotContaining throws for non-arrays', () => {
});

test('ObjectContaining matches', () => {
const foo = Symbol('foo');
[
objectContaining({}).asymmetricMatch('jest'),
objectContaining({foo: 'foo'}).asymmetricMatch({foo: 'foo', jest: 'jest'}),
Expand All @@ -192,12 +193,15 @@ test('ObjectContaining matches', () => {
foo: Buffer.from('foo'),
jest: 'jest',
}),
objectContaining({[foo]: 'foo'}).asymmetricMatch({[foo]: 'foo'}),
].forEach(test => {
jestExpect(test).toEqual(true);
});
});

test('ObjectContaining does not match', () => {
const foo = Symbol('foo');
const bar = Symbol('bar');
[
objectContaining({foo: 'foo'}).asymmetricMatch({bar: 'bar'}),
objectContaining({foo: 'foo'}).asymmetricMatch({foo: 'foox'}),
Expand All @@ -206,6 +210,7 @@ test('ObjectContaining does not match', () => {
answer: 42,
foo: {bar: 'baz', foobar: 'qux'},
}).asymmetricMatch({foo: {bar: 'baz'}}),
objectContaining({[foo]: 'foo'}).asymmetricMatch({[bar]: 'bar'}),
].forEach(test => {
jestExpect(test).toEqual(false);
});
Expand Down Expand Up @@ -250,9 +255,12 @@ test('ObjectContaining does not mutate the sample', () => {
});

test('ObjectNotContaining matches', () => {
const foo = Symbol('foo');
const bar = Symbol('bar');
[
objectContaining({}).asymmetricMatch(null),
objectContaining({}).asymmetricMatch(undefined),
objectNotContaining({[foo]: 'foo'}).asymmetricMatch({[bar]: 'bar'}),
objectNotContaining({foo: 'foo'}).asymmetricMatch({bar: 'bar'}),
objectNotContaining({foo: 'foo'}).asymmetricMatch({foo: 'foox'}),
objectNotContaining({foo: undefined}).asymmetricMatch({}),
Expand Down
24 changes: 14 additions & 10 deletions packages/expect/src/asymmetricMatchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import {
equals,
getObjectKeys,
isA,
iterableEquality,
subsetEquality,
Expand Down Expand Up @@ -52,7 +53,10 @@ function getPrototype(obj: object) {
return obj.constructor.prototype;
}

export function hasProperty(obj: object | null, property: string): boolean {
export function hasProperty(
obj: object | null,
property: string | symbol,
): boolean {
if (!obj) {
return false;
}
Expand Down Expand Up @@ -216,8 +220,10 @@ class ArrayContaining extends AsymmetricMatcher<Array<unknown>> {
}
}

class ObjectContaining extends AsymmetricMatcher<Record<string, unknown>> {
constructor(sample: Record<string, unknown>, inverse = false) {
class ObjectContaining extends AsymmetricMatcher<
Record<string | symbol, unknown>
> {
constructor(sample: Record<string | symbol, unknown>, inverse = false) {
super(sample, inverse);
}

Expand All @@ -232,14 +238,12 @@ class ObjectContaining extends AsymmetricMatcher<Record<string, unknown>> {
let result = true;

const matcherContext = this.getMatcherContext();
for (const property in this.sample) {
const objectKeys = getObjectKeys(this.sample);

for (const key of objectKeys) {
if (
!hasProperty(other, property) ||
!equals(
this.sample[property],
other[property],
matcherContext.customTesters,
)
!hasProperty(other, key) ||
!equals(this.sample[key], other[key], matcherContext.customTesters)
) {
result = false;
break;
Expand Down

0 comments on commit 9c8fdbb

Please sign in to comment.