diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dc1ac98bc44..b7889b8dacd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ ### Fixes +- `[expect]` Show `AggregateError` to display ([#15346](https://github.com/facebook/jest/pull/15346)) - `[*]` Replace `exit` with `exit-x` ([#15399](https://github.com/jestjs/jest/pull/15399)) - `[babel-plugin-jest-hoist]` Use `denylist` instead of the deprecated `blacklist` for Babel 8 support ([#14109](https://github.com/jestjs/jest/pull/14109)) - `[babel-plugin-jest-hoist]` Do not rely on buggy Babel behaviour ([#15415](https://github.com/jestjs/jest/pull/15415)) diff --git a/packages/expect/src/__tests__/toThrowMatchers.test.ts b/packages/expect/src/__tests__/toThrowMatchers.test.ts index 54339e38b74c..5685771c7ac4 100644 --- a/packages/expect/src/__tests__/toThrowMatchers.test.ts +++ b/packages/expect/src/__tests__/toThrowMatchers.test.ts @@ -363,6 +363,36 @@ describe('toThrow', () => { }); }); + describe('aggregate-errors', () => { + const fetchFromApi1 = Promise.reject(new Error('API 1 failed')); + const fetchFromApi2 = Promise.reject(new Error('API 2 failed')); + const promiseAny = Promise.any([fetchFromApi1, fetchFromApi2]); + + test('string', () => { + jestExpect(promiseAny).rejects.toThrow('All promises were rejected'); + }); + + test('undefined', () => { + jestExpect(promiseAny).rejects.toThrow(); + }); + + test('asymmetricMatch', () => { + jestExpect(promiseAny).rejects.toThrow( + expect.objectContaining({ + message: 'All promises were rejected', + }), + ); + }); + + test('regexp', () => { + jestExpect(promiseAny).rejects.toThrow(/All promises were rejected/); + }); + + test('class', () => { + jestExpect(promiseAny).rejects.toThrow(AggregateError); + }); + }); + describe('asymmetric', () => { describe('any-Class', () => { describe('pass', () => { diff --git a/packages/expect/src/__tests__/tsconfig.json b/packages/expect/src/__tests__/tsconfig.json index 3e19aea5423e..082b9d01c3c3 100644 --- a/packages/expect/src/__tests__/tsconfig.json +++ b/packages/expect/src/__tests__/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../../../tsconfig.test.json", "compilerOptions": { - "lib": ["es2022.error"], + "lib": ["es2022.error", "es2021.promise"], "types": ["node", "@jest/test-globals"] }, "include": ["./**/*"], diff --git a/packages/expect/src/toThrowMatchers.ts b/packages/expect/src/toThrowMatchers.ts index 50bf4a3c8427..9c6ec8989625 100644 --- a/packages/expect/src/toThrowMatchers.ts +++ b/packages/expect/src/toThrowMatchers.ts @@ -18,7 +18,11 @@ import { printReceived, printWithType, } from 'jest-matcher-utils'; -import {formatStackTrace, separateMessageFromStack} from 'jest-message-util'; +import { + formatExecError, + formatStackTrace, + separateMessageFromStack, +} from 'jest-message-util'; import { printExpectedConstructorName, printExpectedConstructorNameNot, @@ -451,19 +455,28 @@ const formatReceived = ( return ''; }; -const formatStack = (thrown: Thrown | null) => - thrown === null || !thrown.isError - ? '' - : formatStackTrace( +const formatStack = (thrown: Thrown | null) => { + if (thrown === null || !thrown.isError) { + return ''; + } else { + const config = { + rootDir: process.cwd(), + testMatch: [], + }; + const options = { + noStackTrace: false, + }; + if (thrown.value instanceof AggregateError) { + return formatExecError(thrown.value, config, options); + } else { + return formatStackTrace( separateMessageFromStack(thrown.value.stack!).stack, - { - rootDir: process.cwd(), - testMatch: [], - }, - { - noStackTrace: false, - }, + config, + options, ); + } + } +}; function createMessageAndCause(error: Error) { if (error.cause) {