Using the Chai Assertion Library with Mocha
Chai is one of the most popular assertion libraries when writing test suites with Mocha. This article assumes you are already acquainted with Mocha, so check out our introduction to Mocha first.
Chai supports 3 different assertion styles: expect
, should
, and assert
. expect
is most common, because should
modifies Object.prototype
and assert
doesn't provide much benefit over the built-in Node.js assert
library.
Getting Started with expect
Suppose you have a basic function sum()
that adds two numbers together:
module.exports = function sum(a, b) {
return a + b;
};
Here's how you would write a sum.test.js
file that tests the above sum.js
file.
const { expect } = require('chai');
const sum = require('./sum');
describe('sum()', function() {
it('adds two numbers', function() {
// `expect()` takes in a parameter value and returns what Chai calls
// a "chain"
expect(sum(2, 4)).to.equal(6);
});
it('ignores additional arguments', function() {
expect(sum(2, 4, 6)).to.equal(6);
});
});
The goal of Chai's expect
and should
interfaces is to allow you to write assertions in a way that mimics natural language. For example, to assert that a value is an array that includes '3', you would write:
expect([1, 2, 3]).to.be.an('array').that.includes(3);
// Throws "AssertionError: expected [ 1, 2, 3 ] to include 4"
expect([1, 2, 3]).to.be.an('array').that.includes(4);
The Chai docs have a complete list of language chains and comparisons.
Object Comparisons with expect
The expect
API is chainable and very expressive. Advanced Chai users can
often write all their assertions with one expect
chain.
For example, suppose you have an object with several properties:
const movie = {
title: 'Jingle All The Way',
releaseDate: new Date('1996-11-22'),
imdb: 'https://www.imdb.com/title/tt0116705/?ref_=nv_sr_1?ref_=nv_sr_1'
};
To assert that another object is deep equal to movie
, you could do:
const value = Object.assign({}, movie);
// Add the `deep` modifier to make Chai check whether the object properties
// are equal, rather than the top-level objects.
expect(value).to.deep.equal(movie);
Often you don't want to assert that two objects are exactly deep equal, but
that an object has certain properties set. For example, to check that movie
has
the correct title
and releaseDate
, but ignore imdb
and other properties, use .include()
.
expect(movie).to.deep.include({
title: 'Jingle All The Way',
releaseDate: new Date('1996-11-22')
});
Getting Started with should
The should
interface supports the same chaining interface as expect()
. The key difference is that Chai adds a should()
function to every JavaScript value. That means you don't have to call expect()
explicitly, which makes assertions read more like natural language.
require('chai').should();
const sum = require('./sum');
describe('sum()', function() {
it('adds two numbers', function() {
// Numbers now have a `.should()` function
sum(2, 4).should.equal(6);
});
it('ignores additional arguments', function() {
sum(2, 4, 6).should.equal(6);
});
});
Many projects avoid using should()
because, in production, your values won't have a should()
function. What if the code under test uses should()
? Your tests will succeed, but your code will fail in production. Because of this trade-off, expect()
is more common than should()
, but people do use should()
.