Setting up Mocha & JSCoverage

Since publishing my article on Javascript Testing with Mocha and follow-up on using JSCoverage, I’ve had some people asking questions about how to get it all set up.  I’m going to go through a brief guide on how to take a project with tests in Mocha, and get coverage running on it.

Here’s a motivational sample of the output we’ll be getting to:

Step 1: Installing JSCoverage and Mocha

If you’re on a machine with Homebrew installed, getting this set up will be as easy as:

$ brew install jscoverage

There’s also an apt package for you lucky linux folks:

$ sudo apt-get install jscoverage

If you don’t have either of these, you’ll be building it yourself.  Which is really easy too:

wget http://siliconforks.com/jscoverage/download/jscoverage-0.5.tar.bz2

tar xvfj jscoverage-0.5.tar.bz2

cd jscoverage-0.5

./configure

make

make install

It will be installed into /usr/local and you should be all set.  Give `jscoverage` a shot and you should see its default output.

There is an npm package by the creator of mocha, but I haven’t given it a go yet.

You’ll need a global version of mocha installed for the Makefile at the end, and for that you can roll with:

$ npm install -g mocha

Step 2: Loading JSCoverage in Tests

Now that we have jscoverage installed, we need to call into it from our tests.  Because of the way JSCoverage has to work, we first generate a folder equivalent to our `lib` folder but jscoverag’ed:

$ jscoverage lib lib-cov

On newer version of jscoverage, the library also can do highlight – but since that will mess up the test output, we’ll want to turn it off.  To run jscoverage without highlighting we go instead for:

jscoverage --no-highlight lib lib-cov

Once we have this, our tests are still loading the copy in `lib`.  We need to go into each of our tests files, and if a certain environment variable is present, use `lib-cov` instead.  I like to do this by defining a variable at the top of my test and then basing other loads off of that:

var libpath = process.env['YOUR_LIBRARY_NAME_COV'] ? ‘../lib-cov’ : ‘../lib’;

var something = require(libpath + ‘/something’);

var other = require(libpath + ‘/other’);

The name of the environment variable should be something unique.  The reason for a unique name is that if you using something like “COV” as the environment variable name, you’ll end up also loading jscoverage’ed versions of other libraries you have as dependencies, and they’ll cloud up your coverage reports.

Now we can run the tests with:

YOUR_LIBRARY_NAME_COV=1 mocha -R html-cov > coverage.html

And the coverage.html file will contain our coverage report

Step 3: Using a Makefile

All of this typing will get annoying pretty fast, and for that I use a Makefile.  Here’s what it should look like:

test:

 npm test

coverage:

 jscoverage --no-highlight lib lib-cov

 YOUR_LIBRARY_NAME_COV=1 mocha -R html-cov > coverage.html

 rm -rf lib-cov

.PHONY: test

With this in place, running `make` or `make test` will run your tests, and running `make coverage` will generate your coverage report!

A Few Notes

I’d advise adding `coverage.html` and `lib-cov` to your `.gitignore` file, so that they don’t get versioned.

Also – “html-cov” will not show you test failures, so make sure you run `make test` before pushing out new versions of anything.

Example

For an example of all of this in action, check out seejohnrun/htmlcov-example on GitHub!

 

