Mocha
async/await
asynchronous programming
JavaScript testing
Node.js

Mocha - running and resolving two async/await calls

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Mocha, the clean way to test two asynchronous operations is to make the test function async and then await the promises you care about. The real decision is whether those operations should run sequentially or in parallel, because the Mocha part is simple once you understand that distinction.

Use an async Test Function

Mocha understands a returned promise. An async test automatically returns one, so this is enough:

javascript
1const assert = require("assert");
2
3describe("user service", function () {
4  it("loads profile and settings", async function () {
5    const profile = await getProfile();
6    const settings = await getSettings();
7
8    assert.strictEqual(profile.id, 42);
9    assert.strictEqual(settings.theme, "dark");
10  });
11});

Mocha waits for the test promise to resolve. If one of the awaited calls rejects, the test fails automatically.

Run the Calls Sequentially When Order Matters

The previous example is sequential. getSettings() does not start until getProfile() has finished. That is correct when:

  • the second call depends on the first result
  • the order is part of the behavior being tested
  • you want failure to stop the rest of the flow immediately

Here is a more explicit dependent example:

javascript
1it("creates a user and then loads it", async function () {
2  const created = await createUser({ name: "Ada" });
3  const loaded = await getUser(created.id);
4
5  assert.strictEqual(loaded.name, "Ada");
6});

In this case, sequential awaits are not just acceptable, they are the right model.

Use Promise.all When the Calls Are Independent

If both async calls can happen at the same time, start them together and await them together:

javascript
1it("loads profile and settings in parallel", async function () {
2  const [profile, settings] = await Promise.all([
3    getProfile(),
4    getSettings(),
5  ]);
6
7  assert.strictEqual(profile.id, 42);
8  assert.strictEqual(settings.theme, "dark");
9});

This is often faster and makes the intent clear: the operations are independent, and the test should wait for both.

Handle Expected Failures Deliberately

When you want to assert that one of the async calls rejects, use try/catch or a promise-aware assertion library:

javascript
1it("fails when settings are unavailable", async function () {
2  try {
3    await getSettingsFromMissingSource();
4    assert.fail("Expected getSettingsFromMissingSource to throw");
5  } catch (error) {
6    assert.match(error.message, /unavailable/i);
7  }
8});

This is clearer than letting the rejection escape when the test is supposed to verify the failure itself.

Do Not Mix done with async

Mocha supports the older done callback style, but you should not combine it with async/await in the same test:

javascript
1it("bad example", async function (done) {
2  await getProfile();
3  done();
4});

That pattern is error-prone because it mixes two completion models. If you are using async, let the returned promise control test completion.

Common Pitfalls

The biggest mistake is writing two await calls sequentially when the operations are actually independent and could be tested with Promise.all.

Another common issue is forgetting to await one of the promises. The test may finish early, producing false positives or unhandled rejection noise later.

People also mix done, returned promises, and async in one test. Pick one async style and keep it consistent.

Finally, do not swallow errors accidentally. If you catch an error in a test, make sure you still assert something about it or rethrow it.

Summary

  • In Mocha, an async test function is enough for promise-based testing.
  • Use sequential await when one async call depends on another.
  • Use Promise.all when two async calls are independent and should run in parallel.
  • Assert expected rejections explicitly with try/catch or promise-aware assertions.
  • Do not mix done callbacks with async/await in the same test.

Course illustration
Course illustration

All Rights Reserved.