Skip to content

Commit 29de7f8

Browse files
authored
test_runner: omit filtered test from output
This commit updates the test runner to suppress any output for filtered tests. Filtered tests no longer generate reporter events, and the unfiltered tests are renumbered in the output as though the filtered tests were not present. Skipped tests that are not filtered are still included in the output. This change is particularly useful when filtering a large number of tests, as the previously displayed skip output could be distracting. Fixes: #51383 PR-URL: #52221 Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Moshe Atlow <[email protected]>
1 parent 27493a1 commit 29de7f8

File tree

6 files changed

+113
-274
lines changed

6 files changed

+113
-274
lines changed

doc/api/test.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,8 @@ If Node.js is started with the [`--test-only`][] command-line option, it is
233233
possible to skip all top level tests except for a selected subset by passing
234234
the `only` option to the tests that should be run. When a test with the `only`
235235
option set is run, all subtests are also run. The test context's `runOnly()`
236-
method can be used to implement the same behavior at the subtest level.
236+
method can be used to implement the same behavior at the subtest level. Tests
237+
that are not executed are omitted from the test runner output.
237238

238239
```js
239240
// Assume Node.js is run with the --test-only command-line option.
@@ -270,7 +271,7 @@ whose name matches the provided pattern. Test name patterns are interpreted as
270271
JavaScript regular expressions. The `--test-name-pattern` option can be
271272
specified multiple times in order to run nested tests. For each test that is
272273
executed, any corresponding test hooks, such as `beforeEach()`, are also
273-
run.
274+
run. Tests that are not executed are omitted from the test runner output.
274275

275276
Given the following test file, starting Node.js with the
276277
`--test-name-pattern="test [1-3]"` option would cause the test runner to execute

lib/internal/test_runner/test.js

+52-23
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ const {
8686
} = parseCommandLine();
8787
let kResistStopPropagation;
8888
let findSourceMap;
89+
let noopTestStream;
8990

9091
function lazyFindSourceMap(file) {
9192
if (findSourceMap === undefined) {
@@ -252,13 +253,20 @@ class Test extends AsyncResource {
252253
parent = null;
253254
}
254255

256+
this.name = name;
257+
this.parent = parent;
258+
this.testNumber = 0;
259+
this.outputSubtestCount = 0;
260+
this.filteredSubtestCount = 0;
261+
this.filtered = false;
262+
255263
if (parent === null) {
256264
this.concurrency = 1;
257265
this.nesting = 0;
258266
this.only = testOnlyFlag;
259267
this.reporter = new TestsStream();
260268
this.runOnlySubtests = this.only;
261-
this.testNumber = 0;
269+
this.childNumber = 0;
262270
this.timeout = kDefaultTimeout;
263271
this.root = this;
264272
this.hooks = {
@@ -277,7 +285,7 @@ class Test extends AsyncResource {
277285
this.only = only ?? !parent.runOnlySubtests;
278286
this.reporter = parent.reporter;
279287
this.runOnlySubtests = !this.only;
280-
this.testNumber = parent.subtests.length + 1;
288+
this.childNumber = parent.subtests.length + 1;
281289
this.timeout = parent.timeout;
282290
this.root = parent.root;
283291
this.hooks = {
@@ -287,6 +295,13 @@ class Test extends AsyncResource {
287295
beforeEach: ArrayPrototypeSlice(parent.hooks.beforeEach),
288296
afterEach: ArrayPrototypeSlice(parent.hooks.afterEach),
289297
};
298+
299+
if ((testNamePatterns !== null && !this.matchesTestNamePatterns()) ||
300+
(testOnlyFlag && !this.only)) {
301+
skip = true;
302+
this.filtered = true;
303+
this.parent.filteredSubtestCount++;
304+
}
290305
}
291306

292307
switch (typeof concurrency) {
@@ -314,17 +329,6 @@ class Test extends AsyncResource {
314329
this.timeout = timeout;
315330
}
316331

317-
this.name = name;
318-
this.parent = parent;
319-
320-
if (testNamePatterns !== null && !this.matchesTestNamePatterns()) {
321-
skip = 'test name does not match pattern';
322-
}
323-
324-
if (testOnlyFlag && !this.only) {
325-
skip = '\'only\' option not set';
326-
}
327-
328332
if (skip) {
329333
fn = noop;
330334
}
@@ -435,14 +439,14 @@ class Test extends AsyncResource {
435439
while (this.pendingSubtests.length > 0 && this.hasConcurrency()) {
436440
const deferred = ArrayPrototypeShift(this.pendingSubtests);
437441
const test = deferred.test;
438-
this.reporter.dequeue(test.nesting, test.loc, test.name);
442+
test.reporter.dequeue(test.nesting, test.loc, test.name);
439443
await test.run();
440444
deferred.resolve();
441445
}
442446
}
443447

444448
addReadySubtest(subtest) {
445-
this.readySubtests.set(subtest.testNumber, subtest);
449+
this.readySubtests.set(subtest.childNumber, subtest);
446450
}
447451

448452
processReadySubtestRange(canSend) {
@@ -503,7 +507,7 @@ class Test extends AsyncResource {
503507
const test = new Factory({ __proto__: null, fn, name, parent, ...options, ...overrides });
504508

505509
if (parent.waitingOn === 0) {
506-
parent.waitingOn = test.testNumber;
510+
parent.waitingOn = test.childNumber;
507511
}
508512

509513
if (preventAddingSubtests) {
@@ -591,6 +595,14 @@ class Test extends AsyncResource {
591595
}
592596

593597
start() {
598+
if (this.filtered) {
599+
noopTestStream ??= new TestsStream();
600+
this.reporter = noopTestStream;
601+
this.run = this.filteredRun;
602+
} else {
603+
this.testNumber = ++this.parent.outputSubtestCount;
604+
}
605+
594606
// If there is enough available concurrency to run the test now, then do
595607
// it. Otherwise, return a Promise to the caller and mark the test as
596608
// pending for later execution.
@@ -639,6 +651,13 @@ class Test extends AsyncResource {
639651
}
640652
}
641653

654+
async filteredRun() {
655+
this.pass();
656+
this.subtests = [];
657+
this.report = noop;
658+
this.postRun();
659+
}
660+
642661
async run() {
643662
if (this.parent !== null) {
644663
this.parent.activeSubtests++;
@@ -784,11 +803,14 @@ class Test extends AsyncResource {
784803
this.mock?.reset();
785804

786805
if (this.parent !== null) {
787-
const report = this.getReportDetails();
788-
report.details.passed = this.passed;
789-
this.reporter.complete(this.nesting, this.loc, this.testNumber, this.name, report.details, report.directive);
806+
if (!this.filtered) {
807+
const report = this.getReportDetails();
808+
report.details.passed = this.passed;
809+
this.testNumber ||= ++this.parent.outputSubtestCount;
810+
this.reporter.complete(this.nesting, this.loc, this.testNumber, this.name, report.details, report.directive);
811+
this.parent.activeSubtests--;
812+
}
790813

791-
this.parent.activeSubtests--;
792814
this.parent.addReadySubtest(this);
793815
this.parent.processReadySubtestRange(false);
794816
this.parent.processPendingSubtests();
@@ -846,7 +868,7 @@ class Test extends AsyncResource {
846868
isClearToSend() {
847869
return this.parent === null ||
848870
(
849-
this.parent.waitingOn === this.testNumber && this.parent.isClearToSend()
871+
this.parent.waitingOn === this.childNumber && this.parent.isClearToSend()
850872
);
851873
}
852874

@@ -893,8 +915,8 @@ class Test extends AsyncResource {
893915

894916
report() {
895917
countCompletedTest(this);
896-
if (this.subtests.length > 0) {
897-
this.reporter.plan(this.subtests[0].nesting, this.loc, this.subtests.length);
918+
if (this.outputSubtestCount > 0) {
919+
this.reporter.plan(this.subtests[0].nesting, this.loc, this.outputSubtestCount);
898920
} else {
899921
this.reportStarted();
900922
}
@@ -996,6 +1018,13 @@ class Suite extends Test {
9961018
}),
9971019
() => {
9981020
this.buildPhaseFinished = true;
1021+
1022+
// A suite can transition from filtered to unfiltered based on the
1023+
// tests that it contains.
1024+
if (this.filtered && this.filteredSubtestCount !== this.subtests.length) {
1025+
this.filtered = false;
1026+
this.parent.filteredSubtestCount--;
1027+
}
9991028
},
10001029
);
10011030
} catch (err) {

0 commit comments

Comments
 (0)