Skip to content
Permalink
Browse files
feat(preprocessor): free instrumenter
Allow any Istanbul instrumenter to be used in the karma-coverage.
Will help #120

Closes #101 #49

BREAKING CHANGE: Karma-coverage does not ship with additional instrumenter. You need to explicitly install the instrumenter you need.

Removed **Ibrik** instrumenter that need to be installed explicitly.

Quick list of known community instrumenters :
- [Ibrik](https://github.com/Constellation/ibrik) (CoffeeScript files instrumenter).
- [Ismailia](https://github.com/Spote/ismailia) (ES6 files instrumenter using Traceur).
- [Isparta](https://github.com/douglasduteil/isparta) (ES6 files instrumenter using 6to5).
  • Loading branch information
douglasduteil committed Feb 3, 2015
1 parent 0c99f75 commit 626e7b0
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 24 deletions.
@@ -206,26 +206,47 @@ coverageReporter: {
```

#### instrumenter
Karma-coverage infers the instrumenter regarding of the file extension.
The `.coffee` files are by default covered using
[Ibrik](https://github.com/Constellation/ibrik) (an
[Istanbul](https://github.com/gotwarlost/istanbul) analog for
CoffeeScript files). It is possible to override this behavior and point out an
Karma-coverage can infers the instrumenter regarding of the file extension.
It is possible to override this behavior and point out an
instrumenter for the files matching a specific pattern.
To do so, you need to declare an object under with the keys represents the
pattern to match, and the instrumenter to apply. The matching will be done
using [minimatch](https://github.com/isaacs/minimatch).
If two patterns match, the last one will take the precedence.

For example you can use [Ibrik](https://github.com/Constellation/ibrik) (an
[Istanbul](https://github.com/gotwarlost/istanbul) analog for
CoffeeScript files) with:

```javascript
coverageReporter: {
instrumenters: { ibrik : require('ibrik') }
instrumenter: {
'**/*.coffee': 'istanbul' // Force the use of the Istanbul instrumenter to cover CoffeeScript files
'**/*.coffee': 'ibrik'
},
// ...
}
```

You can pass options additional options to specific instrumenter with:

```javascript
var to5Options = { experimental: true };
// [...]
coverageReporter: {
instrumenters: { isparta : require('isparta') },
instrumenter: {
'**/*.js': 'isparta'
},
instrumenterOptions: {
isparta: { to5 : to5Options }
}
}
```


----

For more information on Karma see the [homepage].
@@ -1,13 +1,17 @@
var istanbul = require('istanbul'),
ibrik = require('ibrik'),
minimatch = require('minimatch'),
globalSourceCache = require('./sourceCache');
globalSourceCache = require('./sourceCache'),
extend = require('util')._extend;

var createCoveragePreprocessor = function(logger, basePath, reporters, coverageReporter) {
var log = logger.create('preprocessor.coverage');
var instrumenterOverrides = (coverageReporter && coverageReporter.instrumenter) || {};
var instrumenters = {istanbul: istanbul, ibrik: ibrik};
var instrumenters = extend({istanbul: istanbul}, (coverageReporter && coverageReporter.instrumenters));
var sourceCache = globalSourceCache.getByBasePath(basePath);
var instrumentersOptions = Object.keys(instrumenters).reduce(function getInstumenterOptions(memo, instrumenterName){
memo[instrumenterName] = (coverageReporter && coverageReporter.instrumenterOptions && coverageReporter.instrumenterOptions[instrumenterName]) || {};
return memo;
}, {});

// if coverage reporter is not used, do not preprocess the files
if (reporters.indexOf('coverage') === -1) {
@@ -20,8 +24,8 @@ var createCoveragePreprocessor = function(logger, basePath, reporters, coverageR
function checkInstrumenters() {
var literal;
for (var pattern in instrumenterOverrides) {
literal = String(instrumenterOverrides[pattern]).toLowerCase();
if (literal !== 'istanbul' && literal !== 'ibrik') {
literal = String(instrumenterOverrides[pattern]);
if (Object.keys(instrumenters).indexOf(literal) < 0) {
log.error('Unknown instrumenter: %s', literal);
return false;
}
@@ -38,25 +42,23 @@ var createCoveragePreprocessor = function(logger, basePath, reporters, coverageR
log.debug('Processing "%s".', file.originalPath);

var jsPath = file.originalPath.replace(basePath + '/', './');
var instrumenterLiteral = jsPath.match(/\.coffee$/) ? 'ibrik' : 'istanbul';
// default instrumenters
var instrumenterLiteral = 'istanbul';

for (var pattern in instrumenterOverrides) {
if (minimatch(file.originalPath, pattern, {dot: true})) {
instrumenterLiteral = String(instrumenterOverrides[pattern]).toLowerCase();
instrumenterLiteral = String(instrumenterOverrides[pattern]);
}
}

var instrumenter = new instrumenters[instrumenterLiteral].Instrumenter();
var instrumenter = new instrumenters[instrumenterLiteral].Instrumenter(instrumentersOptions[instrumenterLiteral] || {});

instrumenter.instrument(content, jsPath, function(err, instrumentedCode) {

if (err) {
log.error('%s\n at %s', err.message, file.originalPath);
}

if (instrumenterLiteral === 'ibrik') {
file.path = file.path.replace(/\.coffee$/, '.js');
}

// remember the actual immediate instrumented JS for given original path
sourceCache[jsPath] = content;

@@ -20,7 +20,6 @@
"author": "SATO taichi <ryushi@gmail.com>",
"dependencies": {
"istanbul": "~0.3.0",
"ibrik": "~2.0.0",
"dateformat": "~1.0.6",
"minimatch": "~0.3.0"
},
@@ -57,20 +57,50 @@ describe 'preprocessor', ->
expect(sandbox.__coverage__).to.have.ownProperty './file.js'
done()

it 'should preprocess the coffee code', (done) ->
process = createPreprocessor mockLogger, '/base/path', ['coverage', 'progress'], {}
file = new File '/base/path/file.coffee'
it 'should preprocess the fake code', (done) ->
fakeInstanbulLikeInstrumenter = ->
fakeInstanbulLikeInstrumenter::instrument = (_a, _b, callback) ->
callback()
return
process = createPreprocessor mockLogger, '/base/path', ['coverage', 'progress'],
instrumenters:
fakeInstanbulLike :
Instrumenter : fakeInstanbulLikeInstrumenter
instrumenter:
'**/*.fake': 'fakeInstanbulLike'
file = new File '/base/path/file.fake'

process ORIGINAL_COFFEE_CODE, file, (preprocessedCode) ->
sandbox =
a: true
something: ->

vm.runInNewContext preprocessedCode, sandbox
expect(file.path).to.equal '/base/path/file.js'
expect(sandbox.__coverage__).to.have.ownProperty './file.coffee'
expect(file.path).to.equal '/base/path/file.fake'
done()

it 'should preprocess the fake code with the config options', (done) ->
fakeInstanbulLikeInstrumenter = (options) ->
expect(options.experimental).to.be.ok
return
fakeInstanbulLikeInstrumenter::instrument = (_a, _b, callback) ->
callback()
return

process = createPreprocessor mockLogger, '/base/path', ['coverage', 'progress'],
instrumenters:
fakeInstanbulLike:
Instrumenter: fakeInstanbulLikeInstrumenter
instrumenterOptions:
fakeInstanbulLike:
experimental: yes
instrumenter:
'**/*.fake': 'fakeInstanbulLike'

file = new File '/base/path/file.fake'

process ORIGINAL_COFFEE_CODE, file, done

it 'should not preprocess the coffee code', (done) ->
process = createPreprocessor mockLogger, '/base/path', ['coverage', 'progress'],
instrumenter:

0 comments on commit 626e7b0

Please sign in to comment.