In our first post of this series, we walked through using Travis to automate project testing. This time, I’ll show you how to use code coverage to assert code quality, and how to use Coveralls to do so as part of continuous integration.

Let’s say your project has a test suite. Great! …how do you know it’s running your code? Code coverage!

Code coverage tools show which lines of your project’s code are being run by your test suite. This identifies logic branches that aren’t being tested, and places where your code follows unexpected branches, even if it returns the values your tests expect. And if you’re using coveralls.io, you’ll get a sweet badge to show off your code’s quality :D

So, how do we make it happen?

Coverage

Most languages have tools for code coverage, but because we’re using Node.js, we’ll use jscoverage, which will modify our code so we can see which lines ran. To get jscoverage, use NPM:

npm install -g jscoverage

jscoverage will modify our code in pretty wild ways. For example, this:

if (process.env.DEBUG) {
  console.log("Let's get debuggy!");
}

… turns into this:

// ... truncated for sanity

var BASE;
if (_$jscmd("/Users/deus/.nvm/v0.11.13/lib/node_modules/jscoverage/lib/jscoverage.js", "cond", "30_8_13", typeof global) === "object") {
  _$jscmd("/Users/deus/.nvm/v0.11.13/lib/node_modules/jscoverage/lib/jscoverage.js", "line", 31);
  BASE = global;
} else if (_$jscmd("/Users/deus/.nvm/v0.11.13/lib/node_modules/jscoverage/lib/jscoverage.js", "cond", "32_15_13", typeof window) === "object") {
  _$jscmd("/Users/deus/.nvm/v0.11.13/lib/node_modules/jscoverage/lib/jscoverage.js", "line", 33);
  BASE = window;
} else {
  _$jscmd("/Users/deus/.nvm/v0.11.13/lib/node_modules/jscoverage/lib/jscoverage.js", "line", 35);
  throw new Error("[jscoverage] unknow ENV!");
}
if (BASE._$jscoverage) {
  _$jscmd("/Users/deus/.nvm/v0.11.13/lib/node_modules/jscoverage/lib/jscoverage.js", "line", 38);
  BASE._$jscmd(file, "init", lines, conds, source);
  _$jscmd("/Users/deus/.nvm/v0.11.13/lib/node_modules/jscoverage/lib/jscoverage.js", "line", 39);
  return;
}
_$jscmd("/Users/deus/.nvm/v0.11.13/lib/node_modules/jscoverage/lib/jscoverage.js", "line", 41);
var cov = {};

// ... truncated for sanity

if (process.env.DEBUG) {
    _$jscmd("test.js", "line", 2);
    console.log("Let's get debuggy!");
}

Gross!

That mess of code instruments our project so that every line has an “I ran!” statement right next to it. This lets us know which lines ran during tests and which lines didn’t. Luckily, the interface for the instrumented code is exactly the same as the uninstrumented version, but because jscoverage alters our code, we’ll want to place its output in a different folder before our tests try to require it:

jscoverage lib lib-cov

That instruments all the code in the lib folder, and puts the instrumented versions into lib-cov. The cov is short for coverage. Now our tests can require the instrumented code just the same as before:

// test.js
var app = require('../lib-cov');

Now we can get a coverage report — that is, a report on how well our tests cover our code — but how we do so will depend on what we’re using to run our tests. Many test runners, like Mocha or Istanbul, have built-in support for reporting coverage stats, so see if yours has documentation on working with jscoverage. For this series, we’ll be using Mocha, which generates reports like this:

mocha YOUR_TESTS/**.js -R html-cov > coverage.html

Which generates an HTML page displaying your coverage results.

Hooray! Coverage! But, how do we tell The Internet?

Coveralls

Coveralls.io is a service that saves your coverage reports to show coverage changes over time and to give you a sweet badge like this one:

orchestrate-coverage

To start using Coveralls, sign up! Then, in your project, install node-coveralls like this:

npm install coveralls --save-dev

If you’re using Mocha like I am, you’ll also need the mocha-lcov-reporter package to properly format your coverage report:

npm install mocha-lcov-reporter --save-dev

Then, in your .travis.yml file from [Part One], add an after_success step like this:

after_success:
- ./node_modules/.bin/jscoverage lib lib-cov
- ./node_modules/.bin/mocha YOUR_TESTS/**.js -R mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js

Wahoo! You’re all set. Now, the next time you commit code to your project, Travis will run your tests, and Coveralls will pick up the coverage report.

To get the badge, sign in to Coveralls, go to your project’s page, and click “Get Badge URLs”. That will give you badges in Markdown, RST, HTML, and other formats. Choose as you please, and you’re done.

Next up, we’ll talk about deploying our project to production based on test success and coverage reports.

Happy coding!