Monday 16 February 2015

Running debuggable tests & coverage on the same karma server

Karma is one of the more popular javascript testing frameworks. But so far, there has been no option to run debugging & coverage on the same server. This issue’s been sitting on github for some years.

The main issue is that karma uses istanbul under the hood for coverage, which does not support source maps. Furthermore, due to istanbul’s detailed branch coverage, debugging, even if it were possible, would be rather slow. This appears to introduce the need for running two karma instances, one configured for debugging, another for coverage.

But there is a much simpler way. What if we were to include both builds within the same page? This configuration is too complex for karma’s build system to support without writing additional plugins, but hey, why not use the popular nodejs build systems directly? Here’s a simplified setup of mine which does exactly this:

var gulp = require('gulp');
var concat = require('gulp-concat-util');
var istanbul = require('gulp-istanbul');
var watch = require('gulp-watch');
var karma = require('karma');
var path = require('path');

gulp.task('test', function(){
  karma.server.start({
    frameworks: ['qunit'],
    reporters: ['coverage', 'progress'],
    autoWatch: false,
    files: ['dist/**.js']
  });
  watch('**/*.js', {}, function(){
    gulp.src('**/*.js')
      .pipe(concat.header('if(window.location.href.endsWith("debug.html")){'))
      .pipe(concat.footer('}'))
      .pipe(gulp.dest('dist/test'));
    gulp.src('**/*.js')
      .pipe(istanbul())
      .pipe(istanbul.hookRequire())
      .pipe(concat.header('if(!window.location.href.endsWith("debug.html")){'))
      .pipe(concat.footer('}'))
      .pipe(gulp.dest('dist/cover'))
      .on('end', function(){
        // monkey-patch to get rid of stdout
        var http = require('http');
        var request = http.request;
        http.request = function(options, response){return request(options);};
        karma.runner.run({});
        http.request = request;
      });
  });
  open('http://localhost:9876/');
});

The concat magic determines which script to run based on the current url (debug.html is, quite simply, karma’s debug page), and run fires off the signal to run tests.

If you’ve been reading carefully, the monkey-patch may appear to be rather confusing, but that’s due to karma.runner.run outputting the test results to the console, which is what the server’s doing at the same time. We wouldn’t want to have two outputs writing over each other, would we? (bug’s filed here).

Happy debugging!

No comments:

Post a Comment