Skip to content

Commit 7aeb2bd

Browse files
committed
test_runner: feat add coverage threshold for tests
1 parent 62ca050 commit 7aeb2bd

File tree

4 files changed

+45
-6
lines changed

4 files changed

+45
-6
lines changed

lib/internal/test_runner/coverage.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ const kIgnoreRegex = /\/\* node:coverage ignore next (?<count>\d+ )?\*\//;
3131
const kLineEndingRegex = /\r?\n$/u;
3232
const kLineSplitRegex = /(?<=\r?\n)/u;
3333
const kStatusRegex = /\/\* node:coverage (?<status>enable|disable) \*\//;
34+
const defaultMinumumThreshold = {
35+
lines: 0,
36+
functions: 0,
37+
branches: 0
38+
}
3439

3540
class CoverageLine {
3641
#covered;
@@ -63,10 +68,11 @@ class CoverageLine {
6368
}
6469

6570
class TestCoverage {
66-
constructor(coverageDirectory, originalCoverageDirectory, workingDirectory) {
71+
constructor(coverageDirectory, originalCoverageDirectory, workingDirectory, minimumThreshold = defaultMinumumThreshold) {
6772
this.coverageDirectory = coverageDirectory;
6873
this.originalCoverageDirectory = originalCoverageDirectory;
6974
this.workingDirectory = workingDirectory;
75+
this.minimumThreshold = minimumThreshold;
7076
}
7177

7278
summary() {
@@ -260,6 +266,11 @@ class TestCoverage {
260266
);
261267
coverageSummary.files.sort(sortCoverageFiles);
262268

269+
coverageSummary.threshold = {
270+
lines: this.minimumThreshold.lines ? coverageSummary.totals.coveredLinePercent >= this.minimumThreshold.lines: true,
271+
functions: this.minimumThreshold.functions ? coverageSummary.totals.coveredFunctionCount >= this.minimumThreshold.functions: true,
272+
branches: this.minimumThreshold.branches ? coverageSummary.totals.coveredBranchCount >= this.minimumThreshold.branches: true,
273+
}
263274
return coverageSummary;
264275
}
265276

@@ -299,7 +310,7 @@ function sortCoverageFiles(a, b) {
299310
return StringPrototypeLocaleCompare(a.path, b.path);
300311
}
301312

302-
function setupCoverage() {
313+
function setupCoverage(minimumThreshold) {
303314
let originalCoverageDirectory = process.env.NODE_V8_COVERAGE;
304315
const cwd = process.cwd();
305316

@@ -323,7 +334,7 @@ function setupCoverage() {
323334
// child processes.
324335
process.env.NODE_V8_COVERAGE = coverageDirectory;
325336

326-
return new TestCoverage(coverageDirectory, originalCoverageDirectory, cwd);
337+
return new TestCoverage(coverageDirectory, originalCoverageDirectory, cwd, minimumThreshold);
327338
}
328339

329340
function mapRangeToLines(range, lines) {

lib/internal/test_runner/harness.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
'use strict';
22
const {
3+
ArrayPrototypeFilter,
34
ArrayPrototypeForEach,
45
FunctionPrototypeBind,
56
PromiseResolve,
67
SafeMap,
8+
StringPrototypeSplit,
79
} = primordials;
810
const { getCallerLocation } = internalBinding('util');
911
const {
@@ -82,10 +84,11 @@ function configureCoverage(rootTest, globalOptions) {
8284
return null;
8385
}
8486

87+
const [_, value] = StringPrototypeSplit(ArrayPrototypeFilter(process.execArgv, (arg) => arg.startsWith("--experimental-test-coverage")), '=')
8588
const { setupCoverage } = require('internal/test_runner/coverage');
8689

8790
try {
88-
return setupCoverage();
91+
return setupCoverage({ lines: value });
8992
} catch (err) {
9093
const msg = `Warning: Code coverage could not be enabled. ${err}`;
9194

lib/internal/test_runner/utils.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,16 @@ function getCoverageReport(pad, summary, symbol, color, table) {
405405
`${ArrayPrototypeJoin(ArrayPrototypeMap(kColumnsKeys, (columnKey, j) => getCell(NumberPrototypeToFixed(summary.totals[columnKey], 2), columnPadLengths[j], StringPrototypePadStart, false, summary.totals[columnKey])), kSeparator)} |\n`;
406406
if (table) report += addTableLine(prefix, tableWidth);
407407

408+
if(!summary.threshold.lines) {
409+
report += `${red}${prefix}coverage threshold for lines not met\n${color}`;
410+
}
411+
if(!summary.threshold.branches) {
412+
report += `${red}${prefix}coverage threshold for branches not met\n${color}`;
413+
}
414+
if(!summary.threshold.functions) {
415+
report += `${red}${prefix}coverage threshold for functions not met\n${color}`;
416+
}
417+
408418
report += `${prefix}end of coverage report\n`;
409419
if (color) {
410420
report += white;

test/parallel/test-runner-coverage.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function findCoverageFileForPid(pid) {
2121
});
2222
}
2323

24-
function getTapCoverageFixtureReport() {
24+
function getTapCoverageFixtureReport(extraReport = []) {
2525
/* eslint-disable max-len */
2626
const report = [
2727
'# start of coverage report',
@@ -34,6 +34,7 @@ function getTapCoverageFixtureReport() {
3434
'# -------------------------------------------------------------------------------------------------------------------',
3535
'# all files | 78.35 | 43.75 | 60.00 |',
3636
'# -------------------------------------------------------------------------------------------------------------------',
37+
...extraReport,
3738
'# end of coverage report',
3839
].join('\n');
3940
/* eslint-enable max-len */
@@ -45,7 +46,7 @@ function getTapCoverageFixtureReport() {
4546
return report;
4647
}
4748

48-
function getSpecCoverageFixtureReport() {
49+
function getSpecCoverageFixtureReport(extraReport = []) {
4950
/* eslint-disable max-len */
5051
const report = [
5152
'\u2139 start of coverage report',
@@ -58,6 +59,7 @@ function getSpecCoverageFixtureReport() {
5859
'\u2139 -------------------------------------------------------------------------------------------------------------------',
5960
'\u2139 all files | 78.35 | 43.75 | 60.00 |',
6061
'\u2139 -------------------------------------------------------------------------------------------------------------------',
62+
...extraReport,
6163
'\u2139 end of coverage report',
6264
].join('\n');
6365
/* eslint-enable max-len */
@@ -242,3 +244,16 @@ test('coverage reports on lines, functions, and branches', skipIfNoInspector, as
242244
});
243245
});
244246
});
247+
248+
test('test tap coverage reporter with threshold value', skipIfNoInspector, async (t) => {
249+
const fixture = fixtures.path('test-runner', 'coverage.js');
250+
const args = ['--experimental-test-coverage=100', '--test-reporter', 'tap', fixture];
251+
const options = { env: { ...process.env } };
252+
const result = spawnSync(process.execPath, args, options);
253+
const report = getTapCoverageFixtureReport(['# coverage threshold for lines not met']);
254+
console.log(result.stdout.toString(),'\n')
255+
console.log(report)
256+
assert(result.stdout.toString().includes(report));
257+
assert.strictEqual(result.stderr.toString(), '');
258+
assert.strictEqual(result.status, 0);
259+
});

0 commit comments

Comments
 (0)