w3resource

Assertions and asynchronous code


Continuing from our previous tutorial, recall that we gave you had an example which utilized Node.js built-in assert module:

var assert = require('assert');
describe('Array', function() {
  describe('#indexOf()', function() {
    it('has to return -1 when the value is not present', function() {
      assert.equal([1, 2, 3].indexOf(4), -1);
    });
  });
});

Generally, when this module throws an Error, it works! This implies that you can use libraries such as:

should.js: This is a BDD style (behavioral driven development).

better-assert: This is a C-style self-documenting assert()

expect.js: This is an expect() style assertion

unexpected: This is the extensible BDD assertion toolkit.

chai: This is expect(), assert() and should ?style assertions.

asynchronous code

This is the second feature we will discuss, when it comes to testing asynchronous code, Mocha makes it so simple. All you need to do is to invoke the callback when your test complete. When you add a callback (which is usually named done) to it(), Mocha knows that it should wait for this function to be called to complete the test. This callback will accept both an Error instance or subclass thereof) or a falsy value; anything else causes a failed test.

describe('User', function() {
  describe('#save()', function() {
    it('has to save without error', function(done) {
      var user = new User('Luna');
      user.save(function(err) {
        if (err) done(err);
        else done();
      });
    });
  });
});

An alternative approach is to use the done() callback directly ( which handles an error argument, in the case where it exists):

describe('User', function() {
  describe('#save()', function() {
    it('has to save without error', function(done) {
      var user = new User('Luna');
      user.save(done);
    });
  });
});

Working with Promises

If you don't want to use the done() callback, you can return a Promise. This is useful when the APIs that you are testing returns promises rather than callbacks:

beforeEach(function() {
  return db.clear().then(function() {
    return db.save([tobi, loki, jane]);
  });
});
describe('#find()', function() {
  it('will respond with matching records', function() {
    return db.find({type: 'User'}).should.eventually.have.length(3);
  });
});

In versions of Mocha greater than v3.0.0, returning a Promise and calling done() results in an exception, as it is generally a mistake:

const assert = require('assert');

// antipattern
it('has to complete this test', function(done) {
  return new Promise(function(resolve) {
    assert.ok(true);
    resolve();
  }).then(done);
});

The test above will fail with the error: ```Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both```. In versions of Mocha older than v3.0.0, the call to done() will be effectively ignored.

Using async/await

In the case where your JS environment supports async/await, you can as well write asynchronous tests like this:

beforeEach(async function() {
  await db.clear();
  await db.save([tobi, loki, jane]);
});

describe('#find()', function() {
  it('will respond with matching records', async function() {
    const users = await db.find({type: 'User'});
    users.should.have.length(3);
  });
});


Inviting useful, relevant, well-written and unique guest posts