Skip to content

Commit ea9a675

Browse files
pmarchiniaduh95
authored andcommitted
test_runner: exclude test files from coverage by default
PR-URL: #56060 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Moshe Atlow <[email protected]>
1 parent 78743b1 commit ea9a675

18 files changed

+328
-55
lines changed

doc/api/cli.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2267,6 +2267,9 @@ This option may be specified multiple times to exclude multiple glob patterns.
22672267
If both `--test-coverage-exclude` and `--test-coverage-include` are provided,
22682268
files must meet **both** criteria to be included in the coverage report.
22692269

2270+
By default all the matching test files are excluded from the coverage report.
2271+
Specifying this option will override the default behavior.
2272+
22702273
### `--test-coverage-functions=threshold`
22712274

22722275
<!-- YAML

doc/api/test.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,8 +476,10 @@ all tests have completed. If the [`NODE_V8_COVERAGE`][] environment variable is
476476
used to specify a code coverage directory, the generated V8 coverage files are
477477
written to that directory. Node.js core modules and files within
478478
`node_modules/` directories are, by default, not included in the coverage report.
479-
However, they can be explicitly included via the [`--test-coverage-include`][] flag. If
480-
coverage is enabled, the coverage report is sent to any [test reporters][] via
479+
However, they can be explicitly included via the [`--test-coverage-include`][] flag.
480+
By default all the matching test files are excluded from the coverage report.
481+
Exclusions can be overridden by using the [`--test-coverage-exclude`][] flag.
482+
If coverage is enabled, the coverage report is sent to any [test reporters][] via
481483
the `'test:coverage'` event.
482484

483485
Coverage can be disabled on a series of lines using the following
@@ -3592,6 +3594,7 @@ Can be used to abort test subtasks when the test has been aborted.
35923594
[`--experimental-test-module-mocks`]: cli.md#--experimental-test-module-mocks
35933595
[`--import`]: cli.md#--importmodule
35943596
[`--test-concurrency`]: cli.md#--test-concurrency
3597+
[`--test-coverage-exclude`]: cli.md#--test-coverage-exclude
35953598
[`--test-coverage-include`]: cli.md#--test-coverage-include
35963599
[`--test-name-pattern`]: cli.md#--test-name-pattern
35973600
[`--test-only`]: cli.md#--test-only

lib/internal/fs/glob.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,30 @@ class Glob {
650650
}
651651
}
652652

653+
/**
654+
* Check if a path matches a glob pattern
655+
* @param {string} path the path to check
656+
* @param {string} pattern the glob pattern to match
657+
* @param {boolean} windows whether the path is on a Windows system, defaults to `isWindows`
658+
* @returns {boolean}
659+
*/
660+
function matchGlobPattern(path, pattern, windows = isWindows) {
661+
validateString(path, 'path');
662+
validateString(pattern, 'pattern');
663+
return lazyMinimatch().minimatch(path, pattern, {
664+
kEmptyObject,
665+
nocase: isMacOS || isWindows,
666+
windowsPathsNoEscape: true,
667+
nonegate: true,
668+
nocomment: true,
669+
optimizationLevel: 2,
670+
platform: windows ? 'win32' : 'posix',
671+
nocaseMagicOnly: true,
672+
});
673+
}
674+
653675
module.exports = {
654676
__proto__: null,
655677
Glob,
678+
matchGlobPattern,
656679
};

lib/internal/test_runner/coverage.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const {
2727
} = require('fs');
2828
const { setupCoverageHooks } = require('internal/util');
2929
const { tmpdir } = require('os');
30-
const { join, resolve, relative, matchesGlob } = require('path');
30+
const { join, resolve, relative } = require('path');
3131
const { fileURLToPath } = require('internal/url');
3232
const { kMappings, SourceMap } = require('internal/source_map/source_map');
3333
const {
@@ -36,6 +36,8 @@ const {
3636
ERR_SOURCE_MAP_MISSING_SOURCE,
3737
},
3838
} = require('internal/errors');
39+
const { matchGlobPattern } = require('internal/fs/glob');
40+
3941
const kCoverageFileRegex = /^coverage-(\d+)-(\d{13})-(\d+)\.json$/;
4042
const kIgnoreRegex = /\/\* node:coverage ignore next (?<count>\d+ )?\*\//;
4143
const kLineEndingRegex = /\r?\n$/u;
@@ -464,19 +466,24 @@ class TestCoverage {
464466
coverageExcludeGlobs: excludeGlobs,
465467
coverageIncludeGlobs: includeGlobs,
466468
} = this.options;
469+
467470
// This check filters out files that match the exclude globs.
468471
if (excludeGlobs?.length > 0) {
469472
for (let i = 0; i < excludeGlobs.length; ++i) {
470-
if (matchesGlob(relativePath, excludeGlobs[i]) ||
471-
matchesGlob(absolutePath, excludeGlobs[i])) return true;
473+
if (
474+
matchGlobPattern(relativePath, excludeGlobs[i]) ||
475+
matchGlobPattern(absolutePath, excludeGlobs[i])
476+
) return true;
472477
}
473478
}
474479

