diff --git a/CHANGELOG.md b/CHANGELOG.md index 36585ad88d65..bbfa3ec54860 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixes - `[expect, @jest/expect]` Provide type of `actual` as a generic argument to `Matchers` to allow better-typed extensions ([#13848](https://github.com/facebook/jest/pull/13848)) +- `[jest-circus]` Added explicit mention of test failing because `done()` is not being called in error message ([#13847](https://github.com/facebook/jest/pull/13847)) ### Chore & Maintenance diff --git a/e2e/__tests__/__snapshots__/timeouts.test.ts.snap b/e2e/__tests__/__snapshots__/timeouts.test.ts.snap index 45abed912e71..70a79392c7cc 100644 --- a/e2e/__tests__/__snapshots__/timeouts.test.ts.snap +++ b/e2e/__tests__/__snapshots__/timeouts.test.ts.snap @@ -41,3 +41,11 @@ Snapshots: 0 total Time: <> Ran all test suites." `; + +exports[`exceeds the timeout specifying that \`done\` has not been called 1`] = ` +"Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites." +`; diff --git a/e2e/__tests__/timeouts.test.ts b/e2e/__tests__/timeouts.test.ts index 0e28573f7185..b15f08bf6270 100644 --- a/e2e/__tests__/timeouts.test.ts +++ b/e2e/__tests__/timeouts.test.ts @@ -107,3 +107,24 @@ test('does not exceed the command line testTimeout', () => { expect(summary).toMatchSnapshot(); expect(exitCode).toBe(0); }); + +test('exceeds the timeout specifying that `done` has not been called', () => { + writeFiles(DIR, { + '__tests__/a-banana.js': ` + jest.setTimeout(20); + + test('banana', (done) => { + expect(1 + 1).toBe(2); + }); + `, + 'package.json': '{}', + }); + + const {stderr, exitCode} = runJest(DIR, ['-w=1', '--ci=false']); + const {rest, summary} = extractSummary(stderr); + expect(rest).toMatch( + /(jest\.setTimeout|Exceeded timeout\.while waiting for `done()` to be called)/, + ); + expect(summary).toMatchSnapshot(); + expect(exitCode).toBe(1); +}); diff --git a/packages/jest-circus/src/utils.ts b/packages/jest-circus/src/utils.ts index d45bf21e91f5..65c9a295dc66 100644 --- a/packages/jest-circus/src/utils.ts +++ b/packages/jest-circus/src/utils.ts @@ -171,9 +171,15 @@ export const describeBlockHasTests = ( child => child.type === 'test' || describeBlockHasTests(child), ); -const _makeTimeoutMessage = (timeout: number, isHook: boolean) => +const _makeTimeoutMessage = ( + timeout: number, + isHook: boolean, + takesDoneCallback: boolean, +) => `Exceeded timeout of ${formatTime(timeout)} for a ${ isHook ? 'hook' : 'test' + }${ + takesDoneCallback && ' while waiting for `done()` to be called' }.\nUse jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test.`; // Global values can be overwritten by mocks or tests. We'll capture @@ -193,16 +199,17 @@ export const callAsyncCircusFn = ( let completed = false; const {fn, asyncError} = testOrHook; + const doneCallback = takesDoneCallback(fn); return new Promise((resolve, reject) => { timeoutID = setTimeout( - () => reject(_makeTimeoutMessage(timeout, isHook)), + () => reject(_makeTimeoutMessage(timeout, isHook, doneCallback)), timeout, ); // If this fn accepts `done` callback we return a promise that fulfills as // soon as `done` called. - if (takesDoneCallback(fn)) { + if (doneCallback) { let returnedValue: unknown = undefined; const done = (reason?: Error | string): void => {