diff --git a/CHANGELOG.md b/CHANGELOG.md index a4a0a94d680f..36eb4dbbea3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ ### Fixes +- `[expect]` `toStrictEqual` considers sparseness of arrays. ([#7591](https://github.com/facebook/jest/pull/7591)) - `[jest-cli]` Fix empty coverage data for untested files ([#7388](https://github.com/facebook/jest/pull/7388)) - `[jest-cli]` [**BREAKING**] Do not use `text-summary` coverage reporter by default if other reporters are configured ([#7058](https://github.com/facebook/jest/pull/7058)) - `[jest-mock]` [**BREAKING**] Fix bugs with mock/spy result tracking of recursive functions ([#6381](https://github.com/facebook/jest/pull/6381)) diff --git a/docs/ExpectAPI.md b/docs/ExpectAPI.md index a0ac61bef2a6..b0f297bc0c51 100644 --- a/docs/ExpectAPI.md +++ b/docs/ExpectAPI.md @@ -1125,6 +1125,7 @@ Use `.toStrictEqual` to test that objects have the same types as well as structu Differences from `.toEqual`: - Keys with `undefined` properties are checked. e.g. `{a: undefined, b: 2}` does not match `{b: 2}` when using `.toStrictEqual`. +- Array sparseness is checked. e.g. `[, 1]` does not match `[undefined, 1]` when using `.toStrictEqual`. - Object types are checked to be equal. e.g. A class instance with fields `a` and `b` will not equal a literal object with fields `a` and `b`. ```js diff --git a/packages/expect/src/__tests__/matchers.test.js b/packages/expect/src/__tests__/matchers.test.js index 8d27231a6a0b..15c1f9c62c56 100644 --- a/packages/expect/src/__tests__/matchers.test.js +++ b/packages/expect/src/__tests__/matchers.test.js @@ -271,6 +271,22 @@ describe('.toStrictEqual()', () => { expect(c.constructor.name).toEqual(d.constructor.name); expect({test: c}).not.toStrictEqual({test: d}); }); + + /* eslint-disable no-sparse-arrays */ + it('passes for matching sparse arrays', () => { + expect([, 1]).toStrictEqual([, 1]); + }); + + it('does not pass when sparseness of arrays do not match', () => { + expect([, 1]).not.toStrictEqual([undefined, 1]); + expect([undefined, 1]).not.toStrictEqual([, 1]); + expect([, , , 1]).not.toStrictEqual([, 1]); + }); + + it('does not pass when equally sparse arrays have different values', () => { + expect([, 1]).not.toStrictEqual([, 2]); + }); + /* eslint-enable */ }); describe('.toEqual()', () => { diff --git a/packages/expect/src/matchers.js b/packages/expect/src/matchers.js index 8549f544753d..eb2609442f43 100644 --- a/packages/expect/src/matchers.js +++ b/packages/expect/src/matchers.js @@ -30,6 +30,7 @@ import { getObjectSubset, getPath, iterableEquality, + sparseArrayEquality, subsetEquality, typeEquality, isOneline, @@ -666,7 +667,7 @@ const matchers: MatchersObject = { const pass = equals( received, expected, - [iterableEquality, typeEquality], + [iterableEquality, typeEquality, sparseArrayEquality], true, ); diff --git a/packages/expect/src/utils.js b/packages/expect/src/utils.js index 5a086749c479..f99a5fdde95f 100644 --- a/packages/expect/src/utils.js +++ b/packages/expect/src/utils.js @@ -243,6 +243,17 @@ export const typeEquality = (a: any, b: any) => { return false; }; +export const sparseArrayEquality = (a: any, b: any) => { + if (!Array.isArray(a) || !Array.isArray(b)) { + return undefined; + } + + // A sparse array [, , 1] will have keys ["2"] whereas [undefined, undefined, 1] will have keys ["0", "1", "2"] + const aKeys = Object.keys(a); + const bKeys = Object.keys(b); + return equals(a, b) && equals(aKeys, bKeys); +}; + export const partition = ( items: Array, predicate: T => boolean,