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 Node.js and 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.

The next step is to write some code to test. As mentioned earlier we will write it in ES6, so people who are not familiar with the new additions to the JavaScript language may feel a bit lost. Don’t worry, I’ll explain the new keywords in the comments as we go along.

We’ll create a simple class that describes a rectangle, so fire up your favorite editor and create a file called rectangle.js.

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:

Should

let chai = require('chai'); 
chai.should();
1.should.be.a('number');

Expect

var expect = require('chai').expect; 
expect(1).to.be.a('number');

Assert

let assert = require('chai').assert; 
assert.typeOf(1, 'number');

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
.$ ./node_modules/.bin/mocha

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

Code coverage is metric used to see how well your code is tested. If a piece of software has 100% test coverage it means that every line is executed at least once in the tests. One of the most popular way to generate coverage in JavaScript is using a library called Istanbul. It will output information about the code coverage to the command line as well as generating a comprehensive HTML report.

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 istanbul command.

$ 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!

Great! Using isparta and 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!

Conclusion

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.

Happy testing!


Originally published at onsen.io on August 4, 2015.

Like what you read? Give Onsen UI & Monaca Team a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.