288

I'm running Jest tests via npm test. Jest runs tests in parallel by default. Is there any way to make the tests run sequentially?

I have some tests calling third-party code that relies on changing the current working directory.

Martin Konicek
  • 39,126
  • 20
  • 90
  • 98

12 Answers12

375

CLI options are documented and also accessible by running the command jest --help.

You'll see the option you are looking for : --runInBand.

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
ncuillery
  • 14,308
  • 2
  • 22
  • 31
  • 13
    Thanks a lot! Is it `npm test --runInBand`? Offtopic: Not sure where the name "band" comes from. --runSequentially would probably make more sense :) – Martin Konicek Jan 21 '17 at 05:33
  • 23
    @MartinKonicek `npm test -- --runInBand` is correct. – Ondrej Slinták Feb 22 '17 at 15:49
  • 1
    Can anyone comment on how to make the Jest run files in a specific order? I tried changing the filenames but it doesn't have any effect. – Brennan Cheung Mar 13 '18 at 02:41
  • 1
    Jest "learns" the fastest order from the previous executions. I don't think it is possible to change that because this is pretty bad: every test in your test suite shouldn't depend on whether the others are executed or not. – ncuillery Mar 13 '18 at 22:38
  • 74
    Unfortunately, the fact that execution order can't be controlled makes Jest pretty much useless for integration tests. – Evan Byrne Jul 06 '18 at 18:43
  • @EvanByrne what I did was to create a "def file" for each spec file, with functions that correspond to user actions. Then, each def file references other defs which has previous actions needed. So my specs only contain a call to a specific action + testing of that, everything else is in those other files – Bernardo Dal Corno Dec 05 '18 at 19:49
  • @Z.Khullah can you please give an example for that – Mustafa Magdy Jan 06 '19 at 07:17
  • 1
    You can use `isSerial` if you implement your own test runner. See https://jestjs.io/docs/en/configuration#runner-string – mmell Feb 13 '19 at 21:48
  • 53
    @Evan The fact you need your tests run in a certain order is a smell. – Nico Van Belle Jun 03 '19 at 18:25
  • 69
    @NicoVanBelle It's simply the price you pay for true end-to-end testing of sufficiently complex stateful systems. I'm open to alternatives, but I have yet to see a solution that doesn't either involve naively swapping out key parts of the stack or prohibitively slow database resets between tests. Doesn't mean Jest is a bad tool, just the wrong one for this particular kind of test. – Evan Byrne Jun 04 '19 at 17:56
  • There is a ready-made serial test runner you can install. See my answer below. – Joachim Lous Nov 07 '19 at 08:05
  • 9
    @EvanB. Good news! As of Jest version 24.7.0, you can now provide your own `TestSequencer` and set any order that you want: https://github.com/facebook/jest/issues/6194#issuecomment-479356058 We created a `RandomTestSequencer` and then just set it with configuration `testSequencer: 'path/to/RandomTestSequencer.js'`. – Joshua Pinter Apr 11 '20 at 18:07
  • You can use @kmnowak 's answer to truly serialize E2E testing on Jest. I'm using it. And it works fine. – Lucio Mollinedo May 02 '21 at 16:58
  • @NicoVanBelle: Not necessarily. Maybe I want to run the tests in a certain order or sequentially, only to ensure that it does run sequentially, but not parallelly. Once I see that happening, then it might be the case that I'd work further to make it work parallelly as well. Some tools help you to narrow down the problem, not necessarily that you'll use them in production. sequentially is a tool just like `console.verbose` or so. – Nawaz Nov 17 '21 at 09:55
  • Try to use beforeEach or beforeAll if you have some dependency to create something – Khuram Niaz Jul 02 '22 at 20:57
  • 1
    This issue is often the result of your tests sharing a DB. As a result of that they can either be altering the DB together in real time which will obviously produce unpredictable results. Alternatively the tests may fail to clean up after themselves so data is leaking from test to test. An ideal solution is one DB per test. So total isolation. An issue here of course is increased overhead in spinning up and down DBs. I've used sqlite here as a low lift solution. – Scott Wright Aug 05 '22 at 14:17
  • 1
    if you're running tests against your DB (which will give you much greater confidence in those tests versus mocking), then running them in sequence is required. – ICW Jan 16 '23 at 01:53