Tags: , ,

  • Yuan Feng

    I found out jscoverage deal with no-ascii string wrong.

    e.g: ‘你好’ will convert to “u00e4u00bdu00a0u00e5u00a5u00bd”

  • Pascal

    Very good guideline. Helped me a lot. works!

  • http://www.facebook.com/fjvera Javi Vera

    thanks for the nice guide!

  • Guest

    can anyone tell me what YOUR_LIBARARY_NAME_COV is suppose to be? how are ppl who have never seen code coverage suppose to even understand that part?

    • http://seejohncode.com/ John Crepezzi

      It can be any name, as long as it is the same in the places that it is used.
      The reason isn’t not just COV, is that will actually run the tests for mocha itself also

      In general, if you library is called StoryBoard, I’d name the constant something like STORYBOARD_COV

  • Matthew

    What should be in the “lib” folder that we recreate as lib-cov? I think our project has a bit of a strange folder structure – should “lib” just be the root folder of all our own (non-engine, non-external-library) code?

    • http://seejohncode.com/ John Crepezzi

      yep – `lib` would be your project files – can be called anything though

    • Matthew

      Hah, wow! Quick reply on an old blog post. Thanks heaps :)

    • http://seejohncode.com/ John Crepezzi

      Any time :)

  • Joshua Gough

    Thanks, this was very useful to me.

    I created a helper wrapper of require to make this easier when you have multiple test files. Here it is:

    module.exports = (appName, envVarCoverageToggleName=”, pathToRawFiles=”, pathToCoveredFiles=”) ->
    return (moduleName) ->
    envVarCoverageToggleName = “#{appName}_cov” if envVarCoverageToggleName is ”
    pathToRawFiles = “../#{appName}” if pathToRawFiles is ”
    pathToCoveredFiles = “../#{appName}_cov” if pathToCoveredFiles is ”
    modulesPath = if process.env[envVarCoverageToggleName]? then pathToCoveredFiles else pathToRawFiles
    modulePath = “#{modulesPath}/#{moduleName}”
    return require(modulePath)

    In practice:

    requireCover = require(‘./requireCover’)(‘app’)
    server = requireCover ‘serverClass’
    testData = requireCover ‘testData’
    config = requireCover ‘config’

    From my command line I do this:

    #!/usr/bin/sh
    export app_cov=1
    ../../lib/jscoverage –no-highlight ../app ../app_cov
    mocha -R html-cov *.tests*js >coverage.html

  • Joshua Gough

    Here’s a repo for the helper file in both coffee and js: https://github.com/JogoShugh/requireCover

  • JoshuaToenyes

    Thank you! This helped a lot! I love your method of defining an environment variable to modify the require() directory.

  • Jon

    Its a nice example but I’m using mocha-phantomjs, how does this fit in with your testrunner html file which you need to supply when you run mocha-phantomjs? Any ideas? Also which directory do you run the run command from?

    • http://seejohncode.com/ John Crepezzi

      I haven’t worked specifically with mocha-phantomjs, but I’d imagine those two don’t really interact. The command is run from the root of your project directory as long as your lib/ directories are the same as mine – if not, you’ll need to update some paths

  • Leonardo Apolonio

    i’m trying to run this manually from command line (to possible integrate with jenkins) after “jscoverage test test-cov” where do i run “mocha -R html-cov > coverage.html”? running the command in test-cov throws an error….

    • http://seejohncode.com/ John Crepezzi

      I advocate using a Makefile like in the tutorial
      What error are you seeing?

    • Leonardo Apolonio

      dev@ubuntu:~/Documents/test$ jscoverage –no-highlight files/ test-cov/

      dev@ubuntu:~/Documents/test$ cd test-cov/

      dev@ubuntu:~/Documents/test/test-cov$ mocha -R html-cov > coverage.html

      node.js:201

      throw e; // process.nextTick error, or ‘error’ event on first tick

      ^

      ReferenceError: _$jscoverage is not defined

      at Object. (/home/dev/Documents/test/test-cov/test.js:40:7)

      at Module._compile (module.js:441:26)

      at Object..js (module.js:459:10)

      at Module.load (module.js:348:32)

      at Function._load (module.js:308:12)

      at Module.require (module.js:354:17)

      at require (module.js:370:17)

      at /usr/local/lib/node_modules/mocha/lib/mocha.js:152:27

      at Array.forEach (native)

      at Mocha.loadFiles (/usr/local/lib/node_modules/mocha/lib/mocha.js:149:14)

      at Mocha.run (/usr/local/lib/node_modules/mocha/lib/mocha.js:306:31)

      at Object. (/usr/local/lib/node_modules/mocha/bin/_mocha:339:7)

      at Module._compile (module.js:441:26)

      at Object..js (module.js:459:10)

      at Module.load (module.js:348:32)

      at Function._load (module.js:308:12)

      at Array.0 (module.js:479:10)

      at EventEmitter._tickCallback (node.js:192:41)

    • http://seejohncode.com/ John Crepezzi

      Don’t `cd` into the test-cov directory, and you need an environment variable when you call mocha to indicate it should run with the test-cov directory instead of the test directory

  • Alexander Bykhov

    Thanks. Great post! =)

    • http://seejohncode.com/ John Crepezzi

      thanks :)

  • David

    There’s no more new releases for jscoverage, have you tried JSCover to run a test with Mocha?

    • http://seejohncode.com/ John Crepezzi

      I’ve not personally tried JSCover, but it looks like it should be a compatible output, so you should be able to just substitute it for jscoverage