Code Coverage for Karma/Angular/Browserify/ES6

Code Coverage for Karma/Angular/Browserify/ES6

If I thought it was painful getting code coverage working for a Node TypeScript project, then getting it working in Karma was even more painful. The worst thing is, there’s precious little (useful) documentation out there for it. After two days worth of experiments, I got it working.

The biggest issue is instrumenting the code correctly, so that the ES6 code is displayed in your tests AND the coverage reports on the ES6 code, not the compiled ES5 code.

Some of the tutorials I found would display the ES6 code, but perform the tests on the ES5 code. For example, when writing a class, the if/else statements generated during transpilation to ensure it was called with new were coming out as untested code.

class Hello {
}

Compiles to…

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Hello = function Hello() {
    _classCallCheck(this, Hello);
};

We don’t want to test the _classCallCheck function every time we use a class - that’s the transpiler’s responsibility.

Dependencies Required
IMPORTANT

The karma-coverage package requires a fork in GitHub and not the one hosted on npm. This is irritating and I’d like to do something about that. However, for the time being, install it like this…

npm install git://github.com/douglasduteil/karma-coverage.git#next --save-dev
Gruntfile.js
var isparta = require("isparta");
var istanbul = require("browserify-istanbul");
var loader = require("load-grunt-tasks");

module.exports = function (grunt) {

    /* Load all grunt tasks */
    loader(grunt);

    grunt.initConfig({

        karma: {
            coverage: {

                autoWatch: false,

                browsers: [
                    "PhantomJS"
                ],

                browserify: {
                    debug: true,
                    transform: [
                        "babelify",
                        istanbul({
                            instrumenter: isparta,
                            ignore: [
                                "**/node_modules/**",
                                "**/test/**"
                            ]
                        })
                    ]
                },

                colors: true,

                coverageReporter: {
                    dir: "./coverage",
                    reporters: [{
                        type: "lcov",
                        subdir: "/"
                    }, {
                        type: "json",
                        subdir: "/",
                        file: "coverage.json"
                    }]
                },

                files: [
                    "node_modules/angular/angular.js",
                    "src/scripts/app.js",
                    "src/views/**/*.html",
                    "node_modules/angular-mocks/angular-mocks.js",
                    "test/unit/**/*.js"
                ],

                frameworks: [
                    "browserify",
                    "mocha",
                    "chai",
                    "chai-sinon"
                ],

                preprocessors: {
                    "src/scripts/app.js": [
                        "browserify",
                        "coverage"
                    ],
                    "test/unit/**/*.js": [
                        "browserify"
                    ]
                },

                reporters: [
                    "mocha",
                    "coverage"
                ],

                singleRun: true

            }
        }

    });

}

If you want to run checks to ensure that the coverage meets a minimum threshold, then the instructions in my TypeScript post are the way to do it.