diff --git a/lib/internal/test_runner/coverage.js b/lib/internal/test_runner/coverage.js index 3d0fcde700a4..af94b1ff3b54 100644 --- a/lib/internal/test_runner/coverage.js +++ b/lib/internal/test_runner/coverage.js @@ -263,10 +263,8 @@ class TestCoverage { for (let j = 0; j < functions.length; ++j) { const { isBlockCoverage, ranges } = functions[j]; - let maxCountPerFunction = 0; for (let k = 0; k < ranges.length; ++k) { const range = ranges[k]; - maxCountPerFunction = MathMax(maxCountPerFunction, range.count); // Add some useful data to the range. The test runner has read these ranges // from a file, so we own the data structures and can do what we want. @@ -294,7 +292,7 @@ class TestCoverage { ArrayPrototypePush(functionReports, { __proto__: null, name: functions[j].functionName, - count: maxCountPerFunction, + count: range.count, line: range.lines[0]?.line, }); diff --git a/test/fixtures/test-runner/coverage-function-count.js b/test/fixtures/test-runner/coverage-function-count.js new file mode 100644 index 000000000000..f52cb2918a28 --- /dev/null +++ b/test/fixtures/test-runner/coverage-function-count.js @@ -0,0 +1,15 @@ +'use strict'; +const assert = require('node:assert'); +const { test } = require('node:test'); + +function sum(n) { + let result = 0; + for (let i = 0; i < n; i++) { + result += i; + } + return result; +} + +test('sum', () => { + assert.strictEqual(sum(10), 45); +}); diff --git a/test/parallel/test-runner-coverage-function-count.js b/test/parallel/test-runner-coverage-function-count.js new file mode 100644 index 000000000000..cf923bd1d380 --- /dev/null +++ b/test/parallel/test-runner-coverage-function-count.js @@ -0,0 +1,40 @@ +'use strict'; +const common = require('../common'); +common.skipIfInspectorDisabled(); + +// Loop iterations must not inflate function call counts. +const assert = require('node:assert'); +const { spawnSync } = require('node:child_process'); +const fixtures = require('../common/fixtures'); + +const fixture = fixtures.path('test-runner', 'coverage-function-count.js'); +const jsonReporter = fixtures.fileURL('test-runner/custom_reporters/coverage.mjs'); + +for (const isolation of ['process', 'none']) { + for (const reporter of [jsonReporter, 'lcov']) { + const { status, signal, stdout, stderr } = spawnSync(process.execPath, [ + '--test', + '--experimental-test-coverage', + `--test-isolation=${isolation}`, + '--test-coverage-exclude=!test/**', + `--test-coverage-include=${fixture}`, + '--test-reporter', reporter, + fixture, + ], { encoding: 'utf8' }); + + assert.strictEqual(status, 0, stderr); + assert.strictEqual(signal, null); + assert.strictEqual(stderr, ''); + + if (reporter === 'lcov') { + assert.match(stdout, /^FNDA:1,sum$/m); + } else { + const { summary: { files } } = JSON.parse(stdout); + assert.strictEqual(files.length, 1); + const [file] = files; + assert.strictEqual(file.functions.find((fn) => fn.name === 'sum').count, 1); + assert.strictEqual(file.lines.find((line) => line.line === 8).count, 10); + assert(file.branches.some((branch) => branch.count === 10)); + } + } +}