69

I'm still getting familiar with Jest, but it appears that describe blocks run synchronously whereas test blocks run asynchronously. I'm running multiple describe blocks within an outer describe that looks something like this:

describe
    describe
        test1
        test2

    describe
        test3

In this case, test3 does not run until test2 is complete because test3 is in a describe block that follows the describe block that contains test2.

SuperCodeBrah
  • 2,874
  • 2
  • 19
  • 33
  • 10
    Maybe it will still run in parallel. – LCB Jan 21 '19 at 03:32
  • This is great. Makes it possible to first check behavior with missing environment variables, then set the variables and do further tests. – Nicolai Lissau May 01 '19 at 07:41
  • 1
    IMO this should be the accepted answer. Easier than dealing with CLI options or defining a sequencer. – ZCaceres Aug 20 '20 at 14:49
  • 3
    This worked well for me for testing a stateful WebSocket server (connection, login, logout), which obviously must be run in the correct order. The outer `describe` is not required, though. – terrymorse Nov 19 '20 at 18:46
  • 1
    This pretty much looks like implementation details which is not safe to rely upon. – Mesqalito Jun 09 '22 at 15:28
  • tested this method, it does not work. The execution of the inner describe block is not sequential – Jonah Jul 10 '23 at 15:11
42

It worked for me ensuring sequential running of nicely separated to modules tests:

1) Keep tests in separated files, but without spec/test in naming.

|__testsToRunSequentially.test.js
|__tests
   |__testSuite1.js
   |__testSuite2.js
   |__index.js

2) File with test suite also should look like this (testSuite1.js):

export const testSuite1 = () => describe(/*your suite inside*/)

3) Import them to testToRunSequentially.test.js and run with --runInBand:

import { testSuite1, testSuite2 } from './tests'

describe('sequentially run tests', () => {
   testSuite1()
   testSuite2()
})
kmnowak
  • 804
  • 1
  • 8
  • 23
  • 3
    You don't need to run with --runInBand since you already have two test suites. Child Test Suites are executed in sequence. – RICKY KUMAR May 27 '19 at 13:31
20

Use the serial test runner:

npm install jest-serial-runner --save-dev

Set up jest to use it, e.g. in jest.config.js:

module.exports = {
   ...,
   runner: 'jest-serial-runner'
};

You could use the project feature to apply it only to a subset of tests. See https://jestjs.io/docs/en/configuration#projects-arraystring--projectconfig

Joachim Lous
  • 1,316
  • 1
  • 14
  • 22
  • *You could use the project feature to use it for only a subset of tests.*, How? – Nux Feb 01 '20 at 09:25
  • 1
    @Nux The 'projects' config setting in Jest lets you apply other configuration settings selectively to specific sets of tests. Answer updated with link to docs and example. – Joachim Lous Feb 05 '20 at 08:35
  • Any idea how to use it with `--testRunner` parameter? This is for CI/CD only, I don't want to amend my runner in the configuration. Also, I am not talking about `--runInBand` option. – Greg Wozniak Jul 25 '21 at 11:32
16

As copied from https://github.com/facebook/jest/issues/6194#issuecomment-419837314

test.spec.js

import { signuptests } from './signup'
import { logintests } from './login'

describe('Signup', signuptests)
describe('Login', logintests)

signup.js

export const signuptests = () => {
     it('Should have login elements', () => {});
     it('Should Signup', () => {}});
}

login.js

export const logintests = () => {
    it('Should Login', () => {}});
}
Mor Shemesh
  • 2,689
  • 1
  • 24
  • 36
14

