From ee3e68e8d1db99411dd7d0600677b1af91f01802 Mon Sep 17 00:00:00 2001 From: Greg Varsanyi Date: Wed, 21 May 2014 00:08:43 -0700 Subject: [PATCH] feat(config): instrumenter override option 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 --- README.md | 24 ++++++++++++++++- lib/preprocessor.js | 51 ++++++++++++++++++++++++++++------- package.json | 5 ++-- test/preprocessor.spec.coffee | 30 ++++++++++++++++++--- 4 files changed, 95 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 8e3a451..3c3cf1e 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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]. diff --git a/lib/preprocessor.js b/lib/preprocessor.js index 9d515e9..c27a7ee 100644 --- a/lib/preprocessor.js +++ b/lib/preprocessor.js @@ -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) { @@ -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; diff --git a/package.json b/package.json index f021298..3ba6e25 100644 --- a/package.json +++ b/package.json @@ -19,9 +19,10 @@ ], "author": "SATO taichi ", "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" diff --git a/test/preprocessor.spec.coffee b/test/preprocessor.spec.coffee index 59728b0..1963e6e 100644 --- a/test/preprocessor.spec.coffee +++ b/test/preprocessor.spec.coffee @@ -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) -> @@ -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) -> @@ -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) -> @@ -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()