From 02f255d0d20f2c08768461bb9c031e45feaae96c Mon Sep 17 00:00:00 2001 From: Jon Denly Date: Fri, 2 Dec 2016 12:47:47 +1100 Subject: [PATCH] Add coverage-merge command and parallel configuration to allow use with parallel testing. --- README.md | 4 +++ index.js | 10 +++++++ lib/attach-middleware.js | 9 +++++++ lib/coverage-merge.js | 56 ++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 5 files changed, 80 insertions(+) create mode 100644 lib/coverage-merge.js diff --git a/README.md b/README.md index 68b72b2e..ad858696 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,8 @@ and then: `cross-env COVERAGE=true ember test` +When running with `parallel` set to true, the final reports can be merged by using `ember coverage-merge`. The final merged output will be stored in the `coverageFolder`. + ## Configuration Configuration is optional. It should be put in a file at `config/coverage.js`. @@ -45,6 +47,8 @@ Configuration is optional. It should be put in a file at `config/coverage.js`. - `useBabelInstrumenter`: Defaults to `false`. Whether or not to use Babel instrumenter instead of default instrumenter. The Babel instrumenter is useful when you are using features of ESNext as it uses your Babel configuration defined in `ember-cli-build.js`. +- `parallel`: Defaults to `false`. Should be set to true if parallel testing is being used, for example when using [ember-exam](https://github.com/trentmwillis/ember-exam) with the `--parallel` flag. This will generate the coverage reports in directories suffixed with `_` to avoid overwriting other threads reports. These reports can be joined by using the `ember coverage-merge` command. + #### Example ```js module.exports = { diff --git a/index.js b/index.js index a36e3016..b02045fe 100644 --- a/index.js +++ b/index.js @@ -61,6 +61,16 @@ module.exports = { return new BroccoliMergeTrees([tree, instrumentedNode], { overwrite: true }); }, + includedCommands: function () { + return { + 'coverage-merge': require('./lib/coverage-merge') + }; + }, + + /** + * If coverage is enabled attach coverage middleware to the express server run by ember-cli + * @param {Object} startOptions - Express server start options + */ serverMiddleware: function(startOptions) { this.testemMiddleware(startOptions.app); }, diff --git a/lib/attach-middleware.js b/lib/attach-middleware.js index b3134497..5626cba1 100644 --- a/lib/attach-middleware.js +++ b/lib/attach-middleware.js @@ -5,6 +5,7 @@ var Istanbul = require('istanbul'); var config = require('./config'); var path = require('path'); var fs = require('fs-extra'); +var crypto = require('crypto'); function logError(err, req, res, next) { console.error(err.stack); @@ -17,6 +18,14 @@ module.exports = function(app, options) { function(req, res) { var collector = new Istanbul.Collector(); var _config = config(options.root); + + if (_config.parallel) { + _config.coverageFolder = _config.coverageFolder + '_' + crypto.randomBytes(4).toString('hex'); + if (_config.reporters.indexOf('json') === -1) { + _config.reporters.push('json'); + } + } + var reporter = new Istanbul.Reporter(null, path.join(options.root, _config.coverageFolder)); var sync = true; diff --git a/lib/coverage-merge.js b/lib/coverage-merge.js new file mode 100644 index 00000000..8b7ae0f2 --- /dev/null +++ b/lib/coverage-merge.js @@ -0,0 +1,56 @@ +'use strict'; + +var path = require('path'); +var Istanbul = require('istanbul'); +var config = require('./config'); +var dir = require('node-dir'); +var Promise = require('rsvp').Promise; + +/** + * Merge together coverage files created when running in multiple threads, + * for example when being used with ember exam and parallel runs. + */ +module.exports = { + name: 'coverage-merge', + description: 'Merge multiple coverage files together.', + run: function () { + var collector = new Istanbul.Collector(); + var _config = this._getConfig(); + var projectRoot = this.project.root; + var reporter = new Istanbul.Reporter(null, path.join(projectRoot, _config.coverageFolder)); + var coverageDirRegex = new RegExp(_config.coverageFolder + '_.*'); + + return new Promise(function (resolve, reject) { + dir.readFiles(projectRoot, {matchDir: coverageDirRegex, match: /coverage-final\.json/}, + function (err, coverageSummary, next) { + if (err) { + reject(err); + } + collector.add(JSON.parse(coverageSummary)); + next(); + }, + function (err) { + if (err) { + reject(err); + } + + if (_config.reporters.indexOf('json-summary') === -1) { + _config.reporters.push('json-summary'); + } + + reporter.addAll(_config.reporters); + reporter.write(collector, false, function () { + resolve(); + }); + }); + }); + }, + + /** + * Get project configuration + * @returns {Configuration} project configuration + */ + _getConfig: function () { + return config(this.project.root); + } +}; diff --git a/package.json b/package.json index f2c6d08b..014ac00d 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "extend": "^3.0.0", "fs-extra": "^0.26.7", "istanbul": "^0.4.3", + "node-dir": "^0.1.16", "source-map": "0.5.6", "string.prototype.startswith": "^0.2.0" },