An Introduction to the Mocha Test Runner

Jun 12, 2019

Mocha is one of the most popular testing frameworks for JavaScript. In particular, Mocha has been the test runner of choice in the Node.js community essentially since it was first introduced in 2011.

Writing Your First Mocha Test

By default, you define Mocha tests using describe() and it(). Mocha calls this the BDD (short for "behavior-driven development") test interface. The describe() function defines a suite of tests, and the it() function defines an individual test. Suppose you have a simple function that adds two numbers:

function sum(a, b) {
  return a + b;
}

Here's how you might write a Mocha test test.js for this function.

// Node.js' built-in assertion library
const assert = require('assert');

const sum = require('./sum');

describe('sum()', function() {
  it('adds two numbers', function() {
    assert.equal(sum(2, 4), 6);
  });

  it('ignores additional arguments', function() {
    assert.equal(sum(2, 4, 6), 6);
  });
});

The describe() and it() functions are globals that the Mocha test runner creates. You can't run the above test using node. You instead need to npm install mocha and then run ./node_modules/.bin/mocha test.js.

If you try to run node test.js, you will get the below error message:

ReferenceError: describe is not defined

Assertion Libraries

Unlike many other test frameworks, Mocha doesn't come with a built-in assertion library. The previous example used Node.js' built-in assert library. Many popular JavaScript libraries and frameworks, like Express, use Mocha and Node.js assert for tests.

At its most basic level, an assertion library throws an error if a certain condition is not met. For example, the below code will throw an AssertionError:

// Throws "AssertionError [ERR_ASSERTION]: false == true"
assert.ok(false);

There is nothing special about an AssertionError in Mocha. Mocha will treat any uncaught error as a test failure, so you could theoretically write the test.js test suite without any assertion library:

describe('sum()', function() {
  it('adds two numbers', function() {
    const res = sum(2, 4);
    if (res !== 6) {
      throw new Error('Incorrect result: ' + res);
    }
  });

  it('ignores additional arguments', function() {
    const res = sum(2, 4, 6);
    if (res !== 6) {
      throw new Error('Incorrect result: ' + res);
    }
  });
});

However, just because you can, doesn't mean you should. Most test suites involve a lot of assertions, so a good assertion framework can make your test suite much more concise and readable.

Chai is another popular assertion library that many projects use in conjunction with Mocha.

Async Tests

Mocha has excellent support for promises and async functions. For example, the below test.js file works as expected:

describe('sum()', function() {
  it('adds two numbers', function() {
    return Promise.resolve().then(() => {
      assert.equal(sum(2, 4), 6);
    });
  });

  it('ignores additional arguments', async function() {
    assert.equal(sum(2, 4, 6), 6);
  });
});

For older, callback-based libraries, you may see Mocha's done() callback. Mocha passes an optional callback done() to the function you pass to it().

it('callback-style test', function(done) {
  setTimeout(() => done(), 50);
});

How Does Mocha Compare?


Did you find this tutorial useful? Say thanks by starring our repo on GitHub!

More Mocha Tutorials