'How to run Jest tests sequentially?
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.
Solution 1:[1]
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.
Solution 2:[2]
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()
})
Solution 3:[3]
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
Solution 4:[4]
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', () => {}});
}
Solution 5:[5]
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.
My
jest.config.jslooks like this:module.exports = { testSequencer: "./__e2e__/jest/customSequencer.js", projects: [{ "rootDir": "<rootDir>/__e2e__", "displayName": "end-to-end", ...Here, I explicitly added the
displayNameto beend-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
testSequencerfield 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.The
testSequencerfield 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 theend-to-endproject, 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.
Solution 6:[6]
While --runInBand works, it does a little more than you need - according to Jest's documentation:
Run all tests serially in the current process, rather than creating a worker pool of child processes that run tests (...)
Typically, Jest runs using one parent dispatcher process, which dispatches child-processes as workers that effectively run your tests, in parallel. runInBand seems to break that architecture by crunching everything into a single process.
In order to retain that core paradigm and run sequentially nonetheless, you can use --maxWorkers 1, which would simply limit the number of concurrently running workers to 1 (thus resulting in a sequential run):
jest --maxWorkers 1
jest -w 1also works, as an alias.
The benefit is that you would be playing it more safe by not taking any special same-JS-context-all-around assumptions as you would with runInBand (e.g. in various configuration / environment setup files), which would hold you from embracing parallelism in the future, if possible.
Solution 7:[7]
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$",
...
}
...
Solution 8:[8]
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
--runInBandas an option when running jest, e.g. inpackage.json. This will run tests in sequence rather than in parallel (asynchronously). Using--runInBandcan 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__, namedtest_suites):__tests__test_suitestest1.jstest2.jsConfigure jest in
package.jsonto ignore thistest_suitesfolder:"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,requirethe 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.
Solution 9:[9]
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.
Solution 10:[10]
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:
- Create a file called "testSequencer.js" in any path you'd like.
- 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 (auth_test_index == -1) {
return tests;
}
const target_test = tests[target_test_index];
const ordered_tests = tests;
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;
- Set "maxWorkers" option as "true" 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
}
}
- 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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | SuperCodeBrah |
| Solution 2 | kmnowak |
| Solution 3 | |
| Solution 4 | Mor Shemesh |
| Solution 5 | Stuart Watt |
| Solution 6 | d4vidi |
| Solution 7 | Dharman |
| Solution 8 | |
| Solution 9 | BigMan73 |
| Solution 10 |
