Mocha + Chai.js unit testing for ES6 with Istanbul code coverage
Testing is very important for finding bugs, verifying the functionality and improving the general stability of a piece of software. Almost all (if not all) developers test their code in some way. One way to test would be to manually run the program and try out all the functions to see if everything is working as expected. Another (and better) way is to write automated tests that are run every time the code changes.
In Onsen UI we do end to end testing of all the AngularJS directives using Protractor and we also test the internal logic of the components with the Karma test runner. This helps us find and fix bugs quickly and also makes it a lot easier to refactor the code without worrying about breaking something.
Lately we’ve reimplemented all the Onsen UI components using ES6 (recently renamed to ES2015). This introduces some challenges when testing since most browsers don’t currently support running ES6 code directly, so we need to transpile it into ES5 which the browser can understand. In this article we will take a look at how ES6 code can be tested with Mocha and also how to generate coverage for the ES6 code with Istanbul. Chai.js is used for the assertions, but of course you can use any assertion library you like. For the Onsen UI unit tests we use Chai.js and we love it!
The code used in this article is available on my GitHub page.
The code to test
I’ll assume that you already have
npm installed. If you don’t please download and install them before continuing. You can find them at the official Node.js website.
Let’s start by creating a new project. Create an empty directory and run the following command:
$ npm init
It will ask you to answer a bunch of questions. When you’ve answered every questions a
package.json will be generated for you in the current directory. The
package.json file contains meta data about a Node.js module.
We’ll create a simple class that describes a rectangle, so fire up your favorite editor and create a file called
Please save the file after you’ve finished editing it. If at this point you try to execute it using node you will get an error:
If you don’t get this error you are probably from the future where all the ES6 features have already been implemented. As we can see from the error message it complains that the
class keyword is used. In the current implementation of V8,
class is a reserved word but the functionality has not yet been implemented. This is to avoid breaking older code when classes are finally added to the interpreter.
Writing unit tests with Chai.js
Before we start writing the tests we need to install Mocha and Chai.js. We also need to install Babel, which is a transpiler that translates ES6 code to ES5 so it can be executed in Node.js.
$ npm install --save-dev mocha chai babel
Mocha is the program we use to run the tests and Chai.js is a library that we use to write the test assertions. Chai.js implements three different assertion styles:
let chai = require('chai');
var expect = require('chai').expect;
let assert = require('chai').assert;
Which one you choose is just a matter of preference. In this tutorial I will be using
should since I think it’s the one that produces the cleanest tests.
Let’s start by writing a simple test for the
width attribute. We’ll be writing the tests in ES6 as well. Make a directory called
test and create a new file called
rectangle.spec.js and type the following code.
Running the tests with Mocha
Let’s run the test and see if it works! Do so by typing
# We have installed mocha locally in the project
Since we put the test file in a directory called
test Mocha will find it automatically. However, the tests will not work and Node.js will spit out the following error:
The tests are written in ES6 and Node.js can not execute them. This is the reason why we installed Babel earlier. Mocha accepts a
--compilers parameter so we can tell it to use Babel to transpile the code before running the tests:
Let’s try running it again:
Great! This time the tests worked. However, it’s not time to celebrate yet. We also need to add code coverage generation.
Generating coverage using Istanbul
Let’s start by installing Istanbul:
$ npm install --save-dev istanbul
We can now create a code coverage report by running:
As we can see 80% of the lines in the project have been covered. Istanbul also generates HTML report in
coverage/lcov-report/index.html. Open it in your browser and we can see which lines were not covered.
Well that’s a mess! It turns out since we’re using the
--compilers parameter to transpile the code into ES5, the code that Istanbul generates coverage for is actually the transpiled code. Even though the coverage was generated succesfully, this is not really what we want.
Coverage for the original ES6 code
So how do we get the coverage for the original ES6 code? To do that we want to make Node.js itself be able to execute ES6 code. Luckily, with Babel there’s an easy way to do that. When you install Babel it will also add a script called
babel-node which works just like the regular
node executable but it pipes all the code through Babel before executing it. However, this is not enough since Istanbul must also be able to understand ES6. To do that we need to install a module called
isparta which works as a drop-in replacement for the
$ npm install --save-dev isparta
Using this we can modify the test running command:
This outputs a nasty error message but if we take a look at the Mocha code it’s not actually a problem since the program was terminating at that line anyway. The reason for the error is that when using
babel-node return statements are only allowed within functions, while in the Mocha source code there is a return statement in the outermost scope.
In spite of the error it looks like the tests were run and the coverage report was generated succesfully. Let’s take a look at it!
babel-node we were able to generate a coverage report for the ES6 code. This makes it a lot more easy to read the coverage report.
The command used to run the tests is getting rather long and messy. To avoid having to write it every time you run the tests you can add it to your
package.json file. Edit the file and add the following line:
By doing this the tests can be run by just doing:
$ npm test
We will finish up the testing by increasing the coverage to 100%.
After adding these tests we have covered every line in our tests so we will get the following summary.
Finally, every line is covered and we’ve generated a nice coverage report for the ES6 code!
We hope this tutorial will be useful for people who are starting to write projects using ES6 and want a simple way to unit test and generate coverage for their code. So far we have only looked at how to do it for a Node.js module but in the upcoming weeks we will also publish an article on how to test ES6 code in the browser, which is a bit more complicated but definitely doable.
Originally published at onsen.io on August 4, 2015.