Use of done() in Mocha/Chai

Hello there.

I´m working on my first project in the Quality Assurance section.

One of the things I have to do is write two tests: unit tests and functional tests.

My unite test code looks something like this:

describe("Unit Tests", function () {
  describe("ConvertHandler functions", function () {
    it("Should correctly read a whole number input.", function () {
      assert.equal(convertHandler.getNum("10L"), 10);
    });
});

My functional test (which I am working at right now) looks something like this:

describe("Functional Tests", function () {
  describe("GET request to /api/convert", function () {
    it("Convert a valid input such as 10L: GET request to /api/convert", function () {
      chai
        .request(server)
        .get("/api/convert")
        .query({ input: "10L" }) // /api/convert?input=10L
        .end((err, res) => {
          assert.equal(res.status, 200);
          assert.equal(res.body.initNum, 10);
          assert.equal(res.body.initUnit, "L");
          assert.equal(res.body.returnNum, 2.64172);
          assert.equal(res.body.returnUnit, "gal");
          assert.equal(
            res.body.string,
            "10 liters converts to 2.64172 gallons"
          );
        });
    });
  });
});

I´m still struggling to understand some things related to Mocha/Chai but one of the things I don´t understand is when to use “done” in a callback function and then “done()” at the end. As you can see, I haven´t used this in my code, but I keep seeing this when I do research.

As far as I know, is used to make the function asychronous.
Do I need to make my code asychronous for some reason?
I’m not sure if I’m understanding this right, but I would make a function asynchronous to access a promise result, is that right?

I’m really confused with using or not “done()”, why I need to access the promise…

By adding an argument (usually named done ) to it() to a test callback, Mocha will know that it should wait for this function to be called to complete the test. This callback accepts both an Error instance (or subclass thereof) or a falsy value; anything else is invalid usage and throws an error (usually causing a failed test). Mocha usually throws an error if done is not called.

1 Like

This callback accepts both an Error instance (or subclass thereof) or a falsy value; anything else is invalid usage and throws an error (usually causing a failed test).

I´m not sure I understood this. The callback function is the one inside it, right? When you mention that is accepts “Error” instance or a falsy value, do you mean that the “done” parameter meets thiese requirements?

Blockquote Mocha usually throws an error if done is not called.

Does that mean that is good/better practice to use done? In my case I don´t have errors (at the moment).

Yeah, it is better to call done function.

1 Like

So Mocha is a test runner. It’s a small program that will run a set of test functions in order, one after the other.

A test runner normally lets you write code for the tests that looks like:

test("first one", function () {
  // some assertion
})

test("second one", function () {
  // some assertion
})

test("third one", function () {
  // some assertion
})

Then when you run the program, it goes through each test function call, prints the message, and then runs the callback (which contains the assertion, the thing you want to check is true) and prints the result of that.

If the thing you’re asserting is dependent on an asynchronous call, then what will happen is that the callback will be run, the async call will happen, then the program will move onto the next test. The result of the async call won’t return immediately. So the test for that particular thing will break.

One way to deal with this is to have a callback function after the assertion that has to run before going into the next test. This only matters if the thing you’re testing is async.

So like

test("async thing", function (done) {
  // some assertion that 
  // depends on async things

  done()
})

That function (done) {, Mocha has been written in such a way as to understand that you can pass a function to the test callback.

So now, instead of just moving straight onto the next test, the test is not complete until that done function runs.

2 Likes