Skip to content

Commit

Permalink
feat(jest-message-util): Add support for Error cause in test and `i…
Browse files Browse the repository at this point in the history
…t` (#13935)
  • Loading branch information
dubzzz committed Feb 24, 2023
1 parent 302d783 commit eccb9b0
Show file tree
Hide file tree
Showing 10 changed files with 487 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,7 @@
- `[jest-config]` Add `openHandlesTimeout` option to configure possible open handles warning. ([#13875](https://github.com/facebook/jest/pull/13875))
- `[@jest/create-cache-key-function]` Allow passing `length` argument to `createCacheKey()` function and set its default value to `16` on Windows ([#13827](https://github.com/facebook/jest/pull/13827))
- `[jest-message-util]` Add support for [AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError) ([#13946](https://github.com/facebook/jest/pull/13946) & [#13947](https://github.com/facebook/jest/pull/13947))
- `[jest-message-util]` Add support for [Error causes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause) in `test` and `it` ([#13935](https://github.com/facebook/jest/pull/13935))
- `[jest-worker]` Add `start` method to worker farms ([#13937](https://github.com/facebook/jest/pull/13937))

### Fixes
Expand Down
124 changes: 124 additions & 0 deletions e2e/__tests__/__snapshots__/failures.test.ts.snap
Expand Up @@ -404,6 +404,130 @@ exports[`works with async failures 1`] = `
at Object.test (__tests__/asyncFailures.test.js:22:1)"
`;
exports[`works with error with cause 1`] = `
"FAIL __tests__/errorWithCause.test.js
✕ error with cause in test
describe block
✕ error with cause in describe/it
✕ error with string cause in describe/it
● error with cause in test
error during f
10 |
11 | function buildErrorWithCause(message: string, opts: {cause: unknown}): Error {
> 12 | const error = new Error(message, opts);
| ^
13 | if (opts.cause !== error.cause) {
14 | // Error with cause not supported in legacy versions of node, we just polyfill it
15 | Object.assign(error, opts);
at buildErrorWithCause (__tests__/errorWithCause.test.js:12:17)
at buildErrorWithCause (__tests__/errorWithCause.test.js:27:11)
at Object.f (__tests__/errorWithCause.test.js:32:3)
Cause:
error during g
19 |
20 | function g() {
> 21 | throw new Error('error during g');
| ^
22 | }
23 | function f() {
24 | try {
at g (__tests__/errorWithCause.test.js:21:9)
at g (__tests__/errorWithCause.test.js:25:5)
at Object.f (__tests__/errorWithCause.test.js:32:3)
describe blockerror with cause in describe/it
error during f
10 |
11 | function buildErrorWithCause(message: string, opts: {cause: unknown}): Error {
> 12 | const error = new Error(message, opts);
| ^
13 | if (opts.cause !== error.cause) {
14 | // Error with cause not supported in legacy versions of node, we just polyfill it
15 | Object.assign(error, opts);
at buildErrorWithCause (__tests__/errorWithCause.test.js:12:17)
at buildErrorWithCause (__tests__/errorWithCause.test.js:27:11)
at Object.f (__tests__/errorWithCause.test.js:37:5)
Cause:
error during g
19 |
20 | function g() {
> 21 | throw new Error('error during g');
| ^
22 | }
23 | function f() {
24 | try {
at g (__tests__/errorWithCause.test.js:21:9)
at g (__tests__/errorWithCause.test.js:25:5)
at Object.f (__tests__/errorWithCause.test.js:37:5)
describe blockerror with string cause in describe/it
with string cause
10 |
11 | function buildErrorWithCause(message: string, opts: {cause: unknown}): Error {
> 12 | const error = new Error(message, opts);
| ^
13 | if (opts.cause !== error.cause) {
14 | // Error with cause not supported in legacy versions of node, we just polyfill it
15 | Object.assign(error, opts);
at buildErrorWithCause (__tests__/errorWithCause.test.js:12:17)
at Object.buildErrorWithCause (__tests__/errorWithCause.test.js:41:11)
Cause:
here is the cause"
`;
exports[`works with error with cause thrown outside tests 1`] = `
"FAIL __tests__/errorWithCauseInDescribe.test.js
● Test suite failed to run
error during f
10 |
11 | function buildErrorWithCause(message: string, opts: {cause: unknown}): Error {
> 12 | const error = new Error(message, opts);
| ^
13 | if (opts.cause !== error.cause) {
14 | // Error with cause not supported in legacy versions of node, we just polyfill it
15 | Object.assign(error, opts);
at buildErrorWithCause (__tests__/errorWithCauseInDescribe.test.js:12:17)
at buildErrorWithCause (__tests__/errorWithCauseInDescribe.test.js:27:11)
at f (__tests__/errorWithCauseInDescribe.test.js:32:3)
at Object.describe (__tests__/errorWithCauseInDescribe.test.js:31:1)
Cause:
error during g
19 |
20 | function g() {
> 21 | throw new Error('error during g');
| ^
22 | }
23 | function f() {
24 | try {
at g (__tests__/errorWithCauseInDescribe.test.js:21:9)
at g (__tests__/errorWithCauseInDescribe.test.js:25:5)
at f (__tests__/errorWithCauseInDescribe.test.js:32:3)
at Object.describe (__tests__/errorWithCauseInDescribe.test.js:31:1)"
`;
exports[`works with node assert 1`] = `
"FAIL __tests__/assertionError.test.js
✕ assert
Expand Down
18 changes: 18 additions & 0 deletions e2e/__tests__/failures.test.ts
Expand Up @@ -6,6 +6,7 @@
*/

import * as path from 'path';
import {isJestJasmineRun} from '@jest/test-utils';
import {extractSummary, runYarnInstall} from '../Utils';
import runJest from '../runJest';

Expand Down Expand Up @@ -93,6 +94,23 @@ test('works with snapshot failures with hint', () => {
).toMatchSnapshot();
});

(isJestJasmineRun() ? test.skip : test)('works with error with cause', () => {
const {stderr} = runJest(dir, ['errorWithCause.test.js']);
const summary = normalizeDots(cleanStderr(stderr));

expect(summary).toMatchSnapshot();
});

(isJestJasmineRun() ? test.skip : test)(
'works with error with cause thrown outside tests',
() => {
const {stderr} = runJest(dir, ['errorWithCauseInDescribe.test.js']);
const summary = normalizeDots(cleanStderr(stderr));

expect(summary).toMatchSnapshot();
},
);

test('errors after test has completed', () => {
const {stderr} = runJest(dir, ['errorAfterTestComplete.test.js']);

Expand Down
45 changes: 45 additions & 0 deletions e2e/failures/__tests__/errorWithCause.test.js
@@ -0,0 +1,45 @@
/**
* 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.
*
*/

'use strict';

function buildErrorWithCause(message: string, opts: {cause: unknown}): Error {
const error = new Error(message, opts);
if (opts.cause !== error.cause) {
// Error with cause not supported in legacy versions of node, we just polyfill it
Object.assign(error, opts);
}
return error;
}

function g() {
throw new Error('error during g');
}
function f() {
try {
g();
} catch (err) {
throw buildErrorWithCause('error during f', {cause: err});
}
}

test('error with cause in test', () => {
f();
});

describe('describe block', () => {
it('error with cause in describe/it', () => {
f();
});

it('error with string cause in describe/it', () => {
throw buildErrorWithCause('with string cause', {
cause: 'here is the cause',
});
});
});
33 changes: 33 additions & 0 deletions e2e/failures/__tests__/errorWithCauseInDescribe.test.js
@@ -0,0 +1,33 @@
/**
* 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.
*
*/

'use strict';

function buildErrorWithCause(message: string, opts: {cause: unknown}): Error {
const error = new Error(message, opts);
if (opts.cause !== error.cause) {
// Error with cause not supported in legacy versions of node, we just polyfill it
Object.assign(error, opts);
}
return error;
}

function g() {
throw new Error('error during g');
}
function f() {
try {
g();
} catch (err) {
throw buildErrorWithCause('error during f', {cause: err});
}
}

describe('error with cause in describe', () => {
f();
});
1 change: 1 addition & 0 deletions e2e/transform/transform-esm-testrunner/test-runner.mjs
Expand Up @@ -23,6 +23,7 @@ export default async function testRunner(
{
ancestorTitles: [],
duration: 2,
failureDetails: [],
failureMessages: [],
fullName: 'sample test',
location: null,
Expand Down
1 change: 1 addition & 0 deletions e2e/transform/transform-testrunner/test-runner.ts
Expand Up @@ -24,6 +24,7 @@ export default async function testRunner(
{
ancestorTitles: [],
duration: 2,
failureDetails: [],
failureMessages: [],
fullName: 'sample test',
location: null,
Expand Down
Expand Up @@ -40,6 +40,46 @@ exports[`formatStackTrace prints code frame and stacktrace 1`] = `
"
`;
exports[`formatStackTrace should properly handle deeply nested causes 1`] = `
"<bold><red> <bold>● </intensity><bold>Error with cause test</color></intensity>
intercepted by f
<dim></intensity>
<dim> <dim>at f (</intensity><dim>cause.test.js<dim>:15:11)</intensity><dim></intensity>
<dim> <dim>at Object.f (</intensity><dim>cause.test.js<dim>:20:5)</intensity><dim></intensity>
Cause:
intercepted by g
<dim></intensity>
<dim> <dim>at g (</intensity><dim>cause.test.js<dim>:8:11)</intensity><dim></intensity>
<dim> <dim>at g (</intensity><dim>cause.test.js<dim>:13:5)</intensity><dim></intensity>
<dim> <dim>at Object.f (</intensity><dim>cause.test.js<dim>:20:5)</intensity><dim></intensity>
Cause:
boom
<dim></intensity>
<dim> <dim>at h (</intensity><dim>cause.test.js<dim>:2:9)</intensity><dim></intensity>
<dim> <dim>at h (</intensity><dim>cause.test.js<dim>:6:5)</intensity><dim></intensity>
<dim> <dim>at g (</intensity><dim>cause.test.js<dim>:13:5)</intensity><dim></intensity>
<dim> <dim>at Object.f (</intensity><dim>cause.test.js<dim>:20:5)</intensity><dim></intensity>
"
`;
exports[`formatStackTrace should properly handle string causes 1`] = `
"<bold><red> <bold>● </intensity><bold>Error with string cause test</color></intensity>
boom
<dim></intensity>
<dim> <dim>at f (</intensity><dim>cause.test.js<dim>:15:11)</intensity><dim></intensity>
<dim> <dim>at Object.f (</intensity><dim>cause.test.js<dim>:20:5)</intensity><dim></intensity>
Cause:
string cause
<dim></intensity>
<dim></intensity>
"
`;
exports[`formatStackTrace should strip node internals 1`] = `
"<bold><red> <bold>● </intensity><bold>Unix test</color></intensity>
Expand Down Expand Up @@ -76,16 +116,16 @@ exports[`on node >=15.0.0 should return the inner errors of an AggregateError 1`
AggregateError:
<dim>at Object.<anonymous> (</intensity>packages/jest-message-util/src/__tests__/messages.test.ts<dim>:440:22)</intensity>
<dim>at Object.<anonymous> (</intensity>packages/jest-message-util/src/__tests__/messages.test.ts<dim>:588:22)</intensity>
Errors contained in AggregateError:
Err 1
<dim>at Object.<anonymous> (</intensity>packages/jest-message-util/src/__tests__/messages.test.ts<dim>:441:7)</intensity>
<dim>at Object.<anonymous> (</intensity>packages/jest-message-util/src/__tests__/messages.test.ts<dim>:589:7)</intensity>
Err 2
<dim>at Object.<anonymous> (</intensity>packages/jest-message-util/src/__tests__/messages.test.ts<dim>:442:7)</intensity>
<dim>at Object.<anonymous> (</intensity>packages/jest-message-util/src/__tests__/messages.test.ts<dim>:590:7)</intensity>
"
`;
Expand Down Expand Up @@ -137,12 +177,12 @@ exports[`should return the error cause if there is one 1`] = `
Test exception
<dim>at Object.<anonymous> (</intensity>packages/jest-message-util/src/__tests__/messages.test.ts<dim>:419:17)</intensity>
<dim>at Object.<anonymous> (</intensity>packages/jest-message-util/src/__tests__/messages.test.ts<dim>:567:17)</intensity>
Cause:
Cause Error
<dim>at Object.<anonymous> (</intensity>packages/jest-message-util/src/__tests__/messages.test.ts<dim>:422:17)</intensity>
<dim>at Object.<anonymous> (</intensity>packages/jest-message-util/src/__tests__/messages.test.ts<dim>:570:17)</intensity>
"
`;

0 comments on commit eccb9b0

Please sign in to comment.