Testing React Web Apps with Mocha (Part 2)
21 Feb 2015In the last post, we used Mocha to test a React app with JSX and ECMAScript 6 (Harmony).
In this post we’ll set up continuous testing on Travis-CI. We’ll also take advantage of our Mocha testing setup to track code coverage on every build.
If you want to skip straight to the finished product, check out this repo.
Running Tests on Every Commit
Tests are more effective when they’re run on every commit, allowing for a clear association between each test failure and the commit at fault.
The easiest way to do this for a GitHub project is with Travis-CI. To set this
up, create a .travis.yml
file like this one file and enable
your project at travis-ci.org.
Why Code Coverage?
Running your tests on every commit is helpful, but how do you know that you’ve written enough tests? One way to answer this question is with code coverage, which tells you which lines of your code are executed by your tests.
(The red lines show that the failure case is untested.)
Code coverage can help guide your test writing. If one branch of an
if
statement is covered but the other isn’t, then it’s clear that you need to
write a new test.
Writing tests isn’t always the most fun part of software development. Tracking test coverage over time adds a dash of gamification to the process: it can be motivating to watch the coverage percentage go up!
Generating Code Coverage Data
Generating code coverage data can be fairly involved. It requires instrumenting your code with counters that track how many times each line is executed. In fact, we don’t know of any way to do this for Jest tests, which we used before switching to Mocha. It’s also hard to generate coverage data with Mocha, but here we get to benefit from its extensive ecosystem: someone has already done the hard work for us!
We used Blanket to instrument our code for coverage:
npm install --save-dev blanket glob
We also had to add a blanket
config section to our package.json
:
blanket-stub-jsx.js
is a custom compiler that we had to
write. As before, our decision to use JSX, Harmony and stubs has
simplified our code but made the processes that operate on our code more
complicated. This is a trade-off.
The "pattern": "src"
tells Blanket where to find modules to instrument for
coverage. If you don’t specify this, only files which are explicitly included
by your tests will contribute to coverage. Untested files won’t count. Telling
Blanket about them will reduce your test coverage percentage, but at least
you’re being honest. And it will encourage you to write more tests for those
untested files to bring that percentage back up!
Mocha includes a few “reporters” for displaying code coverage data. One of
these is html-cov
, which will generate an HTML page summarizing your code
coverage:
Here’s what it looks like:
(A web view of test coverage for BigComplicatedComponent.js. Note that this is the compiled code, not our original JSX/Harmony code. More on that below.)
Check out this repo for a fully-worked test setup based on the
Jest/React example. The single test is in
CheckboxWithLabel-test.js
.
Tracking Code Coverage on Every Commit
Much like the tests themselves, code coverage works best when you track it on every commit. If you don’t, coverage might drop without your realizing it.
coveralls.io is a test coverage site which is free for open source projects and integrates nicely with GitHub and Travis-CI. So long as you can produce coverage data in the correct format, coveralls will track the changes in your project’s test coverage, generate badges for your project and provide a nice test coverage browser.
Coveralls works best when you send it coverage data directly from a Travis worker. To set this up we installed a few NPM packages…
… and added this bit to our .travis.yml
file’s script
section:
Here’s what the code coverage data looks like on coveralls:
(Coverage of BigComplicatedComponent. Note that its render
method is never
called, because it’s stubbed in the test.)
It’s worth noting that coverage is measured on the transpiled JavaScript code, but displayed against the original code on Coveralls. This only works because the JSX/Harmony compiler preserves line numbers.
Conclusions
Continuous code coverage is one of the big wins of using Mocha to test React apps. It takes a bit of work to set up, but the motivation it gives you to write more tests is well worth the effort.
If you have any issues or ideas regarding this setup, please file an issue on our example repo.