Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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(Please correct me If I am missing something, 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 which is antipattern. 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.

like image 347
Suresh Prajapati Avatar asked Sep 21 '18 18:09

Suresh Prajapati


People also ask

What is done () in Mocha?

This argument is a function, and is usually called done by convention. This signals to Mocha that what we're doing inside of before() runs asynchronously, and tells it to wait until we call done() to start running the tests.

How do you test async in Mocha?

Writing Asynchronous Tests with Mocha. To indicate that a test is asynchronous in Mocha, you simply pass a callback as the first argument to the it() method: it('should be asynchronous', function(done) { setTimeout(function() { done(); }, 500); });

How do you test your promises in Mocha?

Create a file named teams. js, import the API using require and create the function getTeamByPlayer it will return a promise, using setTimeout simulate the async process. Our promise return the resolve if the team with the player is found or the reject with an error if not found. Export the function to be used.

Does await wait for function to finish?

The keyword await is used to wait for a Promise. It can only be used inside an async function. This keyword makes JavaScript wait until that promise settles and returns its result.


1 Answers

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.

These concerns also apply to other JS testing frameworks with similar API, Jest and Jasmine.

like image 82
Estus Flask Avatar answered Nov 08 '22 23:11

Estus Flask