gunnarlium / babel-jspm-karma-jasmine-istanbul

Babel JSPM Karma Jasmine Istanbul Coverage example and tutorial
54 stars 11 forks source link

Babel JSPM Karma Jasmine Istanbul Coverage Test

A sample repo to show what's need to get HTML code coverage reports working when using Babel, JSPM, Karma, Jasmine and Istanbul.

To install and run:

$ npm install -g jspm karma-cli
$ npm install
$ karma start karma.conf.js
$ open coverage/phantomjs/index.html

Tutorial

When living on the edge, getting the tooling of the past to work as expected requires a bit of extra work. I'll walk you through the steps you need to get set up.

The goal

Set up Karma testing with code coverage for a project that uses Babel, JSPM and Jasmine.

The problem

Both your tests and your code written in ES6 need to be transpiled to ES5 before being run. However, you want your code coverage report to show you the files as they were before transpilation, so you recognize the content.

The solution

Use source maps to make the generated HTML match you're original files.

Bootstrapping your project

Make sure you have jspm installed globally.

$ npm install -g jspm

Init JSPM:

$ jspm init

Use the defaults for everything except server baseURL, set this to src. It should look something like this:

$ jspm init
Package.json file does not exist, create it? [yes]:
Would you like jspm to prefix the jspm package.json properties under jspm? [yes]:
Enter server baseURL (public folder path) [./]:src
Enter jspm packages folder [src/jspm_packages]:
Enter config file path [src/config.js]:
Configuration file src/config.js doesn't exist, create it? [yes]:
Enter client baseURL (public folder URL) [/]:
Which ES6 transpiler would you like to use, Traceur or Babel? [babel]:

With package.json created, also lock down the version of jspm:

$ npm install --save-dev jspm

As JSPM currently defaults to Babel 5, update the jspm key in package.json to use Babel 6:

  "jspm": {
    "directories": {
      "baseURL": "src"
    },
    "devDependencies": {
      "babel": "npm:babel-core@^6.3.17",
      "babel-runtime": "npm:babel-runtime@^6.3.17",
      "core-js": "npm:core-js@^1.1.4"
    }
  }

As the purpose is to get tests set up, we'll start by writing a simple test. In src/hello.spec.js, enter:

'use strict';

import {hello} from './hello';

describe('hello', () => {

    it('should return Hello Foo', function () {
        expect(hello()).toEqual('Hello Foo');
    });
});

We're using a little bit of ES6 here, to show that your tests can also be written in ES6.

Go ahead an create the implementation at the same time. In src/hello.js enter:

'use strict';

export function hello() {
    let name = 'Foo';
    let greeting = `Hello ${name}`;

    if (false) {
        // Should not be covered
        return 'Good bye';
    }

    return greeting;
}

Setting up the test environment

With our test written, it's time to start adding a few test related dependencies, so we can run it.

First, let's install the basics needed for Jasmine and Karma with PhantomJS:

$ npm install -g karma-cli
$ npm install --save-dev jasmine jasmine-core karma karma-jasmine karma-chrome-launcher karma-jspm

Also, create a simple karma.conf.js:

/* global module */
module.exports = function (config) {
    'use strict';
    config.set({
        autoWatch: true,
        singleRun: true,

        frameworks: ['jspm', 'jasmine'],

        jspm: {
            config: 'src/config.js',
            loadFiles: [
                'src/*.spec.js'
            ],
            serveFiles: [
                'src/!(*spec).js'
            ]
        },

        proxies: {
            '/src/': '/base/src/',
            '/jspm_packages/': '/src/jspm_packages/'
        },

        browsers: ['ChromeHeadless'],

        reporters: ['progress'],

    });

};

At this point, you should be able to run karma start karma.conf.js, but it will error without much explanation, as your transpiling isn't quite ready yet. You need to install babel-core and karma-babel-preprocessor:

$ npm install --save-dev babel-core babel-preset-es2015 babel-polyfill karma-babel-preprocessor

Load the polyfill in your Karma config:

files: [
    'node_modules/babel-polyfill/dist/polyfill.js'
]

Set up your Babel config in .babelrc:

{
  "presets": ["es2015"]
}

This is needed since SystemJS depends on Function.bind(), which is not supported in PhantomJS.

If you rerun Karma, your tests should be passing. If you didn't care about HTML coverage reports, you could go on your way, and have a fully working ES6, Karma, Jasmine, JSPM and Babel setup. Not too bad!

Coverage

For coverage reports, we'll use Istanbul and the Karma coverage plugin:

$ npm install --save-dev istanbul karma-coverage

You also need to update your karma config:


reporters: ['progress', 'coverage'],

preprocessors: {
    'src/!(*spec).js': ['babel', 'coverage']
},

coverageReporter: {
    reporters: [
        {
            type: 'text-summary'
        },
        {
            type: 'html',
            dir: 'coverage/'
        }
    ]
}

If you run your tests now, you should find a coverage report in the coverage folder, with proper highlighting of covered code. However, what you're seeing is the transpiled code. For this simple code, that shouldn't be too hard to mentally connect to your source files, but wouldn't it better if you could be looking at ES6 code instead? Let's fix that!

You'll need a couple more dependencies. First, we'll install isparta, which is designed to be used with Istanbul with Babel and Karma/Karma Coverage:

$ npm install --save-dev isparta

isparta works as a custom instrumentor, which must be registred in Karma config:

coverageReporter: {
    instrumenters: {isparta: require('isparta')},
    instrumenter: {
        'src/*.js': 'isparta'
    },

    reporters: [
        {
            type: 'text-summary',
        },
        {
            type: 'html',
            dir: 'coverage/',
        }
    ]
}

If you're reading this in the future, your coverage report may already be showing you ES6 code. As I'm stuck in the past, I need to use a custom version of karma-coverage. Update your package.json to use douglasduteil/karma-coverage#next:

"karma-coverage": "douglasduteil/karma-coverage#next"

Now you're almost there. Your tests are running, you get coverage reports, and their all in beautiful ES6. There's one problem, however. If you look closely at the coverage for hello.js, you'll see that the coverage is highlighting the wrong lines. We can fix this by adding source maps.

$ npm install --save-dev karma-sourcemap-loader

In Karma config:


preprocessors: {
    'src/!(*spec).js': ['babel', 'sourcemap', 'coverage']
},

babelPreprocessor: {
    options: {
        sourceMap: 'inline',
        blacklist: ['useStrict']
    },
    sourceFileName: function(file) {
        return file.originalPath;
    }
},

Again, if you're living in the future, this might already be working for you. If not, you need to use another custom version of a dependency, this time Istanbul:

"istanbul": "gotwarlost/istanbul.git#source-map"

Boom! If you run Karma again, line highlighting should also be working.