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 Jun 7, 2016
1 parent b4faa9e commit d0fa726
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 2 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 @@ -27,7 +27,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": "^1.0.0",
"minimatch": "^3.0.0",
"remap-istanbul": "^0.6.3"
},
"devDependencies": {
"gulp": "^3.8.7",
Expand Down
13 changes: 13 additions & 0 deletions src/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,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.address.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].content.replace(re, host);
}
return systemInstantiate.call(SystemJS, 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
105 changes: 105 additions & 0 deletions src/preprocessor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
var fs = require('fs')
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) {
// 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 = basePath + '/__karma-jspm-tmp__/'

// 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]) {
var filename
// arrange sourcemaps
if (load.metadata.sourceMap) {
// put file's transpiled counterpart in temp folder
filename = tempDirectory + encodeURIComponent(fileKey)
// keeping sourcesContent causes duplicate reports
delete load.metadata.sourceMap.sourcesContent
// this is the file being "instrumented"
load.metadata.sourceMap.file = tempDirectory + encodeURIComponent(fileKey)
// removing "file://" from paths
load.metadata.sourceMap.sources = load.metadata.sourceMap.sources.map(
filename => getOSFilePath(filename)
)
// write transpiled file with an inlined-sourceMap to temp directory
fs.writeFileSync(
filename,
load.source + '\n' + inlineSourceMap(load.metadata.sourceMap)
)
} else {
// keep file as is since it doesn't have a sourcemap to be remaped
filename = getOSFilePath(load.address)
}
// 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) {
console.log(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) {
console.log(err)
// remove temp directory since something went wrong
rimraf.sync(tempDirectory)
})
}
}

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

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

function CoverageReporter(rootConfig, helper, logger, emitter) {
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

0 comments on commit d0fa726

Please sign in to comment.