Code coverage tests in ES6, TypeScript or CoffeeScript

Code coverage tests in ES6, TypeScript or CoffeeScript

Generally speaking, I like my projects to have a code coverage check to ensure it has above a certain level of coverage. I usually set this quite high (typically 100%) so it’s actually a challenge and it enforces a good level of rigour.

In POJS (plain old JavaScript), this is nice and easy as there are plenty of packages for checking - my favourite is Grunt Mocha Istanbul.

Grunt, really?

Yup. I still, use Grunt as it meets my needs well enough that I don’t yet need to move to Gulp. I keep my tasks lean, so there’s no appreciable speed difference. And I’ve been using Grunt for about 3 years, so have pretty much every task I’ll ever need in a repo somewhere which I’d need to write in Gulp if I were to switch. I’ve toyed with the idea, but I’ve never found enough benefit to justify the cost.

But what about when you want to transpile your JavaScript from ES6, TypeScript or CoffeeScript? There are some packages out there, such as Coffee Coverage or Ibrik certainly, but I find these a bit clunky, difficult to configure and don’t work with ES6 or TypeScript. And you can’t use the existing Istanbul package as it will output the transpiled JavaScript. This may be minified and is almost certainly going to contain stuff which won’t be used in your runtime, such as the extenders.

Enter Remap Istanbul. This rewrites your generated coverage files to look the same as your source code (to my mind, Istanbul should support this natively and hopefully they will one day). This, however, doesn’t help you with generating the coverage files or check that you’ve met the coverage thresholds.

How I Do It

As a workflow, this is the process I follow:

  • Transpile my source code and unit test files
  • Run the transpiled tests through Istanbul and generate the coverage files
  • Rewrite the coverage files
  • Check that the thresholds are met

And to illustrate, this is my Gruntfile.js. You need to install these dependencies to run:

Run with grunt codecoverage.

module.exports = function (grunt) {

    require("load-grunt-tasks"); // Loads all grunt tasks
    grunt.loadNpmTasks("remap-istanbul"); // Manually load remap-istanbul

    grunt.initConfig({

        /* Cleans out transpiled files */
        clean: {
            dist: {
                files: [{
                    src: [
                        "./coverage",
                        "./dist"
                    ]
                }]
            }
        },

        /* Generates the coverage JSON and HTML files */
        "mocha_istanbul": {
            generateReport: {
                options: {
                    recursive: true,
                    root: "./dist/src"
                },
                src: "./dist/test/unit/**/*.js"
            }
        },

        /* Rewrites the JSON and HTML coverage files with your actual ES6/TS/CS files */
        remapIstanbul: {
            dist: {
                options: {
                    reports: {
                        "html": "./coverage/lcov-report",
                        "json": "./coverage/coverage.json"
                    }
                },
                src: "./coverage/coverage.json"
            }
        },

        /* Checks the coverage meets the threshold */
        coverage: {
            check: {
                options: {
                    thresholds: {
                        branches: 100,
                        functions: 100,
                        lines: 100,
                        statements: 100
                    },
                    dir: "./coverage"
                }
            }
        },

    });

    grunt.registerTask("transpile", function () {
        /*
         Define your own transpile task, depending upon the
         language (ES6, TS, CS) you are using. Be sure to
         include both the /src and /test directories.
         */
    });

    grunt.registerTask("codecoverage", "Runs the code coverage tests", [
        "clean",
        "transpile",
        "mocha_istanbul:generateReport",
        "remapIstanbul:dist",
        "coverage:check"
    ]);

};