91

Jest states in docs: "Jest virtualizes JavaScript environments and runs tests in parallel across worker processes."

But what about multiple tests inside one file, do they run in parallel or this statement applies just to the test files? Can I assume that tests in one file run in order of appearance and in serial?

Jarda
  • 1,188
  • 1
  • 7
  • 12

6 Answers6

74

You can safely assume tests inside a single file will run in the order of appearance. You could prove this by putting a console.log in each it block.

It's probably worth mentioning that it's generally bad practice to rely on the order of execution / external state...and you never know, Jest (or the current underlying test runner, Jasmine) may decide to run them in a random order in a newer version.

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
Richard Scarrott
  • 6,638
  • 1
  • 35
  • 46
  • Even now, using `only` and `skip` may become troublesome if you rely on order of execution. – Shawn Jan 17 '18 at 22:30
  • 60
    Well, the problem is, that `beforeEach` and `afterEach` would be useless in a variety of cases when tests are `async` functions, because if Jest were to run `async` tests in parallel, then it's no longer possible to reset state or clean up after each test, which would make testing very prone to bugs. `beforeEach` and `afterEach` serve to set up or clean up between tests, and in order for this to be meaningful, tests need to be executed in series, not in parallel. It would be a bad API design for Jest (or any runner) to run `async` function tests in parallel... – trusktr Feb 19 '18 at 02:03
  • @trusktr `beforeEach` `it` and `afterEach` etc. would obviously need to be run in series, but each individual `it` could be run in parallel if this proved to be more efficient. – Richard Scarrott Feb 21 '18 at 11:05
  • 13
    By the way @trusktr Jest DOES run tests in parallel, just not ones in the same file. So you can run into issues with interference between tests if they are running on the same database. – Dobes Vandermeer Aug 09 '18 at 05:16
  • But is there an optional switch maybe to enable running test from the same file in parallel? – jayarjo Nov 25 '18 at 08:22
  • @trusktr I'm facing the same issue regarding database migration and cleanup on beforeEach tests. Did you find a way to sort it out? – Jaime Sangcap Nov 27 '18 at 15:16
  • @DobesVandermeer did you find a way to manage the test when running database cleanup on each tests? – Jaime Sangcap Nov 27 '18 at 15:17
  • 4
    @JaimeSangcap We currently use a different database for each test suite. In the jest config we have `setupFiles: ['/src/testing/integration/targetRandomDatabase.js'],` and in `targetRandomDatabase.js` we set a random fresh database URL each time. The setup files are run separately for each test suite, so this prevents interference. We use `mongodb-memory-server` to run a fresh mongodb for each run of jest, so the databases are thrown away automatically. – Dobes Vandermeer Nov 28 '18 at 19:03
  • 3
    @JaimeSangcap Sorry, I moved to Karma. – trusktr Nov 29 '18 at 01:57
  • @DobesVandermeer thank you, I will be implementing the same, just create fresh database and delete it after. – Jaime Sangcap Nov 29 '18 at 11:05
  • 1
    @trusktr So Karma supports running tests sequently? Any other testing framework to recommend? Thanks. – LiweiZ Jan 18 '19 at 22:30
  • 1
    @LiweiZ inside the same file, they are sequential. It may run different test files in parallel. I recommend Karma with an electron runner, because it has Node.js APIs, Electron APIs, and real (not mock) browser APIs all in one. Other setups (f.e. using jsdom) have mock browser API, and when some API is missing then you're out of luck. For example, imagine DOM code coupled to WebGL API calls. good luck mocking that out! No problem with an electron-runner, because the WebGL APIs will be there. – trusktr Jan 24 '19 at 23:55
  • @trusktr Thank you very much for taking your time on the confirmation and further explanation. Very helpful. – LiweiZ Jan 25 '19 at 01:03
  • 9
    The `--runInBand` CLI flag prevents jest from running files in parallel – Matthias Mar 21 '19 at 05:17
  • So I have been able to prove that a DB call that gets stalled will allow another test to start before the first finishes. It is calling major problems. Is there anyway to be COMPLETELY sure this does not happen? – R Claven Mar 10 '20 at 19:52
  • @RClaven you must make sure you return a promise in the test so jest is aware something async is happening. – Richard Scarrott Mar 12 '20 at 15:30
  • @riscarrott thanks for the answer I have a question I am working on application which have redux implemented too now in jest tests what I am doing is I am right now dependent on previes tests to provide the new it block data. the reason for this is I have imported the store from live appication to jest and I am initiating it on beforeeach althouch mount is changing on eash it but imported store is the same for all the it blocks please let me know how I can reset the store for each it – Hitesh Ranaut Oct 01 '21 at 09:04
  • beforeEach and AfterEach are not strictly barred from running in parallel. The issue is the current way requires you to create shared variables that are assigned via closure. If each test had a context such as a `this` in the before/afterEach then we could avoid the collisions on shared variables. – Mike Graf May 15 '23 at 14:26
