Skip to content

Commit

Permalink
Release candidate for sustainable coverage approach
Browse files Browse the repository at this point in the history
  • Loading branch information
m-a-r-c-e-l-i-n-o committed Jul 9, 2016
1 parent 9e6c663 commit 7915f75
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 3 deletions.
4 changes: 3 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ var initJspm = require('./src/init');
initJspm.$inject = ['config.files', 'config.basePath', 'config.jspm', 'config.client', 'emitter'];

module.exports = {
'framework:jspm': ['factory', initJspm]
'preprocessor:jspm': ['factory', require('./src/preprocessor')],
'framework:jspm': ['factory', initJspm],
'reporter:jspm': ['type', require('./src/reporter')]
};
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@
"url": "git@github.com:Workiva/karma-jspm.git"
},
"dependencies": {
"glob": "~3.2"
"glob": "~3.2",
"inline-source-map-comment": "^1.0.5",
"istanbul": "^0.4.3",
"karma-coverage": "github:karma-runner/karma-coverage",
"minimatch": "^3.0.0",
"remap-istanbul": "github:m-a-r-c-e-l-i-n-o/remap-istanbul"
},
"devDependencies": {
"cross-env": "^1.0.7",
Expand Down
13 changes: 13 additions & 0 deletions src/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,19 @@
System.bundles = [];
}

var systemInstantiate = System.instantiate;
var http = location.protocol;
var slashes = http.concat('//');
var host = slashes.concat(window.location.host) + '/base/';
System.instantiate = function(load) {
var fileKey = load.name.replace(host, '');
if (karma.config.jspm.coverageFiles[fileKey]) {
var re = new RegExp('file://' + karma.config.jspm.basePath + '/','g');
load.source = karma.config.jspm.coverageFiles[fileKey].replace(re, host);
}
return systemInstantiate.call(System, load);
};

