jest: beforeAll() executed in parallel with test case in case of timeout

🐛 Bug Report

Test case is executed even if beforeAll did not finish.

To Reproduce

This test file:

beforeAll(async () => new Promise((resolve, reject) => {
  // Never resolves
}));

test('test case', async () => {
  console.log('should never be executed');
});

Displays this:

% npx jest t.spec.js
 FAIL  ./t.spec.js (5.415s)
  ✕ test case (8ms)

  ● test case

    Timeout - Async callback was not invoked within the 5000ms timeout specified by jes
t.setTimeout.Error: Timeout - Async callback was not invoked within the 5000ms timeout 
specified by jest.setTimeout.

      at mapper (node_modules/jest-jasmine2/build/queueRunner.js:25:45)

  console.log t.spec.js:6
    should never be executed

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        5.436s, estimated 6s
Ran all test suites matching /t.spec.js/i.

Expected behavior

Test case code should never be executed because beforeAll() did not finish. The error message should be at the beforeAll level and not at the test case level. This is very confusing as you may think that the test case itself failed when in reality it has nothing to do with the test case.

Link to repl or repo (highly encouraged)

https://repl.it/repls/KindlyAutomaticLocation

envinfo

% npx envinfo --preset jest
npx: installed 1 in 0.645s

  System:
    OS: Linux 5.3 Manjaro Linux
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
  Binaries:
    Node: 13.7.0 - /usr/bin/node
    Yarn: 1.21.1 - /usr/bin/yarn
    npm: 6.13.6 - /usr/bin/npm
  npmPackages:
    jest: ^24.9.0 => 24.9.0 

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 39
  • Comments: 36 (9 by maintainers)

Commits related to this issue

Most upvoted comments

Our company lost 4 man-days of development because of this bug. Please fix this so others don’t suffer the same fate. Return proper error for this and don’t run test if beforeAll etc timeouts. So they know that they need to put bigger timeout as second argument for beforeAll and afterAll etc.

I’m facing this issue. Agree with @albert-schilling. There is no point in testing being run before preparation (beforeAll and beforeEach) is complete.

@hananmalka Use bigger timeout. beforeEach should also support timeout in milliseconds as second argument. So example beforeEach(function {...}, 60000); for 1 minute timeout.

I have the same issue. Planned on using a deleteAllEntries() function to clean my collection in db before tests and placed the function in beforeAll(), but apparently other test functions are already adding entries to the db, while deleteAllEntries() has not yet finished.

The parallel execution of beforeAll() and afterAll() with the tests somehow defies their inherent purpose?

Anyone found a good solution to this?

For anyone else having trouble with this, the problematic behavior comes from the default Jasmine2 test runner. Specifying jest-circus as your test runner will stop tests from running when a before hook fails, and yields a more intelligible error. To run your tests with jest-circus, from the root of your project run yarn add jest-circus, and pass in the appropriate CLI option whenever you invoke jest:

yarn jest --testRunner=jest-circus/runner [...other options]

Alternatively, add the following to your jest config file:

{
//...your other config options
"testRunner": "jest-circus/runner"
}

We have been bitten by this unexpected behaviour as well, here is a simple repro case where the log output will show the improper sequencing

//Keeping default jest timeout of 5s

beforeAll(async () => {
  console.log("In beforeAll, starting sleep");
  await sleep(12);
  console.log("beforeAll finally finished sleeping");
});

describe("outerDescribe", () => {
  beforeEach(async () => {
    console.log("In beforeEach, starting sleep");
    await sleep(6);
    console.log("beforeEach finally finished sleeping");
  });
  describe("innerDescribe", () => {
    it("Does absolutely nothing useful", () => {
      console.log("Executing testcase 1");
    });
    it("Also does nothing useful", () => {
      console.log("Executing testcase 2");
    });
  });
});

function sleep(seconds) {
  return new Promise(resolve => setTimeout(resolve, seconds * 1000));
}

Output: In beforeAll, starting sleep In beforeEach, starting sleep Executing testcase 1 Error: Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout. console.log app/tests/test.js:9 In beforeEach, starting sleep beforeEach finally finished sleeping beforeAll finally finished sleeping Executing testcase 2 Error: Timeout - Async callback was not invoked within the 5000ms timeout specified by

I guess the problem in your example is you’re never resolving the promise and the global timeout is firing because of that. What I’ve catched here is similar but different since my test case was running in parallel with beforeAll even I’m respecting the 5s limit and, a variable that might be defined by beforeAll was being used before it was ready. That way, my test case failed saying that variable X wasn’t defined. In a tweet, I think the issue here is jest isn’t respecting the execution order of a global beforeAll (out of any scope).

Same with using beforeEach().

Anyone found any workaround for this? At least until it will be fixed?

I’m facing the same issue in beforEach() when running playwright tests