Skip to content

Commit

Permalink
feat(jest-message-util): add support for error causes (#13868)
Browse files Browse the repository at this point in the history
  • Loading branch information
brodo committed Feb 8, 2023
1 parent 66fb417 commit 68e7025
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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))
Expand Down
Expand Up @@ -112,3 +112,18 @@ exports[`should not exclude vendor from stack trace 1`] = `
<dim> <dim>at Object.asyncFn (</intensity><dim>__tests__/vendor/sulu/node_modules/sulu-content-bundle/best_component.js<dim>:1:5)</intensity><dim></intensity>
"
`;
exports[`should return the error cause if there is one 1`] = `
" <bold>● </intensity>Test suite failed to run
Test exception
<dim>at Object.<anonymous> (</intensity>packages/jest-message-util/src/__tests__/messages.test.ts<dim>:418:17)</intensity>
Cause:
Cause Error
<dim>at Object.<anonymous> (</intensity>packages/jest-message-util/src/__tests__/messages.test.ts<dim>:421:17)</intensity>
"
`;
18 changes: 18 additions & 0 deletions packages/jest-message-util/src/__tests__/messages.test.ts
Expand Up @@ -413,3 +413,21 @@ 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();
});
29 changes: 26 additions & 3 deletions packages/jest-message-util/src/index.ts
Expand Up @@ -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';
Expand Down Expand Up @@ -122,18 +123,20 @@ 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`);
error.stack = '';
}

let message, stack;
let cause = '';

if (typeof error === 'string' || !error) {
error || (error = 'EMPTY ERROR');
Expand All @@ -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 || '');
Expand Down Expand Up @@ -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 = (
Expand Down

0 comments on commit 68e7025

Please sign in to comment.