Skip to content

Commit

Permalink
feat(config): instrumenter override option
Browse files Browse the repository at this point in the history
Enable fine-tuning which preprocessor should be used for which files
Add README.md section
Add tests
Update existing tests to comply with new dependency requirement
  • Loading branch information
gvarsanyi committed May 22, 2014
1 parent b0580ee commit ee3e68e
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 15 deletions.
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ module.exports = function(config) {
preprocessors: {
// source files, that you wanna generate coverage for
// do not include tests or libraries
// (these files will be instrumented by Istanbul via Ibrik)
// (these files will be instrumented by Istanbul via Ibrik unless
// specified otherwise in coverageReporter.instrumenter)
'src/*.coffee': ['coverage'],

// note: project files will already be converted to
Expand Down Expand Up @@ -127,6 +128,27 @@ 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
instrumenter for the files matching a specific pattern.
To do so, you need to declare an object under with the keys representing 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.

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

----

For more information on Karma see the [homepage].
Expand Down
51 changes: 42 additions & 9 deletions lib/preprocessor.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
var istanbul = require('istanbul'),
ibrik = require('ibrik');
var istanbul = require('istanbul'),
ibrik = require('ibrik'),
minimatch = require('minimatch');

var createCoveragePreprocessor = function(logger, basePath, reporters) {
var createCoveragePreprocessor = function(logger, basePath, reporters, coverageReporter) {
var log = logger.create('preprocessor.coverage');
var jsInstrumenter = new istanbul.Instrumenter();
var coffeeInstrumenter = new ibrik.Instrumenter();
var instrumenterOverrides = coverageReporter.instrumenter || {};
var instrumenters = {istanbul: istanbul, ibrik: ibrik};

// if coverage reporter is not used, do not preprocess the files
if (reporters.indexOf('coverage') === -1) {
Expand All @@ -13,23 +14,55 @@ var createCoveragePreprocessor = function(logger, basePath, reporters) {
};
}

// check instrumenter override requests
function checkInstrumenters() {
var literal;
for (var pattern in instrumenterOverrides) {
literal = String(instrumenterOverrides[pattern]).toLowerCase();
if (literal !== 'istanbul' && literal !== 'ibrik') {
log.error('Unknown instrumenter: %s', literal);
return false;
}
}
return true;
}
if (!checkInstrumenters()) {
return function(content, _, done) {
return done(1);
};
}

return function(content, file, done) {
log.debug('Processing "%s".', file.originalPath);

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

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

var instrumenter = new instrumenters[instrumenterLiteral].Instrumenter();

instrumenter.instrument(content, jsPath, function(err, instrumentedCode) {
if(err) {
if (err) {
log.error('%s\n at %s', err.message, file.originalPath);
}

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

done(instrumentedCode);
});
};
};

createCoveragePreprocessor.$inject = ['logger', 'config.basePath', 'config.reporters'];
createCoveragePreprocessor.$inject = ['logger',
'config.basePath',
'config.reporters',
'config.coverageReporter'];

module.exports = createCoveragePreprocessor;
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
],
"author": "SATO taichi <ryushi@gmail.com>",
"dependencies": {
"dateformat": "~1.0.6",
"ibrik": "~1.1.1",
"istanbul": "~0.2.3",
"ibrik": "~1.1.1",
"dateformat": "~1.0.6"
"minimatch": "~0.3.0"
},
"peerDependencies": {
"karma": ">=0.9"
Expand Down
30 changes: 27 additions & 3 deletions test/preprocessor.spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe 'preprocessor', ->


it 'should not do anything if coverage reporter is not used', (done) ->
process = createPreprocessor mockLogger, null, ['dots', 'progress']
process = createPreprocessor mockLogger, null, ['dots', 'progress'], {}
file = new File '/base/path/file.js'

process ORIGINAL_CODE, file, (preprocessedCode) ->
Expand All @@ -45,7 +45,7 @@ describe 'preprocessor', ->


it 'should preprocess the code', (done) ->
process = createPreprocessor mockLogger, '/base/path', ['coverage', 'progress']
process = createPreprocessor mockLogger, '/base/path', ['coverage', 'progress'], {}
file = new File '/base/path/file.js'

process ORIGINAL_CODE, file, (preprocessedCode) ->
Expand All @@ -58,7 +58,7 @@ describe 'preprocessor', ->
done()

it 'should preprocess the coffee code', (done) ->
process = createPreprocessor mockLogger, '/base/path', ['coverage', 'progress']
process = createPreprocessor mockLogger, '/base/path', ['coverage', 'progress'], {}
file = new File '/base/path/file.coffee'

process ORIGINAL_COFFEE_CODE, file, (preprocessedCode) ->
Expand All @@ -70,3 +70,27 @@ describe 'preprocessor', ->
expect(file.path).to.equal '/base/path/file.js'
expect(sandbox.__coverage__).to.have.ownProperty './file.coffee'
done()

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

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

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

it 'should fail if invalid instrumenter provided', (done) ->
work = ->
createPreprocessor mockLogger, '/base/path', ['coverage', 'progress'],
instrumenter:
'**/*.coffee': 'madeup'
expect(work).to.throw()
done()

0 comments on commit ee3e68e

Please sign in to comment.