Code Coverage with es6, Babel, Karma, Mocha, and Webpack

I was trying to get JavaScript unit testing set up at work and was really struggling. While I could get unit tests and established a testing framework I wasn’t able to determine my code coverage. For those of you that haven’t tested before, code coverage is a really important aspect of unit tests because it will tell you where you have gaps in your tests. If you’re not testing a specific branch or function you have a greater chance of pushing out a bug because the code isn’t tested.  So code coverage is pretty important.

Take this piece of my devDependencies within my package.json.

package.json:

"devDependencies": { 
    "babel-core": "6.23.1", 
    "babel-loader": "6.3.2", 
    "babel-preset-es2015": "6.22.0", 
    "babel-preset-stage-1": "6.22.0", 
    "chai": "3.5.0", 
    "gulp-mocha": "4.0.1", 
    "karma": "1.5.0", 
    "karma-cli": "1.0.1", 
    "karma-coverage": "1.1.1", 
    "karma-mocha": "1.3.0", 
    "karma-phantomjs-launcher": "1.0.2", 
    "karma-sinon-chai": "1.2.4", 
    "karma-webpack": "2.0.2", 
    "mocha": "3.2.0", 
    "sinon": "1.17.7", 
    "sinon-chai": "2.8.0", 
    "webpack": "2.2.1" 
} 

This is a pretty standard build out when you’re using es6 (Babel) and are transpiling down from 6 to 5 as part of your bundling/minifying/uglifying process (Webpack). I chose the Karma/Mocha/Sinon/Chai technology stack simply because it’s widely adopted and lightweight. Some people prefer Jasmine more, which is fine, Jasmine comes with a lot of this functionality built-in, but I like to have options.

A lot of sites tell you to set up your karma.conf.js file something like this:

karma.conf,js


const src = './scripts/**/*.js',
      tests = './tests/**/*.spec.js';

const karmaConfig = {
    frameworks: ['mocha', 'sinon-chai'],
    files: [
        src,
        tests
    ],
    preprocessors: {
        src: ['webpack', 'coverage'],
        tests: ['webpack']
    },
    webpack: webpackConfig('test'),
    reporters: ['coverage'],
    browsers: ['PhantomJS'],
    client: {
        captureConsole: false
    },
    specReporter: {
        showSpecTiming: true
    },
    reportSlowerThan: 25,
    coverageReporter: {
        dir: 'coverage',
        reporters: [
            { type: 'text' },
            { type: 'text-summary' },
            { type: 'html' }
        ]
    }
};

karmaConfig.preprocessors[src] = ['webpack', 'coverage'];
karmaConfig.preprocessors[tests] = ['webpack'];

module.exports = function (config) {
    config.set(karmaConfig);
}

If you have something like this you’ll get bundled output and your tests will run, but your test coverage will be extremely low. If you add the coverage reporter to the tests you’ll likely get an error saying you can’t require the module because the module is already required. You’ve created a cyclical reference.

What we want really is to run the tests, and from the tests determine what source code was executed by the tests. But we also need to run the tests and code coverage on the non-transpiled code. In order to do this we need to include another handy babel package:

npm install babel-plugin-istanbul --save-dev

Istanbul is pretty much the gold standard when it comes to coverage reporting in the front-end world and it does this extremely well. I also have a JSON file of config settings, that currently has this node for Babel:

config.json


"babel": {
     "presets": [
          ["es2015", {
               "modules": false
          }],
          "stage-1"
     ]
}

So I need to add another configuration to this file:


"babel": {
     "presets": [
          ["es2015", {
               "modules": false
          }],
          "stage-1"
     ],
     "plugins": [
          ["istanbul", {
               "exclude": [
                    "**/*.spec.js"
                ]
          }]
     ]
}

You’ll notice a line about exclusions. This plugin by default will exclude certain naming conventions from your code coverage. If you don’t use one of the standards (which sometimes I don’t) it will include the test code files as part of your code coverage report – not good!  So I just add in the path to my test files to prevent this.

We also need to remove the coverage reporter from the files but leave the coverage reporter settings. This seems wrong but I promise this works. We also don’t want to include source files in our karma.conf.js file because right now we only want to get coverage for files that we have created a test file for. Why? Well what if we had a vendor script? If we included that file we’d be penalized for not writing unit tests on the file or maybe we’d write unit tests on the file anyway, which could be troublesome if it’s not written for testability. Ideally third-party and vendor scripts have been tested during the development phase.


const tests = './tests/**/*.spec.js';

const karmaConfig = {
    frameworks: ['mocha', 'sinon-chai'],
    files: [
        tests
    ],
    preprocessors: {
        tests: ['webpack']
    },
    webpack: webpackConfig('test'),
    reporters: ['coverage'],
    browsers: ['PhantomJS'],
    client: {
        captureConsole: false
    },
    specReporter: {
        showSpecTiming: true
    },
    reportSlowerThan: 25,
    coverageReporter: {
        dir: 'coverage',
        reporters: [
            { type: 'text' },
            { type: 'text-summary' },
            { type: 'html' }
        ]
    }
};

karmaConfig.preprocessors[tests] = ['webpack'];

module.exports = function (config) {
    config.set(karmaConfig);
}

Now when we run our tests we will get coverage only on the files that we want to have coverage for. Look out for posts on how to write unit tests and how to write your code to be testable in the future. There will also be a post on how to test third-party scripts, because sometimes it’s a critical component and you need the certainty that upgrades won’t break functionality on the site.

Pin It
Read More Leave comment

Simple NodeJS Web Server

I’m working on a personal project where I need to spin up a simple web server to serve up some deployable assets. In order to get a low overhead server I’m looking into a NodeJS web server.  So I set out to create one. This is the first, and simplest, one I could fine. It gets the job done but I think I probably need something more feature rich. This is as bare bones as it gets.  Let’s dig into this.

package.json:

"dependencies": {
    "connect": "^3.5.0",
    "serve-static": "^1.11.2"
}

This web server, outside of Node, only requires two packages: connect and serve-static. Then, I create a server.js file with the following code:

const connect = require('connect'),
      serveStatic = require('serve-static');

const port = '8080';
const location = './dist';

connect().use(serveStatic(location)).listen(port, function() {
    console.info('Server running on http://localhost:'+port+'...');
});

In a command prompt that’s navigated to the location where this code is located, type node server.js and it starts the web browser.

This initializes a simple web server at http://localhost:8080 and then loads up anything loaded in the location variable. It works, but doesn’t really have any features other than this. So I’ll be looking for a second version of this, but wanted to share this one as it’s super simple and in a pinch can be used to spin up the most basic of web servers.

Pin It
Read More Leave comment