From 38bb7982d7627ba8376815562bc35599051ce218 Mon Sep 17 00:00:00 2001 From: Dan Beam <251287+danbeam@users.noreply.github.com> Date: Mon, 29 Jan 2024 07:51:34 -0800 Subject: [PATCH] [jest-circus] Omit `expect.hasAssertions()` errors if a test already has errors (#14866) --- CHANGELOG.md | 1 + .../__tests__/jestAdapterInit.test.ts | 46 +++++++++++++++++++ .../__tests__/tsconfig.json | 5 ++ .../jestAdapterInit.ts | 13 ++++-- 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 packages/jest-circus/src/legacy-code-todo-rewrite/__tests__/jestAdapterInit.test.ts create mode 100644 packages/jest-circus/src/legacy-code-todo-rewrite/__tests__/tsconfig.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fa1775c9024..f4060efb0059 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ - `[expect]` Check error instance type for `toThrow/toThrowError` ([#14576](https://github.com/jestjs/jest/pull/14576)) - `[jest-circus]` [**BREAKING**] Prevent false test failures caused by promise rejections handled asynchronously ([#14315](https://github.com/jestjs/jest/pull/14315)) - `[jest-circus]` Replace recursive `makeTestResults` implementation with iterative one ([#14760](https://github.com/jestjs/jest/pull/14760)) +- `[jest-circus]` Omit `expect.hasAssertions()` errors if a test already has errors ([#14866](https://github.com/jestjs/jest/pull/14866)) - `[jest-circus, jest-expect, jest-snapshot]` Pass `test.failing` tests when containing failing snapshot matchers ([#14313](https://github.com/jestjs/jest/pull/14313)) - `[jest-cli]` [**BREAKING**] Validate CLI flags that require arguments receives them ([#14783](https://github.com/jestjs/jest/pull/14783)) - `[jest-config]` Make sure to respect `runInBand` option ([#14578](https://github.com/jestjs/jest/pull/14578)) diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/__tests__/jestAdapterInit.test.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/__tests__/jestAdapterInit.test.ts new file mode 100644 index 000000000000..ef8e599c60d0 --- /dev/null +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/__tests__/jestAdapterInit.test.ts @@ -0,0 +1,46 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {beforeEach, it} from '@jest/globals'; +import type {Circus} from '@jest/types'; +import {eventHandler} from '../jestAdapterInit'; + +beforeEach(() => expect.hasAssertions()); + +it("pushes a hasAssertion() error if there's no assertions/errors", () => { + const event: Circus.Event = { + name: 'test_done', + test: {errors: []} as unknown as Circus.TestEntry, + }; + const beforeLength = event.test.errors.length; + + eventHandler(event); + + expect(event.test.errors).toHaveLength(beforeLength + 1); + expect(event.test.errors).toEqual([ + expect.getState().isExpectingAssertionsError, + ]); +}); + +it("omits hasAssertion() errors if there's already an error", () => { + const errors = [new Error('ruh roh'), new Error('not good')]; + const event: Circus.Event = { + name: 'test_done', + test: {errors} as unknown as Circus.TestEntry, + }; + const beforeLength = event.test.errors.length; + + eventHandler(event); + + expect(event.test.errors).toHaveLength(beforeLength); + expect(event.test.errors).not.toContain( + expect.getState().isExpectingAssertionsError, + ); + + // Ensure test state is not accidentally leaked by e.g. not calling extractExpectedAssertionsErrors() at all. + expect(expect.getState().isExpectingAssertions).toBe(false); +}); diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/__tests__/tsconfig.json b/packages/jest-circus/src/legacy-code-todo-rewrite/__tests__/tsconfig.json new file mode 100644 index 000000000000..facea41430cf --- /dev/null +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/__tests__/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../../../../tsconfig.test.json", + "include": ["./**/*"], + "references": [{"path": "../../../"}] +} diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index 5c71ce1aafa4..7eb6268ca0c8 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -254,7 +254,8 @@ const handleSnapshotStateAfterRetry = } }; -const eventHandler = async (event: Circus.Event) => { +// Exported for direct access from unit tests. +export const eventHandler = async (event: Circus.Event): Promise => { switch (event.name) { case 'test_start': { jestExpect.setState({ @@ -273,9 +274,13 @@ const eventHandler = async (event: Circus.Event) => { }; const _addExpectedAssertionErrors = (test: Circus.TestEntry) => { + const {isExpectingAssertions} = jestExpect.getState(); const failures = jestExpect.extractExpectedAssertionsErrors(); - const errors = failures.map(failure => failure.error); - test.errors = [...test.errors, ...errors]; + if (isExpectingAssertions && test.errors.length > 0) { + // Only show errors from `expect.hasAssertions()` when no other failure has happened. + return; + } + test.errors.push(...failures.map(failure => failure.error)); }; // Get suppressed errors from ``jest-matchers`` that weren't throw during @@ -285,6 +290,6 @@ const _addSuppressedErrors = (test: Circus.TestEntry) => { const {suppressedErrors} = jestExpect.getState(); jestExpect.setState({suppressedErrors: []}); if (suppressedErrors.length > 0) { - test.errors = [...test.errors, ...suppressedErrors]; + test.errors.push(...suppressedErrors); } };