Last updated: Mar 7, 2024
Reading timeยท4 min
The mocha error Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. occurs for multiple reasons:
done()
function when testing async
code.To solve the error, make sure to call the done()
function when testing async
code and increase your timeout if necessary.
Here is the complete stack trace.
1) tests the type of a thrown error: Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/home/borislav/Desktop/bobbyhadz-rest/bobbyhadz-js/test/index.test.js)
Here is an example of how the error occurs.
import assert from 'assert'; it('tests an async function', done => { const p = new Promise(resolve => setTimeout(() => resolve('success'), 3000), ); p.then(result => { assert(result === 'success'); done(); }).catch(done); });
The Promise is resolved after 3 seconds but the default mocha
timeout is 2000
milliseconds (2 seconds).
If I run the test with npx mocha
, it fails because the timeout is exceeded.
The first thing you should try is to exceed the timeout of your tests.
You can specify the --timeout
flag when issuing the mocha
command.
One way to increase your timeout is to update the test
script in your
package.json
file.
{ "scripts": { "test": "mocha --timeout 10000" } }
The example sets the timeout of your mocha
tests to 10000 ms (10 seconds).
The next time you now issue the npm run test
command, the timeout will be set
to 10 seconds instead of 2.
You can also specify the flag when running the command with npx
.
npx mocha --timeout 10000
You can also set the timeout by calling the timeout()
function on the object
that is returned from the it()
function.
import assert from 'assert'; it('tests an async function', done => { const p = new Promise(resolve => setTimeout(() => resolve('success'), 3000), ); p.then(result => { assert(result === 'success'); done(); }).catch(done); }).timeout(10000); // ๐๏ธ specify timeout here
If you run your mocha
command, the timeout will be set to 10 seconds for the
specific test.
If you convert your arrow function to a named function, you can also set the
timeout on the this
object.
import assert from 'assert'; // ๐๏ธ using a named function (NOT arrow) it('tests an async function', function (done) { // ๐๏ธ set timeout here this.timeout(10000); const p = new Promise(resolve => setTimeout(() => resolve('success'), 3000), ); p.then(result => { assert(result === 'success'); done(); }).catch(done); });
Notice that we didn't use an arrow function to be able to access properties on
the this
object.
If you pass an arrow function as the second argument to it
, then the this
keyword will be undefined
.
This example also sets the timeout for the specific test.
done()
function after your assertionsMake sure to call the done()
function after your assertions.
import assert from 'assert'; it('tests an async function', done => { const p = Promise.resolve('success'); p.then(result => { assert(result === 'success'); // ๐๏ธ call done here done(); }).catch(done); });
The callback function we passed to it()
takes the done()
function as a
parameter.
The done
function is used to indicate to mocha
that we're done testing the
async
code.
async/await
syntax to test your codeAn alternative approach is to use the async/await
syntax to test your code.
import assert from 'assert'; it('tests an async function', async () => { const p = Promise.resolve('success'); const result = await p; assert(result === 'success'); });
We marked the callback function as
async to be able to use the
await
keyword to await Promises.
The result
variable stores the
resolved value.
Notice that we didn't have to call the done()
function when using the
async/await
syntax.
If your function takes the done
argument and doesn't call it, the test will
fail.
import assert from 'assert'; // ๐๏ธ takes done it('tests async code', async done => { const p = Promise.reject('success'); const result = await p; assert(result === 'success'); });
The test above fails with the following error message:
The reason the test fails is that the callback function takes the done
argument and doesn't call it.
Make sure to remove the done
argument when testing async code with
async/await
.
Removing the done
argument resolves the issue.
import assert from 'assert'; // โ Test passes it('tests async code', async () => { const p = Promise.resolve('success'); const result = await p; assert(result === 'success'); });
If you take the done()
argument in an async/await
function and try to call
it, you'd get the following error:
import assert from 'assert'; it('tests async code', async done => { const p = Promise.resolve('success'); const result = await p; assert(result === 'success'); // โ๏ธ Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both. done(); });
To solve the error, remove the done
argument from the callback function.
The done
argument should only be used with the .then()
syntax and callbacks
when testing async code.
If you use the async/await
syntax, you don't have to use done()
.
Basically, when you await
your Promises, mocha
knows when your tests end.
On the other hand, when you use callbacks, you have to inform mocha
when your
test ends using done()
.
You can learn more about the related topics by checking out the following tutorials: