Mocha, Chai, Istanbul, Sinon, and More

Mocha, Chai, Istanbul, Sinon, and More
Mocha, Chai, Istanbul, Sinon, and More
Among the most popular testing frameworks in JavaScript, Mocha has always ranked near the top. Even with Facebook-backed Jest, it has been difficult to replace Mocha on a large scale. A big reason for Mocha’s popularity is how well it works with other frameworks and tools. The tools that pair best with Mocha include Chai, Istanbul (nyc), Sinon, and Karma. It is precisely this strong ecosystem that has made JavaScript BDD and TDD so effective.
1. Mocha
Mocha officially describes itself as simple, flexible, and fun. It is a JavaScript testing framework that can run in Node.js or in the browser. It can provide assertions, async testing, coverage reports, and other features, although some of these work best when combined with other tools.
Like other Node.js packages, Mocha can be installed globally with npm (or yarn, or cnpm/Taobao’s npm mirror), or installed only in a specific project. Using cnpm as an example:
# Install globally
cnpm install --global mocha
# Install as a development dependency in the project
cnpm install --save-dev mocha
By default, Mocha automatically runs test files under the test folder, so you should create a test directory in your project. If you want to add a test command to the project, add the following to package.json:
"scripts": {
"test": "mocha"
}
Mocha supports Node.js’s built-in assert module by default. However, if you want more flexible assertions, you will need an assertion library—Chai is the most popular one.
A typical test using the built-in assert module looks like this (official example):
var assert = require('assert');
describe('Array', function() {
describe('#indexOf()', function() {
it('should return -1 when the value is not present', function() {
assert.equal([1, 2, 3].indexOf(4), -1);
});
});
});
2. Chai
Chai can be considered Mocha’s golden partner. It is an assertion library that supports both BDD (Behavior-Driven Development) and TDD (Test-Driven Development), and it works in both Node.js and browser environments. Installing Chai is similar to installing Mocha, and in practice they are often installed together.
Chai supports three assertion styles: Should, Expect, and Assert. You can choose whichever fits your habits and preferences. A typical canary test using Chai looks like this. In real-world usage, a canary test is usually the first test written to confirm that the environment is set up correctly.
var expect = require('chai').expect;
describe('Canary tests', () => {
it('should pass the canary test', () => {
expect(true).to.be.true;
});
});
To keep a consistent assertion style, Chai also has some extension libraries. For example, if you want to keep using Chai-style assertions when testing promises, you can install chai-as-promised. If you want to use Chai-style assertions in Karma, you can install karma-chai-as-promised. If you want to use Chai-style assertions with Sinon, you may need sinon-chai. Using cnpm as an example:
cnpm install --save-dev chai
cnpm install --save-dev chai-as-promised
cnpm install --save-dev karma-chai-as-promised
cnpm install --save-dev sinon-chai
2.1 Chai-as-promised
Without chai-as-promised, code for testing a promise might look like this (official example):
doSomethingAsync().then(
function (result) {
result.should.equal("foo");
done();
},
function (err) {
done(err);
}
);
After installing chai-as-promised, it may look like this instead (Expect style):
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
var expect = chai.use(chaiAsPromised).expect;
return expect(doSomethingAsync()).to.eventually.eql('foo');
Some of the extended chai-as-promised assertion APIs are as follows (Expect style):
return expect(PromiseFn).to.be.fulfilled;
return expect(PromiseFn).to.be.eventually.eql('foo');
return expect(PromiseFn).to.be.rejected;
return expect(PromiseFn).to.be.rejectedWith(Error);
return expect(PromseFn.resolve({'foo':'bar'})).to.eventually.have.property('foo');
expect(PromiseFn).to.be.fulfilled.notify(done);
2.2 Sinon-Chai
An official sinon-chai example looks like this:
"use strict";
var chai = require("chai");
var sinon = require("sinon");
var sinonChai = require("sinon-chai");
var expect = chai.expect;
chai.use(sinonChai);
function hello(name, cb) {
cb("hello " + name);
}
describe("hello", function () {
it("should call callback with correct greeting", function () {
var cb = sinon.spy();
hello("foo", cb);
expect(cb).to.have.been.calledWith("hello foo");
});
});
3. Istanbul (nyc)
Istanbul was the former name of the nyc package. nyc is a test coverage tool that makes it easy to inspect the status and coverage of your tests. It is also installed as an npm package.
cnpm install --save-dev nyc
After installation, you can configure scripts in package.json and run it directly. If you do not want to overwrite the usual test command used for Mocha, you can add something like cov or coverage and run it from the command line:
{
"scripts": {
"cov": "nyc mocha"
}
}
nyc also supports configuration files and command-line options for outputting different report formats.
{
"scripts": {
"cov": "nyc --reporter=html --reporter=text mocha"
}
}
npm run cov
4. Sinon
The name Sinon may come from the French word for “otherwise,” though that is only a guess and there is no official explanation. Sinon is not a testing framework, but rather a testing library that claims to work with any JavaScript testing framework. Its main purpose is to provide spies, stubs, and mocks, which are used to create the environment needed for the code under test.
In BDD or TDD-style development, when testing a piece of code, the supporting code it depends on often does not exist yet, or real networks, databases, and other systems may not be available or suitable for testing. In such cases, Sinon can be used to simulate and mock the environment so that the code under test has the context it needs, allowing code to be tested in parts.
Among Sinon’s tools, spies do what their name suggests: they observe function calls and collect information about them, which can then be used to verify whether the code ran correctly. Spies do not alter the function’s actual runtime context, so they often need to be combined with other tools. Stubs replace a function or module and stand in for part of the original implementation. For example, if function A parses file contents and needs function B to open and read the file, then when testing A, you can use a stubbed version of B to provide test content. In that case, the real B will not run—and may not even have been implemented yet. This allows modules, including specific branches within a module, to be run and tested independently. The mock module is somewhat similar to stubs, but not quite the same. Mocks can verify more specific functionality and behavior. For example, if function A is supposed to call function B when an exception occurs, then mocking B can verify how many times B was called, what arguments it received, and so on.
To keep tests independent, Sinon provides a sandbox module. Sandboxes help avoid polluting project code during testing. In addition to the modules mentioned above, Sinon also provides powerful utilities such as fake timers and fakes, which can simulate real-world timing behavior like setTimeout and setInterval, making tests faster and easier to manage.
An official Sinon test example is shown below. If you have also installed sinon-chai as mentioned earlier, you can use Expect or Should style assertions as well.
const expect = require('chai').expect;
const sinon = require('sinon');
const fs = require('fs');
var Stockfetch = require('../src/stockfetch');
describe('Stockfetch tests', () => {
let stockfetch;
let sandbox;
beforeEach(() => {
stockfetch = new Stockfetch();
sandbox = sinon.createSandbox();
})
afterEach(() => {
sandbox.restore();
})
it('should pass this canary test', () => {
expect(true).to.be.true;
});
5. Karma
Karma is mainly used to verify the behavior of client-side code. It is a lightweight server that can run in different browser environments. When installing Karma, you may need to choose and configure different plugins depending on your situation, for example:
cnpm install --save-dev karma
cnpm install --save-dev karma-mocha
cnpm install --save-dev karma-chai
cnpm install --save-dev karma-chrome-launcher
cnpm install --save-dev karma-firefox-launcher
cnpm install --save-dev karma-clear-screen-reporter
cnpm install --save-dev karma-cli
cnpm install --save-dev karma-coverage
After installation, you need to initialize and configure Karma by running:
node node_modules/karma/bin/karma init
Then select the testing framework (Jasmine is the default, so if you are using Mocha you need to change it), browsers, and other options according to your needs. After initialization, you can also modify the generated karma.conf.js file to adjust the configuration. Karma supports automatic watching and rerunning: as long as the source code changes, it will automatically run the tests.


