49

How do I test async code with mocha? I wanna use multiple await inside mocha

var assert = require('assert');

async function callAsync1() {
  // async stuff
}

async function callAsync2() {
  return true;
}

describe('test', function () {
  it('should resolve', async (done) => {
      await callAsync1();
      let res = await callAsync2();
      assert.equal(res, true);
      done();
      });
});

This produces error below:

  1) test
       should resolve:
     Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.
      at Context.it (test.js:8:4)

If I remove done() I get:

  1) test
       should resolve:
     Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/tmp/test/test.js)
ted
  • 13,596
  • 9
  • 65
  • 107
deathangel908
  • 8,601
  • 8
  • 47
  • 81

1 Answers1

86

Mocha supports Promises out-of-the-box; You just have to return the Promise to it()'s callback.

If the Promise resolves then the test passes. In contrast, if the Promise rejects then the test fails. As simple as that.

Now, since async functions always implicitly return a Promise you can just do:

async function getFoo() {
  return 'foo'
}

describe('#getFoo', () => {
  it('resolves with foo', () => {
    return getFoo().then(result => {
      assert.equal(result, 'foo')
    })
  })
})

You don't need done nor async for your it.

However, if you still insist on using async/await:

async function getFoo() {
  return 'foo'
}

describe('#getFoo', () => {
  it('returns foo', async () => {
    const result = await getFoo()
    assert.equal(result, 'foo')
  })
})

In either case, DO NOT declare done as a function argument.

If you use any of the methods described above you need to remove done completely from your code. Passing done as an argument to it() callbacks hints to Mocha that you intent to eventually call it.

Using both Promises and done will result in:

Error: Resolution method is overspecified. Specify a callback or return a Promise; not both

The done method is only used for testing callback-based or event-based code. You shouldn't use it if you're testing Promise-based or async/await functions.

nicholaswmin
  • 21,686
  • 15
  • 91
  • 167
  • I want to call multiple async code. That's why I put `async` under function. Furthermore I want to make assertion after calling it, so I can't return a promise. I edited my question accordingly – deathangel908 Oct 04 '18 at 07:48
  • 1
    Got it; Edited. Either way when I say you don't need `done`, it means you *shouldn't* even pass it in the `it` callback. Remove `done` completely from your code. Passing `done` as an argument hints to Mocha that you intent to eventually call it. – nicholaswmin Oct 04 '18 at 07:55
  • 1
    I'm doing same as async function getFoo() { return 'foo' } describe('#getFoo', () => { it('returns foo', async () => { const result = await getFoo() assert.equal(result, 'foo') }) }) but it gives me this error. Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. Do I still not need done()? What is the workaround? – Gowthamss Aug 12 '22 at 10:23
  • I don't understand why it fails for async-await, but it worked using promises. – Gowthamss Aug 12 '22 at 10:32
  • @Gowthamss and that's the only test in your test file? It looks OK to me. Can you write up a test JS Fiddle I could copy/paste and run? – nicholaswmin Aug 13 '22 at 05:11