From 586b17ab9b521cbd7eb70beae174e88f976360e7 Mon Sep 17 00:00:00 2001 From: Wei An Yen Date: Mon, 2 Dec 2019 11:10:19 +0800 Subject: [PATCH 01/44] Do not diff attribute which match asymmetricMatcher. --- packages/jest-diff/src/__tests__/diff.test.ts | 112 +++++++++++++++--- packages/jest-diff/src/index.ts | 31 ++++- 2 files changed, 123 insertions(+), 20 deletions(-) diff --git a/packages/jest-diff/src/__tests__/diff.test.ts b/packages/jest-diff/src/__tests__/diff.test.ts index 3367839b8cfe..2ef8c92b8c6a 100644 --- a/packages/jest-diff/src/__tests__/diff.test.ts +++ b/packages/jest-diff/src/__tests__/diff.test.ts @@ -192,24 +192,104 @@ line 4`; }); describe('objects', () => { - const a = {a: {b: {c: 5}}}; - const b = {a: {b: {c: 6}}}; - const expected = [ - ' Object {', - ' "a": Object {', - ' "b": Object {', - '- "c": 5,', - '+ "c": 6,', - ' },', - ' },', - ' }', - ].join('\n'); + describe('expand', () => { + const a = {a: {b: {c: 5}}}; + const b = {a: {b: {c: 6}}}; + const expected = [ + ' Object {', + ' "a": Object {', + ' "b": Object {', + '- "c": 5,', + '+ "c": 6,', + ' },', + ' },', + ' }', + ].join('\n'); - test('(unexpanded)', () => { - expect(diff(a, b, unexpandedBe)).toBe(expected); + test('(unexpanded)', () => { + expect(diff(a, b, unexpandedBe)).toBe(expected); + }); + test('(expanded)', () => { + expect(diff(a, b, expandedBe)).toBe(expected); + }); }); - test('(expanded)', () => { - expect(diff(a, b, expandedBe)).toBe(expected); + + describe('asymmetricMatcher', () => { + test('jest asymmetricMatcher', () => { + const a = { + a: expect.any(Number), + b: expect.anything(), + c: expect.arrayContaining([1, 3]), + d: 'jest is awesome', + e: 'jest is awesome', + f: { + a: new Date(), + b: 'jest is awesome', + }, + g: true, + }; + const b = { + a: 1, + b: 'anything', + c: [1, 2, 3], + d: expect.stringContaining('jest'), + e: expect.stringMatching(/^jest/), + f: expect.objectContaining({ + a: expect.any(Date), + }), + g: false, + }; + const expected = [ + ' Object {', + ' "a": Any,', + ' "b": Anything,', + ' "c": ArrayContaining [', + ' 1,', + ' 3,', + ' ],', + ' "d": StringContaining "jest",', + ' "e": StringMatching /^jest/,', + ' "f": ObjectContaining {', + ' "a": Any,', + ' },', + '- "g": true,', + '+ "g": false,', + ' }', + ].join('\n'); + expect(diff(a, b, optionsBe)).toBe(expected); + }); + + test('custom asymmetricMatcher', () => { + expect.extend({ + equal5(received: any) { + if (received === 5) + return { + message: () => `expected ${received} not to be 5`, + pass: true, + }; + return { + message: () => `expected ${received} to be 5`, + pass: false, + }; + }, + }); + const a = { + a: 5, + b: true, + }; + const b = { + a: expect.equal5(), + b: false, + }; + const expected = [ + ' Object {', + ' "a": equal5<>,', + '- "b": true,', + '+ "b": false,', + ' }', + ].join('\n'); + expect(diff(a, b, optionsBe)).toBe(expected); + }); }); }); diff --git a/packages/jest-diff/src/index.ts b/packages/jest-diff/src/index.ts index e7c4c3752bc5..179f07d5c62e 100644 --- a/packages/jest-diff/src/index.ts +++ b/packages/jest-diff/src/index.ts @@ -131,16 +131,17 @@ function compareObjects( ) { let difference; let hasThrown = false; + const {replacedA, replacedB} = replaceMatchedToAsymmetricMatcher(a, b); try { - const aCompare = prettyFormat(a, FORMAT_OPTIONS_0); - const bCompare = prettyFormat(b, FORMAT_OPTIONS_0); + const aCompare = prettyFormat(replacedA, FORMAT_OPTIONS_0); + const bCompare = prettyFormat(replacedB, FORMAT_OPTIONS_0); if (aCompare === bCompare) { difference = NO_DIFF_MESSAGE; } else { - const aDisplay = prettyFormat(a, FORMAT_OPTIONS); - const bDisplay = prettyFormat(b, FORMAT_OPTIONS); + const aDisplay = prettyFormat(replacedA, FORMAT_OPTIONS); + const bDisplay = prettyFormat(replacedB, FORMAT_OPTIONS); difference = diffLinesUnified2( aDisplay.split('\n'), @@ -183,4 +184,26 @@ function compareObjects( return difference; } +function replaceMatchedToAsymmetricMatcher( + a: Record, + b: Record, +) { + const replacedA = {...a}; + const replacedB = {...b}; + Object.entries(replacedB).forEach(([key, bValue]) => { + const aValue = a[key]; + if (isAsymmetricMatcher(bValue)) { + if (bValue.asymmetricMatch(aValue)) replacedA[key] = bValue; + } else if (isAsymmetricMatcher(aValue)) { + if (aValue.asymmetricMatch(bValue)) replacedB[key] = aValue; + } + }); + return {replacedA, replacedB}; +} + +function isAsymmetricMatcher(data: any) { + const type = getType(data); + return type === 'object' && typeof data.asymmetricMatch === 'function'; +} + export default diff; From ec68d66b23e5db46eabeb54481754a8f069191d4 Mon Sep 17 00:00:00 2001 From: Wei An Yen Date: Mon, 2 Dec 2019 18:01:47 +0800 Subject: [PATCH 02/44] Use 'new' to copy RegExp. Fix calling method error after copied by Object.create. --- packages/jest-util/src/__tests__/deepCyclicCopy.test.ts | 5 +++++ packages/jest-util/src/deepCyclicCopy.ts | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/packages/jest-util/src/__tests__/deepCyclicCopy.test.ts b/packages/jest-util/src/__tests__/deepCyclicCopy.test.ts index 73ea0f451da0..4011777bec1e 100644 --- a/packages/jest-util/src/__tests__/deepCyclicCopy.test.ts +++ b/packages/jest-util/src/__tests__/deepCyclicCopy.test.ts @@ -235,3 +235,8 @@ it('keeps the prototype for objects when keepPrototype = true', () => { ); spy.mockRestore(); }); + +it('RegExp should work correctly after copied', () => { + const regExp = deepCyclicCopy(/jest/i, {keepPrototype: true}); + expect(regExp.test('JEST is awesome')).toBe(true); +}); diff --git a/packages/jest-util/src/deepCyclicCopy.ts b/packages/jest-util/src/deepCyclicCopy.ts index d9f59bc409bb..4f86da299c5b 100644 --- a/packages/jest-util/src/deepCyclicCopy.ts +++ b/packages/jest-util/src/deepCyclicCopy.ts @@ -33,6 +33,12 @@ function deepCyclicCopyObject( options: DeepCyclicCopyOptions, cycles: WeakMap, ): T { + if (object instanceof RegExp && options.keepPrototype) { + const result = new RegExp(object.source, object.flags); + result.lastIndex = object.lastIndex; + return result as typeof object; + } + const newObject = options.keepPrototype ? Object.create(Object.getPrototypeOf(object)) : {}; From 4f7c31a930142adaebf70c2fe151801dfbfac97e Mon Sep 17 00:00:00 2001 From: Wei An Yen Date: Mon, 2 Dec 2019 18:02:32 +0800 Subject: [PATCH 03/44] Use jest-util deepCopy to copy record. --- packages/jest-diff/package.json | 1 + packages/jest-diff/src/index.ts | 5 +++-- packages/jest-diff/tsconfig.json | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/jest-diff/package.json b/packages/jest-diff/package.json index 6e5163e348d8..65433aa78315 100644 --- a/packages/jest-diff/package.json +++ b/packages/jest-diff/package.json @@ -13,6 +13,7 @@ "chalk": "^3.0.0", "diff-sequences": "^24.9.0", "jest-get-type": "^24.9.0", + "jest-util": "^24.9.0", "pretty-format": "^24.9.0" }, "devDependencies": { diff --git a/packages/jest-diff/src/index.ts b/packages/jest-diff/src/index.ts index 179f07d5c62e..800f971c14e7 100644 --- a/packages/jest-diff/src/index.ts +++ b/packages/jest-diff/src/index.ts @@ -8,6 +8,7 @@ import prettyFormat = require('pretty-format'); import chalk = require('chalk'); import getType = require('jest-get-type'); +import {deepCyclicCopy} from 'jest-util'; import {DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, Diff} from './cleanupSemantic'; import {diffLinesRaw, diffLinesUnified, diffLinesUnified2} from './diffLines'; import {diffStringsRaw, diffStringsUnified} from './printDiffs'; @@ -188,8 +189,8 @@ function replaceMatchedToAsymmetricMatcher( a: Record, b: Record, ) { - const replacedA = {...a}; - const replacedB = {...b}; + const replacedA = deepCyclicCopy(a, {keepPrototype: true}); + const replacedB = deepCyclicCopy(b, {keepPrototype: true}); Object.entries(replacedB).forEach(([key, bValue]) => { const aValue = a[key]; if (isAsymmetricMatcher(bValue)) { diff --git a/packages/jest-diff/tsconfig.json b/packages/jest-diff/tsconfig.json index 0e6330874c83..281f5019295a 100644 --- a/packages/jest-diff/tsconfig.json +++ b/packages/jest-diff/tsconfig.json @@ -8,6 +8,7 @@ {"path": "../diff-sequences"}, {"path": "../jest-get-type"}, {"path": "../pretty-format"}, - {"path": "../test-utils"} + {"path": "../test-utils"}, + {"path": "../jest-util"} ] } From e69b81625451aeed38c79e23ae38b2b51130e1bd Mon Sep 17 00:00:00 2001 From: Wei An Yen Date: Mon, 2 Dec 2019 18:02:38 +0800 Subject: [PATCH 04/44] update snapshot --- .../expect/src/__tests__/__snapshots__/matchers.test.js.snap | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap index 162652bbe6b4..52cf381f1fcd 100644 --- a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap @@ -364,6 +364,9 @@ exports[`.toBe() fails for: {"a": [Function a], "b": 2} and {"a": Any, If it should pass with deep equality, replace "toBe" with "toStrictEqual" +Compared values serialize to the same structure. +Printing internal object structure without calling \`toJSON\` instead. + - Expected - 1 + Received + 1 From 2c88e99e853add54ff93112e4f250fa606fa8ea7 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Tue, 3 Dec 2019 01:42:12 +0800 Subject: [PATCH 05/44] update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f22279851bf..31f90e83e584 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,9 @@ - `[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)) +- `[jest-diff]` Do not highlight matched asymmetricMatcher in diffs ([#9257](https://github.com/facebook/jest/pull/9257)) +- `[jest-util]` Use `new` to `deepCyclicCopy` RegExp. Fix error of calling method after copied by `Object.create` ([#9257](https://github.com/facebook/jest/pull/9257)) + ### Chore & Maintenance From 3885f56b2ff5637b69e499351fc5afe9b6463c9f Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Tue, 3 Dec 2019 02:12:48 +0800 Subject: [PATCH 06/44] remove line --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31f90e83e584..c798f2fc4d04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,7 +68,6 @@ - `[jest-diff]` Do not highlight matched asymmetricMatcher in diffs ([#9257](https://github.com/facebook/jest/pull/9257)) - `[jest-util]` Use `new` to `deepCyclicCopy` RegExp. Fix error of calling method after copied by `Object.create` ([#9257](https://github.com/facebook/jest/pull/9257)) - ### Chore & Maintenance - `[*]` [**BREAKING**] Drop support for Node 6 ([#8455](https://github.com/facebook/jest/pull/8455)) From 7a04cb031284bca92a9ff21321936733ba3fa295 Mon Sep 17 00:00:00 2001 From: Wei An Yen Date: Tue, 3 Dec 2019 16:22:42 +0800 Subject: [PATCH 07/44] sort changelog --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c798f2fc4d04..1d37c009c4fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,7 +48,9 @@ - `[jest-core]` Don't include unref'd timers in --detectOpenHandles results ([#8941](https://github.com/facebook/jest/pull/8941)) - `[jest-diff]` Do not inverse format if line consists of one change ([#8903](https://github.com/facebook/jest/pull/8903)) - `[jest-diff]` Rename some new options and change their default values ([#9077](https://github.com/facebook/jest/pull/9077)) +- `[jest-diff]` Do not highlight matched asymmetricMatcher in diffs ([#9257](https://github.com/facebook/jest/pull/9257)) - `[jest-fake-timers]` `getTimerCount` will not include cancelled immediates ([#8764](https://github.com/facebook/jest/pull/8764)) +- `[jest-fake-timers]` Support `util.promisify` on `setTimeout` ([#9180](https://github.com/facebook/jest/pull/9180)) - `[jest-leak-detector]` [**BREAKING**] Use `weak-napi` instead of `weak` package ([#8686](https://github.com/facebook/jest/pull/8686)) - `[jest-mock]` Fix for mockReturnValue overriding mockImplementationOnce ([#8398](https://github.com/facebook/jest/pull/8398)) - `[jest-reporters]` Make node-notifier an optional dependency ([#8918](https://github.com/facebook/jest/pull/8918)) @@ -62,11 +64,9 @@ - `[jest-transform]` Properly cache transformed files across tests ([#8890](https://github.com/facebook/jest/pull/8890)) - `[jest-transform]` Don't fail the test suite when a generated source map is invalid ([#9058](https://github.com/facebook/jest/pull/9058)) - `[jest-types]` [**BREAKING**] Use less `null | undefined` in config types ([#9200](https://github.com/facebook/jest/pull/9200)) -- `[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)) -- `[jest-diff]` Do not highlight matched asymmetricMatcher in diffs ([#9257](https://github.com/facebook/jest/pull/9257)) +- `[jest-util]` Allow querying process.domain ([#9136](https://github.com/facebook/jest/pull/9136)) - `[jest-util]` Use `new` to `deepCyclicCopy` RegExp. Fix error of calling method after copied by `Object.create` ([#9257](https://github.com/facebook/jest/pull/9257)) +- `[pretty-format]` Correctly detect memoized elements ([#9196](https://github.com/facebook/jest/pull/9196)) ### Chore & Maintenance From 48ab2327747790486d8b629df8f7f4d4b1fa0799 Mon Sep 17 00:00:00 2001 From: Wei An Yen Date: Tue, 3 Dec 2019 16:24:13 +0800 Subject: [PATCH 08/44] sort path --- packages/jest-diff/tsconfig.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jest-diff/tsconfig.json b/packages/jest-diff/tsconfig.json index 281f5019295a..9c719c5e3ab2 100644 --- a/packages/jest-diff/tsconfig.json +++ b/packages/jest-diff/tsconfig.json @@ -7,8 +7,8 @@ "references": [ {"path": "../diff-sequences"}, {"path": "../jest-get-type"}, + {"path": "../jest-util"}, {"path": "../pretty-format"}, - {"path": "../test-utils"}, - {"path": "../jest-util"} + {"path": "../test-utils"} ] } From 69fbc5de7d1d9a97747f6034bc1d763e3c9e64ea Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sat, 7 Dec 2019 16:20:18 +0800 Subject: [PATCH 09/44] move replaceMatchedToAsymmetricMatcher to jest-matcher-utils --- packages/jest-diff/package.json | 1 - packages/jest-diff/src/__tests__/diff.test.ts | 78 ---------- packages/jest-diff/src/index.ts | 32 +--- packages/jest-diff/tsconfig.json | 1 - packages/jest-matcher-utils/package.json | 1 + .../printDiffOrStringify.test.ts.snap | 96 ++++++++++++ .../__tests__/printDiffOrStringify.test.ts | 137 +++++++++++++++++- packages/jest-matcher-utils/src/index.ts | 86 ++++++++++- packages/jest-matcher-utils/tsconfig.json | 1 + 9 files changed, 317 insertions(+), 116 deletions(-) diff --git a/packages/jest-diff/package.json b/packages/jest-diff/package.json index 65433aa78315..6e5163e348d8 100644 --- a/packages/jest-diff/package.json +++ b/packages/jest-diff/package.json @@ -13,7 +13,6 @@ "chalk": "^3.0.0", "diff-sequences": "^24.9.0", "jest-get-type": "^24.9.0", - "jest-util": "^24.9.0", "pretty-format": "^24.9.0" }, "devDependencies": { diff --git a/packages/jest-diff/src/__tests__/diff.test.ts b/packages/jest-diff/src/__tests__/diff.test.ts index 2ef8c92b8c6a..471ebb255fcb 100644 --- a/packages/jest-diff/src/__tests__/diff.test.ts +++ b/packages/jest-diff/src/__tests__/diff.test.ts @@ -213,84 +213,6 @@ describe('objects', () => { expect(diff(a, b, expandedBe)).toBe(expected); }); }); - - describe('asymmetricMatcher', () => { - test('jest asymmetricMatcher', () => { - const a = { - a: expect.any(Number), - b: expect.anything(), - c: expect.arrayContaining([1, 3]), - d: 'jest is awesome', - e: 'jest is awesome', - f: { - a: new Date(), - b: 'jest is awesome', - }, - g: true, - }; - const b = { - a: 1, - b: 'anything', - c: [1, 2, 3], - d: expect.stringContaining('jest'), - e: expect.stringMatching(/^jest/), - f: expect.objectContaining({ - a: expect.any(Date), - }), - g: false, - }; - const expected = [ - ' Object {', - ' "a": Any,', - ' "b": Anything,', - ' "c": ArrayContaining [', - ' 1,', - ' 3,', - ' ],', - ' "d": StringContaining "jest",', - ' "e": StringMatching /^jest/,', - ' "f": ObjectContaining {', - ' "a": Any,', - ' },', - '- "g": true,', - '+ "g": false,', - ' }', - ].join('\n'); - expect(diff(a, b, optionsBe)).toBe(expected); - }); - - test('custom asymmetricMatcher', () => { - expect.extend({ - equal5(received: any) { - if (received === 5) - return { - message: () => `expected ${received} not to be 5`, - pass: true, - }; - return { - message: () => `expected ${received} to be 5`, - pass: false, - }; - }, - }); - const a = { - a: 5, - b: true, - }; - const b = { - a: expect.equal5(), - b: false, - }; - const expected = [ - ' Object {', - ' "a": equal5<>,', - '- "b": true,', - '+ "b": false,', - ' }', - ].join('\n'); - expect(diff(a, b, optionsBe)).toBe(expected); - }); - }); }); test('numbers', () => { diff --git a/packages/jest-diff/src/index.ts b/packages/jest-diff/src/index.ts index 800f971c14e7..e7c4c3752bc5 100644 --- a/packages/jest-diff/src/index.ts +++ b/packages/jest-diff/src/index.ts @@ -8,7 +8,6 @@ import prettyFormat = require('pretty-format'); import chalk = require('chalk'); import getType = require('jest-get-type'); -import {deepCyclicCopy} from 'jest-util'; import {DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, Diff} from './cleanupSemantic'; import {diffLinesRaw, diffLinesUnified, diffLinesUnified2} from './diffLines'; import {diffStringsRaw, diffStringsUnified} from './printDiffs'; @@ -132,17 +131,16 @@ function compareObjects( ) { let difference; let hasThrown = false; - const {replacedA, replacedB} = replaceMatchedToAsymmetricMatcher(a, b); try { - const aCompare = prettyFormat(replacedA, FORMAT_OPTIONS_0); - const bCompare = prettyFormat(replacedB, FORMAT_OPTIONS_0); + const aCompare = prettyFormat(a, FORMAT_OPTIONS_0); + const bCompare = prettyFormat(b, FORMAT_OPTIONS_0); if (aCompare === bCompare) { difference = NO_DIFF_MESSAGE; } else { - const aDisplay = prettyFormat(replacedA, FORMAT_OPTIONS); - const bDisplay = prettyFormat(replacedB, FORMAT_OPTIONS); + const aDisplay = prettyFormat(a, FORMAT_OPTIONS); + const bDisplay = prettyFormat(b, FORMAT_OPTIONS); difference = diffLinesUnified2( aDisplay.split('\n'), @@ -185,26 +183,4 @@ function compareObjects( return difference; } -function replaceMatchedToAsymmetricMatcher( - a: Record, - b: Record, -) { - const replacedA = deepCyclicCopy(a, {keepPrototype: true}); - const replacedB = deepCyclicCopy(b, {keepPrototype: true}); - Object.entries(replacedB).forEach(([key, bValue]) => { - const aValue = a[key]; - if (isAsymmetricMatcher(bValue)) { - if (bValue.asymmetricMatch(aValue)) replacedA[key] = bValue; - } else if (isAsymmetricMatcher(aValue)) { - if (aValue.asymmetricMatch(bValue)) replacedB[key] = aValue; - } - }); - return {replacedA, replacedB}; -} - -function isAsymmetricMatcher(data: any) { - const type = getType(data); - return type === 'object' && typeof data.asymmetricMatch === 'function'; -} - export default diff; diff --git a/packages/jest-diff/tsconfig.json b/packages/jest-diff/tsconfig.json index 9c719c5e3ab2..0e6330874c83 100644 --- a/packages/jest-diff/tsconfig.json +++ b/packages/jest-diff/tsconfig.json @@ -7,7 +7,6 @@ "references": [ {"path": "../diff-sequences"}, {"path": "../jest-get-type"}, - {"path": "../jest-util"}, {"path": "../pretty-format"}, {"path": "../test-utils"} ] diff --git a/packages/jest-matcher-utils/package.json b/packages/jest-matcher-utils/package.json index 1c3746f07f12..87165b05525e 100644 --- a/packages/jest-matcher-utils/package.json +++ b/packages/jest-matcher-utils/package.json @@ -16,6 +16,7 @@ "chalk": "^3.0.0", "jest-diff": "^24.9.0", "jest-get-type": "^24.9.0", + "jest-util": "^24.9.0", "pretty-format": "^24.9.0" }, "publishConfig": { diff --git a/packages/jest-matcher-utils/src/__tests__/__snapshots__/printDiffOrStringify.test.ts.snap b/packages/jest-matcher-utils/src/__tests__/__snapshots__/printDiffOrStringify.test.ts.snap index bb0566e91835..4302468e0a2c 100644 --- a/packages/jest-matcher-utils/src/__tests__/__snapshots__/printDiffOrStringify.test.ts.snap +++ b/packages/jest-matcher-utils/src/__tests__/__snapshots__/printDiffOrStringify.test.ts.snap @@ -1,5 +1,101 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`printDiffOrStringify asymmetricMatcher circular 1`] = ` +- Expected - 1 ++ Received + 1 + + Object { + "a": [Circular], + "b": Any, +- "c": 3, ++ "c": 2, + } +`; + +exports[`printDiffOrStringify asymmetricMatcher custom asymmetricMatcher 1`] = ` +- Expected - 1 ++ Received + 1 + + Object { + "a": equal5<>, +- "b": false, ++ "b": true, + } +`; + +exports[`printDiffOrStringify asymmetricMatcher jest asymmetricMatcher 1`] = ` +- Expected - 1 ++ Received + 1 + + Object { + "a": Any, + "b": Anything, + "c": ArrayContaining [ + 1, + 3, + ], + "d": StringContaining "jest", + "e": StringMatching /^jest/, + "f": ObjectContaining { + "a": Any, + }, +- "g": true, ++ "g": false, + } +`; + +exports[`printDiffOrStringify asymmetricMatcher minimal test 1`] = ` +- Expected - 1 ++ Received + 1 + + Object { + "a": Any, +- "b": 2, ++ "b": 1, + } +`; + +exports[`printDiffOrStringify asymmetricMatcher nested object 1`] = ` +- Expected - 1 ++ Received + 1 + + Object { + "a": Any, + "b": Object { + "a": 1, + "b": Any, + }, +- "c": 2, ++ "c": 1, + } +`; + +exports[`printDiffOrStringify asymmetricMatcher should not ignore asymmetric match 1`] = ` +- Expected - 2 ++ Received + 2 + + Object { +- "a": Any, +- "b": 2, ++ "a": 1, ++ "b": 1, + } +`; + +exports[`printDiffOrStringify asymmetricMatcher transitive circular 1`] = ` +- Expected - 1 ++ Received + 1 + + Object { +- "a": 3, ++ "a": 2, + "nested": Object { + "b": Any, + "parent": [Circular], + }, + } +`; + exports[`printDiffOrStringify expected and received are multi line with trailing spaces 1`] = ` - Expected - 3 + Received + 3 diff --git a/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts b/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts index df1bf6051714..9b7c86e4352b 100644 --- a/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts +++ b/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts @@ -11,8 +11,25 @@ import {INVERTED_COLOR, printDiffOrStringify} from '../index'; expect.addSnapshotSerializer(alignedAnsiStyleSerializer); describe('printDiffOrStringify', () => { - const testDiffOrStringify = (expected: string, received: string): string => - printDiffOrStringify(expected, received, 'Expected', 'Received', true); + const testDiffOrStringify = (expected: any, received: any): string => + printDiffOrStringify( + expected, + received, + 'Expected', + 'Received', + true, + true, + ); + + const testDiffOrStringifyNotIgnore = (expected: any, received: any): string => + printDiffOrStringify( + expected, + received, + 'Expected', + 'Received', + true, + false, + ); test('expected is empty and received is single line', () => { const expected = ''; @@ -86,4 +103,120 @@ describe('printDiffOrStringify', () => { expect(difference).not.toMatch(lessChange); }); }); + + describe('asymmetricMatcher', () => { + test('minimal test', () => { + const expected = {a: expect.any(Number), b: 2}; + const received = {a: 1, b: 1}; + expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); + }); + + test('jest asymmetricMatcher', () => { + const expected = { + a: expect.any(Number), + b: expect.anything(), + c: expect.arrayContaining([1, 3]), + d: 'jest is awesome', + e: 'jest is awesome', + f: { + a: new Date(), + b: 'jest is awesome', + }, + g: true, + }; + const received = { + a: 1, + b: 'anything', + c: [1, 2, 3], + d: expect.stringContaining('jest'), + e: expect.stringMatching(/^jest/), + f: expect.objectContaining({ + a: expect.any(Date), + }), + g: false, + }; + + expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); + }); + + test('custom asymmetricMatcher', () => { + expect.extend({ + equal5(received: any) { + if (received === 5) + return { + message: () => `expected ${received} not to be 5`, + pass: true, + }; + return { + message: () => `expected ${received} to be 5`, + pass: false, + }; + }, + }); + const expected = { + a: expect.equal5(), + b: false, + }; + const received = { + a: 5, + b: true, + }; + + expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); + }); + + test('nested object', () => { + const expected = { + a: 1, + b: { + a: 1, + b: expect.any(Number), + }, + c: 2, + }; + const received = { + a: expect.any(Number), + b: { + a: 1, + b: 2, + }, + c: 1, + }; + expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); + }); + + test('circular', () => { + const expected: any = { + b: expect.any(Number), + c: 3, + }; + expected.a = expected; + const received: any = { + b: 2, + c: 2, + }; + received.a = received; + expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); + }); + + test('transitive circular', () => { + const expected: any = { + a: 3, + }; + expected.nested = {parent: expected, b: expect.any(Number)}; + const received: any = { + a: 2, + }; + received.nested = {parent: received, b: 2}; + expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); + }); + + test('should not ignore asymmetric match', () => { + const expected = {a: expect.any(Number), b: 2}; + const received = {a: 1, b: 1}; + expect( + testDiffOrStringifyNotIgnore(expected, received), + ).toMatchSnapshot(); + }); + }); }); diff --git a/packages/jest-matcher-utils/src/index.ts b/packages/jest-matcher-utils/src/index.ts index 84f1bcbe6fb2..89698b54ab29 100644 --- a/packages/jest-matcher-utils/src/index.ts +++ b/packages/jest-matcher-utils/src/index.ts @@ -16,6 +16,7 @@ import diffDefault, { diffStringsUnified, } from 'jest-diff'; import getType = require('jest-get-type'); +import {deepCyclicCopy} from 'jest-util'; import prettyFormat = require('pretty-format'); const { @@ -310,6 +311,7 @@ export const printDiffOrStringify = ( expectedLabel: string, receivedLabel: string, expand: boolean, // CLI options: true if `--expand` or false if `--no-expand` + ignoreAsymmetricMatches: boolean, ): string => { if ( typeof expected === 'string' && @@ -351,12 +353,31 @@ export const printDiffOrStringify = ( } if (isLineDiffable(expected, received)) { - const difference = diffDefault(expected, received, { - aAnnotation: expectedLabel, - bAnnotation: receivedLabel, - expand, - includeChangeCounts: true, - }); + let difference; + if (ignoreAsymmetricMatches) { + const { + replacedExpected, + replacedReceived, + } = replaceMatchedToAsymmetricMatcher( + deepCyclicCopy(expected, {keepPrototype: true}), + deepCyclicCopy(received, {keepPrototype: true}), + [], + [], + ); + difference = diffDefault(replacedExpected, replacedReceived, { + aAnnotation: expectedLabel, + bAnnotation: receivedLabel, + expand, + includeChangeCounts: true, + }); + } else { + difference = diffDefault(expected, received, { + aAnnotation: expectedLabel, + bAnnotation: receivedLabel, + expand, + includeChangeCounts: true, + }); + } if ( typeof difference === 'string' && @@ -394,6 +415,59 @@ const shouldPrintDiff = (actual: unknown, expected: unknown) => { return true; }; +function replaceMatchedToAsymmetricMatcher( + replacedExpected: any, + replacedReceived: any, + expectedCycles: Array, + receivedCycles: Array, +) { + if ( + getType(replacedExpected) !== 'object' || + getType(replacedReceived) !== 'object' + ) + return {replacedExpected, replacedReceived}; + + if ( + expectedCycles.includes(replacedExpected) || + receivedCycles.includes(replacedReceived) + ) + return {replacedExpected, replacedReceived}; + + expectedCycles.push(replacedExpected); + receivedCycles.push(replacedReceived); + + Object.entries(replacedExpected).forEach( + ([key, expectedAttribute]: [string, any]) => { + const receivedAttribute = replacedReceived[key]; + if (isAsymmetricMatcher(expectedAttribute)) { + if (expectedAttribute.asymmetricMatch(receivedAttribute)) + replacedReceived[key] = expectedAttribute; + } else if (isAsymmetricMatcher(receivedAttribute)) { + if (receivedAttribute.asymmetricMatch(expectedAttribute)) + replacedExpected[key] = receivedAttribute; + } else if ( + getType(expectedAttribute) === 'object' && + getType(receivedAttribute) === 'object' + ) { + const replacedAttribute = replaceMatchedToAsymmetricMatcher( + expectedAttribute, + receivedAttribute, + expectedCycles, + receivedCycles, + ); + replacedExpected[key] = replacedAttribute.replacedExpected; + replacedReceived[key] = replacedAttribute.replacedReceived; + } + }, + ); + return {replacedExpected, replacedReceived}; +} + +function isAsymmetricMatcher(data: any) { + const type = getType(data); + return type === 'object' && typeof data.asymmetricMatch === 'function'; +} + export const diff = (a: any, b: any, options?: DiffOptions): string | null => shouldPrintDiff(a, b) ? diffDefault(a, b, options) : null; diff --git a/packages/jest-matcher-utils/tsconfig.json b/packages/jest-matcher-utils/tsconfig.json index febd499d97ae..53a40ed97530 100644 --- a/packages/jest-matcher-utils/tsconfig.json +++ b/packages/jest-matcher-utils/tsconfig.json @@ -7,6 +7,7 @@ "references": [ {"path": "../jest-diff"}, {"path": "../jest-get-type"}, + {"path": "../jest-util"}, {"path": "../pretty-format"}, {"path": "../test-utils"} ] From 149783b3e235b597bfb16f84404d93086767061b Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sat, 7 Dec 2019 21:31:59 +0800 Subject: [PATCH 10/44] fix object attribute order --- .../src/__tests__/printDiffOrStringify.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts b/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts index 9b7c86e4352b..59032d9ecf06 100644 --- a/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts +++ b/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts @@ -203,11 +203,11 @@ describe('printDiffOrStringify', () => { const expected: any = { a: 3, }; - expected.nested = {parent: expected, b: expect.any(Number)}; + expected.nested = {b: expect.any(Number), parent: expected}; const received: any = { a: 2, }; - received.nested = {parent: received, b: 2}; + received.nested = {b: 2, parent: received}; expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); }); From 883f4cd0ef034100200dcc3d4ace16349728e05f Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sat, 7 Dec 2019 21:52:58 +0800 Subject: [PATCH 11/44] add `ignoreAsymmetricMatches` option --- e2e/__tests__/__snapshots__/showConfig.test.ts.snap | 1 + packages/expect/src/matchers.ts | 6 ++++++ packages/expect/src/toThrowMatchers.ts | 11 ++++++++++- packages/expect/src/types.ts | 1 + .../src/legacy-code-todo-rewrite/jestExpect.ts | 6 +++++- packages/jest-cli/src/cli/args.ts | 4 ++++ packages/jest-config/src/Defaults.ts | 1 + packages/jest-config/src/ValidConfig.ts | 1 + packages/jest-config/src/index.ts | 1 + packages/jest-config/src/normalize.ts | 1 + packages/jest-jasmine2/src/index.ts | 1 + packages/jest-jasmine2/src/jestExpect.ts | 10 ++++++++-- packages/jest-types/src/Config.ts | 4 ++++ .../src/__tests__/fixtures/jestConfig.ts | 2 ++ 14 files changed, 46 insertions(+), 4 deletions(-) diff --git a/e2e/__tests__/__snapshots__/showConfig.test.ts.snap b/e2e/__tests__/__snapshots__/showConfig.test.ts.snap index e7bd2b9c3273..82f7bfb6e254 100644 --- a/e2e/__tests__/__snapshots__/showConfig.test.ts.snap +++ b/e2e/__tests__/__snapshots__/showConfig.test.ts.snap @@ -96,6 +96,7 @@ exports[`--showConfig outputs config info and exits 1`] = ` "expand": false, "findRelatedTests": false, "forceExit": false, + "ignoreAsymmetricMatches": false, "json": false, "lastCommit": false, "listTests": false, diff --git a/packages/expect/src/matchers.ts b/packages/expect/src/matchers.ts index ca51e52291ba..945ddb2c7f4f 100644 --- a/packages/expect/src/matchers.ts +++ b/packages/expect/src/matchers.ts @@ -54,6 +54,7 @@ const RECEIVED_VALUE_LABEL = 'Received value'; // The optional property of matcher context is true if undefined. const isExpand = (expand?: boolean): boolean => expand !== false; +const ignoreAsymmetricMatches = (ignore?: boolean): boolean => ignore === true; const toStrictEqualTesters = [ iterableEquality, @@ -112,6 +113,7 @@ const matchers: MatchersObject = { EXPECTED_LABEL, RECEIVED_LABEL, isExpand(this.expand), + ignoreAsymmetricMatches(this.ignoreAsymmetricMatches), ) ); }; @@ -612,6 +614,7 @@ const matchers: MatchersObject = { EXPECTED_LABEL, RECEIVED_LABEL, isExpand(this.expand), + ignoreAsymmetricMatches(this.ignoreAsymmetricMatches), ); // Passing the actual and expected objects so that a custom reporter @@ -786,6 +789,7 @@ const matchers: MatchersObject = { EXPECTED_VALUE_LABEL, RECEIVED_VALUE_LABEL, isExpand(this.expand), + ignoreAsymmetricMatches(this.ignoreAsymmetricMatches), ) : `Received path: ${printReceived( expectedPathType === 'array' || receivedPath.length === 0 @@ -921,6 +925,7 @@ const matchers: MatchersObject = { EXPECTED_LABEL, RECEIVED_LABEL, isExpand(this.expand), + ignoreAsymmetricMatches(this.ignoreAsymmetricMatches), ); return {message, pass}; @@ -953,6 +958,7 @@ const matchers: MatchersObject = { EXPECTED_LABEL, RECEIVED_LABEL, isExpand(this.expand), + ignoreAsymmetricMatches(this.ignoreAsymmetricMatches), ); // Passing the actual and expected objects so that a custom reporter diff --git a/packages/expect/src/toThrowMatchers.ts b/packages/expect/src/toThrowMatchers.ts index 0262f533df43..0140eaf96d11 100644 --- a/packages/expect/src/toThrowMatchers.ts +++ b/packages/expect/src/toThrowMatchers.ts @@ -35,6 +35,7 @@ import { import {isError} from './utils'; const DID_NOT_THROW = 'Received function did not throw'; +const ignoreAsymmetricMatches = (ignore?: boolean): boolean => ignore === true; type Thrown = | { @@ -120,7 +121,13 @@ export const createMatcher = ( ) { return toThrowExpectedAsymmetric(matcherName, options, thrown, expected); } else if (expected !== null && typeof expected === 'object') { - return toThrowExpectedObject(matcherName, options, thrown, expected); + return toThrowExpectedObject( + matcherName, + options, + thrown, + expected, + ignoreAsymmetricMatches(this.ignoreAsymmetricMatches), + ); } else { throw new Error( matcherErrorMessage( @@ -218,6 +225,7 @@ const toThrowExpectedObject = ( options: MatcherHintOptions, thrown: Thrown | null, expected: any, + ignoreAsymmetricMatches: boolean, ): SyncExpectationResult => { const pass = thrown !== null && thrown.message === expected.message; @@ -243,6 +251,7 @@ const toThrowExpectedObject = ( 'Expected message', 'Received message', true, + ignoreAsymmetricMatches, ) + '\n' + formatStack(thrown) diff --git a/packages/expect/src/types.ts b/packages/expect/src/types.ts index 529d12014df4..ee3800f05a2a 100644 --- a/packages/expect/src/types.ts +++ b/packages/expect/src/types.ts @@ -40,6 +40,7 @@ export type MatcherState = { strictCheck?: boolean, ) => boolean; expand?: boolean; + ignoreAsymmetricMatches?: boolean; expectedAssertionsNumber?: number; isExpectingAssertions?: boolean; isNot: boolean; diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts index fa5436dbaf94..ef770af02e5f 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts @@ -15,10 +15,14 @@ import { toThrowErrorMatchingSnapshot, } from 'jest-snapshot'; -export default (config: {expand: boolean}) => { +export default (config: { + expand: boolean; + ignoreAsymmetricMatches: boolean; +}) => { global.expect = expect; expect.setState({ expand: config.expand, + ignoreAsymmetricMatches: config.ignoreAsymmetricMatches, }); expect.extend({ toMatchInlineSnapshot, diff --git a/packages/jest-cli/src/cli/args.ts b/packages/jest-cli/src/cli/args.ts index 6bc9650b7a01..696c01c2ead4 100644 --- a/packages/jest-cli/src/cli/args.ts +++ b/packages/jest-cli/src/cli/args.ts @@ -297,6 +297,10 @@ export const options = { 'A JSON string with map of variables for the haste module system', type: 'string', }, + ignoreAsymmetricMatches: { + description: 'Ignore asymmetric matches in diffing', + type: 'boolean', + }, init: { description: 'Generate a basic configuration file', type: 'boolean', diff --git a/packages/jest-config/src/Defaults.ts b/packages/jest-config/src/Defaults.ts index e096029b7795..432c8a1f27c1 100644 --- a/packages/jest-config/src/Defaults.ts +++ b/packages/jest-config/src/Defaults.ts @@ -32,6 +32,7 @@ const defaultOptions: Config.DefaultOptions = { providesModuleNodeModules: [], throwOnModuleCollision: false, }, + ignoreAsymmetricMatches: false, maxConcurrency: 5, maxWorkers: '50%', moduleDirectories: ['node_modules'], diff --git a/packages/jest-config/src/ValidConfig.ts b/packages/jest-config/src/ValidConfig.ts index 28178876d529..2f65bbe4c2ea 100644 --- a/packages/jest-config/src/ValidConfig.ts +++ b/packages/jest-config/src/ValidConfig.ts @@ -59,6 +59,7 @@ const initialOptions: Config.InitialOptions = { providesModuleNodeModules: ['react', 'react-native'], throwOnModuleCollision: false, }, + ignoreAsymmetricMatches: false, json: false, lastCommit: false, logHeapUsage: true, diff --git a/packages/jest-config/src/index.ts b/packages/jest-config/src/index.ts index eb392317c02b..1a48df6d5f2b 100644 --- a/packages/jest-config/src/index.ts +++ b/packages/jest-config/src/index.ts @@ -122,6 +122,7 @@ const groupOptions = ( forceExit: options.forceExit, globalSetup: options.globalSetup, globalTeardown: options.globalTeardown, + ignoreAsymmetricMatches: options.ignoreAsymmetricMatches, json: options.json, lastCommit: options.lastCommit, listTests: options.listTests, diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index 96111241f9d3..494189268024 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -847,6 +847,7 @@ export default function normalize( case 'findRelatedTests': case 'forceCoverageMatch': case 'forceExit': + case 'ignoreAsymmetricMatches': case 'lastCommit': case 'listTests': case 'logHeapUsage': diff --git a/packages/jest-jasmine2/src/index.ts b/packages/jest-jasmine2/src/index.ts index 53598542b031..c93ae8ea6ff2 100644 --- a/packages/jest-jasmine2/src/index.ts +++ b/packages/jest-jasmine2/src/index.ts @@ -123,6 +123,7 @@ async function jasmine2( .requireInternalModule(path.resolve(__dirname, './jestExpect.js')) .default({ expand: globalConfig.expand, + ignoreAsymmetricMatches: globalConfig.ignoreAsymmetricMatches, }); if (globalConfig.errorOnDeprecated) { diff --git a/packages/jest-jasmine2/src/jestExpect.ts b/packages/jest-jasmine2/src/jestExpect.ts index e6d33d121192..18460d829cf4 100644 --- a/packages/jest-jasmine2/src/jestExpect.ts +++ b/packages/jest-jasmine2/src/jestExpect.ts @@ -26,9 +26,15 @@ type JasmineMatcher = { type JasmineMatchersObject = {[id: string]: JasmineMatcher}; -export default (config: {expand: boolean}) => { +export default (config: { + expand: boolean; + ignoreAsymmetricMatches: boolean; +}) => { global.expect = expect; - expect.setState({expand: config.expand}); + expect.setState({ + expand: config.expand, + ignoreAsymmetricMatches: config.ignoreAsymmetricMatches, + }); expect.extend({ toMatchInlineSnapshot, toMatchSnapshot, diff --git a/packages/jest-types/src/Config.ts b/packages/jest-types/src/Config.ts index aca89876a7c1..6e572326373b 100644 --- a/packages/jest-types/src/Config.ts +++ b/packages/jest-types/src/Config.ts @@ -43,6 +43,7 @@ export type DefaultOptions = { forceCoverageMatch: Array; globals: ConfigGlobals; haste: HasteConfig; + ignoreAsymmetricMatches: boolean; maxConcurrency: number; maxWorkers: number | string; moduleDirectories: Array; @@ -128,6 +129,7 @@ export type InitialOptions = Partial<{ globalSetup: string | null | undefined; globalTeardown: string | null | undefined; haste: HasteConfig; + ignoreAsymmetricMatches: boolean; reporters: Array; logHeapUsage: boolean; lastCommit: boolean; @@ -252,6 +254,7 @@ export type GlobalConfig = { json: boolean; globalSetup?: string; globalTeardown?: string; + ignoreAsymmetricMatches: boolean; lastCommit: boolean; logHeapUsage: boolean; listTests: boolean; @@ -381,6 +384,7 @@ export type Argv = Arguments< globalSetup: string | null | undefined; globalTeardown: string | null | undefined; haste: string; + ignoreAsymmetricMatches: boolean; init: boolean; json: boolean; lastCommit: boolean; diff --git a/packages/jest-validate/src/__tests__/fixtures/jestConfig.ts b/packages/jest-validate/src/__tests__/fixtures/jestConfig.ts index 3e841c5bbf36..d8908fa35029 100644 --- a/packages/jest-validate/src/__tests__/fixtures/jestConfig.ts +++ b/packages/jest-validate/src/__tests__/fixtures/jestConfig.ts @@ -32,6 +32,7 @@ const defaultConfig = { haste: { providesModuleNodeModules: [], }, + ignoreAsymmetricMatches: false, moduleDirectories: ['node_modules'], moduleFileExtensions: ['js', 'json', 'jsx', 'node'], moduleNameMapper: {}, @@ -85,6 +86,7 @@ const validConfig = { haste: { providesModuleNodeModules: ['react', 'react-native'], }, + ignoreAsymmetricMatches: false, logHeapUsage: true, moduleDirectories: ['node_modules'], moduleFileExtensions: ['js', 'json', 'jsx', 'node'], From a6632eda522f3853ebcfad0bd0abb6da65330afb Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sat, 7 Dec 2019 22:04:58 +0800 Subject: [PATCH 12/44] update docs --- docs/CLI.md | 4 ++++ docs/Configuration.md | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/docs/CLI.md b/docs/CLI.md index de9bee433d67..4c1a2bd5a242 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -184,6 +184,10 @@ Force Jest to exit after all tests have completed running. This is useful when r Show the help information, similar to this page. +### `--ignoreAsymmetricMatches` + +Ignore asymmetric matches in diffing. + ### `--init` Generate a basic configuration file. Based on your project, Jest will ask you a few questions that will help to generate a `jest.config.js` file with a short description for each option. diff --git a/docs/Configuration.md b/docs/Configuration.md index 709686c84c38..341431421928 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -428,6 +428,31 @@ _Note: A global teardown module configured in a project (using multi-project run _Note: The same caveat concerning transformation of `node_modules` as for `globalSetup` applies to `globalTeardown`._ +### `ignoreAsymmetricMatches` [boolean] + +Default: `false` + +If setting this option true, it will not highlight asymmetric matches + +ignoreAsymmetricMatches = `true` +```diff + Object { + a: expect.any(Number), +- b: 2, ++ b: 1, + } +``` + +ignoreAsymmetricMatches = `false` +```diff + Object { +- a: expect.any(Number), +- b: 2, ++ a: 1, ++ b: 1, + } +``` + ### `maxConcurrency` [number] Default: `5` From 4f5c1a992103c22489915c82e4da910bfde37b51 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sat, 7 Dec 2019 22:05:04 +0800 Subject: [PATCH 13/44] update snapshot --- .../expect/src/__tests__/__snapshots__/matchers.test.js.snap | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap index 52cf381f1fcd..162652bbe6b4 100644 --- a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap @@ -364,9 +364,6 @@ exports[`.toBe() fails for: {"a": [Function a], "b": 2} and {"a": Any, If it should pass with deep equality, replace "toBe" with "toStrictEqual" -Compared values serialize to the same structure. -Printing internal object structure without calling \`toJSON\` instead. - - Expected - 1 + Received + 1 From 29154cda886b9cd6c7f0ff94a1fb49ebb7f59076 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sat, 7 Dec 2019 22:30:40 +0800 Subject: [PATCH 14/44] add e2e test --- .../ignoreAsymmetricMatches.test.ts.snap | 679 ++++++++++++++++++ e2e/__tests__/ignoreAsymmetricMatches.test.ts | 36 + .../asymmetrictMatcher.test.js | 105 +++ e2e/ignore-asymmetric-matches/package.json | 5 + 4 files changed, 825 insertions(+) create mode 100644 e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap create mode 100644 e2e/__tests__/ignoreAsymmetricMatches.test.ts create mode 100644 e2e/ignore-asymmetric-matches/asymmetrictMatcher.test.js create mode 100644 e2e/ignore-asymmetric-matches/package.json diff --git a/e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap b/e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap new file mode 100644 index 000000000000..bda0842cc317 --- /dev/null +++ b/e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap @@ -0,0 +1,679 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` +"FAIL ./asymmetrictMatcher.test.js + ✕ minimal test + ✕ jest asymmetricMatcher + ✕ custom asymmetricMatcher + ✕ nested object + ✕ circular + ✕ transitive circular + + ● minimal test + + expect(received).toEqual(expected) // deep equality + + - Expected - 1 + + Received + 1 + + Object { + \\"a\\": Any, + - \\"b\\": 1, + + \\"b\\": 2, + } + + 2 | const expected = {a: expect.any(Number), b: 2}; + 3 | const received = {a: 1, b: 1}; + > 4 | expect(expected).toEqual(received); + | ^ + 5 | }); + 6 | + 7 | test('jest asymmetricMatcher', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:4:20) + + ● jest asymmetricMatcher + + expect(received).toEqual(expected) // deep equality + + - Expected - 1 + + Received + 1 + + @@ -8,7 +8,7 @@ + \\"d\\": StringContaining \\"jest\\", + \\"e\\": StringMatching /^jest/, + \\"f\\": ObjectContaining { + \\"a\\": Any, + }, + - \\"g\\": false, + + \\"g\\": true, + } + + 30 | }; + 31 | + > 32 | expect(expected).toEqual(received); + | ^ + 33 | }); + 34 | + 35 | test('custom asymmetricMatcher', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:32:20) + + ● custom asymmetricMatcher + + expect(received).toEqual(expected) // deep equality + + - Expected - 1 + + Received + 1 + + Object { + \\"a\\": equal5<>, + - \\"b\\": true, + + \\"b\\": false, + } + + 56 | }; + 57 | + > 58 | expect(expected).toEqual(received); + | ^ + 59 | }); + 60 | + 61 | test('nested object', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:58:20) + + ● nested object + + expect(received).toEqual(expected) // deep equality + + - Expected - 1 + + Received + 1 + + @@ -2,7 +2,7 @@ + \\"a\\": Any, + \\"b\\": Object { + \\"a\\": 1, + \\"b\\": Any, + }, + - \\"c\\": 1, + + \\"c\\": 2, + } + + 76 | c: 1, + 77 | }; + > 78 | expect(expected).toEqual(received); + | ^ + 79 | }); + 80 | + 81 | test('circular', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:78:20) + + ● circular + + expect(received).toEqual(expected) // deep equality + + - Expected - 1 + + Received + 1 + + Object { + \\"a\\": [Circular], + \\"b\\": Any, + - \\"c\\": 2, + + \\"c\\": 3, + } + + 90 | }; + 91 | received.a = received; + > 92 | expect(expected).toEqual(received); + | ^ + 93 | }); + 94 | + 95 | test('transitive circular', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:92:20) + + ● transitive circular + + expect(received).toEqual(expected) // deep equality + + - Expected - 1 + + Received + 1 + + Object { + - \\"a\\": 2, + + \\"a\\": 3, + \\"nested\\": Object { + \\"b\\": Any, + \\"parent\\": [Circular], + }, + } + + 102 | }; + 103 | received.nested = {b: 2, parent: received}; + > 104 | expect(expected).toEqual(received); + | ^ + 105 | }); + 106 | + + at Object.toEqual (asymmetrictMatcher.test.js:104:20)" +`; + +exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` +"FAIL ./asymmetrictMatcher.test.js + ✕ minimal test + ✕ jest asymmetricMatcher + ✕ custom asymmetricMatcher + ✕ nested object + ✕ circular + ✕ transitive circular + + ● minimal test + + expect(received).toEqual(expected) // deep equality + + - Expected - 1 + + Received + 1 + + Object { + \\"a\\": Any, + - \\"b\\": 1, + + \\"b\\": 2, + } + + 2 | const expected = {a: expect.any(Number), b: 2}; + 3 | const received = {a: 1, b: 1}; + > 4 | expect(expected).toEqual(received); + | ^ + 5 | }); + 6 | + 7 | test('jest asymmetricMatcher', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:4:20) + + ● jest asymmetricMatcher + + expect(received).toEqual(expected) // deep equality + + - Expected - 1 + + Received + 1 + + @@ -8,7 +8,7 @@ + \\"d\\": StringContaining \\"jest\\", + \\"e\\": StringMatching /^jest/, + \\"f\\": ObjectContaining { + \\"a\\": Any, + }, + - \\"g\\": false, + + \\"g\\": true, + } + + 30 | }; + 31 | + > 32 | expect(expected).toEqual(received); + | ^ + 33 | }); + 34 | + 35 | test('custom asymmetricMatcher', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:32:20) + + ● custom asymmetricMatcher + + expect(received).toEqual(expected) // deep equality + + - Expected - 1 + + Received + 1 + + Object { + \\"a\\": equal5<>, + - \\"b\\": true, + + \\"b\\": false, + } + + 56 | }; + 57 | + > 58 | expect(expected).toEqual(received); + | ^ + 59 | }); + 60 | + 61 | test('nested object', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:58:20) + + ● nested object + + expect(received).toEqual(expected) // deep equality + + - Expected - 1 + + Received + 1 + + @@ -2,7 +2,7 @@ + \\"a\\": Any, + \\"b\\": Object { + \\"a\\": 1, + \\"b\\": Any, + }, + - \\"c\\": 1, + + \\"c\\": 2, + } + + 76 | c: 1, + 77 | }; + > 78 | expect(expected).toEqual(received); + | ^ + 79 | }); + 80 | + 81 | test('circular', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:78:20) + + ● circular + + expect(received).toEqual(expected) // deep equality + + - Expected - 1 + + Received + 1 + + Object { + \\"a\\": [Circular], + \\"b\\": Any, + - \\"c\\": 2, + + \\"c\\": 3, + } + + 90 | }; + 91 | received.a = received; + > 92 | expect(expected).toEqual(received); + | ^ + 93 | }); + 94 | + 95 | test('transitive circular', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:92:20) + + ● transitive circular + + expect(received).toEqual(expected) // deep equality + + - Expected - 1 + + Received + 1 + + Object { + - \\"a\\": 2, + + \\"a\\": 3, + \\"nested\\": Object { + \\"b\\": Any, + \\"parent\\": [Circular], + }, + } + + 102 | }; + 103 | received.nested = {b: 2, parent: received}; + > 104 | expect(expected).toEqual(received); + | ^ + 105 | }); + 106 | + + at Object.toEqual (asymmetrictMatcher.test.js:104:20)" +`; + +exports[`should not ignore in default 1`] = ` +"FAIL ./asymmetrictMatcher.test.js + ✕ minimal test + ✕ jest asymmetricMatcher + ✕ custom asymmetricMatcher + ✕ nested object + ✕ circular + ✕ transitive circular + + ● minimal test + + expect(received).toEqual(expected) // deep equality + + - Expected - 2 + + Received + 2 + + Object { + - \\"a\\": 1, + - \\"b\\": 1, + + \\"a\\": Any, + + \\"b\\": 2, + } + + 2 | const expected = {a: expect.any(Number), b: 2}; + 3 | const received = {a: 1, b: 1}; + > 4 | expect(expected).toEqual(received); + | ^ + 5 | }); + 6 | + 7 | test('jest asymmetricMatcher', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:4:20) + + ● jest asymmetricMatcher + + expect(received).toEqual(expected) // deep equality + + - Expected - 9 + + Received + 9 + + Object { + - \\"a\\": 1, + - \\"b\\": \\"anything\\", + - \\"c\\": Array [ + + \\"a\\": Any, + + \\"b\\": Anything, + + \\"c\\": ArrayContaining [ + 1, + - 2, + 3, + ], + - \\"d\\": StringContaining \\"jest\\", + - \\"e\\": StringMatching /^jest/, + - \\"f\\": ObjectContaining { + - \\"a\\": Any, + + \\"d\\": \\"jest is awesome\\", + + \\"e\\": \\"jest is awesome\\", + + \\"f\\": Object { + + \\"a\\": 1970-01-01T00:00:00.000Z, + + \\"b\\": \\"jest is awesome\\", + }, + - \\"g\\": false, + + \\"g\\": true, + } + + 30 | }; + 31 | + > 32 | expect(expected).toEqual(received); + | ^ + 33 | }); + 34 | + 35 | test('custom asymmetricMatcher', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:32:20) + + ● custom asymmetricMatcher + + expect(received).toEqual(expected) // deep equality + + - Expected - 2 + + Received + 2 + + Object { + - \\"a\\": 5, + - \\"b\\": true, + + \\"a\\": equal5<>, + + \\"b\\": false, + } + + 56 | }; + 57 | + > 58 | expect(expected).toEqual(received); + | ^ + 59 | }); + 60 | + 61 | test('nested object', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:58:20) + + ● nested object + + expect(received).toEqual(expected) // deep equality + + - Expected - 3 + + Received + 3 + + Object { + - \\"a\\": Any, + + \\"a\\": 1, + \\"b\\": Object { + \\"a\\": 1, + - \\"b\\": 2, + + \\"b\\": Any, + }, + - \\"c\\": 1, + + \\"c\\": 2, + } + + 76 | c: 1, + 77 | }; + > 78 | expect(expected).toEqual(received); + | ^ + 79 | }); + 80 | + 81 | test('circular', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:78:20) + + ● circular + + expect(received).toEqual(expected) // deep equality + + - Expected - 2 + + Received + 2 + + Object { + \\"a\\": [Circular], + - \\"b\\": 2, + - \\"c\\": 2, + + \\"b\\": Any, + + \\"c\\": 3, + } + + 90 | }; + 91 | received.a = received; + > 92 | expect(expected).toEqual(received); + | ^ + 93 | }); + 94 | + 95 | test('transitive circular', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:92:20) + + ● transitive circular + + expect(received).toEqual(expected) // deep equality + + - Expected - 2 + + Received + 2 + + Object { + - \\"a\\": 2, + + \\"a\\": 3, + \\"nested\\": Object { + - \\"b\\": 2, + + \\"b\\": Any, + \\"parent\\": [Circular], + }, + } + + 102 | }; + 103 | received.nested = {b: 2, parent: received}; + > 104 | expect(expected).toEqual(received); + | ^ + 105 | }); + 106 | + + at Object.toEqual (asymmetrictMatcher.test.js:104:20)" +`; + +exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` +"FAIL ./asymmetrictMatcher.test.js + ✕ minimal test + ✕ jest asymmetricMatcher + ✕ custom asymmetricMatcher + ✕ nested object + ✕ circular + ✕ transitive circular + + ● minimal test + + expect(received).toEqual(expected) // deep equality + + - Expected - 2 + + Received + 2 + + Object { + - \\"a\\": 1, + - \\"b\\": 1, + + \\"a\\": Any, + + \\"b\\": 2, + } + + 2 | const expected = {a: expect.any(Number), b: 2}; + 3 | const received = {a: 1, b: 1}; + > 4 | expect(expected).toEqual(received); + | ^ + 5 | }); + 6 | + 7 | test('jest asymmetricMatcher', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:4:20) + + ● jest asymmetricMatcher + + expect(received).toEqual(expected) // deep equality + + - Expected - 9 + + Received + 9 + + Object { + - \\"a\\": 1, + - \\"b\\": \\"anything\\", + - \\"c\\": Array [ + + \\"a\\": Any, + + \\"b\\": Anything, + + \\"c\\": ArrayContaining [ + 1, + - 2, + 3, + ], + - \\"d\\": StringContaining \\"jest\\", + - \\"e\\": StringMatching /^jest/, + - \\"f\\": ObjectContaining { + - \\"a\\": Any, + + \\"d\\": \\"jest is awesome\\", + + \\"e\\": \\"jest is awesome\\", + + \\"f\\": Object { + + \\"a\\": 1970-01-01T00:00:00.000Z, + + \\"b\\": \\"jest is awesome\\", + }, + - \\"g\\": false, + + \\"g\\": true, + } + + 30 | }; + 31 | + > 32 | expect(expected).toEqual(received); + | ^ + 33 | }); + 34 | + 35 | test('custom asymmetricMatcher', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:32:20) + + ● custom asymmetricMatcher + + expect(received).toEqual(expected) // deep equality + + - Expected - 2 + + Received + 2 + + Object { + - \\"a\\": 5, + - \\"b\\": true, + + \\"a\\": equal5<>, + + \\"b\\": false, + } + + 56 | }; + 57 | + > 58 | expect(expected).toEqual(received); + | ^ + 59 | }); + 60 | + 61 | test('nested object', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:58:20) + + ● nested object + + expect(received).toEqual(expected) // deep equality + + - Expected - 3 + + Received + 3 + + Object { + - \\"a\\": Any, + + \\"a\\": 1, + \\"b\\": Object { + \\"a\\": 1, + - \\"b\\": 2, + + \\"b\\": Any, + }, + - \\"c\\": 1, + + \\"c\\": 2, + } + + 76 | c: 1, + 77 | }; + > 78 | expect(expected).toEqual(received); + | ^ + 79 | }); + 80 | + 81 | test('circular', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:78:20) + + ● circular + + expect(received).toEqual(expected) // deep equality + + - Expected - 2 + + Received + 2 + + Object { + \\"a\\": [Circular], + - \\"b\\": 2, + - \\"c\\": 2, + + \\"b\\": Any, + + \\"c\\": 3, + } + + 90 | }; + 91 | received.a = received; + > 92 | expect(expected).toEqual(received); + | ^ + 93 | }); + 94 | + 95 | test('transitive circular', () => { + + at Object.toEqual (asymmetrictMatcher.test.js:92:20) + + ● transitive circular + + expect(received).toEqual(expected) // deep equality + + - Expected - 2 + + Received + 2 + + Object { + - \\"a\\": 2, + + \\"a\\": 3, + \\"nested\\": Object { + - \\"b\\": 2, + + \\"b\\": Any, + \\"parent\\": [Circular], + }, + } + + 102 | }; + 103 | received.nested = {b: 2, parent: received}; + > 104 | expect(expected).toEqual(received); + | ^ + 105 | }); + 106 | + + at Object.toEqual (asymmetrictMatcher.test.js:104:20)" +`; diff --git a/e2e/__tests__/ignoreAsymmetricMatches.test.ts b/e2e/__tests__/ignoreAsymmetricMatches.test.ts new file mode 100644 index 000000000000..d9744298e7da --- /dev/null +++ b/e2e/__tests__/ignoreAsymmetricMatches.test.ts @@ -0,0 +1,36 @@ +import * as path from 'path'; +import runJest from '../runJest'; +import {wrap} from 'jest-snapshot-serializer-raw'; +import {extractSummary} from '../Utils'; + +const dir = path.resolve(__dirname, '../ignore-asymmetric-matches'); + +test('should not ignore in default', () => { + const {stderr} = runJest(dir); + const {rest} = extractSummary(stderr); + expect(rest).toMatchSnapshot(); +}); + +test('should ignore with --ignoreAsymmetricMatches cli option', () => { + const {stderr} = runJest(dir, ['--ignoreAsymmetricMatches']); + const {rest} = extractSummary(stderr); + expect(rest).toMatchSnapshot(); +}); + +test('should ignore with ignoreAsymmetricMatches=true in config', () => { + const {stderr} = runJest(dir, [ + '--config', + JSON.stringify({ignoreAsymmetricMatches: true}), + ]); + const {rest} = extractSummary(stderr); + expect(rest).toMatchSnapshot(); +}); + +test('should not ignore with ignoreAsymmetricMatches=false in config', () => { + const {stderr} = runJest(dir, [ + '--config', + JSON.stringify({ignoreAsymmetricMatches: false}), + ]); + const {rest} = extractSummary(stderr); + expect(rest).toMatchSnapshot(); +}); diff --git a/e2e/ignore-asymmetric-matches/asymmetrictMatcher.test.js b/e2e/ignore-asymmetric-matches/asymmetrictMatcher.test.js new file mode 100644 index 000000000000..d4c5dcd1b7e9 --- /dev/null +++ b/e2e/ignore-asymmetric-matches/asymmetrictMatcher.test.js @@ -0,0 +1,105 @@ +test('minimal test', () => { + const expected = {a: expect.any(Number), b: 2}; + const received = {a: 1, b: 1}; + expect(expected).toEqual(received); +}); + +test('jest asymmetricMatcher', () => { + const expected = { + a: expect.any(Number), + b: expect.anything(), + c: expect.arrayContaining([1, 3]), + d: 'jest is awesome', + e: 'jest is awesome', + f: { + a: new Date(0), + b: 'jest is awesome', + }, + g: true, + }; + const received = { + a: 1, + b: 'anything', + c: [1, 2, 3], + d: expect.stringContaining('jest'), + e: expect.stringMatching(/^jest/), + f: expect.objectContaining({ + a: expect.any(Date), + }), + g: false, + }; + + expect(expected).toEqual(received); +}); + +test('custom asymmetricMatcher', () => { + expect.extend({ + equal5(received) { + if (received === 5) + return { + message: () => `expected ${received} not to be 5`, + pass: true, + }; + return { + message: () => `expected ${received} to be 5`, + pass: false, + }; + }, + }); + const expected = { + a: expect.equal5(), + b: false, + }; + const received = { + a: 5, + b: true, + }; + + expect(expected).toEqual(received); +}); + +test('nested object', () => { + const expected = { + a: 1, + b: { + a: 1, + b: expect.any(Number), + }, + c: 2, + }; + const received = { + a: expect.any(Number), + b: { + a: 1, + b: 2, + }, + c: 1, + }; + expect(expected).toEqual(received); +}); + +test('circular', () => { + const expected = { + b: expect.any(Number), + c: 3, + }; + expected.a = expected; + const received = { + b: 2, + c: 2, + }; + received.a = received; + expect(expected).toEqual(received); +}); + +test('transitive circular', () => { + const expected = { + a: 3, + }; + expected.nested = {b: expect.any(Number), parent: expected}; + const received = { + a: 2, + }; + received.nested = {b: 2, parent: received}; + expect(expected).toEqual(received); +}); diff --git a/e2e/ignore-asymmetric-matches/package.json b/e2e/ignore-asymmetric-matches/package.json new file mode 100644 index 000000000000..a39800c4abd6 --- /dev/null +++ b/e2e/ignore-asymmetric-matches/package.json @@ -0,0 +1,5 @@ +{ + "jest": { + "testEnvironment": "node" + } +} \ No newline at end of file From 7aa6f2793ad45e55e005b294c7a8216f7d0c45c8 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sat, 7 Dec 2019 22:44:07 +0800 Subject: [PATCH 15/44] update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3126218c491d..03d01b501f8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - `[@jest/fake-timers]` Add Lolex as implementation of fake timers ([#8897](https://github.com/facebook/jest/pull/8897)) - `[jest-get-type]` Add `BigInt` support. ([#8382](https://github.com/facebook/jest/pull/8382)) - `[jest-matcher-utils]` Add `BigInt` support to `ensureNumbers` `ensureActualIsNumber`, `ensureExpectedIsNumber` ([#8382](https://github.com/facebook/jest/pull/8382)) +- `[jest-matcher-utils]` Add `ignoreAsymmetricMatches` to ignore highlighting matched asymmetricMatcher in diffs ([#9257](https://github.com/facebook/jest/pull/9257)) - `[jest-reporters]` Export utils for path formatting ([#9162](https://github.com/facebook/jest/pull/9162)) - `[jest-runner]` Warn if a worker had to be force exited ([#8206](https://github.com/facebook/jest/pull/8206)) - `[jest-runtime]` [**BREAKING**] Do not export `ScriptTransformer` - it can be imported from `@jest/transform` instead ([#9256](https://github.com/facebook/jest/pull/9256)) @@ -52,7 +53,6 @@ - `[jest-core]` Limit number of workers when creating haste maps in projects ([#9259](https://github.com/facebook/jest/pull/9259)) - `[jest-diff]` Do not inverse format if line consists of one change ([#8903](https://github.com/facebook/jest/pull/8903)) - `[jest-diff]` Rename some new options and change their default values ([#9077](https://github.com/facebook/jest/pull/9077)) -- `[jest-diff]` Do not highlight matched asymmetricMatcher in diffs ([#9257](https://github.com/facebook/jest/pull/9257)) - `[jest-environment-node]` Fix `TextEncoder.encode` not referencing same global `Uint8Array` constructor ([#9261](https://github.com/facebook/jest/pull/9261)) - `[jest-fake-timers]` `getTimerCount` will not include cancelled immediates ([#8764](https://github.com/facebook/jest/pull/8764)) - `[jest-fake-timers]` Support `util.promisify` on `setTimeout` ([#9180](https://github.com/facebook/jest/pull/9180)) From b148c0f3fc285dc9508800d19bdf49339684dff5 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sat, 7 Dec 2019 22:47:55 +0800 Subject: [PATCH 16/44] ignore e2e test file --- .../{ => __tests__}/asymmetrictMatcher.test.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename e2e/ignore-asymmetric-matches/{ => __tests__}/asymmetrictMatcher.test.js (100%) diff --git a/e2e/ignore-asymmetric-matches/asymmetrictMatcher.test.js b/e2e/ignore-asymmetric-matches/__tests__/asymmetrictMatcher.test.js similarity index 100% rename from e2e/ignore-asymmetric-matches/asymmetrictMatcher.test.js rename to e2e/ignore-asymmetric-matches/__tests__/asymmetrictMatcher.test.js From fd6443eaf91efec4b10af468c86f463948278343 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sat, 7 Dec 2019 22:49:40 +0800 Subject: [PATCH 17/44] lint --- e2e/__tests__/ignoreAsymmetricMatches.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/e2e/__tests__/ignoreAsymmetricMatches.test.ts b/e2e/__tests__/ignoreAsymmetricMatches.test.ts index d9744298e7da..b65faa5efe7f 100644 --- a/e2e/__tests__/ignoreAsymmetricMatches.test.ts +++ b/e2e/__tests__/ignoreAsymmetricMatches.test.ts @@ -1,6 +1,5 @@ import * as path from 'path'; import runJest from '../runJest'; -import {wrap} from 'jest-snapshot-serializer-raw'; import {extractSummary} from '../Utils'; const dir = path.resolve(__dirname, '../ignore-asymmetric-matches'); From ba5d7ecbbd8adde6827bd30b337eec7f98f2c662 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sat, 7 Dec 2019 22:56:44 +0800 Subject: [PATCH 18/44] update snapshot --- .../ignoreAsymmetricMatches.test.ts.snap | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap b/e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap index bda0842cc317..269ef26fa513 100644 --- a/e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap +++ b/e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` -"FAIL ./asymmetrictMatcher.test.js +"FAIL __tests__/asymmetrictMatcher.test.js ✕ minimal test ✕ jest asymmetricMatcher ✕ custom asymmetricMatcher @@ -30,7 +30,7 @@ exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` 6 | 7 | test('jest asymmetricMatcher', () => { - at Object.toEqual (asymmetrictMatcher.test.js:4:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:4:20) ● jest asymmetricMatcher @@ -57,7 +57,7 @@ exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` 34 | 35 | test('custom asymmetricMatcher', () => { - at Object.toEqual (asymmetrictMatcher.test.js:32:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:32:20) ● custom asymmetricMatcher @@ -80,7 +80,7 @@ exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` 60 | 61 | test('nested object', () => { - at Object.toEqual (asymmetrictMatcher.test.js:58:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:58:20) ● nested object @@ -107,7 +107,7 @@ exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` 80 | 81 | test('circular', () => { - at Object.toEqual (asymmetrictMatcher.test.js:78:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:78:20) ● circular @@ -131,7 +131,7 @@ exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` 94 | 95 | test('transitive circular', () => { - at Object.toEqual (asymmetrictMatcher.test.js:92:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:92:20) ● transitive circular @@ -156,11 +156,11 @@ exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` 105 | }); 106 | - at Object.toEqual (asymmetrictMatcher.test.js:104:20)" + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:104:20)" `; exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` -"FAIL ./asymmetrictMatcher.test.js +"FAIL __tests__/asymmetrictMatcher.test.js ✕ minimal test ✕ jest asymmetricMatcher ✕ custom asymmetricMatcher @@ -189,7 +189,7 @@ exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` 6 | 7 | test('jest asymmetricMatcher', () => { - at Object.toEqual (asymmetrictMatcher.test.js:4:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:4:20) ● jest asymmetricMatcher @@ -216,7 +216,7 @@ exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` 34 | 35 | test('custom asymmetricMatcher', () => { - at Object.toEqual (asymmetrictMatcher.test.js:32:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:32:20) ● custom asymmetricMatcher @@ -239,7 +239,7 @@ exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` 60 | 61 | test('nested object', () => { - at Object.toEqual (asymmetrictMatcher.test.js:58:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:58:20) ● nested object @@ -266,7 +266,7 @@ exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` 80 | 81 | test('circular', () => { - at Object.toEqual (asymmetrictMatcher.test.js:78:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:78:20) ● circular @@ -290,7 +290,7 @@ exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` 94 | 95 | test('transitive circular', () => { - at Object.toEqual (asymmetrictMatcher.test.js:92:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:92:20) ● transitive circular @@ -315,11 +315,11 @@ exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` 105 | }); 106 | - at Object.toEqual (asymmetrictMatcher.test.js:104:20)" + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:104:20)" `; exports[`should not ignore in default 1`] = ` -"FAIL ./asymmetrictMatcher.test.js +"FAIL __tests__/asymmetrictMatcher.test.js ✕ minimal test ✕ jest asymmetricMatcher ✕ custom asymmetricMatcher @@ -349,7 +349,7 @@ exports[`should not ignore in default 1`] = ` 6 | 7 | test('jest asymmetricMatcher', () => { - at Object.toEqual (asymmetrictMatcher.test.js:4:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:4:20) ● jest asymmetricMatcher @@ -391,7 +391,7 @@ exports[`should not ignore in default 1`] = ` 34 | 35 | test('custom asymmetricMatcher', () => { - at Object.toEqual (asymmetrictMatcher.test.js:32:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:32:20) ● custom asymmetricMatcher @@ -415,7 +415,7 @@ exports[`should not ignore in default 1`] = ` 60 | 61 | test('nested object', () => { - at Object.toEqual (asymmetrictMatcher.test.js:58:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:58:20) ● nested object @@ -444,7 +444,7 @@ exports[`should not ignore in default 1`] = ` 80 | 81 | test('circular', () => { - at Object.toEqual (asymmetrictMatcher.test.js:78:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:78:20) ● circular @@ -469,7 +469,7 @@ exports[`should not ignore in default 1`] = ` 94 | 95 | test('transitive circular', () => { - at Object.toEqual (asymmetrictMatcher.test.js:92:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:92:20) ● transitive circular @@ -495,11 +495,11 @@ exports[`should not ignore in default 1`] = ` 105 | }); 106 | - at Object.toEqual (asymmetrictMatcher.test.js:104:20)" + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:104:20)" `; exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` -"FAIL ./asymmetrictMatcher.test.js +"FAIL __tests__/asymmetrictMatcher.test.js ✕ minimal test ✕ jest asymmetricMatcher ✕ custom asymmetricMatcher @@ -529,7 +529,7 @@ exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` 6 | 7 | test('jest asymmetricMatcher', () => { - at Object.toEqual (asymmetrictMatcher.test.js:4:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:4:20) ● jest asymmetricMatcher @@ -571,7 +571,7 @@ exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` 34 | 35 | test('custom asymmetricMatcher', () => { - at Object.toEqual (asymmetrictMatcher.test.js:32:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:32:20) ● custom asymmetricMatcher @@ -595,7 +595,7 @@ exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` 60 | 61 | test('nested object', () => { - at Object.toEqual (asymmetrictMatcher.test.js:58:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:58:20) ● nested object @@ -624,7 +624,7 @@ exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` 80 | 81 | test('circular', () => { - at Object.toEqual (asymmetrictMatcher.test.js:78:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:78:20) ● circular @@ -649,7 +649,7 @@ exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` 94 | 95 | test('transitive circular', () => { - at Object.toEqual (asymmetrictMatcher.test.js:92:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:92:20) ● transitive circular @@ -675,5 +675,5 @@ exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` 105 | }); 106 | - at Object.toEqual (asymmetrictMatcher.test.js:104:20)" + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:104:20)" `; From 34c18dcc877890a12fa4d6c5861324e4d339a5f2 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 8 Dec 2019 01:09:02 +0800 Subject: [PATCH 19/44] fix jest-circus doesn't get ignoreAsymmetricMatches value --- packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts | 1 + packages/jest-circus/src/state.ts | 1 + packages/jest-types/src/Circus.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts index 202744c87b54..b37f50e05b49 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -30,6 +30,7 @@ const jestAdapter = async ( .requireInternalModule(path.resolve(__dirname, './jestExpect.js')) .default({ expand: globalConfig.expand, + ignoreAsymmetricMatches: globalConfig.ignoreAsymmetricMatches }); const getPrettier = () => diff --git a/packages/jest-circus/src/state.ts b/packages/jest-circus/src/state.ts index d42928e90bfa..3afde01426d9 100644 --- a/packages/jest-circus/src/state.ts +++ b/packages/jest-circus/src/state.ts @@ -25,6 +25,7 @@ const INITIAL_STATE: Circus.State = { currentlyRunningTest: null, expand: undefined, hasFocusedTests: false, // whether .only has been used on any test/describe + ignoreAsymmetricMatches: false, includeTestLocationInResult: false, parentProcess: null, rootDescribeBlock: ROOT_DESCRIBE_BLOCK, diff --git a/packages/jest-types/src/Circus.ts b/packages/jest-types/src/Circus.ts index 6ae1bddd4baa..876ce5dc81e1 100644 --- a/packages/jest-types/src/Circus.ts +++ b/packages/jest-types/src/Circus.ts @@ -183,6 +183,7 @@ export type State = { // Store process error handlers. During the run we inject our own // handlers (so we could fail tests on unhandled errors) and later restore // the original ones. + ignoreAsymmetricMatches: boolean; originalGlobalErrorHandlers?: GlobalErrorHandlers; parentProcess: Process | null; // process object from the outer scope rootDescribeBlock: DescribeBlock; From e0a628807a70d27eb1ea0f055a6bc90c5fd56967 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 8 Dec 2019 01:59:07 +0800 Subject: [PATCH 20/44] only import deepCyclicCopy to avoid loading incompatible packages in browser --- packages/jest-matcher-utils/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-matcher-utils/src/index.ts b/packages/jest-matcher-utils/src/index.ts index 89698b54ab29..a47348158b28 100644 --- a/packages/jest-matcher-utils/src/index.ts +++ b/packages/jest-matcher-utils/src/index.ts @@ -16,7 +16,7 @@ import diffDefault, { diffStringsUnified, } from 'jest-diff'; import getType = require('jest-get-type'); -import {deepCyclicCopy} from 'jest-util'; +import deepCyclicCopy from 'jest-util/build/deepCyclicCopy'; import prettyFormat = require('pretty-format'); const { From c5361b4ba14da77782024bfb2b6ddde811a08f8b Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 8 Dec 2019 02:36:45 +0800 Subject: [PATCH 21/44] lint --- .../jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts index b37f50e05b49..0fd4cb272c0d 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -30,7 +30,7 @@ const jestAdapter = async ( .requireInternalModule(path.resolve(__dirname, './jestExpect.js')) .default({ expand: globalConfig.expand, - ignoreAsymmetricMatches: globalConfig.ignoreAsymmetricMatches + ignoreAsymmetricMatches: globalConfig.ignoreAsymmetricMatches, }); const getPrettier = () => From c90a4ed0c0d9c0a68307592952eef63cedd258af Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 8 Dec 2019 02:57:46 +0800 Subject: [PATCH 22/44] prettier Configuration.md --- docs/Configuration.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/Configuration.md b/docs/Configuration.md index 341431421928..7e4a0a762bfc 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -435,6 +435,7 @@ Default: `false` If setting this option true, it will not highlight asymmetric matches ignoreAsymmetricMatches = `true` + ```diff Object { a: expect.any(Number), @@ -444,6 +445,7 @@ ignoreAsymmetricMatches = `true` ``` ignoreAsymmetricMatches = `false` + ```diff Object { - a: expect.any(Number), From d7c9a55172e785a6ccc5bad90993cdab3ca2701f Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 8 Dec 2019 03:08:35 +0800 Subject: [PATCH 23/44] add copyright headers --- e2e/__tests__/ignoreAsymmetricMatches.test.ts | 7 +++++++ .../__tests__/asymmetrictMatcher.test.js | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/e2e/__tests__/ignoreAsymmetricMatches.test.ts b/e2e/__tests__/ignoreAsymmetricMatches.test.ts index b65faa5efe7f..fc16c0e6f547 100644 --- a/e2e/__tests__/ignoreAsymmetricMatches.test.ts +++ b/e2e/__tests__/ignoreAsymmetricMatches.test.ts @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + import * as path from 'path'; import runJest from '../runJest'; import {extractSummary} from '../Utils'; diff --git a/e2e/ignore-asymmetric-matches/__tests__/asymmetrictMatcher.test.js b/e2e/ignore-asymmetric-matches/__tests__/asymmetrictMatcher.test.js index d4c5dcd1b7e9..7f0a912137f2 100644 --- a/e2e/ignore-asymmetric-matches/__tests__/asymmetrictMatcher.test.js +++ b/e2e/ignore-asymmetric-matches/__tests__/asymmetrictMatcher.test.js @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + test('minimal test', () => { const expected = {a: expect.any(Number), b: 2}; const received = {a: 1, b: 1}; From b438d6ddcaa853052da56ccfdb5f0a755fa672ac Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 8 Dec 2019 03:40:50 +0800 Subject: [PATCH 24/44] update snapshot --- .../ignoreAsymmetricMatches.test.ts.snap | 344 +++++++++--------- 1 file changed, 172 insertions(+), 172 deletions(-) diff --git a/e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap b/e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap index 269ef26fa513..92a67abda398 100644 --- a/e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap +++ b/e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap @@ -22,15 +22,15 @@ exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` + \\"b\\": 2, } - 2 | const expected = {a: expect.any(Number), b: 2}; - 3 | const received = {a: 1, b: 1}; - > 4 | expect(expected).toEqual(received); - | ^ - 5 | }); - 6 | - 7 | test('jest asymmetricMatcher', () => { + 9 | const expected = {a: expect.any(Number), b: 2}; + 10 | const received = {a: 1, b: 1}; + > 11 | expect(expected).toEqual(received); + | ^ + 12 | }); + 13 | + 14 | test('jest asymmetricMatcher', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:4:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:11:20) ● jest asymmetricMatcher @@ -49,15 +49,15 @@ exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` + \\"g\\": true, } - 30 | }; - 31 | - > 32 | expect(expected).toEqual(received); + 37 | }; + 38 | + > 39 | expect(expected).toEqual(received); | ^ - 33 | }); - 34 | - 35 | test('custom asymmetricMatcher', () => { + 40 | }); + 41 | + 42 | test('custom asymmetricMatcher', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:32:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:39:20) ● custom asymmetricMatcher @@ -72,15 +72,15 @@ exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` + \\"b\\": false, } - 56 | }; - 57 | - > 58 | expect(expected).toEqual(received); + 63 | }; + 64 | + > 65 | expect(expected).toEqual(received); | ^ - 59 | }); - 60 | - 61 | test('nested object', () => { + 66 | }); + 67 | + 68 | test('nested object', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:58:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:65:20) ● nested object @@ -99,15 +99,15 @@ exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` + \\"c\\": 2, } - 76 | c: 1, - 77 | }; - > 78 | expect(expected).toEqual(received); + 83 | c: 1, + 84 | }; + > 85 | expect(expected).toEqual(received); | ^ - 79 | }); - 80 | - 81 | test('circular', () => { + 86 | }); + 87 | + 88 | test('circular', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:78:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:85:20) ● circular @@ -123,15 +123,15 @@ exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` + \\"c\\": 3, } - 90 | }; - 91 | received.a = received; - > 92 | expect(expected).toEqual(received); - | ^ - 93 | }); - 94 | - 95 | test('transitive circular', () => { + 97 | }; + 98 | received.a = received; + > 99 | expect(expected).toEqual(received); + | ^ + 100 | }); + 101 | + 102 | test('transitive circular', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:92:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:99:20) ● transitive circular @@ -149,14 +149,14 @@ exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` }, } - 102 | }; - 103 | received.nested = {b: 2, parent: received}; - > 104 | expect(expected).toEqual(received); + 109 | }; + 110 | received.nested = {b: 2, parent: received}; + > 111 | expect(expected).toEqual(received); | ^ - 105 | }); - 106 | + 112 | }); + 113 | - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:104:20)" + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:111:20)" `; exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` @@ -181,15 +181,15 @@ exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` + \\"b\\": 2, } - 2 | const expected = {a: expect.any(Number), b: 2}; - 3 | const received = {a: 1, b: 1}; - > 4 | expect(expected).toEqual(received); - | ^ - 5 | }); - 6 | - 7 | test('jest asymmetricMatcher', () => { + 9 | const expected = {a: expect.any(Number), b: 2}; + 10 | const received = {a: 1, b: 1}; + > 11 | expect(expected).toEqual(received); + | ^ + 12 | }); + 13 | + 14 | test('jest asymmetricMatcher', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:4:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:11:20) ● jest asymmetricMatcher @@ -208,15 +208,15 @@ exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` + \\"g\\": true, } - 30 | }; - 31 | - > 32 | expect(expected).toEqual(received); + 37 | }; + 38 | + > 39 | expect(expected).toEqual(received); | ^ - 33 | }); - 34 | - 35 | test('custom asymmetricMatcher', () => { + 40 | }); + 41 | + 42 | test('custom asymmetricMatcher', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:32:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:39:20) ● custom asymmetricMatcher @@ -231,15 +231,15 @@ exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` + \\"b\\": false, } - 56 | }; - 57 | - > 58 | expect(expected).toEqual(received); + 63 | }; + 64 | + > 65 | expect(expected).toEqual(received); | ^ - 59 | }); - 60 | - 61 | test('nested object', () => { + 66 | }); + 67 | + 68 | test('nested object', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:58:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:65:20) ● nested object @@ -258,15 +258,15 @@ exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` + \\"c\\": 2, } - 76 | c: 1, - 77 | }; - > 78 | expect(expected).toEqual(received); + 83 | c: 1, + 84 | }; + > 85 | expect(expected).toEqual(received); | ^ - 79 | }); - 80 | - 81 | test('circular', () => { + 86 | }); + 87 | + 88 | test('circular', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:78:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:85:20) ● circular @@ -282,15 +282,15 @@ exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` + \\"c\\": 3, } - 90 | }; - 91 | received.a = received; - > 92 | expect(expected).toEqual(received); - | ^ - 93 | }); - 94 | - 95 | test('transitive circular', () => { + 97 | }; + 98 | received.a = received; + > 99 | expect(expected).toEqual(received); + | ^ + 100 | }); + 101 | + 102 | test('transitive circular', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:92:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:99:20) ● transitive circular @@ -308,14 +308,14 @@ exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` }, } - 102 | }; - 103 | received.nested = {b: 2, parent: received}; - > 104 | expect(expected).toEqual(received); + 109 | }; + 110 | received.nested = {b: 2, parent: received}; + > 111 | expect(expected).toEqual(received); | ^ - 105 | }); - 106 | + 112 | }); + 113 | - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:104:20)" + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:111:20)" `; exports[`should not ignore in default 1`] = ` @@ -341,15 +341,15 @@ exports[`should not ignore in default 1`] = ` + \\"b\\": 2, } - 2 | const expected = {a: expect.any(Number), b: 2}; - 3 | const received = {a: 1, b: 1}; - > 4 | expect(expected).toEqual(received); - | ^ - 5 | }); - 6 | - 7 | test('jest asymmetricMatcher', () => { + 9 | const expected = {a: expect.any(Number), b: 2}; + 10 | const received = {a: 1, b: 1}; + > 11 | expect(expected).toEqual(received); + | ^ + 12 | }); + 13 | + 14 | test('jest asymmetricMatcher', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:4:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:11:20) ● jest asymmetricMatcher @@ -383,15 +383,15 @@ exports[`should not ignore in default 1`] = ` + \\"g\\": true, } - 30 | }; - 31 | - > 32 | expect(expected).toEqual(received); + 37 | }; + 38 | + > 39 | expect(expected).toEqual(received); | ^ - 33 | }); - 34 | - 35 | test('custom asymmetricMatcher', () => { + 40 | }); + 41 | + 42 | test('custom asymmetricMatcher', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:32:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:39:20) ● custom asymmetricMatcher @@ -407,15 +407,15 @@ exports[`should not ignore in default 1`] = ` + \\"b\\": false, } - 56 | }; - 57 | - > 58 | expect(expected).toEqual(received); + 63 | }; + 64 | + > 65 | expect(expected).toEqual(received); | ^ - 59 | }); - 60 | - 61 | test('nested object', () => { + 66 | }); + 67 | + 68 | test('nested object', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:58:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:65:20) ● nested object @@ -436,15 +436,15 @@ exports[`should not ignore in default 1`] = ` + \\"c\\": 2, } - 76 | c: 1, - 77 | }; - > 78 | expect(expected).toEqual(received); + 83 | c: 1, + 84 | }; + > 85 | expect(expected).toEqual(received); | ^ - 79 | }); - 80 | - 81 | test('circular', () => { + 86 | }); + 87 | + 88 | test('circular', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:78:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:85:20) ● circular @@ -461,15 +461,15 @@ exports[`should not ignore in default 1`] = ` + \\"c\\": 3, } - 90 | }; - 91 | received.a = received; - > 92 | expect(expected).toEqual(received); - | ^ - 93 | }); - 94 | - 95 | test('transitive circular', () => { + 97 | }; + 98 | received.a = received; + > 99 | expect(expected).toEqual(received); + | ^ + 100 | }); + 101 | + 102 | test('transitive circular', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:92:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:99:20) ● transitive circular @@ -488,14 +488,14 @@ exports[`should not ignore in default 1`] = ` }, } - 102 | }; - 103 | received.nested = {b: 2, parent: received}; - > 104 | expect(expected).toEqual(received); + 109 | }; + 110 | received.nested = {b: 2, parent: received}; + > 111 | expect(expected).toEqual(received); | ^ - 105 | }); - 106 | + 112 | }); + 113 | - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:104:20)" + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:111:20)" `; exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` @@ -521,15 +521,15 @@ exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` + \\"b\\": 2, } - 2 | const expected = {a: expect.any(Number), b: 2}; - 3 | const received = {a: 1, b: 1}; - > 4 | expect(expected).toEqual(received); - | ^ - 5 | }); - 6 | - 7 | test('jest asymmetricMatcher', () => { + 9 | const expected = {a: expect.any(Number), b: 2}; + 10 | const received = {a: 1, b: 1}; + > 11 | expect(expected).toEqual(received); + | ^ + 12 | }); + 13 | + 14 | test('jest asymmetricMatcher', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:4:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:11:20) ● jest asymmetricMatcher @@ -563,15 +563,15 @@ exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` + \\"g\\": true, } - 30 | }; - 31 | - > 32 | expect(expected).toEqual(received); + 37 | }; + 38 | + > 39 | expect(expected).toEqual(received); | ^ - 33 | }); - 34 | - 35 | test('custom asymmetricMatcher', () => { + 40 | }); + 41 | + 42 | test('custom asymmetricMatcher', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:32:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:39:20) ● custom asymmetricMatcher @@ -587,15 +587,15 @@ exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` + \\"b\\": false, } - 56 | }; - 57 | - > 58 | expect(expected).toEqual(received); + 63 | }; + 64 | + > 65 | expect(expected).toEqual(received); | ^ - 59 | }); - 60 | - 61 | test('nested object', () => { + 66 | }); + 67 | + 68 | test('nested object', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:58:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:65:20) ● nested object @@ -616,15 +616,15 @@ exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` + \\"c\\": 2, } - 76 | c: 1, - 77 | }; - > 78 | expect(expected).toEqual(received); + 83 | c: 1, + 84 | }; + > 85 | expect(expected).toEqual(received); | ^ - 79 | }); - 80 | - 81 | test('circular', () => { + 86 | }); + 87 | + 88 | test('circular', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:78:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:85:20) ● circular @@ -641,15 +641,15 @@ exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` + \\"c\\": 3, } - 90 | }; - 91 | received.a = received; - > 92 | expect(expected).toEqual(received); - | ^ - 93 | }); - 94 | - 95 | test('transitive circular', () => { + 97 | }; + 98 | received.a = received; + > 99 | expect(expected).toEqual(received); + | ^ + 100 | }); + 101 | + 102 | test('transitive circular', () => { - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:92:20) + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:99:20) ● transitive circular @@ -668,12 +668,12 @@ exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` }, } - 102 | }; - 103 | received.nested = {b: 2, parent: received}; - > 104 | expect(expected).toEqual(received); + 109 | }; + 110 | received.nested = {b: 2, parent: received}; + > 111 | expect(expected).toEqual(received); | ^ - 105 | }); - 106 | + 112 | }); + 113 | - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:104:20)" + at Object.toEqual (__tests__/asymmetrictMatcher.test.js:111:20)" `; From 65bd0ccdab953d47fe65dd737f47f72d3233b84d Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 5 Jan 2020 02:16:26 +0800 Subject: [PATCH 25/44] remove ignoreAsymmetricMatches option --- docs/CLI.md | 4 - docs/Configuration.md | 27 - .../ignoreAsymmetricMatches.test.ts.snap | 679 ------------------ .../__snapshots__/showConfig.test.ts.snap | 1 - e2e/__tests__/ignoreAsymmetricMatches.test.ts | 42 -- .../__tests__/asymmetrictMatcher.test.js | 112 --- e2e/ignore-asymmetric-matches/package.json | 5 - packages/expect/src/matchers.ts | 6 - packages/expect/src/toThrowMatchers.ts | 11 +- packages/expect/src/types.ts | 1 - .../legacy-code-todo-rewrite/jestAdapter.ts | 5 +- .../legacy-code-todo-rewrite/jestExpect.ts | 6 +- packages/jest-circus/src/state.ts | 1 - packages/jest-cli/src/cli/args.ts | 4 - packages/jest-config/src/Defaults.ts | 1 - packages/jest-config/src/ValidConfig.ts | 1 - packages/jest-config/src/index.ts | 1 - packages/jest-config/src/normalize.ts | 1 - packages/jest-jasmine2/src/index.ts | 1 - packages/jest-jasmine2/src/jestExpect.ts | 6 +- .../__tests__/printDiffOrStringify.test.ts | 41 +- packages/jest-matcher-utils/src/index.ts | 42 +- packages/jest-types/src/Circus.ts | 1 - packages/jest-types/src/Config.ts | 4 - .../src/__tests__/fixtures/jestConfig.ts | 2 - 25 files changed, 36 insertions(+), 969 deletions(-) delete mode 100644 e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap delete mode 100644 e2e/__tests__/ignoreAsymmetricMatches.test.ts delete mode 100644 e2e/ignore-asymmetric-matches/__tests__/asymmetrictMatcher.test.js delete mode 100644 e2e/ignore-asymmetric-matches/package.json diff --git a/docs/CLI.md b/docs/CLI.md index 4c1a2bd5a242..de9bee433d67 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -184,10 +184,6 @@ Force Jest to exit after all tests have completed running. This is useful when r Show the help information, similar to this page. -### `--ignoreAsymmetricMatches` - -Ignore asymmetric matches in diffing. - ### `--init` Generate a basic configuration file. Based on your project, Jest will ask you a few questions that will help to generate a `jest.config.js` file with a short description for each option. diff --git a/docs/Configuration.md b/docs/Configuration.md index 7e4a0a762bfc..709686c84c38 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -428,33 +428,6 @@ _Note: A global teardown module configured in a project (using multi-project run _Note: The same caveat concerning transformation of `node_modules` as for `globalSetup` applies to `globalTeardown`._ -### `ignoreAsymmetricMatches` [boolean] - -Default: `false` - -If setting this option true, it will not highlight asymmetric matches - -ignoreAsymmetricMatches = `true` - -```diff - Object { - a: expect.any(Number), -- b: 2, -+ b: 1, - } -``` - -ignoreAsymmetricMatches = `false` - -```diff - Object { -- a: expect.any(Number), -- b: 2, -+ a: 1, -+ b: 1, - } -``` - ### `maxConcurrency` [number] Default: `5` diff --git a/e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap b/e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap deleted file mode 100644 index 92a67abda398..000000000000 --- a/e2e/__tests__/__snapshots__/ignoreAsymmetricMatches.test.ts.snap +++ /dev/null @@ -1,679 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should ignore with --ignoreAsymmetricMatches cli option 1`] = ` -"FAIL __tests__/asymmetrictMatcher.test.js - ✕ minimal test - ✕ jest asymmetricMatcher - ✕ custom asymmetricMatcher - ✕ nested object - ✕ circular - ✕ transitive circular - - ● minimal test - - expect(received).toEqual(expected) // deep equality - - - Expected - 1 - + Received + 1 - - Object { - \\"a\\": Any, - - \\"b\\": 1, - + \\"b\\": 2, - } - - 9 | const expected = {a: expect.any(Number), b: 2}; - 10 | const received = {a: 1, b: 1}; - > 11 | expect(expected).toEqual(received); - | ^ - 12 | }); - 13 | - 14 | test('jest asymmetricMatcher', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:11:20) - - ● jest asymmetricMatcher - - expect(received).toEqual(expected) // deep equality - - - Expected - 1 - + Received + 1 - - @@ -8,7 +8,7 @@ - \\"d\\": StringContaining \\"jest\\", - \\"e\\": StringMatching /^jest/, - \\"f\\": ObjectContaining { - \\"a\\": Any, - }, - - \\"g\\": false, - + \\"g\\": true, - } - - 37 | }; - 38 | - > 39 | expect(expected).toEqual(received); - | ^ - 40 | }); - 41 | - 42 | test('custom asymmetricMatcher', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:39:20) - - ● custom asymmetricMatcher - - expect(received).toEqual(expected) // deep equality - - - Expected - 1 - + Received + 1 - - Object { - \\"a\\": equal5<>, - - \\"b\\": true, - + \\"b\\": false, - } - - 63 | }; - 64 | - > 65 | expect(expected).toEqual(received); - | ^ - 66 | }); - 67 | - 68 | test('nested object', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:65:20) - - ● nested object - - expect(received).toEqual(expected) // deep equality - - - Expected - 1 - + Received + 1 - - @@ -2,7 +2,7 @@ - \\"a\\": Any, - \\"b\\": Object { - \\"a\\": 1, - \\"b\\": Any, - }, - - \\"c\\": 1, - + \\"c\\": 2, - } - - 83 | c: 1, - 84 | }; - > 85 | expect(expected).toEqual(received); - | ^ - 86 | }); - 87 | - 88 | test('circular', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:85:20) - - ● circular - - expect(received).toEqual(expected) // deep equality - - - Expected - 1 - + Received + 1 - - Object { - \\"a\\": [Circular], - \\"b\\": Any, - - \\"c\\": 2, - + \\"c\\": 3, - } - - 97 | }; - 98 | received.a = received; - > 99 | expect(expected).toEqual(received); - | ^ - 100 | }); - 101 | - 102 | test('transitive circular', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:99:20) - - ● transitive circular - - expect(received).toEqual(expected) // deep equality - - - Expected - 1 - + Received + 1 - - Object { - - \\"a\\": 2, - + \\"a\\": 3, - \\"nested\\": Object { - \\"b\\": Any, - \\"parent\\": [Circular], - }, - } - - 109 | }; - 110 | received.nested = {b: 2, parent: received}; - > 111 | expect(expected).toEqual(received); - | ^ - 112 | }); - 113 | - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:111:20)" -`; - -exports[`should ignore with ignoreAsymmetricMatches=true in config 1`] = ` -"FAIL __tests__/asymmetrictMatcher.test.js - ✕ minimal test - ✕ jest asymmetricMatcher - ✕ custom asymmetricMatcher - ✕ nested object - ✕ circular - ✕ transitive circular - - ● minimal test - - expect(received).toEqual(expected) // deep equality - - - Expected - 1 - + Received + 1 - - Object { - \\"a\\": Any, - - \\"b\\": 1, - + \\"b\\": 2, - } - - 9 | const expected = {a: expect.any(Number), b: 2}; - 10 | const received = {a: 1, b: 1}; - > 11 | expect(expected).toEqual(received); - | ^ - 12 | }); - 13 | - 14 | test('jest asymmetricMatcher', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:11:20) - - ● jest asymmetricMatcher - - expect(received).toEqual(expected) // deep equality - - - Expected - 1 - + Received + 1 - - @@ -8,7 +8,7 @@ - \\"d\\": StringContaining \\"jest\\", - \\"e\\": StringMatching /^jest/, - \\"f\\": ObjectContaining { - \\"a\\": Any, - }, - - \\"g\\": false, - + \\"g\\": true, - } - - 37 | }; - 38 | - > 39 | expect(expected).toEqual(received); - | ^ - 40 | }); - 41 | - 42 | test('custom asymmetricMatcher', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:39:20) - - ● custom asymmetricMatcher - - expect(received).toEqual(expected) // deep equality - - - Expected - 1 - + Received + 1 - - Object { - \\"a\\": equal5<>, - - \\"b\\": true, - + \\"b\\": false, - } - - 63 | }; - 64 | - > 65 | expect(expected).toEqual(received); - | ^ - 66 | }); - 67 | - 68 | test('nested object', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:65:20) - - ● nested object - - expect(received).toEqual(expected) // deep equality - - - Expected - 1 - + Received + 1 - - @@ -2,7 +2,7 @@ - \\"a\\": Any, - \\"b\\": Object { - \\"a\\": 1, - \\"b\\": Any, - }, - - \\"c\\": 1, - + \\"c\\": 2, - } - - 83 | c: 1, - 84 | }; - > 85 | expect(expected).toEqual(received); - | ^ - 86 | }); - 87 | - 88 | test('circular', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:85:20) - - ● circular - - expect(received).toEqual(expected) // deep equality - - - Expected - 1 - + Received + 1 - - Object { - \\"a\\": [Circular], - \\"b\\": Any, - - \\"c\\": 2, - + \\"c\\": 3, - } - - 97 | }; - 98 | received.a = received; - > 99 | expect(expected).toEqual(received); - | ^ - 100 | }); - 101 | - 102 | test('transitive circular', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:99:20) - - ● transitive circular - - expect(received).toEqual(expected) // deep equality - - - Expected - 1 - + Received + 1 - - Object { - - \\"a\\": 2, - + \\"a\\": 3, - \\"nested\\": Object { - \\"b\\": Any, - \\"parent\\": [Circular], - }, - } - - 109 | }; - 110 | received.nested = {b: 2, parent: received}; - > 111 | expect(expected).toEqual(received); - | ^ - 112 | }); - 113 | - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:111:20)" -`; - -exports[`should not ignore in default 1`] = ` -"FAIL __tests__/asymmetrictMatcher.test.js - ✕ minimal test - ✕ jest asymmetricMatcher - ✕ custom asymmetricMatcher - ✕ nested object - ✕ circular - ✕ transitive circular - - ● minimal test - - expect(received).toEqual(expected) // deep equality - - - Expected - 2 - + Received + 2 - - Object { - - \\"a\\": 1, - - \\"b\\": 1, - + \\"a\\": Any, - + \\"b\\": 2, - } - - 9 | const expected = {a: expect.any(Number), b: 2}; - 10 | const received = {a: 1, b: 1}; - > 11 | expect(expected).toEqual(received); - | ^ - 12 | }); - 13 | - 14 | test('jest asymmetricMatcher', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:11:20) - - ● jest asymmetricMatcher - - expect(received).toEqual(expected) // deep equality - - - Expected - 9 - + Received + 9 - - Object { - - \\"a\\": 1, - - \\"b\\": \\"anything\\", - - \\"c\\": Array [ - + \\"a\\": Any, - + \\"b\\": Anything, - + \\"c\\": ArrayContaining [ - 1, - - 2, - 3, - ], - - \\"d\\": StringContaining \\"jest\\", - - \\"e\\": StringMatching /^jest/, - - \\"f\\": ObjectContaining { - - \\"a\\": Any, - + \\"d\\": \\"jest is awesome\\", - + \\"e\\": \\"jest is awesome\\", - + \\"f\\": Object { - + \\"a\\": 1970-01-01T00:00:00.000Z, - + \\"b\\": \\"jest is awesome\\", - }, - - \\"g\\": false, - + \\"g\\": true, - } - - 37 | }; - 38 | - > 39 | expect(expected).toEqual(received); - | ^ - 40 | }); - 41 | - 42 | test('custom asymmetricMatcher', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:39:20) - - ● custom asymmetricMatcher - - expect(received).toEqual(expected) // deep equality - - - Expected - 2 - + Received + 2 - - Object { - - \\"a\\": 5, - - \\"b\\": true, - + \\"a\\": equal5<>, - + \\"b\\": false, - } - - 63 | }; - 64 | - > 65 | expect(expected).toEqual(received); - | ^ - 66 | }); - 67 | - 68 | test('nested object', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:65:20) - - ● nested object - - expect(received).toEqual(expected) // deep equality - - - Expected - 3 - + Received + 3 - - Object { - - \\"a\\": Any, - + \\"a\\": 1, - \\"b\\": Object { - \\"a\\": 1, - - \\"b\\": 2, - + \\"b\\": Any, - }, - - \\"c\\": 1, - + \\"c\\": 2, - } - - 83 | c: 1, - 84 | }; - > 85 | expect(expected).toEqual(received); - | ^ - 86 | }); - 87 | - 88 | test('circular', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:85:20) - - ● circular - - expect(received).toEqual(expected) // deep equality - - - Expected - 2 - + Received + 2 - - Object { - \\"a\\": [Circular], - - \\"b\\": 2, - - \\"c\\": 2, - + \\"b\\": Any, - + \\"c\\": 3, - } - - 97 | }; - 98 | received.a = received; - > 99 | expect(expected).toEqual(received); - | ^ - 100 | }); - 101 | - 102 | test('transitive circular', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:99:20) - - ● transitive circular - - expect(received).toEqual(expected) // deep equality - - - Expected - 2 - + Received + 2 - - Object { - - \\"a\\": 2, - + \\"a\\": 3, - \\"nested\\": Object { - - \\"b\\": 2, - + \\"b\\": Any, - \\"parent\\": [Circular], - }, - } - - 109 | }; - 110 | received.nested = {b: 2, parent: received}; - > 111 | expect(expected).toEqual(received); - | ^ - 112 | }); - 113 | - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:111:20)" -`; - -exports[`should not ignore with ignoreAsymmetricMatches=false in config 1`] = ` -"FAIL __tests__/asymmetrictMatcher.test.js - ✕ minimal test - ✕ jest asymmetricMatcher - ✕ custom asymmetricMatcher - ✕ nested object - ✕ circular - ✕ transitive circular - - ● minimal test - - expect(received).toEqual(expected) // deep equality - - - Expected - 2 - + Received + 2 - - Object { - - \\"a\\": 1, - - \\"b\\": 1, - + \\"a\\": Any, - + \\"b\\": 2, - } - - 9 | const expected = {a: expect.any(Number), b: 2}; - 10 | const received = {a: 1, b: 1}; - > 11 | expect(expected).toEqual(received); - | ^ - 12 | }); - 13 | - 14 | test('jest asymmetricMatcher', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:11:20) - - ● jest asymmetricMatcher - - expect(received).toEqual(expected) // deep equality - - - Expected - 9 - + Received + 9 - - Object { - - \\"a\\": 1, - - \\"b\\": \\"anything\\", - - \\"c\\": Array [ - + \\"a\\": Any, - + \\"b\\": Anything, - + \\"c\\": ArrayContaining [ - 1, - - 2, - 3, - ], - - \\"d\\": StringContaining \\"jest\\", - - \\"e\\": StringMatching /^jest/, - - \\"f\\": ObjectContaining { - - \\"a\\": Any, - + \\"d\\": \\"jest is awesome\\", - + \\"e\\": \\"jest is awesome\\", - + \\"f\\": Object { - + \\"a\\": 1970-01-01T00:00:00.000Z, - + \\"b\\": \\"jest is awesome\\", - }, - - \\"g\\": false, - + \\"g\\": true, - } - - 37 | }; - 38 | - > 39 | expect(expected).toEqual(received); - | ^ - 40 | }); - 41 | - 42 | test('custom asymmetricMatcher', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:39:20) - - ● custom asymmetricMatcher - - expect(received).toEqual(expected) // deep equality - - - Expected - 2 - + Received + 2 - - Object { - - \\"a\\": 5, - - \\"b\\": true, - + \\"a\\": equal5<>, - + \\"b\\": false, - } - - 63 | }; - 64 | - > 65 | expect(expected).toEqual(received); - | ^ - 66 | }); - 67 | - 68 | test('nested object', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:65:20) - - ● nested object - - expect(received).toEqual(expected) // deep equality - - - Expected - 3 - + Received + 3 - - Object { - - \\"a\\": Any, - + \\"a\\": 1, - \\"b\\": Object { - \\"a\\": 1, - - \\"b\\": 2, - + \\"b\\": Any, - }, - - \\"c\\": 1, - + \\"c\\": 2, - } - - 83 | c: 1, - 84 | }; - > 85 | expect(expected).toEqual(received); - | ^ - 86 | }); - 87 | - 88 | test('circular', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:85:20) - - ● circular - - expect(received).toEqual(expected) // deep equality - - - Expected - 2 - + Received + 2 - - Object { - \\"a\\": [Circular], - - \\"b\\": 2, - - \\"c\\": 2, - + \\"b\\": Any, - + \\"c\\": 3, - } - - 97 | }; - 98 | received.a = received; - > 99 | expect(expected).toEqual(received); - | ^ - 100 | }); - 101 | - 102 | test('transitive circular', () => { - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:99:20) - - ● transitive circular - - expect(received).toEqual(expected) // deep equality - - - Expected - 2 - + Received + 2 - - Object { - - \\"a\\": 2, - + \\"a\\": 3, - \\"nested\\": Object { - - \\"b\\": 2, - + \\"b\\": Any, - \\"parent\\": [Circular], - }, - } - - 109 | }; - 110 | received.nested = {b: 2, parent: received}; - > 111 | expect(expected).toEqual(received); - | ^ - 112 | }); - 113 | - - at Object.toEqual (__tests__/asymmetrictMatcher.test.js:111:20)" -`; diff --git a/e2e/__tests__/__snapshots__/showConfig.test.ts.snap b/e2e/__tests__/__snapshots__/showConfig.test.ts.snap index 82f7bfb6e254..e7bd2b9c3273 100644 --- a/e2e/__tests__/__snapshots__/showConfig.test.ts.snap +++ b/e2e/__tests__/__snapshots__/showConfig.test.ts.snap @@ -96,7 +96,6 @@ exports[`--showConfig outputs config info and exits 1`] = ` "expand": false, "findRelatedTests": false, "forceExit": false, - "ignoreAsymmetricMatches": false, "json": false, "lastCommit": false, "listTests": false, diff --git a/e2e/__tests__/ignoreAsymmetricMatches.test.ts b/e2e/__tests__/ignoreAsymmetricMatches.test.ts deleted file mode 100644 index fc16c0e6f547..000000000000 --- a/e2e/__tests__/ignoreAsymmetricMatches.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import * as path from 'path'; -import runJest from '../runJest'; -import {extractSummary} from '../Utils'; - -const dir = path.resolve(__dirname, '../ignore-asymmetric-matches'); - -test('should not ignore in default', () => { - const {stderr} = runJest(dir); - const {rest} = extractSummary(stderr); - expect(rest).toMatchSnapshot(); -}); - -test('should ignore with --ignoreAsymmetricMatches cli option', () => { - const {stderr} = runJest(dir, ['--ignoreAsymmetricMatches']); - const {rest} = extractSummary(stderr); - expect(rest).toMatchSnapshot(); -}); - -test('should ignore with ignoreAsymmetricMatches=true in config', () => { - const {stderr} = runJest(dir, [ - '--config', - JSON.stringify({ignoreAsymmetricMatches: true}), - ]); - const {rest} = extractSummary(stderr); - expect(rest).toMatchSnapshot(); -}); - -test('should not ignore with ignoreAsymmetricMatches=false in config', () => { - const {stderr} = runJest(dir, [ - '--config', - JSON.stringify({ignoreAsymmetricMatches: false}), - ]); - const {rest} = extractSummary(stderr); - expect(rest).toMatchSnapshot(); -}); diff --git a/e2e/ignore-asymmetric-matches/__tests__/asymmetrictMatcher.test.js b/e2e/ignore-asymmetric-matches/__tests__/asymmetrictMatcher.test.js deleted file mode 100644 index 7f0a912137f2..000000000000 --- a/e2e/ignore-asymmetric-matches/__tests__/asymmetrictMatcher.test.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -test('minimal test', () => { - const expected = {a: expect.any(Number), b: 2}; - const received = {a: 1, b: 1}; - expect(expected).toEqual(received); -}); - -test('jest asymmetricMatcher', () => { - const expected = { - a: expect.any(Number), - b: expect.anything(), - c: expect.arrayContaining([1, 3]), - d: 'jest is awesome', - e: 'jest is awesome', - f: { - a: new Date(0), - b: 'jest is awesome', - }, - g: true, - }; - const received = { - a: 1, - b: 'anything', - c: [1, 2, 3], - d: expect.stringContaining('jest'), - e: expect.stringMatching(/^jest/), - f: expect.objectContaining({ - a: expect.any(Date), - }), - g: false, - }; - - expect(expected).toEqual(received); -}); - -test('custom asymmetricMatcher', () => { - expect.extend({ - equal5(received) { - if (received === 5) - return { - message: () => `expected ${received} not to be 5`, - pass: true, - }; - return { - message: () => `expected ${received} to be 5`, - pass: false, - }; - }, - }); - const expected = { - a: expect.equal5(), - b: false, - }; - const received = { - a: 5, - b: true, - }; - - expect(expected).toEqual(received); -}); - -test('nested object', () => { - const expected = { - a: 1, - b: { - a: 1, - b: expect.any(Number), - }, - c: 2, - }; - const received = { - a: expect.any(Number), - b: { - a: 1, - b: 2, - }, - c: 1, - }; - expect(expected).toEqual(received); -}); - -test('circular', () => { - const expected = { - b: expect.any(Number), - c: 3, - }; - expected.a = expected; - const received = { - b: 2, - c: 2, - }; - received.a = received; - expect(expected).toEqual(received); -}); - -test('transitive circular', () => { - const expected = { - a: 3, - }; - expected.nested = {b: expect.any(Number), parent: expected}; - const received = { - a: 2, - }; - received.nested = {b: 2, parent: received}; - expect(expected).toEqual(received); -}); diff --git a/e2e/ignore-asymmetric-matches/package.json b/e2e/ignore-asymmetric-matches/package.json deleted file mode 100644 index a39800c4abd6..000000000000 --- a/e2e/ignore-asymmetric-matches/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "jest": { - "testEnvironment": "node" - } -} \ No newline at end of file diff --git a/packages/expect/src/matchers.ts b/packages/expect/src/matchers.ts index 945ddb2c7f4f..ca51e52291ba 100644 --- a/packages/expect/src/matchers.ts +++ b/packages/expect/src/matchers.ts @@ -54,7 +54,6 @@ const RECEIVED_VALUE_LABEL = 'Received value'; // The optional property of matcher context is true if undefined. const isExpand = (expand?: boolean): boolean => expand !== false; -const ignoreAsymmetricMatches = (ignore?: boolean): boolean => ignore === true; const toStrictEqualTesters = [ iterableEquality, @@ -113,7 +112,6 @@ const matchers: MatchersObject = { EXPECTED_LABEL, RECEIVED_LABEL, isExpand(this.expand), - ignoreAsymmetricMatches(this.ignoreAsymmetricMatches), ) ); }; @@ -614,7 +612,6 @@ const matchers: MatchersObject = { EXPECTED_LABEL, RECEIVED_LABEL, isExpand(this.expand), - ignoreAsymmetricMatches(this.ignoreAsymmetricMatches), ); // Passing the actual and expected objects so that a custom reporter @@ -789,7 +786,6 @@ const matchers: MatchersObject = { EXPECTED_VALUE_LABEL, RECEIVED_VALUE_LABEL, isExpand(this.expand), - ignoreAsymmetricMatches(this.ignoreAsymmetricMatches), ) : `Received path: ${printReceived( expectedPathType === 'array' || receivedPath.length === 0 @@ -925,7 +921,6 @@ const matchers: MatchersObject = { EXPECTED_LABEL, RECEIVED_LABEL, isExpand(this.expand), - ignoreAsymmetricMatches(this.ignoreAsymmetricMatches), ); return {message, pass}; @@ -958,7 +953,6 @@ const matchers: MatchersObject = { EXPECTED_LABEL, RECEIVED_LABEL, isExpand(this.expand), - ignoreAsymmetricMatches(this.ignoreAsymmetricMatches), ); // Passing the actual and expected objects so that a custom reporter diff --git a/packages/expect/src/toThrowMatchers.ts b/packages/expect/src/toThrowMatchers.ts index 0140eaf96d11..0262f533df43 100644 --- a/packages/expect/src/toThrowMatchers.ts +++ b/packages/expect/src/toThrowMatchers.ts @@ -35,7 +35,6 @@ import { import {isError} from './utils'; const DID_NOT_THROW = 'Received function did not throw'; -const ignoreAsymmetricMatches = (ignore?: boolean): boolean => ignore === true; type Thrown = | { @@ -121,13 +120,7 @@ export const createMatcher = ( ) { return toThrowExpectedAsymmetric(matcherName, options, thrown, expected); } else if (expected !== null && typeof expected === 'object') { - return toThrowExpectedObject( - matcherName, - options, - thrown, - expected, - ignoreAsymmetricMatches(this.ignoreAsymmetricMatches), - ); + return toThrowExpectedObject(matcherName, options, thrown, expected); } else { throw new Error( matcherErrorMessage( @@ -225,7 +218,6 @@ const toThrowExpectedObject = ( options: MatcherHintOptions, thrown: Thrown | null, expected: any, - ignoreAsymmetricMatches: boolean, ): SyncExpectationResult => { const pass = thrown !== null && thrown.message === expected.message; @@ -251,7 +243,6 @@ const toThrowExpectedObject = ( 'Expected message', 'Received message', true, - ignoreAsymmetricMatches, ) + '\n' + formatStack(thrown) diff --git a/packages/expect/src/types.ts b/packages/expect/src/types.ts index ee3800f05a2a..529d12014df4 100644 --- a/packages/expect/src/types.ts +++ b/packages/expect/src/types.ts @@ -40,7 +40,6 @@ export type MatcherState = { strictCheck?: boolean, ) => boolean; expand?: boolean; - ignoreAsymmetricMatches?: boolean; expectedAssertionsNumber?: number; isExpectingAssertions?: boolean; isNot: boolean; diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts index 0fd4cb272c0d..5ac79df66568 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -28,10 +28,7 @@ const jestAdapter = async ( runtime .requireInternalModule(path.resolve(__dirname, './jestExpect.js')) - .default({ - expand: globalConfig.expand, - ignoreAsymmetricMatches: globalConfig.ignoreAsymmetricMatches, - }); + .default({expand: globalConfig.expand}); const getPrettier = () => config.prettierPath ? require(config.prettierPath) : null; diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts index ef770af02e5f..fa5436dbaf94 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts @@ -15,14 +15,10 @@ import { toThrowErrorMatchingSnapshot, } from 'jest-snapshot'; -export default (config: { - expand: boolean; - ignoreAsymmetricMatches: boolean; -}) => { +export default (config: {expand: boolean}) => { global.expect = expect; expect.setState({ expand: config.expand, - ignoreAsymmetricMatches: config.ignoreAsymmetricMatches, }); expect.extend({ toMatchInlineSnapshot, diff --git a/packages/jest-circus/src/state.ts b/packages/jest-circus/src/state.ts index 3afde01426d9..d42928e90bfa 100644 --- a/packages/jest-circus/src/state.ts +++ b/packages/jest-circus/src/state.ts @@ -25,7 +25,6 @@ const INITIAL_STATE: Circus.State = { currentlyRunningTest: null, expand: undefined, hasFocusedTests: false, // whether .only has been used on any test/describe - ignoreAsymmetricMatches: false, includeTestLocationInResult: false, parentProcess: null, rootDescribeBlock: ROOT_DESCRIBE_BLOCK, diff --git a/packages/jest-cli/src/cli/args.ts b/packages/jest-cli/src/cli/args.ts index 696c01c2ead4..6bc9650b7a01 100644 --- a/packages/jest-cli/src/cli/args.ts +++ b/packages/jest-cli/src/cli/args.ts @@ -297,10 +297,6 @@ export const options = { 'A JSON string with map of variables for the haste module system', type: 'string', }, - ignoreAsymmetricMatches: { - description: 'Ignore asymmetric matches in diffing', - type: 'boolean', - }, init: { description: 'Generate a basic configuration file', type: 'boolean', diff --git a/packages/jest-config/src/Defaults.ts b/packages/jest-config/src/Defaults.ts index 432c8a1f27c1..e096029b7795 100644 --- a/packages/jest-config/src/Defaults.ts +++ b/packages/jest-config/src/Defaults.ts @@ -32,7 +32,6 @@ const defaultOptions: Config.DefaultOptions = { providesModuleNodeModules: [], throwOnModuleCollision: false, }, - ignoreAsymmetricMatches: false, maxConcurrency: 5, maxWorkers: '50%', moduleDirectories: ['node_modules'], diff --git a/packages/jest-config/src/ValidConfig.ts b/packages/jest-config/src/ValidConfig.ts index 2f65bbe4c2ea..28178876d529 100644 --- a/packages/jest-config/src/ValidConfig.ts +++ b/packages/jest-config/src/ValidConfig.ts @@ -59,7 +59,6 @@ const initialOptions: Config.InitialOptions = { providesModuleNodeModules: ['react', 'react-native'], throwOnModuleCollision: false, }, - ignoreAsymmetricMatches: false, json: false, lastCommit: false, logHeapUsage: true, diff --git a/packages/jest-config/src/index.ts b/packages/jest-config/src/index.ts index 1a48df6d5f2b..eb392317c02b 100644 --- a/packages/jest-config/src/index.ts +++ b/packages/jest-config/src/index.ts @@ -122,7 +122,6 @@ const groupOptions = ( forceExit: options.forceExit, globalSetup: options.globalSetup, globalTeardown: options.globalTeardown, - ignoreAsymmetricMatches: options.ignoreAsymmetricMatches, json: options.json, lastCommit: options.lastCommit, listTests: options.listTests, diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index 494189268024..96111241f9d3 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -847,7 +847,6 @@ export default function normalize( case 'findRelatedTests': case 'forceCoverageMatch': case 'forceExit': - case 'ignoreAsymmetricMatches': case 'lastCommit': case 'listTests': case 'logHeapUsage': diff --git a/packages/jest-jasmine2/src/index.ts b/packages/jest-jasmine2/src/index.ts index c93ae8ea6ff2..53598542b031 100644 --- a/packages/jest-jasmine2/src/index.ts +++ b/packages/jest-jasmine2/src/index.ts @@ -123,7 +123,6 @@ async function jasmine2( .requireInternalModule(path.resolve(__dirname, './jestExpect.js')) .default({ expand: globalConfig.expand, - ignoreAsymmetricMatches: globalConfig.ignoreAsymmetricMatches, }); if (globalConfig.errorOnDeprecated) { diff --git a/packages/jest-jasmine2/src/jestExpect.ts b/packages/jest-jasmine2/src/jestExpect.ts index 18460d829cf4..3389c9ae1ca7 100644 --- a/packages/jest-jasmine2/src/jestExpect.ts +++ b/packages/jest-jasmine2/src/jestExpect.ts @@ -26,14 +26,10 @@ type JasmineMatcher = { type JasmineMatchersObject = {[id: string]: JasmineMatcher}; -export default (config: { - expand: boolean; - ignoreAsymmetricMatches: boolean; -}) => { +export default (config: {expand: boolean}) => { global.expect = expect; expect.setState({ expand: config.expand, - ignoreAsymmetricMatches: config.ignoreAsymmetricMatches, }); expect.extend({ toMatchInlineSnapshot, diff --git a/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts b/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts index 59032d9ecf06..8210f28fafe4 100644 --- a/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts +++ b/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts @@ -12,24 +12,7 @@ expect.addSnapshotSerializer(alignedAnsiStyleSerializer); describe('printDiffOrStringify', () => { const testDiffOrStringify = (expected: any, received: any): string => - printDiffOrStringify( - expected, - received, - 'Expected', - 'Received', - true, - true, - ); - - const testDiffOrStringifyNotIgnore = (expected: any, received: any): string => - printDiffOrStringify( - expected, - received, - 'Expected', - 'Received', - true, - false, - ); + printDiffOrStringify(expected, received, 'Expected', 'Received', true); test('expected is empty and received is single line', () => { const expected = ''; @@ -185,6 +168,20 @@ describe('printDiffOrStringify', () => { expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); }); + test('array', () => { + const expected: Array = [1, expect.any(Number), 3]; + const received: Array = [1, 2, 3]; + console.log(testDiffOrStringify(expected, received)); + expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); + }); + + test('object in array', () => { + const expected: Array = [1, {a: 1, b: expect.any(Number)}, 3]; + const received: Array = [1, {a: 1, b: 2}, 3]; + console.log(testDiffOrStringify(expected, received)); + expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); + }); + test('circular', () => { const expected: any = { b: expect.any(Number), @@ -210,13 +207,5 @@ describe('printDiffOrStringify', () => { received.nested = {b: 2, parent: received}; expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); }); - - test('should not ignore asymmetric match', () => { - const expected = {a: expect.any(Number), b: 2}; - const received = {a: 1, b: 1}; - expect( - testDiffOrStringifyNotIgnore(expected, received), - ).toMatchSnapshot(); - }); }); }); diff --git a/packages/jest-matcher-utils/src/index.ts b/packages/jest-matcher-utils/src/index.ts index a47348158b28..a940a0aecdf4 100644 --- a/packages/jest-matcher-utils/src/index.ts +++ b/packages/jest-matcher-utils/src/index.ts @@ -311,7 +311,6 @@ export const printDiffOrStringify = ( expectedLabel: string, receivedLabel: string, expand: boolean, // CLI options: true if `--expand` or false if `--no-expand` - ignoreAsymmetricMatches: boolean, ): string => { if ( typeof expected === 'string' && @@ -354,30 +353,21 @@ export const printDiffOrStringify = ( if (isLineDiffable(expected, received)) { let difference; - if (ignoreAsymmetricMatches) { - const { - replacedExpected, - replacedReceived, - } = replaceMatchedToAsymmetricMatcher( - deepCyclicCopy(expected, {keepPrototype: true}), - deepCyclicCopy(received, {keepPrototype: true}), - [], - [], - ); - difference = diffDefault(replacedExpected, replacedReceived, { - aAnnotation: expectedLabel, - bAnnotation: receivedLabel, - expand, - includeChangeCounts: true, - }); - } else { - difference = diffDefault(expected, received, { - aAnnotation: expectedLabel, - bAnnotation: receivedLabel, - expand, - includeChangeCounts: true, - }); - } + const { + replacedExpected, + replacedReceived, + } = replaceMatchedToAsymmetricMatcher( + deepCyclicCopy(expected, {keepPrototype: true}), + deepCyclicCopy(received, {keepPrototype: true}), + [], + [], + ); + difference = diffDefault(replacedExpected, replacedReceived, { + aAnnotation: expectedLabel, + bAnnotation: receivedLabel, + expand, + includeChangeCounts: true, + }); if ( typeof difference === 'string' && @@ -436,6 +426,8 @@ function replaceMatchedToAsymmetricMatcher( expectedCycles.push(replacedExpected); receivedCycles.push(replacedReceived); + console.log(replacedExpected, replacedReceived); + Object.entries(replacedExpected).forEach( ([key, expectedAttribute]: [string, any]) => { const receivedAttribute = replacedReceived[key]; diff --git a/packages/jest-types/src/Circus.ts b/packages/jest-types/src/Circus.ts index 876ce5dc81e1..6ae1bddd4baa 100644 --- a/packages/jest-types/src/Circus.ts +++ b/packages/jest-types/src/Circus.ts @@ -183,7 +183,6 @@ export type State = { // Store process error handlers. During the run we inject our own // handlers (so we could fail tests on unhandled errors) and later restore // the original ones. - ignoreAsymmetricMatches: boolean; originalGlobalErrorHandlers?: GlobalErrorHandlers; parentProcess: Process | null; // process object from the outer scope rootDescribeBlock: DescribeBlock; diff --git a/packages/jest-types/src/Config.ts b/packages/jest-types/src/Config.ts index 6e572326373b..aca89876a7c1 100644 --- a/packages/jest-types/src/Config.ts +++ b/packages/jest-types/src/Config.ts @@ -43,7 +43,6 @@ export type DefaultOptions = { forceCoverageMatch: Array; globals: ConfigGlobals; haste: HasteConfig; - ignoreAsymmetricMatches: boolean; maxConcurrency: number; maxWorkers: number | string; moduleDirectories: Array; @@ -129,7 +128,6 @@ export type InitialOptions = Partial<{ globalSetup: string | null | undefined; globalTeardown: string | null | undefined; haste: HasteConfig; - ignoreAsymmetricMatches: boolean; reporters: Array; logHeapUsage: boolean; lastCommit: boolean; @@ -254,7 +252,6 @@ export type GlobalConfig = { json: boolean; globalSetup?: string; globalTeardown?: string; - ignoreAsymmetricMatches: boolean; lastCommit: boolean; logHeapUsage: boolean; listTests: boolean; @@ -384,7 +381,6 @@ export type Argv = Arguments< globalSetup: string | null | undefined; globalTeardown: string | null | undefined; haste: string; - ignoreAsymmetricMatches: boolean; init: boolean; json: boolean; lastCommit: boolean; diff --git a/packages/jest-validate/src/__tests__/fixtures/jestConfig.ts b/packages/jest-validate/src/__tests__/fixtures/jestConfig.ts index d8908fa35029..3e841c5bbf36 100644 --- a/packages/jest-validate/src/__tests__/fixtures/jestConfig.ts +++ b/packages/jest-validate/src/__tests__/fixtures/jestConfig.ts @@ -32,7 +32,6 @@ const defaultConfig = { haste: { providesModuleNodeModules: [], }, - ignoreAsymmetricMatches: false, moduleDirectories: ['node_modules'], moduleFileExtensions: ['js', 'json', 'jsx', 'node'], moduleNameMapper: {}, @@ -86,7 +85,6 @@ const validConfig = { haste: { providesModuleNodeModules: ['react', 'react-native'], }, - ignoreAsymmetricMatches: false, logHeapUsage: true, moduleDirectories: ['node_modules'], moduleFileExtensions: ['js', 'json', 'jsx', 'node'], From 61f2c9f62cf1f4da40433d5258e1063dea76f196 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 5 Jan 2020 15:18:23 +0800 Subject: [PATCH 26/44] support copy built-in objects --- .../src/__tests__/deepCyclicCopy.test.ts | 62 ++++++++++++ packages/jest-util/src/deepCyclicCopy.ts | 94 +++++++++++++++++-- 2 files changed, 148 insertions(+), 8 deletions(-) diff --git a/packages/jest-util/src/__tests__/deepCyclicCopy.test.ts b/packages/jest-util/src/__tests__/deepCyclicCopy.test.ts index 4011777bec1e..b690a6e673be 100644 --- a/packages/jest-util/src/__tests__/deepCyclicCopy.test.ts +++ b/packages/jest-util/src/__tests__/deepCyclicCopy.test.ts @@ -240,3 +240,65 @@ it('RegExp should work correctly after copied', () => { const regExp = deepCyclicCopy(/jest/i, {keepPrototype: true}); expect(regExp.test('JEST is awesome')).toBe(true); }); + +it('Copy Map', () => { + const map = new Map([ + ['a', 1], + ['b', 2], + ]); + const copy = deepCyclicCopy(map); + expect(copy).toEqual(map); + expect(copy.constructor).toBe(Map); +}); + +it('Copy Map with backlist', () => { + const map = new Map([ + ['a', 1], + ['b', 2], + ]); + const copy = deepCyclicCopy(map, {blacklist: new Set(['b'])}); + expect(copy).toEqual(new Map([['a', 1]])); +}); + +it('Copy cyclic Map', () => { + const map: Map = new Map([ + ['a', 1], + ['b', 2], + ]); + map.set('map', map); + expect(deepCyclicCopy(map)).toEqual(map); +}); + +it('Copy Set', () => { + const set = new Set([1, 2, 3]); + const copy = deepCyclicCopy(set); + expect(copy).toEqual(set); + expect(set.constructor).toBe(Set); +}); + +it('Copy cyclic Set', () => { + const set: Set = new Set([1, 2, 3]); + set.add(set); + expect(deepCyclicCopy(set)).toEqual(set); +}); + +it('Copy Buffer', () => { + const buffer = Buffer.from('hello'); + const copy = deepCyclicCopy(buffer); + expect(copy).toEqual(buffer); + expect(copy.constructor).toBe(Buffer); +}); + +it('Copy Date', () => { + const date = new Date(0); + const copy = deepCyclicCopy(date); + expect(copy).toEqual(date); + expect(copy.constructor).toBe(Date); +}); + +it('Copy number array', () => { + const uInt8Array = new Uint8Array([0, 1, 2, 3]); + const copy = deepCyclicCopy(uInt8Array); + expect(copy).toEqual(uInt8Array); + expect(copy.constructor).toBe(Uint8Array); +}); diff --git a/packages/jest-util/src/deepCyclicCopy.ts b/packages/jest-util/src/deepCyclicCopy.ts index 4f86da299c5b..8eae93bb6d7f 100644 --- a/packages/jest-util/src/deepCyclicCopy.ts +++ b/packages/jest-util/src/deepCyclicCopy.ts @@ -7,6 +7,11 @@ const EMPTY = new Set(); +const isDate = (value: any): value is Date => value.constructor === Date; +const isMap = (value: any): value is Map => value.constructor === Map; +const isSet = (value: any): value is Set => value.constructor === Set; +const isRegExp = (value: any): value is RegExp => value.constructor === RegExp; + export type DeepCyclicCopyOptions = { blacklist?: Set; keepPrototype?: boolean; @@ -23,9 +28,20 @@ export default function deepCyclicCopy( return cycles.get(value); } else if (Array.isArray(value)) { return deepCyclicCopyArray(value, options, cycles); - } else { - return deepCyclicCopyObject(value, options, cycles); + } else if (isMap(value)) { + return deepCyclicCopyMap(value, options, cycles); + } else if (isSet(value)) { + return deepCyclicCopySet(value, options, cycles); + } else if (Buffer.isBuffer(value)) { + return Buffer.from(value) as any; + } else if (isDate(value)) { + return new Date(value.getTime()) as any; + } else if (isNumberArray(value)) { + return new (Object.getPrototypeOf(value).constructor)(value); + } else if (isRegExp(value)) { + return deepCyclicCopyRegExp(value); } + return deepCyclicCopyObject(value, options, cycles); } function deepCyclicCopyObject( @@ -33,12 +49,6 @@ function deepCyclicCopyObject( options: DeepCyclicCopyOptions, cycles: WeakMap, ): T { - if (object instanceof RegExp && options.keepPrototype) { - const result = new RegExp(object.source, object.flags); - result.lastIndex = object.lastIndex; - return result as typeof object; - } - const newObject = options.keepPrototype ? Object.create(Object.getPrototypeOf(object)) : {}; @@ -90,3 +100,71 @@ function deepCyclicCopyArray( return newArray; } + +function deepCyclicCopyMap( + map: Map, + options: DeepCyclicCopyOptions, + cycles: WeakMap, +): T { + const newMap = new Map(); + + cycles.set(map, newMap); + + map.forEach((value, key) => { + if (options.blacklist && options.blacklist.has(key)) return; + newMap.set( + key, + deepCyclicCopy( + value, + {blacklist: EMPTY, keepPrototype: options.keepPrototype}, + cycles, + ), + ); + }); + + return newMap as any; +} + +function deepCyclicCopySet( + set: Set, + options: DeepCyclicCopyOptions, + cycles: WeakMap, +): T { + const newSet = new Set(); + + cycles.set(set, newSet); + + set.forEach(value => { + newSet.add( + deepCyclicCopy( + value, + {blacklist: EMPTY, keepPrototype: options.keepPrototype}, + cycles, + ), + ); + }); + + return newSet as any; +} + +function deepCyclicCopyRegExp(regExp: RegExp): T { + const newRegExp = new RegExp(regExp.source, regExp.flags); + newRegExp.lastIndex = regExp.lastIndex; + return newRegExp as any; +} + +function isNumberArray(value: any): Boolean { + return [ + Int8Array, + Uint8Array, + Uint8ClampedArray, + Int16Array, + Uint16Array, + Int32Array, + Uint32Array, + Float32Array, + Float64Array, + BigInt64Array, + BigUint64Array, + ].includes(value.constructor); +} From 4c0f95973cdf99c6ea3862386edae6164d8f61a0 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 5 Jan 2020 15:48:27 +0800 Subject: [PATCH 27/44] add Class Replaceable to provide same api for object operation --- .../jest-matcher-utils/src/Replaceable.ts | 49 ++++++ .../src/__tests__/Replaceable.test.ts | 153 ++++++++++++++++++ 2 files changed, 202 insertions(+) create mode 100644 packages/jest-matcher-utils/src/Replaceable.ts create mode 100644 packages/jest-matcher-utils/src/__tests__/Replaceable.test.ts diff --git a/packages/jest-matcher-utils/src/Replaceable.ts b/packages/jest-matcher-utils/src/Replaceable.ts new file mode 100644 index 000000000000..e92699b51889 --- /dev/null +++ b/packages/jest-matcher-utils/src/Replaceable.ts @@ -0,0 +1,49 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import getType = require('jest-get-type'); + +const supportTypes = ['map', 'array', 'object']; + +type ReplaceableForEachCallBack = (value: any, key: any, object: any) => void; + +export default class Replaceable { + object: any; + type: string; + + constructor(object: any) { + this.object = object; + this.type = getType(object); + if (!supportTypes.includes(this.type)) + throw new Error(`Type ${this.type} is not support in Replaceable!`); + } + + static isReplaceable(obj1: any, obj2: any): Boolean { + const obj1Type = getType(obj1); + const obj2Type = getType(obj2); + return obj1Type === obj2Type && supportTypes.includes(obj1Type); + } + + forEach(cb: ReplaceableForEachCallBack): void { + if (this.type === 'object') + Object.entries(this.object).forEach(([key, value]) => { + cb(value, key, this.object); + }); + else this.object.forEach(cb); + } + + get(key: any): any { + if (['object', 'array'].includes(this.type)) return this.object[key]; + else if (this.type === 'map') return this.object.get(key); + } + + set(key: any, value: any): any { + if (['object', 'array'].includes(this.type)) + return (this.object[key] = value); + else if (this.type === 'map') return this.object.set(key, value); + } +} diff --git a/packages/jest-matcher-utils/src/__tests__/Replaceable.test.ts b/packages/jest-matcher-utils/src/__tests__/Replaceable.test.ts new file mode 100644 index 000000000000..51bf759b379a --- /dev/null +++ b/packages/jest-matcher-utils/src/__tests__/Replaceable.test.ts @@ -0,0 +1,153 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import Replaceable from '../Replaceable'; + +describe('Replaceable', () => { + describe('constructor', () => { + test('init with object', () => { + const replaceable = new Replaceable({a: 1, b: 2}); + expect(replaceable.object).toEqual({a: 1, b: 2}); + expect(replaceable.type).toBe('object'); + }); + + test('init with array', () => { + const replaceable = new Replaceable([1, 2, 3]); + expect(replaceable.object).toEqual([1, 2, 3]); + expect(replaceable.type).toBe('array'); + }); + + test('init with Map', () => { + const replaceable = new Replaceable( + new Map([ + ['a', 1], + ['b', 2], + ]), + ); + expect(replaceable.object).toEqual( + new Map([ + ['a', 1], + ['b', 2], + ]), + ); + expect(replaceable.type).toBe('map'); + }); + + test('init with other type should throw error', () => { + expect(() => { + new Replaceable(new Date()); + }).toThrow('Type date is not support in Replaceable!'); + }); + }); + + describe('get', () => { + test('get object item', () => { + const replaceable = new Replaceable({a: 1, b: 2}); + expect(replaceable.get('b')).toBe(2); + }); + + test('get array item', () => { + const replaceable = new Replaceable([1, 2, 3]); + expect(replaceable.get(1)).toBe(2); + }); + + test('get Map item', () => { + const replaceable = new Replaceable( + new Map([ + ['a', 1], + ['b', 2], + ]), + ); + expect(replaceable.get('b')).toBe(2); + }); + }); + + describe('set', () => { + test('set object item', () => { + const replaceable = new Replaceable({a: 1, b: 2}); + replaceable.set('b', 3); + expect(replaceable.object).toEqual({a: 1, b: 3}); + }); + + test('set array item', () => { + const replaceable = new Replaceable([1, 2, 3]); + replaceable.set(1, 3); + expect(replaceable.object).toEqual([1, 3, 3]); + }); + + test('set Map item', () => { + const replaceable = new Replaceable( + new Map([ + ['a', 1], + ['b', 2], + ]), + ); + replaceable.set('b', 3); + expect(replaceable.object).toEqual( + new Map([ + ['a', 1], + ['b', 3], + ]), + ); + }); + }); + + describe('forEach', () => { + test('object forEach', () => { + const replaceable = new Replaceable({a: 1, b: 2}); + const cb = jest.fn(); + replaceable.forEach(cb); + expect(cb.mock.calls[0]).toEqual([1, 'a', {a: 1, b: 2}]); + expect(cb.mock.calls[1]).toEqual([2, 'b', {a: 1, b: 2}]); + }); + + test('array forEach', () => { + const replaceable = new Replaceable([1, 2, 3]); + const cb = jest.fn(); + replaceable.forEach(cb); + expect(cb.mock.calls[0]).toEqual([1, 0, [1, 2, 3]]); + expect(cb.mock.calls[1]).toEqual([2, 1, [1, 2, 3]]); + expect(cb.mock.calls[2]).toEqual([3, 2, [1, 2, 3]]); + }); + + test('array forEach', () => { + const map = new Map([ + ['a', 1], + ['b', 2], + ]); + const replaceable = new Replaceable(map); + const cb = jest.fn(); + replaceable.forEach(cb); + expect(cb.mock.calls[0]).toEqual([1, 'a', map]); + expect(cb.mock.calls[1]).toEqual([2, 'b', map]); + }); + }); + + describe('isReplaceable', () => { + test('should return true if two object types equal and support', () => { + expect(Replaceable.isReplaceable({a: 1}, {b: 2})).toBe(true); + expect(Replaceable.isReplaceable([], [1, 2, 3])).toBe(true); + expect( + Replaceable.isReplaceable( + new Map(), + new Map([ + ['a', 1], + ['b', 2], + ]), + ), + ).toBe(true); + }); + + test('should return false if two object types not equal', () => { + expect(Replaceable.isReplaceable({a: 1}, [1, 2, 3])).toBe(false); + }); + + test('should return false if object types not support', () => { + expect(Replaceable.isReplaceable('foo', 'bar')).toBe(false); + }); + }); +}); From 03e00c32f1359ff002c31e50096e69cd5eba5547 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 5 Jan 2020 15:50:37 +0800 Subject: [PATCH 28/44] use Replaceable for replacing to asymmetrict matcher --- .../__snapshots__/matchers.test.js.snap | 10 +-- .../printDiffOrStringify.test.ts.snap | 79 ++++++++++++++++--- .../__tests__/printDiffOrStringify.test.ts | 46 +++++++++-- packages/jest-matcher-utils/src/index.ts | 60 +++++++------- 4 files changed, 141 insertions(+), 54 deletions(-) diff --git a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap index b811c13d7360..c95358ee16aa 100644 --- a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap @@ -364,14 +364,8 @@ exports[`.toBe() fails for: {"a": [Function a], "b": 2} and {"a": Any, If it should pass with deep equality, replace "toBe" with "toStrictEqual" -- Expected - 1 -+ Received + 1 - - Object { -- "a": Any, -+ "a": [Function a], - "b": 2, - } +Expected: {"a": Any, "b": 2} +Received: {"a": [Function a], "b": 2} `; exports[`.toBe() fails for: {"a": 1} and {"a": 1} 1`] = ` diff --git a/packages/jest-matcher-utils/src/__tests__/__snapshots__/printDiffOrStringify.test.ts.snap b/packages/jest-matcher-utils/src/__tests__/__snapshots__/printDiffOrStringify.test.ts.snap index 4302468e0a2c..990ea8705924 100644 --- a/packages/jest-matcher-utils/src/__tests__/__snapshots__/printDiffOrStringify.test.ts.snap +++ b/packages/jest-matcher-utils/src/__tests__/__snapshots__/printDiffOrStringify.test.ts.snap @@ -1,6 +1,50 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`printDiffOrStringify asymmetricMatcher circular 1`] = ` +exports[`printDiffOrStringify asymmetricMatcher array 1`] = ` +- Expected - 1 ++ Received + 1 + + Array [ + 1, + Any, +- 3, ++ 2, + ] +`; + +exports[`printDiffOrStringify asymmetricMatcher circular array 1`] = ` +- Expected - 1 ++ Received + 1 + + Array [ + 1, + Any, +- 3, ++ 2, + [Circular], + ] +`; + +exports[`printDiffOrStringify asymmetricMatcher circular map 1`] = ` +- Expected - 2 ++ Received + 2 + + Map { + "a" => 1, + "b" => Any, +- "c" => 3, ++ "c" => 2, + "circular" => Map { + "a" => 1, + "b" => Any, +- "c" => 3, ++ "c" => 2, + "circular" => [Circular], + }, + } +`; + +exports[`printDiffOrStringify asymmetricMatcher circular object 1`] = ` - Expected - 1 + Received + 1 @@ -44,6 +88,18 @@ exports[`printDiffOrStringify asymmetricMatcher jest asymmetricMatcher 1`] = ` } `; +exports[`printDiffOrStringify asymmetricMatcher map 1`] = ` +- Expected - 1 ++ Received + 1 + + Map { + "a" => 1, + "b" => Any, +- "c" => 3, ++ "c" => 2, + } +`; + exports[`printDiffOrStringify asymmetricMatcher minimal test 1`] = ` - Expected - 1 + Received + 1 @@ -70,16 +126,19 @@ exports[`printDiffOrStringify asymmetricMatcher nested object 1`] = ` } `; -exports[`printDiffOrStringify asymmetricMatcher should not ignore asymmetric match 1`] = ` -- Expected - 2 -+ Received + 2 +exports[`printDiffOrStringify asymmetricMatcher object in array 1`] = ` +- Expected - 1 ++ Received + 1 - Object { -- "a": Any, -- "b": 2, -+ "a": 1, -+ "b": 1, - } + Array [ + 1, + Object { + "a": 1, + "b": Any, + }, +- 3, ++ 2, + ] `; exports[`printDiffOrStringify asymmetricMatcher transitive circular 1`] = ` diff --git a/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts b/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts index 8210f28fafe4..21c4892c8959 100644 --- a/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts +++ b/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts @@ -170,19 +170,31 @@ describe('printDiffOrStringify', () => { test('array', () => { const expected: Array = [1, expect.any(Number), 3]; - const received: Array = [1, 2, 3]; - console.log(testDiffOrStringify(expected, received)); + const received: Array = [1, 2, 2]; expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); }); test('object in array', () => { const expected: Array = [1, {a: 1, b: expect.any(Number)}, 3]; - const received: Array = [1, {a: 1, b: 2}, 3]; - console.log(testDiffOrStringify(expected, received)); + const received: Array = [1, {a: 1, b: 2}, 2]; expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); }); - test('circular', () => { + test('map', () => { + const expected: Map = new Map([ + ['a', 1], + ['b', expect.any(Number)], + ['c', 3], + ]); + const received: Map = new Map([ + ['a', 1], + ['b', 2], + ['c', 2], + ]); + expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); + }); + + test('circular object', () => { const expected: any = { b: expect.any(Number), c: 3, @@ -207,5 +219,29 @@ describe('printDiffOrStringify', () => { received.nested = {b: 2, parent: received}; expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); }); + + test('circular array', () => { + const expected: Array = [1, expect.any(Number), 3]; + expected.push(expected); + const received: Array = [1, 2, 2]; + received.push(received); + expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); + }); + + test('circular map', () => { + const expected: Map = new Map([ + ['a', 1], + ['b', expect.any(Number)], + ['c', 3], + ]); + expected.set('circular', expected); + const received: Map = new Map([ + ['a', 1], + ['b', 2], + ['c', 2], + ]); + received.set('circular', received); + expect(testDiffOrStringify(expected, received)).toMatchSnapshot(); + }); }); }); diff --git a/packages/jest-matcher-utils/src/index.ts b/packages/jest-matcher-utils/src/index.ts index a940a0aecdf4..35ee9d4d7375 100644 --- a/packages/jest-matcher-utils/src/index.ts +++ b/packages/jest-matcher-utils/src/index.ts @@ -18,6 +18,7 @@ import diffDefault, { import getType = require('jest-get-type'); import deepCyclicCopy from 'jest-util/build/deepCyclicCopy'; import prettyFormat = require('pretty-format'); +import Replaceable from './Replaceable'; const { AsymmetricMatcher, @@ -411,10 +412,7 @@ function replaceMatchedToAsymmetricMatcher( expectedCycles: Array, receivedCycles: Array, ) { - if ( - getType(replacedExpected) !== 'object' || - getType(replacedReceived) !== 'object' - ) + if (!Replaceable.isReplaceable(replacedExpected, replacedReceived)) return {replacedExpected, replacedReceived}; if ( @@ -426,33 +424,33 @@ function replaceMatchedToAsymmetricMatcher( expectedCycles.push(replacedExpected); receivedCycles.push(replacedReceived); - console.log(replacedExpected, replacedReceived); - - Object.entries(replacedExpected).forEach( - ([key, expectedAttribute]: [string, any]) => { - const receivedAttribute = replacedReceived[key]; - if (isAsymmetricMatcher(expectedAttribute)) { - if (expectedAttribute.asymmetricMatch(receivedAttribute)) - replacedReceived[key] = expectedAttribute; - } else if (isAsymmetricMatcher(receivedAttribute)) { - if (receivedAttribute.asymmetricMatch(expectedAttribute)) - replacedExpected[key] = receivedAttribute; - } else if ( - getType(expectedAttribute) === 'object' && - getType(receivedAttribute) === 'object' - ) { - const replacedAttribute = replaceMatchedToAsymmetricMatcher( - expectedAttribute, - receivedAttribute, - expectedCycles, - receivedCycles, - ); - replacedExpected[key] = replacedAttribute.replacedExpected; - replacedReceived[key] = replacedAttribute.replacedReceived; - } - }, - ); - return {replacedExpected, replacedReceived}; + const expectedReplaceable = new Replaceable(replacedExpected); + const receivedReplaceable = new Replaceable(replacedReceived); + + expectedReplaceable.forEach((expectedValue: any, key: any) => { + const receivedValue = receivedReplaceable.get(key); + if (isAsymmetricMatcher(expectedValue)) { + if (expectedValue.asymmetricMatch(receivedValue)) + receivedReplaceable.set(key, expectedValue); + } else if (isAsymmetricMatcher(receivedValue)) { + if (receivedValue.asymmetricMatch(expectedValue)) + expectedReplaceable.set(key, receivedValue); + } else if (Replaceable.isReplaceable(expectedValue, receivedValue)) { + const replaced = replaceMatchedToAsymmetricMatcher( + expectedValue, + receivedValue, + expectedCycles, + receivedCycles, + ); + expectedReplaceable.set(key, replaced.replacedExpected); + receivedReplaceable.set(key, replaced.replacedReceived); + } + }); + + return { + replacedExpected: expectedReplaceable.object, + replacedReceived: receivedReplaceable.object, + }; } function isAsymmetricMatcher(data: any) { From 9a81ffc4b809f6b065ba12fed845d0584a1582df Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 5 Jan 2020 16:04:17 +0800 Subject: [PATCH 29/44] lint --- packages/jest-matcher-utils/src/Replaceable.ts | 13 ++++++------- .../src/__tests__/Replaceable.test.ts | 5 +++-- packages/jest-matcher-utils/src/index.ts | 3 +-- packages/jest-util/src/deepCyclicCopy.ts | 4 +--- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/packages/jest-matcher-utils/src/Replaceable.ts b/packages/jest-matcher-utils/src/Replaceable.ts index e92699b51889..f25c94a6656e 100644 --- a/packages/jest-matcher-utils/src/Replaceable.ts +++ b/packages/jest-matcher-utils/src/Replaceable.ts @@ -22,7 +22,7 @@ export default class Replaceable { throw new Error(`Type ${this.type} is not support in Replaceable!`); } - static isReplaceable(obj1: any, obj2: any): Boolean { + static isReplaceable(obj1: any, obj2: any): boolean { const obj1Type = getType(obj1); const obj2Type = getType(obj2); return obj1Type === obj2Type && supportTypes.includes(obj1Type); @@ -37,13 +37,12 @@ export default class Replaceable { } get(key: any): any { - if (['object', 'array'].includes(this.type)) return this.object[key]; - else if (this.type === 'map') return this.object.get(key); + if (this.type === 'map') return this.object.get(key); + return this.object[key]; } - set(key: any, value: any): any { - if (['object', 'array'].includes(this.type)) - return (this.object[key] = value); - else if (this.type === 'map') return this.object.set(key, value); + set(key: any, value: any): void { + if (this.type === 'map') this.object.set(key, value); + else this.object[key] = value; } } diff --git a/packages/jest-matcher-utils/src/__tests__/Replaceable.test.ts b/packages/jest-matcher-utils/src/__tests__/Replaceable.test.ts index 51bf759b379a..cb3294296140 100644 --- a/packages/jest-matcher-utils/src/__tests__/Replaceable.test.ts +++ b/packages/jest-matcher-utils/src/__tests__/Replaceable.test.ts @@ -39,7 +39,8 @@ describe('Replaceable', () => { test('init with other type should throw error', () => { expect(() => { - new Replaceable(new Date()); + //eslint-disable-next-line @typescript-eslint/no-unused-vars + const replaceable = new Replaceable(new Date()); }).toThrow('Type date is not support in Replaceable!'); }); }); @@ -114,7 +115,7 @@ describe('Replaceable', () => { expect(cb.mock.calls[2]).toEqual([3, 2, [1, 2, 3]]); }); - test('array forEach', () => { + test('map forEach', () => { const map = new Map([ ['a', 1], ['b', 2], diff --git a/packages/jest-matcher-utils/src/index.ts b/packages/jest-matcher-utils/src/index.ts index 35ee9d4d7375..33096db8cee0 100644 --- a/packages/jest-matcher-utils/src/index.ts +++ b/packages/jest-matcher-utils/src/index.ts @@ -353,7 +353,6 @@ export const printDiffOrStringify = ( } if (isLineDiffable(expected, received)) { - let difference; const { replacedExpected, replacedReceived, @@ -363,7 +362,7 @@ export const printDiffOrStringify = ( [], [], ); - difference = diffDefault(replacedExpected, replacedReceived, { + const difference = diffDefault(replacedExpected, replacedReceived, { aAnnotation: expectedLabel, bAnnotation: receivedLabel, expand, diff --git a/packages/jest-util/src/deepCyclicCopy.ts b/packages/jest-util/src/deepCyclicCopy.ts index 8eae93bb6d7f..84d6be2e929c 100644 --- a/packages/jest-util/src/deepCyclicCopy.ts +++ b/packages/jest-util/src/deepCyclicCopy.ts @@ -153,7 +153,7 @@ function deepCyclicCopyRegExp(regExp: RegExp): T { return newRegExp as any; } -function isNumberArray(value: any): Boolean { +function isNumberArray(value: any): boolean { return [ Int8Array, Uint8Array, @@ -164,7 +164,5 @@ function isNumberArray(value: any): Boolean { Uint32Array, Float32Array, Float64Array, - BigInt64Array, - BigUint64Array, ].includes(value.constructor); } From 67c443eade0aad5ab5a441e6ad0421e64df7e4e2 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 5 Jan 2020 16:04:26 +0800 Subject: [PATCH 30/44] update changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03d01b501f8a..0bf315e5ceb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ - `[@jest/fake-timers]` Add Lolex as implementation of fake timers ([#8897](https://github.com/facebook/jest/pull/8897)) - `[jest-get-type]` Add `BigInt` support. ([#8382](https://github.com/facebook/jest/pull/8382)) - `[jest-matcher-utils]` Add `BigInt` support to `ensureNumbers` `ensureActualIsNumber`, `ensureExpectedIsNumber` ([#8382](https://github.com/facebook/jest/pull/8382)) -- `[jest-matcher-utils]` Add `ignoreAsymmetricMatches` to ignore highlighting matched asymmetricMatcher in diffs ([#9257](https://github.com/facebook/jest/pull/9257)) +- `[jest-matcher-utils]` Ignore highlighting matched asymmetricMatcher in diffs ([#9257](https://github.com/facebook/jest/pull/9257)) - `[jest-reporters]` Export utils for path formatting ([#9162](https://github.com/facebook/jest/pull/9162)) - `[jest-runner]` Warn if a worker had to be force exited ([#8206](https://github.com/facebook/jest/pull/8206)) - `[jest-runtime]` [**BREAKING**] Do not export `ScriptTransformer` - it can be imported from `@jest/transform` instead ([#9256](https://github.com/facebook/jest/pull/9256)) @@ -71,7 +71,7 @@ - `[jest-transform]` Don't fail the test suite when a generated source map is invalid ([#9058](https://github.com/facebook/jest/pull/9058)) - `[jest-types]` [**BREAKING**] Use less `null | undefined` in config types ([#9200](https://github.com/facebook/jest/pull/9200)) - `[jest-util]` Allow querying process.domain ([#9136](https://github.com/facebook/jest/pull/9136)) -- `[jest-util]` Use `new` to `deepCyclicCopy` RegExp. Fix error of calling method after copied by `Object.create` ([#9257](https://github.com/facebook/jest/pull/9257)) +- `[jest-util]` Copy built-in objects will keep their prototypes and value ([#9257](https://github.com/facebook/jest/pull/9257)) - `[pretty-format]` Correctly detect memoized elements ([#9196](https://github.com/facebook/jest/pull/9196)) ### Chore & Maintenance From 263f9a7f5fdd31bda0bb79121aa45f5f9b7bea60 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Mon, 6 Jan 2020 00:09:35 +0800 Subject: [PATCH 31/44] add braces --- .../jest-matcher-utils/src/Replaceable.ts | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/jest-matcher-utils/src/Replaceable.ts b/packages/jest-matcher-utils/src/Replaceable.ts index f25c94a6656e..24862f439f13 100644 --- a/packages/jest-matcher-utils/src/Replaceable.ts +++ b/packages/jest-matcher-utils/src/Replaceable.ts @@ -18,8 +18,9 @@ export default class Replaceable { constructor(object: any) { this.object = object; this.type = getType(object); - if (!supportTypes.includes(this.type)) + if (!supportTypes.includes(this.type)) { throw new Error(`Type ${this.type} is not support in Replaceable!`); + } } static isReplaceable(obj1: any, obj2: any): boolean { @@ -29,20 +30,27 @@ export default class Replaceable { } forEach(cb: ReplaceableForEachCallBack): void { - if (this.type === 'object') + if (this.type === 'object') { Object.entries(this.object).forEach(([key, value]) => { cb(value, key, this.object); }); - else this.object.forEach(cb); + } else { + this.object.forEach(cb); + } } get(key: any): any { - if (this.type === 'map') return this.object.get(key); + if (this.type === 'map') { + return this.object.get(key); + } return this.object[key]; } set(key: any, value: any): void { - if (this.type === 'map') this.object.set(key, value); - else this.object[key] = value; + if (this.type === 'map') { + this.object.set(key, value); + } else { + this.object[key] = value; + } } } From d5863faf29b3fea203fcb46a44b1e524ba81219d Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Mon, 6 Jan 2020 00:25:50 +0800 Subject: [PATCH 32/44] change any type to unknow --- .../src/__tests__/printDiffOrStringify.test.ts | 2 +- packages/jest-matcher-utils/src/index.ts | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts b/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts index 21c4892c8959..450b69363396 100644 --- a/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts +++ b/packages/jest-matcher-utils/src/__tests__/printDiffOrStringify.test.ts @@ -11,7 +11,7 @@ import {INVERTED_COLOR, printDiffOrStringify} from '../index'; expect.addSnapshotSerializer(alignedAnsiStyleSerializer); describe('printDiffOrStringify', () => { - const testDiffOrStringify = (expected: any, received: any): string => + const testDiffOrStringify = (expected: unknown, received: unknown): string => printDiffOrStringify(expected, received, 'Expected', 'Received', true); test('expected is empty and received is single line', () => { diff --git a/packages/jest-matcher-utils/src/index.ts b/packages/jest-matcher-utils/src/index.ts index 33096db8cee0..36ea4ba67692 100644 --- a/packages/jest-matcher-utils/src/index.ts +++ b/packages/jest-matcher-utils/src/index.ts @@ -406,8 +406,8 @@ const shouldPrintDiff = (actual: unknown, expected: unknown) => { }; function replaceMatchedToAsymmetricMatcher( - replacedExpected: any, - replacedReceived: any, + replacedExpected: unknown, + replacedReceived: unknown, expectedCycles: Array, receivedCycles: Array, ) { @@ -426,7 +426,7 @@ function replaceMatchedToAsymmetricMatcher( const expectedReplaceable = new Replaceable(replacedExpected); const receivedReplaceable = new Replaceable(replacedReceived); - expectedReplaceable.forEach((expectedValue: any, key: any) => { + expectedReplaceable.forEach((expectedValue: unknown, key: unknown) => { const receivedValue = receivedReplaceable.get(key); if (isAsymmetricMatcher(expectedValue)) { if (expectedValue.asymmetricMatch(receivedValue)) @@ -452,7 +452,11 @@ function replaceMatchedToAsymmetricMatcher( }; } -function isAsymmetricMatcher(data: any) { +type AsymmetricMatcher = { + asymmetricMatch: Function; +}; + +function isAsymmetricMatcher(data: any): data is AsymmetricMatcher { const type = getType(data); return type === 'object' && typeof data.asymmetricMatch === 'function'; } From 8f5321a7fa4862d24de6aa16b26b7d862a08f74d Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Mon, 6 Jan 2020 00:26:26 +0800 Subject: [PATCH 33/44] import correctly --- packages/jest-matcher-utils/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-matcher-utils/src/index.ts b/packages/jest-matcher-utils/src/index.ts index 36ea4ba67692..88ceadda896a 100644 --- a/packages/jest-matcher-utils/src/index.ts +++ b/packages/jest-matcher-utils/src/index.ts @@ -16,7 +16,7 @@ import diffDefault, { diffStringsUnified, } from 'jest-diff'; import getType = require('jest-get-type'); -import deepCyclicCopy from 'jest-util/build/deepCyclicCopy'; +import {deepCyclicCopy} from 'jest-util'; import prettyFormat = require('pretty-format'); import Replaceable from './Replaceable'; From 83ddb57d6d7a0bda8066a72b731323df77a44c43 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Mon, 6 Jan 2020 01:05:27 +0800 Subject: [PATCH 34/44] avoid browser read property of undefined --- packages/jest-util/src/clearLine.ts | 2 +- packages/jest-util/src/isInteractive.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/jest-util/src/clearLine.ts b/packages/jest-util/src/clearLine.ts index dcf770c9624f..3c8a319afb22 100644 --- a/packages/jest-util/src/clearLine.ts +++ b/packages/jest-util/src/clearLine.ts @@ -6,7 +6,7 @@ */ export default function clearLine(stream: NodeJS.WriteStream) { - if (stream.isTTY) { + if (stream && stream.isTTY) { stream.write('\x1b[999D\x1b[K'); } } diff --git a/packages/jest-util/src/isInteractive.ts b/packages/jest-util/src/isInteractive.ts index e620adadf4df..333b7280076c 100644 --- a/packages/jest-util/src/isInteractive.ts +++ b/packages/jest-util/src/isInteractive.ts @@ -7,4 +7,8 @@ import isCI = require('is-ci'); -export default !!process.stdout.isTTY && process.env.TERM !== 'dumb' && !isCI; +export default process && + process.stdout && + !!process.stdout.isTTY && + process.env.TERM !== 'dumb' && + !isCI; From 4d4b7ce73026b0f3c4bbdf503dceb82e9bdcb5a3 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Mon, 6 Jan 2020 01:08:21 +0800 Subject: [PATCH 35/44] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bf315e5ceb2..4cd4171a0e3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,7 @@ - `[jest-types]` [**BREAKING**] Use less `null | undefined` in config types ([#9200](https://github.com/facebook/jest/pull/9200)) - `[jest-util]` Allow querying process.domain ([#9136](https://github.com/facebook/jest/pull/9136)) - `[jest-util]` Copy built-in objects will keep their prototypes and value ([#9257](https://github.com/facebook/jest/pull/9257)) +- `[jest-util]` Avoid browser read Node.js `process` and `stream` property ([#9257](https://github.com/facebook/jest/pull/9257)) - `[pretty-format]` Correctly detect memoized elements ([#9196](https://github.com/facebook/jest/pull/9196)) ### Chore & Maintenance From d9dd2c40368ee7f3dd9478a017b579f6374436af Mon Sep 17 00:00:00 2001 From: Wei An Yen Date: Tue, 14 Jan 2020 10:58:07 +0800 Subject: [PATCH 36/44] Check value before checking constructor. Co-Authored-By: Simen Bekkhus --- packages/jest-util/src/deepCyclicCopy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-util/src/deepCyclicCopy.ts b/packages/jest-util/src/deepCyclicCopy.ts index 84d6be2e929c..74aa6f8d50b3 100644 --- a/packages/jest-util/src/deepCyclicCopy.ts +++ b/packages/jest-util/src/deepCyclicCopy.ts @@ -164,5 +164,5 @@ function isNumberArray(value: any): boolean { Uint32Array, Float32Array, Float64Array, - ].includes(value.constructor); + ].includes(value && value.constructor); } From d4c2f5ed926da259712c5be93e39876114c20f13 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 19 Jan 2020 00:37:17 +0800 Subject: [PATCH 37/44] restore deepCyclicCopy --- .../src/__tests__/deepCyclicCopy.test.ts | 67 --------------- packages/jest-util/src/deepCyclicCopy.ts | 86 +------------------ 2 files changed, 2 insertions(+), 151 deletions(-) diff --git a/packages/jest-util/src/__tests__/deepCyclicCopy.test.ts b/packages/jest-util/src/__tests__/deepCyclicCopy.test.ts index b690a6e673be..73ea0f451da0 100644 --- a/packages/jest-util/src/__tests__/deepCyclicCopy.test.ts +++ b/packages/jest-util/src/__tests__/deepCyclicCopy.test.ts @@ -235,70 +235,3 @@ it('keeps the prototype for objects when keepPrototype = true', () => { ); spy.mockRestore(); }); - -it('RegExp should work correctly after copied', () => { - const regExp = deepCyclicCopy(/jest/i, {keepPrototype: true}); - expect(regExp.test('JEST is awesome')).toBe(true); -}); - -it('Copy Map', () => { - const map = new Map([ - ['a', 1], - ['b', 2], - ]); - const copy = deepCyclicCopy(map); - expect(copy).toEqual(map); - expect(copy.constructor).toBe(Map); -}); - -it('Copy Map with backlist', () => { - const map = new Map([ - ['a', 1], - ['b', 2], - ]); - const copy = deepCyclicCopy(map, {blacklist: new Set(['b'])}); - expect(copy).toEqual(new Map([['a', 1]])); -}); - -it('Copy cyclic Map', () => { - const map: Map = new Map([ - ['a', 1], - ['b', 2], - ]); - map.set('map', map); - expect(deepCyclicCopy(map)).toEqual(map); -}); - -it('Copy Set', () => { - const set = new Set([1, 2, 3]); - const copy = deepCyclicCopy(set); - expect(copy).toEqual(set); - expect(set.constructor).toBe(Set); -}); - -it('Copy cyclic Set', () => { - const set: Set = new Set([1, 2, 3]); - set.add(set); - expect(deepCyclicCopy(set)).toEqual(set); -}); - -it('Copy Buffer', () => { - const buffer = Buffer.from('hello'); - const copy = deepCyclicCopy(buffer); - expect(copy).toEqual(buffer); - expect(copy.constructor).toBe(Buffer); -}); - -it('Copy Date', () => { - const date = new Date(0); - const copy = deepCyclicCopy(date); - expect(copy).toEqual(date); - expect(copy.constructor).toBe(Date); -}); - -it('Copy number array', () => { - const uInt8Array = new Uint8Array([0, 1, 2, 3]); - const copy = deepCyclicCopy(uInt8Array); - expect(copy).toEqual(uInt8Array); - expect(copy.constructor).toBe(Uint8Array); -}); diff --git a/packages/jest-util/src/deepCyclicCopy.ts b/packages/jest-util/src/deepCyclicCopy.ts index 74aa6f8d50b3..d9f59bc409bb 100644 --- a/packages/jest-util/src/deepCyclicCopy.ts +++ b/packages/jest-util/src/deepCyclicCopy.ts @@ -7,11 +7,6 @@ const EMPTY = new Set(); -const isDate = (value: any): value is Date => value.constructor === Date; -const isMap = (value: any): value is Map => value.constructor === Map; -const isSet = (value: any): value is Set => value.constructor === Set; -const isRegExp = (value: any): value is RegExp => value.constructor === RegExp; - export type DeepCyclicCopyOptions = { blacklist?: Set; keepPrototype?: boolean; @@ -28,20 +23,9 @@ export default function deepCyclicCopy( return cycles.get(value); } else if (Array.isArray(value)) { return deepCyclicCopyArray(value, options, cycles); - } else if (isMap(value)) { - return deepCyclicCopyMap(value, options, cycles); - } else if (isSet(value)) { - return deepCyclicCopySet(value, options, cycles); - } else if (Buffer.isBuffer(value)) { - return Buffer.from(value) as any; - } else if (isDate(value)) { - return new Date(value.getTime()) as any; - } else if (isNumberArray(value)) { - return new (Object.getPrototypeOf(value).constructor)(value); - } else if (isRegExp(value)) { - return deepCyclicCopyRegExp(value); + } else { + return deepCyclicCopyObject(value, options, cycles); } - return deepCyclicCopyObject(value, options, cycles); } function deepCyclicCopyObject( @@ -100,69 +84,3 @@ function deepCyclicCopyArray( return newArray; } - -function deepCyclicCopyMap( - map: Map, - options: DeepCyclicCopyOptions, - cycles: WeakMap, -): T { - const newMap = new Map(); - - cycles.set(map, newMap); - - map.forEach((value, key) => { - if (options.blacklist && options.blacklist.has(key)) return; - newMap.set( - key, - deepCyclicCopy( - value, - {blacklist: EMPTY, keepPrototype: options.keepPrototype}, - cycles, - ), - ); - }); - - return newMap as any; -} - -function deepCyclicCopySet( - set: Set, - options: DeepCyclicCopyOptions, - cycles: WeakMap, -): T { - const newSet = new Set(); - - cycles.set(set, newSet); - - set.forEach(value => { - newSet.add( - deepCyclicCopy( - value, - {blacklist: EMPTY, keepPrototype: options.keepPrototype}, - cycles, - ), - ); - }); - - return newSet as any; -} - -function deepCyclicCopyRegExp(regExp: RegExp): T { - const newRegExp = new RegExp(regExp.source, regExp.flags); - newRegExp.lastIndex = regExp.lastIndex; - return newRegExp as any; -} - -function isNumberArray(value: any): boolean { - return [ - Int8Array, - Uint8Array, - Uint8ClampedArray, - Int16Array, - Uint16Array, - Int32Array, - Uint32Array, - Float32Array, - Float64Array, - ].includes(value && value.constructor); -} From 1db1b73161df22aae9bc9ace24ae8c9c4c2d0cf3 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 19 Jan 2020 02:19:20 +0800 Subject: [PATCH 38/44] create deepCyclicCopyReplaceable --- .../deepCyclicCopyReplaceable.test.ts | 97 +++++++++++++++++++ .../src/deepCyclicCopyReplaceable.ts | 94 ++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 packages/jest-matcher-utils/src/__tests__/deepCyclicCopyReplaceable.test.ts create mode 100644 packages/jest-matcher-utils/src/deepCyclicCopyReplaceable.ts diff --git a/packages/jest-matcher-utils/src/__tests__/deepCyclicCopyReplaceable.test.ts b/packages/jest-matcher-utils/src/__tests__/deepCyclicCopyReplaceable.test.ts new file mode 100644 index 000000000000..3063db1f76f7 --- /dev/null +++ b/packages/jest-matcher-utils/src/__tests__/deepCyclicCopyReplaceable.test.ts @@ -0,0 +1,97 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +import deepCyclicCopyReplaceable from '../deepCyclicCopyReplaceable'; + +test('returns the same value for primitive or function values', () => { + const fn = () => {}; + + expect(deepCyclicCopyReplaceable(undefined)).toBe(undefined); + expect(deepCyclicCopyReplaceable(null)).toBe(null); + expect(deepCyclicCopyReplaceable(true)).toBe(true); + expect(deepCyclicCopyReplaceable(42)).toBe(42); + expect(Number.isNaN(deepCyclicCopyReplaceable(NaN))).toBe(true); + expect(deepCyclicCopyReplaceable('foo')).toBe('foo'); + expect(deepCyclicCopyReplaceable(fn)).toBe(fn); +}); + +test('does not execute getters/setters, but copies them', () => { + const fn = jest.fn(); + const obj = { + // @ts-ignore + get foo() { + fn(); + }, + }; + const copy = deepCyclicCopyReplaceable(obj); + + expect(Object.getOwnPropertyDescriptor(copy, 'foo')).toBeDefined(); + expect(fn).not.toBeCalled(); +}); + +test('copies symbols', () => { + const symbol = Symbol('foo'); + const obj = {[symbol]: 42}; + + expect(deepCyclicCopyReplaceable(obj)[symbol]).toBe(42); +}); + +test('copies arrays as array objects', () => { + const array = [null, 42, 'foo', 'bar', [], {}]; + + expect(deepCyclicCopyReplaceable(array)).toEqual(array); + expect(Array.isArray(deepCyclicCopyReplaceable(array))).toBe(true); +}); + +test('handles cyclic dependencies', () => { + const cyclic: any = {a: 42, subcycle: {}}; + + cyclic.subcycle.baz = cyclic; + cyclic.bar = cyclic; + + expect(() => deepCyclicCopyReplaceable(cyclic)).not.toThrow(); + + const copy = deepCyclicCopyReplaceable(cyclic); + + expect(copy.a).toBe(42); + expect(copy.bar).toEqual(copy); + expect(copy.subcycle.baz).toEqual(copy); +}); + +test('Copy Map', () => { + const map = new Map([ + ['a', 1], + ['b', 2], + ]); + const copy = deepCyclicCopyReplaceable(map); + expect(copy).toEqual(map); + expect(copy.constructor).toBe(Map); +}); + +test('Copy cyclic Map', () => { + const map: Map = new Map([ + ['a', 1], + ['b', 2], + ]); + map.set('map', map); + expect(deepCyclicCopyReplaceable(map)).toEqual(map); +}); + +test('return same value for built-in object type except array, map and object', () => { + const date = new Date(); + const buffer = Buffer.from('jest'); + const numberArray = new Uint8Array([1, 2, 3]); + const regexp = /jest/; + const set = new Set(['foo', 'bar']); + + expect(deepCyclicCopyReplaceable(date)).toBe(date); + expect(deepCyclicCopyReplaceable(buffer)).toBe(buffer); + expect(deepCyclicCopyReplaceable(numberArray)).toBe(numberArray); + expect(deepCyclicCopyReplaceable(regexp)).toBe(regexp); + expect(deepCyclicCopyReplaceable(set)).toBe(set); +}); diff --git a/packages/jest-matcher-utils/src/deepCyclicCopyReplaceable.ts b/packages/jest-matcher-utils/src/deepCyclicCopyReplaceable.ts new file mode 100644 index 000000000000..9d81675ff0e6 --- /dev/null +++ b/packages/jest-matcher-utils/src/deepCyclicCopyReplaceable.ts @@ -0,0 +1,94 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const builtInObject = [ + Array, + Buffer, + Date, + Float32Array, + Float64Array, + Int16Array, + Int32Array, + Int8Array, + Map, + Set, + RegExp, + Uint16Array, + Uint32Array, + Uint8Array, + Uint8ClampedArray, +]; + +const isBuiltInObject = (object: any) => + builtInObject.includes(object.constructor); + +const isMap = (value: any): value is Map => value.constructor === Map; + +export default function deepCyclicCopyReplaceable( + value: T, + cycles: WeakMap = new WeakMap(), +): T { + if (typeof value !== 'object' || value === null) { + return value; + } else if (cycles.has(value)) { + return cycles.get(value); + } else if (Array.isArray(value)) { + return deepCyclicCopyArray(value, cycles); + } else if (isMap(value)) { + return deepCyclicCopyMap(value, cycles); + } else if (isBuiltInObject(value)) { + return value; + } else { + return deepCyclicCopyObject(value, cycles); + } +} + +function deepCyclicCopyObject(object: T, cycles: WeakMap): T { + const newObject = Object.create(Object.getPrototypeOf(object)); + const descriptors = Object.getOwnPropertyDescriptors(object); + + cycles.set(object, newObject); + + Object.keys(descriptors).forEach(key => { + const descriptor = descriptors[key]; + if (typeof descriptor.value !== 'undefined') { + descriptor.value = deepCyclicCopyReplaceable(descriptor.value, cycles); + } + + descriptor.configurable = true; + }); + + return Object.defineProperties(newObject, descriptors); +} + +function deepCyclicCopyArray(array: Array, cycles: WeakMap): T { + const newArray = new (Object.getPrototypeOf(array).constructor)(array.length); + const length = array.length; + + cycles.set(array, newArray); + + for (let i = 0; i < length; i++) { + newArray[i] = deepCyclicCopyReplaceable(array[i], cycles); + } + + return newArray; +} + +function deepCyclicCopyMap( + map: Map, + cycles: WeakMap, +): T { + const newMap = new Map(); + + cycles.set(map, newMap); + + map.forEach((value, key) => { + newMap.set(key, deepCyclicCopyReplaceable(value, cycles)); + }); + + return newMap as any; +} From 739d83584b94efda9a6829d1d10ce0a88a6ff50e Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 19 Jan 2020 02:20:19 +0800 Subject: [PATCH 39/44] change to use deepCyclicCopyReplaceable for copy --- packages/jest-matcher-utils/src/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/jest-matcher-utils/src/index.ts b/packages/jest-matcher-utils/src/index.ts index 88ceadda896a..f95c3a7e6b0e 100644 --- a/packages/jest-matcher-utils/src/index.ts +++ b/packages/jest-matcher-utils/src/index.ts @@ -16,9 +16,9 @@ import diffDefault, { diffStringsUnified, } from 'jest-diff'; import getType = require('jest-get-type'); -import {deepCyclicCopy} from 'jest-util'; import prettyFormat = require('pretty-format'); import Replaceable from './Replaceable'; +import deepCyclicCopyReplaceable from './deepCyclicCopyReplaceable'; const { AsymmetricMatcher, @@ -357,8 +357,8 @@ export const printDiffOrStringify = ( replacedExpected, replacedReceived, } = replaceMatchedToAsymmetricMatcher( - deepCyclicCopy(expected, {keepPrototype: true}), - deepCyclicCopy(received, {keepPrototype: true}), + deepCyclicCopyReplaceable(expected), + deepCyclicCopyReplaceable(received), [], [], ); From 3e200cea3ed8c81a48476c98f94e628eac252d32 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 19 Jan 2020 02:25:23 +0800 Subject: [PATCH 40/44] undo no use change --- .../jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts | 4 +++- packages/jest-jasmine2/src/jestExpect.ts | 4 +--- packages/jest-util/src/clearLine.ts | 2 +- packages/jest-util/src/isInteractive.ts | 6 +----- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts index 5ac79df66568..202744c87b54 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -28,7 +28,9 @@ const jestAdapter = async ( runtime .requireInternalModule(path.resolve(__dirname, './jestExpect.js')) - .default({expand: globalConfig.expand}); + .default({ + expand: globalConfig.expand, + }); const getPrettier = () => config.prettierPath ? require(config.prettierPath) : null; diff --git a/packages/jest-jasmine2/src/jestExpect.ts b/packages/jest-jasmine2/src/jestExpect.ts index 3389c9ae1ca7..e6d33d121192 100644 --- a/packages/jest-jasmine2/src/jestExpect.ts +++ b/packages/jest-jasmine2/src/jestExpect.ts @@ -28,9 +28,7 @@ type JasmineMatchersObject = {[id: string]: JasmineMatcher}; export default (config: {expand: boolean}) => { global.expect = expect; - expect.setState({ - expand: config.expand, - }); + expect.setState({expand: config.expand}); expect.extend({ toMatchInlineSnapshot, toMatchSnapshot, diff --git a/packages/jest-util/src/clearLine.ts b/packages/jest-util/src/clearLine.ts index 3c8a319afb22..dcf770c9624f 100644 --- a/packages/jest-util/src/clearLine.ts +++ b/packages/jest-util/src/clearLine.ts @@ -6,7 +6,7 @@ */ export default function clearLine(stream: NodeJS.WriteStream) { - if (stream && stream.isTTY) { + if (stream.isTTY) { stream.write('\x1b[999D\x1b[K'); } } diff --git a/packages/jest-util/src/isInteractive.ts b/packages/jest-util/src/isInteractive.ts index 333b7280076c..e620adadf4df 100644 --- a/packages/jest-util/src/isInteractive.ts +++ b/packages/jest-util/src/isInteractive.ts @@ -7,8 +7,4 @@ import isCI = require('is-ci'); -export default process && - process.stdout && - !!process.stdout.isTTY && - process.env.TERM !== 'dumb' && - !isCI; +export default !!process.stdout.isTTY && process.env.TERM !== 'dumb' && !isCI; From 829ef89669c6708f5230f908ad0f51fea4ccb34a Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 19 Jan 2020 02:25:39 +0800 Subject: [PATCH 41/44] drop dependency --- packages/jest-matcher-utils/package.json | 1 - packages/jest-matcher-utils/tsconfig.json | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/jest-matcher-utils/package.json b/packages/jest-matcher-utils/package.json index 87165b05525e..1c3746f07f12 100644 --- a/packages/jest-matcher-utils/package.json +++ b/packages/jest-matcher-utils/package.json @@ -16,7 +16,6 @@ "chalk": "^3.0.0", "jest-diff": "^24.9.0", "jest-get-type": "^24.9.0", - "jest-util": "^24.9.0", "pretty-format": "^24.9.0" }, "publishConfig": { diff --git a/packages/jest-matcher-utils/tsconfig.json b/packages/jest-matcher-utils/tsconfig.json index 53a40ed97530..febd499d97ae 100644 --- a/packages/jest-matcher-utils/tsconfig.json +++ b/packages/jest-matcher-utils/tsconfig.json @@ -7,7 +7,6 @@ "references": [ {"path": "../jest-diff"}, {"path": "../jest-get-type"}, - {"path": "../jest-util"}, {"path": "../pretty-format"}, {"path": "../test-utils"} ] From 684b8ffa09d19eb2179413f58ba4716c58809eeb Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 19 Jan 2020 02:30:40 +0800 Subject: [PATCH 42/44] remove outdated changelog --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cd4171a0e3e..083dc5949669 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,8 +71,6 @@ - `[jest-transform]` Don't fail the test suite when a generated source map is invalid ([#9058](https://github.com/facebook/jest/pull/9058)) - `[jest-types]` [**BREAKING**] Use less `null | undefined` in config types ([#9200](https://github.com/facebook/jest/pull/9200)) - `[jest-util]` Allow querying process.domain ([#9136](https://github.com/facebook/jest/pull/9136)) -- `[jest-util]` Copy built-in objects will keep their prototypes and value ([#9257](https://github.com/facebook/jest/pull/9257)) -- `[jest-util]` Avoid browser read Node.js `process` and `stream` property ([#9257](https://github.com/facebook/jest/pull/9257)) - `[pretty-format]` Correctly detect memoized elements ([#9196](https://github.com/facebook/jest/pull/9196)) ### Chore & Maintenance From 0a26b715ad9aee85ee7f84d3850a0a9778d953cd Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 19 Jan 2020 12:44:44 +0800 Subject: [PATCH 43/44] add braces --- packages/jest-matcher-utils/src/index.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/jest-matcher-utils/src/index.ts b/packages/jest-matcher-utils/src/index.ts index f95c3a7e6b0e..708f16ba910d 100644 --- a/packages/jest-matcher-utils/src/index.ts +++ b/packages/jest-matcher-utils/src/index.ts @@ -411,14 +411,16 @@ function replaceMatchedToAsymmetricMatcher( expectedCycles: Array, receivedCycles: Array, ) { - if (!Replaceable.isReplaceable(replacedExpected, replacedReceived)) + if (!Replaceable.isReplaceable(replacedExpected, replacedReceived)) { return {replacedExpected, replacedReceived}; + } if ( expectedCycles.includes(replacedExpected) || receivedCycles.includes(replacedReceived) - ) + ) { return {replacedExpected, replacedReceived}; + } expectedCycles.push(replacedExpected); receivedCycles.push(replacedReceived); @@ -429,11 +431,13 @@ function replaceMatchedToAsymmetricMatcher( expectedReplaceable.forEach((expectedValue: unknown, key: unknown) => { const receivedValue = receivedReplaceable.get(key); if (isAsymmetricMatcher(expectedValue)) { - if (expectedValue.asymmetricMatch(receivedValue)) + if (expectedValue.asymmetricMatch(receivedValue)) { receivedReplaceable.set(key, expectedValue); + } } else if (isAsymmetricMatcher(receivedValue)) { - if (receivedValue.asymmetricMatch(expectedValue)) + if (receivedValue.asymmetricMatch(expectedValue)) { expectedReplaceable.set(key, receivedValue); + } } else if (Replaceable.isReplaceable(expectedValue, receivedValue)) { const replaced = replaceMatchedToAsymmetricMatcher( expectedValue, From 0f441f405387c5873021944d6d39ad18f96917b8 Mon Sep 17 00:00:00 2001 From: WeiAnAn Date: Sun, 19 Jan 2020 12:45:00 +0800 Subject: [PATCH 44/44] undo outdated change --- packages/jest-diff/src/__tests__/diff.test.ts | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/packages/jest-diff/src/__tests__/diff.test.ts b/packages/jest-diff/src/__tests__/diff.test.ts index 471ebb255fcb..3367839b8cfe 100644 --- a/packages/jest-diff/src/__tests__/diff.test.ts +++ b/packages/jest-diff/src/__tests__/diff.test.ts @@ -192,26 +192,24 @@ line 4`; }); describe('objects', () => { - describe('expand', () => { - const a = {a: {b: {c: 5}}}; - const b = {a: {b: {c: 6}}}; - const expected = [ - ' Object {', - ' "a": Object {', - ' "b": Object {', - '- "c": 5,', - '+ "c": 6,', - ' },', - ' },', - ' }', - ].join('\n'); + const a = {a: {b: {c: 5}}}; + const b = {a: {b: {c: 6}}}; + const expected = [ + ' Object {', + ' "a": Object {', + ' "b": Object {', + '- "c": 5,', + '+ "c": 6,', + ' },', + ' },', + ' }', + ].join('\n'); - test('(unexpanded)', () => { - expect(diff(a, b, unexpandedBe)).toBe(expected); - }); - test('(expanded)', () => { - expect(diff(a, b, expandedBe)).toBe(expected); - }); + test('(unexpanded)', () => { + expect(diff(a, b, unexpandedBe)).toBe(expected); + }); + test('(expanded)', () => { + expect(diff(a, b, expandedBe)).toBe(expected); }); });