No line of your JavaScript code uncovered

Published: 2012-12-25 by Lars  pipelineKPIs

Being able to get fast feedback from failing unit tests is useful. And if you could easily identify the parts of your code that you still need to write tests for, you would get more comprehensive feedback.

There is a plugin for Grunt that can use the JSCoverage tool to produce a coverage report while running your unit tests.

First step is to install JSCoverage. Unfortunately I have not been able to find a working npm package for JSCoverage, so what you can do is download a binary and put it somewhere in your path. The grunt-qunit-cov plugin also needs PhantomJS to be on the path, so you might need to install PhantomJS separately for that.

Grunt has a grunt-qunit-cov plugin that will combine the QUnit runner with JSCoverage.

You will need to configure the plugin, so change your Gruntfile.js to include:

    grunt.loadNpmTasks('grunt-qunit-cov');
    gruntConfig['qunit-cov'] = {
        test:
        {
            minimum: 0.99,
            baseDir: 'src',
            srcDir: 'src/js',
            depDirs: ['src/lib', 'src/test'],
            outDir: 'output/coverage',
            testFiles: ['src/test/index.html']
        }
    };
    grunt.registerTask('coverage', 'qunit-cov');

In this example the plugin will fail the build if the coverage is not 99% or more.

To demonstrate the capabilities of JSCoverage, create an application file src/js/password.js:

/*global window*/
window.passwordStrength = function (password) {
    'use strict';
    var result = 0;
    if (password.length > 4) {
        result += 1;
    }
    if (password.length > 8) {
        result += 1;
    }
    return result;
};

Then add a test for it in src/test/index.html:

    <title>jsdevenv tests</title>
    <div id="qunit"></div>
    <script>    
        runTests = function() {
            module('password');
            test('strength is 0', function () {
                 equal(passwordStrength('abc'), 0, 'abc');
            });
        }
    </script>

Then invoke

$ grunt coverage

This will fail with the following output:

  Coverage in 75%
   Error: Coverage don't reach 99%</pre>

A detailed report is saved in output/coverage/out/coverage.html

And if you click on the link to password.js, you will see exactly which lines of password.js is not covered by any of the tests.

To fix the broken build, add the following two tests in src/test/index.html:

   test('strength is 1', function () {
     equal(passwordStrength('lemon'), 1, 'abc');
   });
   test('strength is 2', function () {
     equal(passwordStrength('lemonades'), 2, 'abc');
   });

Now grunt coverage will succeed with this message:

  Coverage in 100%

And the coverage reports looks like this:

Most continuous integration systems (like Jenkins, TeamCity and Bamboo, but not yet Travis-CI) allow you to configure a set of artifacts that are made accessible for every build. See this screenshot from TeamCity:

Now you can make sure that you maintain a comprehensive test suite for your front-end JavaScript code. Enjoy!

This post is part of a series on Continuous Integration for front-end JavaScript, read the other posts in the series:

Discuss on Twitter