Correct way to use done() while testing asyc/await with mocha

I am practicing basic unit test cases with mocha and a bit confused HOW and WHEN to use done() handler.

  1. How to use done() ?

Below is my sample code where I am not able to use done:

it('Testing insertDocumentWithIndex', async (done) => {
  try{
    var data = await db.insertDocumentWithIndex('inspections', {
      "inspectorId" : 1,
      "curStatus" : 1,
      "lastUpdatedTS" : 1535222623216,
      "entryTS" : 1535222623216,
      "venueTypeId" : 1,
      "location" : [
        45.5891279,
        -45.0446183
      ]
    })
    expect(data.result.n).to.equal(1);
    expect(data.result.ok).to.equal(1);
  }
  catch(e){
    logger.error(e);
    done(e);
  }
})

When I run, it fails and throws an error-

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

But done should be called in case of failure only(forgive me if I am saying something incorrect, I am a beginner), which I have done in catch block and coming to the second point of returning a Promise, well that works fine. See below code

it('Testing insertDocumentWithIndex', async () => {
  return new Promise(async (resolve, reject) => {
    try{
      var data = await db.insertDocumentWithIndex('inspections', {
        "inspectorId" : 1,
        "curStatus" : 1,
        "lastUpdatedTS" : 1535222623216,
        "entryTS" : 1535222623216,
        "venueTypeId" : 1,
        "location" : [
          45.5891279,
          -45.0446183
        ]
      })
      expect(data.result.n).to.equal(1);
      expect(data.result.ok).to.equal(1);
      resolve()
    }
    catch(e){
      reject(e);
    }
  })
});

But this requires an additional Promise construction code, not a problem though. But it raises another question

  1. WHEN done should be used ?

Any help or suggestion for a better approach for writing test cases with mocha will help.

1 answer

  • answered 2018-09-21 18:22 estus

    The correct way is to not use done with async..await. Mocha supports promises and is able to chain a promise that is returned from it, etc. functions. And async function is syntactic sugar for a function that always returns a promise:

    it('Testing insertDocumentWithIndex', async () => {
        var data = await db.insertDocumentWithIndex('inspections', {
          "inspectorId" : 1,
          "curStatus" : 1,
          "lastUpdatedTS" : 1535222623216,
          "entryTS" : 1535222623216,
          "venueTypeId" : 1,
          "location" : [
            45.5891279,
            -45.0446183
          ]
        })
        expect(data.result.n).to.equal(1);
        expect(data.result.ok).to.equal(1);
    })
    

    done is needed only for testing asynchronous APIs than don't involve promises. Even then, converting to promises often results in cleaner control flow.

    And this

    it('Testing insertDocumentWithIndex', async () => {
      return new Promise(async (resolve, reject) => {
      ...
    

    is promise construction antipattern, which is even worse because of async promise constructor callback.