39

Jest in 2020

To add a bit more information on this, async tests are run in series inside of a describe() statement. This is useful for IO/Database setup and cleanup functions. Just take a look at the following example:

some.spec.js

describe("my asynchronous tests", () => {
  beforeEach(async () => {
    console.log('> setup test')
    // SOMETHING ASYNCHRONOUS
  });
  afterEach(async () => {
    console.log('< teardown test')
    // SOMETHING ASYNCHRONOUS
  });

  test("test 1", async () => {
    console.log('-- starting test 1');
    // SOMETHING ASYNCHRONOUS
    console.log('-- finished test 1');
  }, 100000);

  test("test 2", async () => {
    console.log('-- starting test 2');
    // SOMETHING ASYNCHRONOUS
    console.log('-- finished test 2');
  }, 100000);
});

Outputs:

> setup test
-- starting test 1
-- finished test 1
< teardown test
> setup test
-- starting test 2
-- finished test 2
< teardown test

Multiple describe() statements will execute in parallel though, even if they're in the same file.

Ben Winding
  • 10,208
  • 4
  • 80
  • 67
  • 4
    " Multiple describe() statements will execute in parallel though, even if they're in the same file. ", I tried two `describe()` in one test file, and first `describe` has a async test case, but found they execute in series. – smilebuz May 08 '20 at 07:11
  • 2
    I wrongly assumed that `describe` statements were the highest level, I guess each file's tests are executed in series regardless of `describe` wrappers – Ben Winding May 09 '20 at 02:22
16

Note, you may get side effects of two tests running in parallel if one of them times out after 5 seconds - jest stops waiting for the timed out test, but it's code continues executing, in parallel with the following test jest picks up.

(pulled out quite an amount of hair before I realised that this was the reason of the side effects that led me here)

Klesun
  • 12,280
  • 5
  • 59
  • 52
  • 1
    Where is this documented? – ZiiMakc Oct 13 '21 at 21:10
  • 1
    Additionally, `afterAll` is called when the test timeouts, but the async code will finish executing, so if you are doing things in `afterAll`, such as disconnecting your database connection, you might get error messages intermixed with subsequent test. You can fix this by calling jest with `--bail 1` – Zikoat May 03 '22 at 08:41
10

You can use test.concurrent('test run concurrently', () => { ... }) if you want to run them in parallel inside one file is too slow. It is a bit buggy and not well documented, but at least there's a way there.

One thing I notice is it does not wait for async stuff in the beforeAll() so you need some of your own trick(like setInterval to wait) to make it work as expected.

LeOn - Han Li
  • 9,388
  • 1
  • 65
  • 59
  • 2
    That saved my day! Each test of mine is running in an isolated environment (a separate temporary database) so this really speeds things up. Especially if you consider that each test runs for 500 ms. – Slava Fomin II Mar 28 '23 at 20:25
  • Are you sure you are awaiting? This could be a bug in jest. – Phil Jul 09 '23 at 11:16
6

To make test files run sequentially use -i or --runInBand flag

jest --runInBand

ref: jest docs

Weirdly enough, running the tests sequentially finishes faster on my M1 Mac!, better test for you use case

Ali80
  • 6,333
  • 2
  • 43
  • 33
  • 2
    This does not answer the question. OP is asking if tests run sequentially if they are in one file rather than being in different files in which case it should run in parallel by default as stated in JEST docs. – Sphinx Jan 13 '22 at 18:24
  • 1
    @Sphinx the question seems to be looking for a way to make sure the tests are run sequentially at least in one file, I was also looking for the same thing! – Ali80 Jan 15 '22 at 11:40
  • 1
    Thanks for this, helped me fix a bunch of errors I've been getting because my tests were running in parallel. – dokgu Mar 08 '23 at 20:03
0

Some additional info to @Klesun answer. One can repeat this with following

test('first test', async () => {
    console.error('first test before waitFor');
    try {
        await waitFor(async () => { throw new Error(''); }, { timeout: 6000 });
    } catch (e) { }
    console.error('first test after waitFor');
}, 5000);

test('second test', async () => {
    console.error('second test before timeout');
    await new Promise((r) => setTimeout(r, 6100));
    console.error('second test after timeout');
}, 6200);

Where the output will be:

first test before waitFor
second test before timeout
first test after waitFor
second test after timeout

Removing setTimeout from second test will hide "first test after waitFor" since test for this file will be finished.

Additionally this causes true cause of failure to be somewhat hidden. For example if we remove try ... catch the only thing that will be reported to us will be thrown: "Exceeded timeout of 5000 ms for a test. for test('first test', async () => { and not exact spot (waitFor in this case). This can be a bit cumbersome to track in longer running tests. I would expect that the best path to track where error lies in these cases would be to increase test timeout.

primus
  • 30
  • 4