// Load everything specified in loadFiles in the specified order
var promiseChain = Promise.resolve();
for (var i = 0; i < karma.config.jspm.expandedFiles.length; i++) {
Expand Down
124 changes: 124 additions & 0 deletions src/preprocessor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
var fs = require('fs');
var path = require('path');
var jspm = require('jspm');
var istanbul = require('istanbul');
var rimraf = require('rimraf');
var inlineSourceMap = require('inline-source-map-comment');

function getFileKey(filename, basePath) {
if(!basePath) throw new Error('Please supply a base path!');
return filename.replace(basePath + '/', '');
}

function getOSFilePath(filename) {
return filename.replace('file://', '');
}

function CoveragePreprocessor(basePath, client, reporters, helper, logger) {
var log = logger.create('preprocessor.coverage');

// if coverage reporter is not used, do not preprocess the files
if (!helper._.includes(reporters, 'jspm')) {
return function (content, _, done) {
done(content);
};
}

// create a jspm namespace to pass data to the browsers
if (!client.jspm) client.jspm = {};
// store instrumented sources to be executed by browser
client.jspm.coverageFiles = {};
// store basePath used to generate the key for each source in the obj above
client.jspm.basePath = basePath;
// temp folder to store instrumented files for sourcemap remapping
client.jspm.tempDirectory = path.join(__dirname, '../no-source-map/');

// make temp directory
var tempDirectory = client.jspm.tempDirectory;
if (!fs.existsSync(tempDirectory)) {
fs.mkdirSync(tempDirectory);
}

// create systemjs hook to allow Istanbul to instrument transpiled sources
var instrument = new istanbul.Instrumenter();
var systemJS = new jspm.Loader();
var systemInstantiate = systemJS.instantiate;

// "instantiate" is the hook that provides the transpiled source
systemJS.instantiate = function(load) {
try {
// create a unique key to store the sources of modules for the browser
var fileKey = getFileKey(getOSFilePath(load.address), basePath);
// exclude the dependency modules (i.e. libraries) from instrumentation
if (client.jspm.coverageFiles[fileKey]) {
// put file's transpiled counterpart in temp folder
var filename;
var sourceMap = '';
// arrange sourcemaps
if (load.metadata.sourceMap) {
filename = path.join(tempDirectory, fileKey.replace(/\//g, '|'));
// keeping sourcesContent causes duplicate reports
// it's an issue with remap-istanbul that hasn't
// been investigated yet.
delete load.metadata.sourceMap.sourcesContent;
// this is the file being "instrumented"
load.metadata.sourceMap.file = filename;
// removing "file://" from paths
load.metadata.sourceMap.sources = load.metadata.sourceMap.sources.map(function (filename) {
return getOSFilePath(filename);
});
// inlined-sourceMap to be added to file
sourceMap = '\n' + inlineSourceMap(load.metadata.sourceMap);
} else if (load.source.trim() === fs.readFileSync(getOSFilePath(load.address), 'utf8').trim()) {
// actual file source is the same as load.source
// let the original file through
filename = getOSFilePath(load.address);
} else {
// there is no source, but is transpiled, so we have no choice but to
// create a temp file that cannot be mapped back to the original
// I think that we should throw an error here, telling the user to figure out
// why it is that no sourcemap is being generated.
filename = path.join(tempDirectory, fileKey.replace(/\//g, '|'));
}

if (filename !== getOSFilePath(load.address)) {
// write transpiled file with to temp directory
fs.writeFileSync(filename, load.source + sourceMap);
}

// instrument with istanbul
client.jspm.coverageFiles[fileKey] = instrument.instrumentSync(
load.source,
// make the path-like file key into something that can be used as a name
filename
);
}
} catch (err) {
log.error(err);
// remove temp directory since something went wrong
rimraf.sync(tempDirectory);
}
// call the original "instantiate" hook function
return systemInstantiate.call(systemJS, load);
};

return function (content, file, done) {
// only files to be instrumented pass through here
// store this information to allow "instantiate" to exclude
// dependency modules (i.e. libraries)
client.jspm.coverageFiles[getFileKey(file.path, basePath)] = true;
// import modules
systemJS.import(file.path).then(function () {
done(content);
}).catch(function(err) {
log.error(err);
// remove temp directory since something went wrong
rimraf.sync(tempDirectory);
});
};
}

CoveragePreprocessor.$inject = ['config.basePath','config.client','config.reporters','helper', 'logger'];

// PUBLISH
module.exports = CoveragePreprocessor;
30 changes: 30 additions & 0 deletions src/reporter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
var rimraf = require('rimraf');
var remapIstanbul = require('remap-istanbul');
var karmaCoverageReport = require('karma-coverage/lib/reporter');

function CoverageReporter(rootConfig, helper, logger, emitter) {
var log = logger.create('reporter-wrapper.coverage');
var config = rootConfig.coverageReporter = rootConfig.coverageReporter || {};
config._onWriteReport = function (collector) {
try {
collector = remapIstanbul.remap(collector.getFinalCoverage());
} catch(e) {
log.error(e);
}
return collector;
};
config._onExit = function (done) {
try {
rimraf.sync(rootConfig.client.jspm.tempDirectory);
} catch(e) {
log.error(e);
}
done();
};
karmaCoverageReport.call(this, rootConfig, helper, logger, emitter);
}

CoverageReporter.$inject = karmaCoverageReport.$inject;

// PUBLISH
module.exports = CoverageReporter;
2 changes: 1 addition & 1 deletion test/testInit.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe('jspm plugin init', function(){
});

it('should add files from jspm.loadFiles to client.expandedFiles', function(){
expect(client.jspm.expandedFiles).toEqual(['src/adapter.js', 'src/init.js']);
expect(client.jspm.expandedFiles).toEqual([ 'src/adapter.js', 'src/init.js', 'src/preprocessor.js', 'src/reporter.js' ]);
});

it('should add files from jspm.serveFiles to the files array as served files', function(){
Expand Down

0 comments on commit 7915f75

Please sign in to comment.