How can I limit the concurrency of test execution in jest? Let's say I only want to run 4 test cases in parallel at the same time.
My current problem is that I have a lot of integration tests using a real database connection. Jest executes too much test cases in parallel, thus often connections timeout or the performance of my test database instance drops significantly because there are too many queries at the same time.
All of my integration test suits have the following structure:
describe('<functionality x>', () => {
test('case 1', async () => {...})
test('case 2', async () => {...})
test('case 3', async () => {...})
})
describe('<functionality y>', () => {
test('case 1', async () => {...})
test('case 2', async () => {...})
test('case 3', async () => {...})
})
I already tried running jest with --maxWorkers=1, but I guess this is the same as --runInBand, which works, but really slows down the overall execution time.
Rather than --maxWorkers=1, you could provide a larger value like --maxWorkers=2 or --maxWorkers=50%.
However, if you are trying to limit the number of tests running in parallel, it seems like you want to use:
jest --maxConcurrency=N
Jest's documentation says:
Prevents Jest from executing more than the specified amount of tests at the same time. Only affects tests that use test.concurrent.
so, note you have to modify your tests by adding the .concurrent:
describe('<functionality x>', () => {
test.concurrent('case 1', async () => {...})
test.concurrent('case 2', async () => {...})
test.concurrent('case 3', async () => {...})
})
describe('<functionality y>', () => {
test.concurrent('case 1', async () => {...})
test.concurrent('case 2', async () => {...})
test.concurrent('case 3', async () => {...})
})
Related
I am trying to implement mocha testing, however it doesn't seem to work the way I expect it to. My code looks like the following:
async function getFoo() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved')
}, 2500)
})
}
describe(`Testing stuff`, function () {
it('resolves with foo', () => {
return getFoo().then(result => {
assert.equal(result, 'foo')
})
})
})
Error message:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
To me it seems like I have to increase the threshold of the timeout.
Is there a better way to do this? Since I don't know how long each test might take. I am testing nodejs child processes
best regards
As it is described in the error you need to use done() end of your test.
function delay(timeout = 2500) {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved')
}, timeout)
})
}
describe(`Testing stuff`, function (done) {
it('resolves with foo', (done) => {
return delay().then(result => {
assert.equal(result, 'foo')
done()
})
})
});
// better readability
describe(`Testing stuff`, function (done) {
it('resolves with foo', (done) => {
const result = await delay();
assert.equal(result, 'foo')
done();
})
});
But as you described you are testing child_processes which I don't recommend. Because to test child_process you need to promisify the child_process which doesn't make sense. Check here for more info How to promisify Node's child_process.exec and child_process.execFile functions with Bluebird?
If you really want to test child_process maybe you can mock the process with the link i gave but only for testing purposes.
I need to run differents describe blocks from different files in determinate order. Also, I need pass 1 argument between this blocks, but the argument needs to keep the state with which it left the previous describes. For example, i have this:
file1.test.js
export const Test1= () => {
describe("Describe 1", () => {
test("test1", async () => {//my test1
})
test("test2", async () => {//my test2
})
describe("Describe 2", () => {
test("test3", async () => {//my test3
})
test("test4", async () => {//my test4
})
}
file2.test.js
export const Test2= () => {
describe("Describe 3", () => {
test("test5", async () => {//my test5
})
test("test6", async () => {//my test6
})
describe("Describe 4", () => {
test("test7", async () => {//my test7
})
test("test8", async () => {//my test8
})
}
I want to run the tests in the following order with this argument:
let myArgument;
Test1
Describe 1(myArgument)
Test2
Describe 3
Test1
Describe 2(myArgument)
Test2
Describe 4
I am using to run the tests: jest --runInBand
It is generally a good idea to keep tests isolated from each other, so that failures of one test do not cascade to other tests. Playwright recommends using different browser contexts for tests – browser contexts are concurrent, isolated execution environments. They are cheap/fast to create, and can reuse a single browser instance.
Having said that, it is possible to achieve your use-case with Jest, with some work:
Define myArgument as a global object. Global objects are shared across tests, and can be defined through globals in your Jest config (docs)
Define a custom sequencer in your Jest config to define the sequence in which tests are executed. Use the testSequencer property in Jest config (docs)
I am having problems loading filenames into jest.each asynchronously.
My code:
let files: string[][]
function getFilesWorking() {
files = [["test1"], ["test2"]]
}
async function getFilesAsync() {
files = await Promise.resolve([["test1"], ["test2"]])
}
beforeAll(() => {
console.log("before")
})
describe.only("Name of the group", () => {
getFilesAsync()
test.each(files)("runs", f => {})
})
beforeAll is executed before each test but NOT before initialization of test.each, so I end up with undefined.
How can I load files before using test.each?
You can pass an async callback to beforeAll and await getFilesAsync within it
beforeAll(async () => {
await getFilesAsync();
})
As of Jest 28.1.3 and prior, this is not possible. There is an open issue documenting this behavior.
The best thing you can do for now is put your tests in a regular it() test and do a deep value comparison:
it('tests an array of cases', async () => {
const data = await getSomeAsyncData()
const expectedData = [ ... ]
expect(data).toEqual(expectedData)
})
You can use beforeEach to set up code that will run prior to tests for any given scope, https://jestjs.io/docs/setup-teardown:
beforeEach(() => {
console.log('before every test');
});
describe.only(('Name of the group') => {
beforeEach(() => {
console.log('before tests in this describe block');
})
})
Jest is only going to run the tests in your describe.only block. If you want to use beforeEach in other blocks and run those tests as well, change describe.only to describe.
(Edit: I know this is a year late, I'm just trying to look for a similar problem/solution set and thought I could answer this.)
I am using jest for unit testing in my node express application,please excuse , because i am new to all this
in my abc.test.js
const s3Helper = require('../../../../../lib/s3_helper');
beforeEach(async () => {
s3Helper.uploadBufferToS3 = jest.fn(() => true);
});
describe('test1', () => {
it('test1', async () => {
expect(s3Helper.uploadBufferToS3)
.toHaveBeenCalled();
});
});
describe('test2', () => {
it('test2', async () => {
expect(s3Helper.uploadBufferToS3)
.toHaveBeenCalled();
});
});
so when i run this test file in test1 it returns that test is passed, however in test2 it returns expected >=1 returned 0.
since i am mocking it beforeEach i expect it should return 1 for each describe block
I am using jest-puppeteer to run my webtests. If I am running my tests all defined in one file, everything works perfectly.
describe('user', () => {
jest.setTimeout(12000);
beforeEach(async () => {
await page.setViewport({width: 1200, height: 2000});
await page.goTo('http://localhost:3000');
});
it('test 1', async () => {
//my test steps
});
it('test 2', async () => {
//my test steps
});
});
However, if I am running each test in its own file, I get an error.
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'addExpectationResult' of undefined
FILE 1
describe('user', () => {
jest.setTimeout(12000);
beforeEach(async () => {
await page.setViewport({width: 1200, height: 2000});
await page.goTo('http://localhost:3000');
});
it('test 1', async () => {
//my test steps
});
});
FILE 2
describe('user', () => {
jest.setTimeout(12000);
beforeEach(async () => {
await page.setViewport({width: 1200, height: 2000});
await page.goTo('http://localhost:3000');
});
it('test 2', async () => {
//my test steps
});
});
Interestingly, if I add a console.log('some statement') as first step in test2, everything works again. That's why I think it might be a timing issue. I am running my tests sequentially, i.e. jest --runInBand
Can anyone help?
As you say i agree that the problem is the async sequentially, as explained in that github bugreport in Patrick Hulce answer:
FWIW I also ran into this and was led to this issue. Only happened in
CI when an async test timed out but the underlying action continued
until after the test suite finished (and I'm guessing the callback
tried to add the result of the expectation). I could never get it to
happen locally though.
so probably your error is inside "//my test steps" where you manipulate something in both the test that you can/need manipulate before running the async process.