Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called

avatar
Borislav Hadzhiev

Last updated: Mar 7, 2024
4 min

banner

# Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called

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:

  1. Forgetting to call the done() function when testing async code.
  2. The Promise you are returning doesn't resolve.
  3. The Promise is resolved after the default timeout of 2000ms (2 seconds).

To solve the error, make sure to call the done() function when testing async code and increase your timeout if necessary.

mocha error timeout of 2000 ms exceeded

Here is the complete stack trace.

shell
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)

# Increase the timeout of your mocha tests

Here is an example of how the error occurs.

test/index.test.js
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.

package.json
{ "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.

shell
npx mocha --timeout 10000

set timeout flag when issuing mocha command

You can also set the timeout by calling the timeout() function on the object that is returned from the it() function.

test/index.test.js
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.

test/index.test.js
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.

# Make sure to call the done() function after your assertions

Make sure to call the done() function after your assertions.

test/index.test.js
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.

# Try using the async/await syntax to test your code

An alternative approach is to use the async/await syntax to test your code.

test/index.test.js
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.

test/index.test.js
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:

  • Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.

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.

test/index.test.js
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:

test/index.test.js
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().

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.

Copyright ยฉ 2024 Borislav Hadzhiev