From 4c4162bb4177b866c323c41025f8f0281844a98c Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 30 Dec 2020 18:03:48 +0100 Subject: [PATCH] fix(jest-runner): handle test failures with circular objects (#10981) --- CHANGELOG.md | 1 + .../circularInequality.test.ts.snap | 53 +++++++++++++++++ e2e/__tests__/circularInequality.test.ts | 58 +++++++++++++++++++ packages/jest-runner/src/index.ts | 7 ++- 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 e2e/__tests__/__snapshots__/circularInequality.test.ts.snap create mode 100644 e2e/__tests__/circularInequality.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b605adb268c1..ea94197a0ad7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ - `[jest-reporter]` Handle empty files when reporting code coverage with V8 ([#10819](https://github.com/facebook/jest/pull/10819)) - `[jest-resolve]` Replace read-pkg-up with escalade package ([#10781](https://github.com/facebook/jest/pull/10781)) - `[jest-resolve]` Disable `jest-pnp-resolver` for Yarn 2 ([#10847](https://github.com/facebook/jest/pull/10847)) +- `[jest-runner]` Handle test failures with circular objects ([#10981](https://github.com/facebook/jest/pull/10981)) - `[jest-runtime]` [**BREAKING**] Do not inject `global` variable into module wrapper ([#10644](https://github.com/facebook/jest/pull/10644)) - `[jest-runtime]` [**BREAKING**] remove long-deprecated `jest.addMatchers`, `jest.resetModuleRegistry`, and `jest.runTimersToTime` ([#9853](https://github.com/facebook/jest/pull/9853)) - `[jest-runtime]` Fix stack overflow and promise deadlock when importing mutual dependant ES module ([#10892](https://github.com/facebook/jest/pull/10892)) diff --git a/e2e/__tests__/__snapshots__/circularInequality.test.ts.snap b/e2e/__tests__/__snapshots__/circularInequality.test.ts.snap new file mode 100644 index 000000000000..c37d9f2edacf --- /dev/null +++ b/e2e/__tests__/__snapshots__/circularInequality.test.ts.snap @@ -0,0 +1,53 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`handles circular inequality properly 1`] = ` +FAIL __tests__/test-1.js + ● test + + expect(received).toEqual(expected) // deep equality + + - Expected - 1 + + Received + 3 + + - Object {} + + Object { + + "ref": [Circular], + + } + + 3 | foo.ref = foo; + 4 | + > 5 | expect(foo).toEqual({}); + | ^ + 6 | }); + + at Object.toEqual (__tests__/test-1.js:5:15) + +FAIL __tests__/test-2.js + ● test + + expect(received).toEqual(expected) // deep equality + + - Expected - 1 + + Received + 3 + + - Object {} + + Object { + + "ref": [Circular], + + } + + 3 | foo.ref = foo; + 4 | + > 5 | expect(foo).toEqual({}); + | ^ + 6 | }); + + at Object.toEqual (__tests__/test-2.js:5:15) +`; + +exports[`handles circular inequality properly 2`] = ` +Test Suites: 2 failed, 2 total +Tests: 2 failed, 2 total +Snapshots: 0 total +Time: <> +Ran all test suites. +`; diff --git a/e2e/__tests__/circularInequality.test.ts b/e2e/__tests__/circularInequality.test.ts new file mode 100644 index 000000000000..49a87762e950 --- /dev/null +++ b/e2e/__tests__/circularInequality.test.ts @@ -0,0 +1,58 @@ +/** + * 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 {tmpdir} from 'os'; +import * as path from 'path'; +import {wrap} from 'jest-snapshot-serializer-raw'; +import { + cleanup, + createEmptyPackage, + extractSortedSummary, + writeFiles, +} from '../Utils'; +import {runContinuous} from '../runJest'; + +const tempDir = path.resolve(tmpdir(), 'circular-inequality-test'); + +beforeEach(() => { + createEmptyPackage(tempDir); +}); + +afterEach(() => { + cleanup(tempDir); +}); + +test('handles circular inequality properly', async () => { + const testFileContent = ` + it('test', () => { + const foo = {}; + foo.ref = foo; + + expect(foo).toEqual({}); + }); + `; + + writeFiles(tempDir, { + '__tests__/test-1.js': testFileContent, + '__tests__/test-2.js': testFileContent, + }); + + const {end, waitUntil} = runContinuous( + tempDir, + ['--no-watchman', '--watch-all'], + // timeout in case the `waitUntil` below doesn't fire + {stripAnsi: true, timeout: 5000}, + ); + + await waitUntil(({stderr}) => stderr.includes('Ran all test suites.')); + + const {stderr} = await end(); + + const {summary, rest} = extractSortedSummary(stderr); + expect(wrap(rest)).toMatchSnapshot(); + expect(wrap(summary)).toMatchSnapshot(); +}); diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index acc8139e1eec..2f4f1195310f 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -166,7 +166,12 @@ export default class TestRunner { const worker = new Worker(TEST_WORKER_PATH, { exposedMethods: ['worker'], - forkOptions: {stdio: 'pipe'}, + forkOptions: { + // use advanced serialization in order to transfer objects with circular references + // @ts-expect-error: option does not exist on the node 10 types + serialization: 'advanced', + stdio: 'pipe', + }, maxRetries: 3, numWorkers: this._globalConfig.maxWorkers, setupArgs: [