diff --git a/README.md b/README.md index 69dcbf6b8..fc190da9b 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,12 @@ nyc --check-coverage --lines 100 npm test The above check fails if coverage falls below 100%. +To check thresholds on a per-file basis run: + +```shell +nyc check-coverage --lines 95 --per-file +``` + ## Running reports Once you've run your tests with nyc, simply run: @@ -240,6 +246,7 @@ Any configuration options that can be set via the command line can also be speci "description": "These are just examples for demonstration, nothing prescriptive", "nyc": { "check-coverage": true, + "per-file": true, "lines": 99, "statements": 99, "functions": 99, diff --git a/bin/nyc.js b/bin/nyc.js index 5428c4e61..26bedddf8 100755 --- a/bin/nyc.js +++ b/bin/nyc.js @@ -97,5 +97,5 @@ function checkCoverage (argv, cb) { functions: argv.functions, branches: argv.branches, statements: argv.statements - }) + }, argv['per-file']) } diff --git a/index.js b/index.js index 4c93cd3bd..4a989749a 100755 --- a/index.js +++ b/index.js @@ -441,21 +441,36 @@ NYC.prototype.showProcessTree = function () { console.log(processTree.render(this)) } -NYC.prototype.checkCoverage = function (thresholds) { +NYC.prototype.checkCoverage = function (thresholds, perFile) { var map = this._getCoverageMapFromAllCoverageFiles() - var summary = map.getCoverageSummary() + var nyc = this - // ERROR: Coverage for lines (90.12%) does not meet global threshold (120%) + if (perFile) { + map.files().forEach(function (file) { + // ERROR: Coverage for lines (90.12%) does not meet threshold (120%) for index.js + nyc._checkCoverage(map.fileCoverageFor(file).toSummary(), thresholds, file) + }) + } else { + // ERROR: Coverage for lines (90.12%) does not meet global threshold (120%) + nyc._checkCoverage(map.getCoverageSummary(), thresholds) + } + + // process.exitCode was not implemented until v0.11.8. + if (/^v0\.(1[0-1]\.|[0-9]\.)/.test(process.version) && process.exitCode !== 0) process.exit(process.exitCode) +} + +NYC.prototype._checkCoverage = function (summary, thresholds, file) { Object.keys(thresholds).forEach(function (key) { var coverage = summary[key].pct if (coverage < thresholds[key]) { process.exitCode = 1 - console.error('ERROR: Coverage for ' + key + ' (' + coverage + '%) does not meet global threshold (' + thresholds[key] + '%)') + if (file) { + console.error('ERROR: Coverage for ' + key + ' (' + coverage + '%) does not meet threshold (' + thresholds[key] + '%) for ' + file) + } else { + console.error('ERROR: Coverage for ' + key + ' (' + coverage + '%) does not meet global threshold (' + thresholds[key] + '%)') + } } }) - - // process.exitCode was not implemented until v0.11.8. - if (/^v0\.(1[0-1]\.|[0-9]\.)/.test(process.version) && process.exitCode !== 0) process.exit(process.exitCode) } NYC.prototype._loadProcessInfos = function () { diff --git a/lib/config-util.js b/lib/config-util.js index 494b62288..4c98a3ec8 100644 --- a/lib/config-util.js +++ b/lib/config-util.js @@ -93,6 +93,10 @@ Config.buildYargs = function (cwd) { default: 0, description: 'what % of statements must be covered?' }) + .option('per-file', { + default: false, + description: 'check thresholds per file' + }) .example('$0 check-coverage --lines 95', "check whether the JSON in nyc's output folder meets the thresholds provided") }) .option('reporter', { @@ -195,6 +199,12 @@ Config.buildYargs = function (cwd) { description: 'should nyc detect and handle source maps?', global: false }) + .option('per-file', { + default: false, + type: 'boolean', + description: 'check thresholds per file', + global: false + }) .option('produce-source-map', { default: false, type: 'boolean', diff --git a/test/nyc-bin.js b/test/nyc-bin.js index f005f6da5..dc0e71a8f 100644 --- a/test/nyc-bin.js +++ b/test/nyc-bin.js @@ -141,6 +141,27 @@ describe('the nyc cli', function () { done() }) }) + + it('fails when the expected file coverage is below a threshold', function (done) { + var args = [bin, '--check-coverage', '--lines', '51', '--per-file', process.execPath, './half-covered.js'] + var matcher = RegExp('ERROR: Coverage for lines \\(50%\\) does not meet threshold \\(51%\\) for .+/half-covered.js') + + var proc = spawn(process.execPath, args, { + cwd: fixturesCLI, + env: env + }) + + var stderr = '' + proc.stderr.on('data', function (chunk) { + stderr += chunk + }) + + proc.on('close', function (code) { + code.should.not.equal(0) + stderr.trim().should.match(matcher) + done() + }) + }) }) // https://github.com/bcoe/nyc/issues/190