From e893b26bdd726a84a7e6720525ba6349699ab9ab Mon Sep 17 00:00:00 2001 From: Julian Dax Date: Tue, 7 Feb 2023 15:26:04 +0100 Subject: [PATCH 1/3] feat(jest-message-util): add support for error causes --- CHANGELOG.md | 1 + .../__snapshots__/messages.test.ts.snap | 15 ++++++++ .../src/__tests__/messages.test.ts | 36 +++++++++++++++++++ packages/jest-message-util/src/index.ts | 29 +++++++++++++-- 4 files changed, 78 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4c3d7053925..47506e2c9b61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Features - `[@jest/core]` Instrument significant lifecycle events with [`performance.mark()`](https://nodejs.org/docs/latest-v16.x/api/perf_hooks.html#performancemarkname-options) ([#13859](https://github.com/facebook/jest/pull/13859)) +- `[jest-message-util]` Add support for [error causes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause) ### Fixes diff --git a/packages/jest-message-util/src/__tests__/__snapshots__/messages.test.ts.snap b/packages/jest-message-util/src/__tests__/__snapshots__/messages.test.ts.snap index 0add9fd94e0c..9f629042d425 100644 --- a/packages/jest-message-util/src/__tests__/__snapshots__/messages.test.ts.snap +++ b/packages/jest-message-util/src/__tests__/__snapshots__/messages.test.ts.snap @@ -112,3 +112,18 @@ exports[`should not exclude vendor from stack trace 1`] = ` at Object.asyncFn (__tests__/vendor/sulu/node_modules/sulu-content-bundle/best_component.js:1:5) " `; + +exports[`should return the error cause if there is one 1`] = ` +" ● Test suite failed to run + + Test exception + + at Object. (packages/jest-message-util/src/__tests__/messages.test.ts:418:17) + + Cause: + Cause Error + + at Object. (packages/jest-message-util/src/__tests__/messages.test.ts:421:17) + +" +`; diff --git a/packages/jest-message-util/src/__tests__/messages.test.ts b/packages/jest-message-util/src/__tests__/messages.test.ts index 7eeabb8dc159..bb2b9d9eb3fe 100644 --- a/packages/jest-message-util/src/__tests__/messages.test.ts +++ b/packages/jest-message-util/src/__tests__/messages.test.ts @@ -413,3 +413,39 @@ it('getTopFrame should return a path for mjs files', () => { expect(frame!.file).toBe(expectedFile); }); + +it('should return the error cause if there is one', () => { + const error = new Error('Test exception'); + // TODO pass `cause` to the `Error` constructor when lowest supported Node version is 16.9.0 and above + // See https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_V16.md#error-cause + error.cause = new Error('Cause Error'); + const message = formatExecError( + error, + { + rootDir: '', + testMatch: [], + }, + { + noStackTrace: false, + }, + ); + expect(message).toMatchSnapshot(); +}); + +it('should print all the errors contained in an AggregateError', () => { + const error = new AggregateError([ + new Error('error 1'), + new Error('error 2'), + ]); + const message = formatExecError( + error, + { + rootDir: '', + testMatch: [], + }, + { + noStackTrace: false, + }, + ); + console.log(message); +}); diff --git a/packages/jest-message-util/src/index.ts b/packages/jest-message-util/src/index.ts index 7ef98dda1931..7cb21f7cde53 100644 --- a/packages/jest-message-util/src/index.ts +++ b/packages/jest-message-util/src/index.ts @@ -7,6 +7,7 @@ import * as path from 'path'; import {fileURLToPath} from 'url'; +import {types} from 'util'; import {codeFrameColumns} from '@babel/code-frame'; import chalk = require('chalk'); import * as fs from 'graceful-fs'; @@ -122,11 +123,12 @@ function warnAboutWrongTestEnvironment(error: string, env: 'jsdom' | 'node') { // `before/after each` hooks). If it's thrown, none of the tests in the file // are executed. export const formatExecError = ( - error: Error | TestResult.SerializableError | string | undefined, + error: Error | TestResult.SerializableError | string | number | undefined, config: StackTraceConfig, options: StackTraceOptions, testPath?: string, reuseMessage?: boolean, + noTitle?: boolean, ): string => { if (!error || typeof error === 'number') { error = new Error(`Expected an Error, but "${String(error)}" was thrown`); @@ -134,6 +136,7 @@ export const formatExecError = ( } let message, stack; + let cause = ''; if (typeof error === 'string' || !error) { error || (error = 'EMPTY ERROR'); @@ -145,6 +148,25 @@ export const formatExecError = ( typeof error.stack === 'string' ? error.stack : `thrown: ${prettyFormat(error, {maxDepth: 3})}`; + if ('cause' in error) { + const prefix = '\n\nCause:\n'; + if (typeof error.cause === 'string' || typeof error.cause === 'number') { + cause += `${prefix}${error.cause}`; + } else if (types.isNativeError(error.cause)) { + const formatted = formatExecError( + error.cause, + config, + options, + testPath, + reuseMessage, + true, + ); + cause += `${prefix}${formatted}`; + } + } + } + if (cause !== '') { + cause = indentAllLines(cause); } const separated = separateMessageFromStack(stack || ''); @@ -174,13 +196,14 @@ export const formatExecError = ( let messageToUse; - if (reuseMessage) { + if (reuseMessage || noTitle) { messageToUse = ` ${message.trim()}`; } else { messageToUse = `${EXEC_ERROR_MESSAGE}\n\n${message}`; } + const title = noTitle ? '' : `${TITLE_INDENT + TITLE_BULLET}`; - return `${TITLE_INDENT + TITLE_BULLET + messageToUse + stack}\n`; + return `${title + messageToUse + stack + cause}\n`; }; const removeInternalStackEntries = ( From 01c1b2aa0415c4f9644fe9bb7e2ab53452972cae Mon Sep 17 00:00:00 2001 From: Julian Dax Date: Wed, 8 Feb 2023 10:42:20 +0100 Subject: [PATCH 2/3] feat(jest-message-util): add support for error causes --- .../src/__tests__/messages.test.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/packages/jest-message-util/src/__tests__/messages.test.ts b/packages/jest-message-util/src/__tests__/messages.test.ts index bb2b9d9eb3fe..03bf68d6153b 100644 --- a/packages/jest-message-util/src/__tests__/messages.test.ts +++ b/packages/jest-message-util/src/__tests__/messages.test.ts @@ -431,21 +431,3 @@ it('should return the error cause if there is one', () => { ); expect(message).toMatchSnapshot(); }); - -it('should print all the errors contained in an AggregateError', () => { - const error = new AggregateError([ - new Error('error 1'), - new Error('error 2'), - ]); - const message = formatExecError( - error, - { - rootDir: '', - testMatch: [], - }, - { - noStackTrace: false, - }, - ); - console.log(message); -}); From e3d439f3ad13adecae5e12accdeb13f9d8d2da2e Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 8 Feb 2023 11:41:40 +0100 Subject: [PATCH 3/3] move changelog entry --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d821aee1562..03ef13cafa2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Features +- `[jest-message-util]` Add support for [error causes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause) + ### Fixes - `[jest-mock]` Clear mock state when `jest.restoreAllMocks()` is called ([#13867](https://github.com/facebook/jest/pull/13867)) @@ -15,7 +17,6 @@ ### Features - `[@jest/core]` Instrument significant lifecycle events with [`performance.mark()`](https://nodejs.org/docs/latest-v16.x/api/perf_hooks.html#performancemarkname-options) ([#13859](https://github.com/facebook/jest/pull/13859)) -- `[jest-message-util]` Add support for [error causes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause) ### Fixes