475480
// This check filters out files that do not match the include globs.
476481
if (includeGlobs?.length > 0) {
477482
for (let i = 0; i < includeGlobs.length; ++i) {
478-
if (matchesGlob(relativePath, includeGlobs[i]) ||
479-
matchesGlob(absolutePath, includeGlobs[i])) return false;
483+
if (
484+
matchGlobPattern(relativePath, includeGlobs[i]) ||
485+
matchGlobPattern(absolutePath, includeGlobs[i])
486+
) return false;
480487
}
481488
return true;
482489
}

lib/internal/test_runner/utils.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,11 @@ function parseCommandLine() {
287287

288288
if (coverage) {
289289
coverageExcludeGlobs = getOptionValue('--test-coverage-exclude');
290+
if (!coverageExcludeGlobs || coverageExcludeGlobs.length === 0) {
291+
// TODO(pmarchini): this default should follow something similar to c8 defaults
292+
// Default exclusions should be also exported to be used by other tools / users
293+
coverageExcludeGlobs = [kDefaultPattern];
294+
}
290295
coverageIncludeGlobs = getOptionValue('--test-coverage-include');
291296

292297
branchCoverage = getOptionValue('--test-coverage-branches');

lib/path.js

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,12 @@ const {
5252
} = require('internal/validators');
5353

5454
const {
55-
getLazy,
5655
emitExperimentalWarning,
5756
isWindows,
58-
isMacOS,
57+
getLazy,
5958
} = require('internal/util');
6059

61-
const lazyMinimatch = getLazy(() => require('internal/deps/minimatch/index'));
60+
const lazyMatchGlobPattern = getLazy(() => require('internal/fs/glob').matchGlobPattern);
6261

6362
function isPathSeparator(code) {
6463
return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
@@ -164,22 +163,6 @@ function _format(sep, pathObject) {
164163
return dir === pathObject.root ? `${dir}${base}` : `${dir}${sep}${base}`;
165164
}
166165

167-
function glob(path, pattern, windows) {
168-
emitExperimentalWarning('glob');
169-
validateString(path, 'path');
170-
validateString(pattern, 'pattern');
171-
return lazyMinimatch().minimatch(path, pattern, {
172-
__proto__: null,
173-
nocase: isMacOS || isWindows,
174-
windowsPathsNoEscape: true,
175-
nonegate: true,
176-
nocomment: true,
177-
optimizationLevel: 2,
178-
platform: windows ? 'win32' : 'posix',
179-
nocaseMagicOnly: true,
180-
});
181-
}
182-
183166
const win32 = {
184167
/**
185168
* path.resolve([from ...], to)
@@ -1140,7 +1123,8 @@ const win32 = {
11401123
},
11411124

11421125
matchesGlob(path, pattern) {
1143-
return glob(path, pattern, true);
1126+
emitExperimentalWarning('glob');
1127+
return lazyMatchGlobPattern()(path, pattern, true);
11441128
},
11451129

11461130
sep: '\\',
@@ -1616,7 +1600,8 @@ const posix = {
16161600
},
16171601

16181602
matchesGlob(path, pattern) {
1619-
return glob(path, pattern, false);
1603+
emitExperimentalWarning('glob');
1604+
return lazyMatchGlobPattern()(path, pattern, false);
16201605
},
16211606

16221607
sep: '/',
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const test = require('node:test');
2+
const assert = require('node:assert');
3+
const { foo } = require('./logic-file');
4+
5+
test('foo returns 1', () => {
6+
assert.strictEqual(foo(), 1);
7+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import test from 'node:test';
2+
import assert from 'node:assert';
3+
import { foo } from './logic-file.js';
4+
5+
test('foo returns 1', () => {
6+
assert.strictEqual(foo(), 1);
7+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import test from 'node:test';
2+
import assert from 'node:assert';
3+
import { foo } from './logic-file.js';
4+
5+
test('foo returns 1', () => {
6+
assert.strictEqual(foo(), 1);
7+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function foo() {
2+
return 1;
3+
}
4+
5+
function bar() {
6+
return 'bar';
7+
}
8+
9+
module.exports = { foo, bar };

0 commit comments

Comments
 (0)