I needed this for handling end-to-end tests alongside regular tests, and the runInBand solution was not enough for me. Yes: it ensures within test suites/files that the order works, but the files themselves run in an order chosen essentially for parallelization by Jest, and it's not easy to control. If you need a stable sequential order for the test suites themselves, this is how you can do it.

So in addition to the --runInBand, I did the following. I'm using separate projects for this, by the way, within a single repository.

  1. My jest.config.js looks like this:

     module.exports = {
       testSequencer: "./__e2e__/jest/customSequencer.js",
       projects: [{
         "rootDir": "<rootDir>/__e2e__",
         "displayName": "end-to-end",
         ...
    

    Here, I explicitly added the displayName to be end-to-end, which I'll use later. You can have as many projects as you like, as usual, but I have two, one for normal unit tests, and one for end-to-end.

    Note that the testSequencer field has to be global. If you attach it to a project, it'll be validated but then ignored silently. That's a Jest decision to make sequencing nice for running multiple projects.

  2. The testSequencer field points to a file containing this. This imports a default version of the test sequencer, and then partitions the tests into two sets, one for the tests in the end-to-end project, and all the rest. All the rest are delegated to the inherited sequencer, but those in the end to end set are sorted alphabetically and then concatenated.

     const Sequencer = require('@jest/test-sequencer').default;
    
     const isEndToEnd = (test) => {
       const contextConfig = test.context.config;
       return contextConfig.displayName.name === 'end-to-end';
     };
    
     class CustomSequencer extends Sequencer {
       sort(tests) {
         const copyTests = Array.from(tests);
         const normalTests = copyTests.filter((t) => ! isEndToEnd(t));
         const endToEndTests = copyTests.filter((t) => isEndToEnd(t));
         return super.sort(normalTests).concat(endToEndTests.sort((a, b) => (a.path > b.path ? 1 : -1)));
       }
     }
    
     module.exports = CustomSequencer;
    

This combo runs all the regular tests as Jest likes, but always runs the end to end ones at the end in alpha order, giving my end-to-end tests the extra stability for user models the order they need.

Stuart Watt
  • 5,242
  • 2
  • 24
  • 31
  • 1
    Yep. exactly this. I wanted to coordinate a sequence of tests. Jest's documentation has a good example of this: https://jestjs.io/docs/configuration#testsequencer-string – davewasthere Sep 09 '21 at 02:53
11

Just in case anyone wants to keep all jest configuration in the package.json options.

runInBand does not seem to be a valid config option. This means that you can end up with the setup below which does not seem 100% perfect.

"scripts": {
    "test": "jest  --runInBand"
},
...
"jest": {
    "verbose": true,
    "forceExit": true,
    "preset": "ts-jest",
    "testURL": "http://localhost/",
    "testRegex": "\\.test\\.ts$",
    ...
  }
...

However, you can add the runInBand using maxWorkers option like below:

  "scripts": {
        "test": "jest"
    },
    ...
    "jest": {
        "verbose": true,
        "maxWorkers": 1,
        "forceExit": true,
        "preset": "ts-jest",
        "testURL": "http://localhost/",
        "testRegex": "\\.test\\.ts$",
        ...
      }
    ...
Dharman
  • 30,962
  • 25
  • 85
  • 135
kimy82
  • 4,069
  • 1
  • 22
  • 25
6

Yes, and you can also run all tests in a specific order, although generally your tests should be independent so I'd strongly caution against relying on any specific ordering. Having said that, there may be a valid case for controlling the test order, so you could do this:

  • Add --runInBand as an option when running jest, e.g. in package.json. This will run tests in sequence rather than in parallel (asynchronously). Using --runInBand can prevent issues like setup/teardown/cleanup in one set of tests intefering with other tests:

  • "scripts": {"test": "jest --runInBand"}

  • Put all tests into separate folder (e.g. a separate folder under __tests__, named test_suites):

    __tests__

    test_suites

    test1.js

    test2.js

  • Configure jest in package.json to ignore this test_suites folder: "jest": { "testPathIgnorePatterns": ["/test_suites"] }

  • Create a new file under __tests__ e.g. tests.js - this is now the only test file that will actually run.

  • In tests.js, require the individual test files in the order that you want to run them:

    require('./test_suites/test1.js');

    require('./test_suites/test2.js');

Note - this will cause the afterAll() in the tests to be run once all tests have completed. Essentially it's breaking the independence of tests and should be used in very limited scenarios.

Chris Halcrow
  • 28,994
  • 18
  • 176
  • 206
5

If you are a newbie in Jest and looking for a complete, step-by-step example on how to make a specific test file ALWAYS run first or last, here it goes:

  1. Create a file called "testSequencer.js" in any path you'd like.
  2. Paste the code below into that file.
const TestSequencer = require('@jest/test-sequencer').default;
const path = require('path');

class CustomSequencer extends TestSequencer {
    sort(tests) {
        const target_test_path = path.join(__dirname, 'target.test.js');

        const target_test_index = tests.findIndex(t => t.path === target_test_path);

        if (target_test_index == -1) {
            return tests;
        }

        const target_test = tests[target_test_index];

        const ordered_tests = tests.slice();

        ordered_tests.splice(target_test_index, 1);
        ordered_tests.push(target_test); // adds to the tail
        // ordered_tests.unshift(target_test); // adds to the head

        return ordered_tests;
    }
}

module.exports = CustomSequencer;
  1. Set "maxWorkers" option as "1" in your package.json jest configuration. Also, set "testSequencer" option as your newly created "testSequencer.js" file's path.
{
  "name": "myApp",
  "version": "1.0.0",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "dev": "nodemon app.js",
    "test": "jest"
  },
  "author": "Company",
  "license": "MIT",
  "dependencies": {
    ...
  },
  "devDependencies": {
    "jest": "^27.5.1",
    ...
  },
  "jest": {
    "testSequencer": "./testSequencer.js",
    "maxWorkers": 1
  }
}
  1. Run npm test and observe that every test file will be run one by one, upon completion of each. You sacrifice some time, but you guarantee the order this way.

Bonus: You can also order your test files alphabetically, by folder name etc. Just modify "testSequencer.js" file to your preference, and return an array that's in the same format as the "tests" array, which is a parameter of your main "sort" function, and you will be good.

Onur Çevik
  • 1,560
  • 13
  • 21
4

From the Jest documentation:

Jest executes all describe handlers in a test file before it executes any of the actual tests. This is another reason to do setup and teardown inside before* and after* handlers rather than inside the describe blocks.

Once the describe blocks are complete, by default Jest runs all the tests serially in the order they were encountered in the collection phase, waiting for each to finish and be tidied up before moving on.

Take a look at the example that the jest site gives.

BigMan73
  • 1,344
  • 15
  • 14
  • 3
    The problem also comes when you have different test files with different before* and after*. Imagine you use a real database to run the tests against it. If you run them in parallel there will be conflicts. It really depends on the type of testing you have setup. – kimy82 Jun 11 '21 at 10:46
0

Jest runs all the tests serially in the order they were encountered in the collection phase

You can leverage that and create special test file alltests.ordered-test.js:

import './first-test'
import './second-test'
// etc.

And add a jest config with testMatch that would run test with that file name.

That will load each file in that order thus execute them in the same order.

unional
  • 14,651
  • 5
  • 32
  • 56
0

I tried a couple of methods mentioned above, but none of them seems to work. Probably due to I don't get the configuration right. Below is what works for me

  1. I set the sequence of execution in script.sh as below
# ./script.sh
npm test pretest

node dosomething.js # this call will take a while to finish

npm test posttest
  1. chmod 755 script.sh
  2. ./script.sh

Basically, pretest and posttest are the names of tests. Each of them has a corresponding test file name (pretest.test.js and posttest.test.js) under the __ tests __ directory.

Jonah
  • 71
  • 6