Last updated: Mar 7, 2024
Reading timeยท6 min
The Jest error "Exceeded timeout of 5000 ms for a test. Add a timeout value to this test to increase the timeout, if this is a long-running test" occurs when you exceed the timeout of 5 seconds for a Jest test.
To solve the error, increase jest's timeout for the test or globally and make sure your Promise resolves.
Here is the complete stack trace:
thrown: "Exceeded timeout of 5000 ms for a test. Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."
The default timeout for a Jest test is 5000 ms (5 seconds).
If a test exceeds the timeout, it automatically fails, even if the Promise would've resolved after 6 seconds.
For example, the following test fails.
it('tests async code', async () => { const employeeData = {id: 1, name: 'bobby hadz', salary: 500}; // ๐๏ธ This resolves after 6 seconds const employeePromise = new Promise(resolve => setTimeout(() => resolve(employeeData), 6000), ); const result = await employeePromise; expect(result.id).toBe(1); expect(result.name).toBe('bobby hadz'); expect(result).toEqual(employeeData); });
The Promise in the example resolves after 6 seconds, so it exceeds the default timeout of 5 seconds and the test fails.
One way to resolve the issue is to increase the timeout for the specific test.
You can pass a third argument to the it()
or test()
functions - the timeout
for the test in milliseconds.
it('tests async code', async () => { const employeeData = {id: 1, name: 'bobby hadz', salary: 500}; const employeePromise = new Promise(resolve => setTimeout(() => resolve(employeeData), 6000), ); const result = await employeePromise; expect(result.id).toBe(1); expect(result.name).toBe('bobby hadz'); expect(result).toEqual(employeeData); }, 30000); // ๐๏ธ increase timeout to 30 seconds
I passed a third argument of 30000
to the it()
function to increase the
timeout of the specific test to 30 seconds.
If I run the test now, it passes.
If you need to increase your Jest timeout globally:
jest.config.cjs
file in the root directory of your project (next
to your package.json
file)./** @type {import('jest').Config} */ const config = { setupFilesAfterEnv: ['<rootDir>/jest.setup.js'], }; module.exports = config;
Make sure you don't misspell the setupFilesAfterEnv
configuration key as this
also causes difficult-to-debug errors.
jest.setup.js
file right next to your jest.config.cjs
file.jest.setTimeout(30000);
Notice that the jest.config.cjs
file has a .cjs
extension (CommonJS).
You could also try to set the file's extension to .js
, however, you'd most
likely get the
Module is not defined in ES module scope
error.
If you don't want to define a separate jest.setup.js
file, you can increase
the timeout directly in your jest.config.cjs
file.
/** @type {import('jest').Config} */ const config = { testTimeout: 30000, }; module.exports = config;
The testTimeout
property can be set directly on the Jest config object that
you export from jest.config.cjs
.
This approach increases the default Jest timeout to 30 seconds for all tests.
You don't have to pass a third argument to the it()
or test()
functions
unless you want to change the default of 30 seconds.
You can also set your Jest timeout with the --testTimeout
flag.
npx jest --testTimeout=30000
You can also update the test
script in your package.json
file to not have to
remember to set the flag.
{ "scripts": { "test": "jest --testTimeout=30000" } }
Now when you issue the npm run test
command, your Jest timeout will be set to
30 seconds globally.
done()
function in your async testsMake sure you aren't using the done()
function in tests that use the
async/await syntax.
For example, the following code sample causes an error.
// ๐๏ธ test takes a `done` function (marked async) it('tests async code', async done => { const employeeData = {id: 1, name: 'bobby hadz', salary: 500}; const employeePromise = new Promise(resolve => setTimeout(() => resolve(employeeData), 6000), ); const result = await employeePromise; expect(result.id).toBe(1); expect(result.name).toBe('bobby hadz'); expect(result).toEqual(employeeData); // โ๏ธ Test functions cannot both take a 'done' callback and return something. Either use a 'done' callback or return a promise. // calls done() function done(); }, 30000);
The test takes the done
function but uses the async/await
syntax which is
not allowed.
async
return a Promise even if you don't explicitly return a value from the function.This is not allowed when taking the done
function as an argument.
In this case, you have 2 options:
done
argument..then()
syntax or callbacks and call done()
after your
assertions.Here is an example of a test that passes and uses the done()
function with the
.then() syntax.
// ๐๏ธ takes the done function it('tests async code', done => { const employeeData = {id: 1, name: 'bobby hadz', salary: 500}; const employeePromise = new Promise(resolve => setTimeout(() => resolve(employeeData), 6000), ); employeePromise.then(result => { expect(result.id).toBe(1); expect(result.name).toBe('bobby hadz'); expect(result).toEqual(employeeData); // ๐๏ธ calls the done() function after all assertions done(); }); }, 30000);
The test takes the done
function and calls it after all assertions.
Once your callback function defines the done
argument, Jest waits for you to
call it to pass or fail your test.
You either have to call done()
or remove it otherwise, Jest is stuck on that
particular test.
The done
argument doesn't even have to be called done
for it to fail your
times due to a timeout.
For example, the following test fails due to a timeout.
// ๐๏ธ defined the done() argument under another name it('tests async code', DEFINED_THIS_BY_MISTAKE => { const employeeData = {id: 1, name: 'bobby hadz', salary: 500}; const employeePromise = new Promise(resolve => setTimeout(() => resolve(employeeData), 6000), ); employeePromise.then(result => { expect(result.id).toBe(1); expect(result.name).toBe('bobby hadz'); expect(result).toEqual(employeeData); }); }, 30000);
The callback function I passed to it()
takes the done
function as an
argument even though the argument is not called done
.
As previously noted, you either have to remove the argument or call the done()
function, otherwise, Jest times your test out.
resolves
You can also use the resolves
matcher to test your async
code.
it('tests async code', async () => { const employeeData = {id: 1, name: 'bobby hadz', salary: 500}; const employeePromise = new Promise(resolve => setTimeout(() => resolve(employeeData), 6000), ); await expect(employeePromise).resolves.toEqual(employeeData); }, 30000);
The example uses the
resolves matcher with
the async/await
syntax but you can also use it with .then()
.
When the resolves
matcher is used in your expect
statement, Jest will wait
for the Promise to resolve.
If the promise is rejected, the test will automatically fail.
However, note that you have to return
the assertion, otherwise, your test will
complete before the Promise is resolved.
it('tests async code', () => { const employeeData = {id: 1, name: 'bobby hadz', salary: 500}; const employeePromise = new Promise(resolve => setTimeout(() => resolve(employeeData), 6000), ); return expect(employeePromise).resolves.toEqual(employeeData); }, 30000);
Notice that I returned the assertion.
This way Jest knows to wait for the Promise to be resolved/rejected.
I've also written a detailed guide on how to test exceptions in Jest (sync and async).
jest.useRealTimers()
Jest timeout errors are also caused if you enable fake timers in your tests.
Fake timers are enabled by calling jest.useFakeTimers()
and replace the
original implementation of setTimeout()
and other timer functions.
This can sometimes cause issues with timeout errors.
Try to add the following line at the top of your test file.
jest.useRealTimers();
You can also try to call the useFakeTimers
function with the legacy
string.
jest.useFakeTimers('legacy')
You can learn more about the related topics by checking out the following tutorials: