Skip to content

Commit 460bcc0

Browse files
MoLowdanielleadams
authored andcommitted
test_runner: count nested tests
PR-URL: #47094 Fixes: #46762 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]>
1 parent d562a7c commit 460bcc0

21 files changed

+163
-93
lines changed

lib/internal/test_runner/harness.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,17 @@ function setup(root) {
166166
__proto__: null,
167167
bootstrapComplete: false,
168168
coverage: null,
169+
counters: {
170+
__proto__: null,
171+
all: 0,
172+
failed: 0,
173+
passed: 0,
174+
cancelled: 0,
175+
skipped: 0,
176+
todo: 0,
177+
planned: 0,
178+
suites: 0,
179+
},
169180
};
170181
root.startTime = hrtime();
171182
return root;

lib/internal/test_runner/reporter/tap.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ function reportDetails(nesting, data = kEmptyObject) {
113113
let details = `${_indent} ---\n`;
114114

115115
details += jsToYaml(_indent, 'duration_ms', duration_ms);
116+
details += jsToYaml(_indent, 'type', data.type);
116117
details += jsToYaml(_indent, null, error);
117118
details += `${_indent} ...\n`;
118119
return details;

lib/internal/test_runner/runner.js

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@ const {
1010
ArrayPrototypeSome,
1111
ArrayPrototypeSort,
1212
ArrayPrototypeSplice,
13-
FunctionPrototypeCall,
1413
Number,
1514
ObjectAssign,
16-
ObjectKeys,
1715
PromisePrototypeThen,
1816
SafePromiseAll,
1917
SafePromiseAllReturnVoid,
@@ -55,8 +53,9 @@ const { YAMLToJs } = require('internal/test_runner/yaml_to_js');
5553
const { TokenKind } = require('internal/test_runner/tap_lexer');
5654

5755
const {
58-
isSupportedFileType,
56+
countCompletedTest,
5957
doesPathMatchFilter,
58+
isSupportedFileType,
6059
} = require('internal/test_runner/utils');
6160
const { basename, join, resolve } = require('path');
6261
const { once } = require('events');
@@ -66,7 +65,7 @@ const {
6665

6766
const kFilterArgs = ['--test', '--experimental-test-coverage', '--watch'];
6867
const kFilterArgValues = ['--test-reporter', '--test-reporter-destination'];
69-
const kDiagnosticsFilterArgs = ['tests', 'pass', 'fail', 'cancelled', 'skipped', 'todo', 'duration_ms'];
68+
const kDiagnosticsFilterArgs = ['tests', 'suites', 'pass', 'fail', 'cancelled', 'skipped', 'todo', 'duration_ms'];
7069

7170
const kCanceledTests = new SafeSet()
7271
.add(kCancelledByParent).add(kAborted).add(kTestTimeoutFailure);
@@ -150,10 +149,10 @@ function getRunArgs({ path, inspectPort }) {
150149

151150
class FileTest extends Test {
152151
#buffer = [];
153-
#counters = { __proto__: null, all: 0, failed: 0, passed: 0, cancelled: 0, skipped: 0, todo: 0, totalFailed: 0 };
152+
#reportedChildren = 0;
154153
failedSubtests = false;
155154
#skipReporting() {
156-
return this.#counters.all > 0 && (!this.error || this.error.failureType === kSubtestsFailed);
155+
return this.#reportedChildren > 0 && (!this.error || this.error.failureType === kSubtestsFailed);
157156
}
158157
#checkNestedComment({ comment }) {
159158
const firstSpaceIndex = StringPrototypeIndexOf(comment, ' ');
@@ -203,11 +202,19 @@ class FileTest extends Test {
203202
const method = pass ? 'ok' : 'fail';
204203
this.reporter[method](nesting, this.name, testNumber, node.description, diagnostics, directive);
205204
if (nesting === 0) {
206-
FunctionPrototypeCall(super.countSubtest,
207-
{ finished: true, skipped: skip, isTodo: todo, passed: pass, cancelled },
208-
this.#counters);
209205
this.failedSubtests ||= !pass;
210206
}
207+
this.#reportedChildren++;
208+
countCompletedTest({
209+
name: node.description,
210+
finished: true,
211+
skipped: skip,
212+
isTodo: todo,
213+
passed: pass,
214+
cancelled,
215+
nesting,
216+
reportedType: diagnostics.type,
217+
}, this.root.harness);
211218
break;
212219

213220
}
@@ -232,14 +239,6 @@ class FileTest extends Test {
232239
this.reportStarted();
233240
this.#handleReportItem(ast);
234241
}
235-
countSubtest(counters) {
236-
if (this.#counters.all === 0) {
237-
return super.countSubtest(counters);
238-
}
239-
ArrayPrototypeForEach(ObjectKeys(counters), (key) => {
240-
counters[key] += this.#counters[key];
241-
});
242-
}
243242
reportStarted() {}
244243
report() {
245244
const skipReporting = this.#skipReporting();

lib/internal/test_runner/test.js

Lines changed: 24 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const { MockTracker } = require('internal/test_runner/mock');
3434
const { TestsStream } = require('internal/test_runner/tests_stream');
3535
const {
3636
createDeferredCallback,
37+
countCompletedTest,
3738
isTestFailureError,
3839
parseCommandLine,
3940
} = require('internal/test_runner/utils');
@@ -186,6 +187,7 @@ class Test extends AsyncResource {
186187
this.runOnlySubtests = this.only;
187188
this.testNumber = 0;
188189
this.timeout = kDefaultTimeout;
190+
this.root = this;
189191
} else {
190192
const nesting = parent.parent === null ? parent.nesting :
191193
parent.nesting + 1;
@@ -197,6 +199,7 @@ class Test extends AsyncResource {
197199
this.runOnlySubtests = !this.only;
198200
this.testNumber = parent.subtests.length + 1;
199201
this.timeout = parent.timeout;
202+
this.root = parent.root;
200203
}
201204

202205
switch (typeof concurrency) {
@@ -575,31 +578,7 @@ class Test extends AsyncResource {
575578
this.postRun();
576579
}
577580

578-
countSubtest(counters) {
579-
// Check SKIP and TODO tests first, as those should not be counted as
580-
// failures.
581-
if (this.skipped) {
582-
counters.skipped++;
583-
} else if (this.isTodo) {
584-
counters.todo++;
585-
} else if (this.cancelled) {
586-
counters.cancelled++;
587-
} else if (!this.passed) {
588-
counters.failed++;
589-
} else {
590-
counters.passed++;
591-
}
592-
593-
if (!this.passed) {
594-
counters.totalFailed++;
595-
}
596-
counters.all++;
597-
}
598-
599581
postRun(pendingSubtestsError) {
600-
const counters = {
601-
__proto__: null, all: 0, failed: 0, passed: 0, cancelled: 0, skipped: 0, todo: 0, totalFailed: 0,
602-
};
603582
// If the test was failed before it even started, then the end time will
604583
// be earlier than the start time. Correct that here.
605584
if (this.endTime < this.startTime) {
@@ -610,19 +589,22 @@ class Test extends AsyncResource {
610589
// The test has run, so recursively cancel any outstanding subtests and
611590
// mark this test as failed if any subtests failed.
612591
this.pendingSubtests = [];
592+
let failed = 0;
613593
for (let i = 0; i < this.subtests.length; i++) {
614594
const subtest = this.subtests[i];
615595

616596
if (!subtest.finished) {
617597
subtest.#cancel(pendingSubtestsError);
618598
subtest.postRun(pendingSubtestsError);
619599
}
620-
subtest.countSubtest(counters);
600+
if (!subtest.passed) {
601+
failed++;
602+
}
621603
}
622604

623-
if ((this.passed || this.parent === null) && counters.totalFailed > 0) {
624-
const subtestString = `subtest${counters.totalFailed > 1 ? 's' : ''}`;
625-
const msg = `${counters.totalFailed} ${subtestString} failed`;
605+
if ((this.passed || this.parent === null) && failed > 0) {
606+
const subtestString = `subtest${failed > 1 ? 's' : ''}`;
607+
const msg = `${failed} ${subtestString} failed`;
626608

627609
this.fail(new ERR_TEST_FAILURE(msg, kSubtestsFailed));
628610
}
@@ -637,18 +619,19 @@ class Test extends AsyncResource {
637619
this.parent.processPendingSubtests();
638620
} else if (!this.reported) {
639621
this.reported = true;
640-
this.reporter.plan(this.nesting, kFilename, counters.all);
622+
this.reporter.plan(this.nesting, kFilename, this.root.harness.counters.planned);
641623

642624
for (let i = 0; i < this.diagnostics.length; i++) {
643625
this.reporter.diagnostic(this.nesting, kFilename, this.diagnostics[i]);
644626
}
645627

646-
this.reporter.diagnostic(this.nesting, kFilename, `tests ${counters.all}`);
647-
this.reporter.diagnostic(this.nesting, kFilename, `pass ${counters.passed}`);
648-
this.reporter.diagnostic(this.nesting, kFilename, `fail ${counters.failed}`);
649-
this.reporter.diagnostic(this.nesting, kFilename, `cancelled ${counters.cancelled}`);
650-
this.reporter.diagnostic(this.nesting, kFilename, `skipped ${counters.skipped}`);
651-
this.reporter.diagnostic(this.nesting, kFilename, `todo ${counters.todo}`);
628+
this.reporter.diagnostic(this.nesting, kFilename, `tests ${this.root.harness.counters.all}`);
629+
this.reporter.diagnostic(this.nesting, kFilename, `suites ${this.root.harness.counters.suites}`);
630+
this.reporter.diagnostic(this.nesting, kFilename, `pass ${this.root.harness.counters.passed}`);
631+
this.reporter.diagnostic(this.nesting, kFilename, `fail ${this.root.harness.counters.failed}`);
632+
this.reporter.diagnostic(this.nesting, kFilename, `cancelled ${this.root.harness.counters.cancelled}`);
633+
this.reporter.diagnostic(this.nesting, kFilename, `skipped ${this.root.harness.counters.skipped}`);
634+
this.reporter.diagnostic(this.nesting, kFilename, `todo ${this.root.harness.counters.todo}`);
652635
this.reporter.diagnostic(this.nesting, kFilename, `duration_ms ${this.#duration()}`);
653636

654637
if (this.harness?.coverage) {
@@ -689,6 +672,7 @@ class Test extends AsyncResource {
689672
}
690673

691674
report() {
675+
countCompletedTest(this);
692676
if (this.subtests.length > 0) {
693677
this.reporter.plan(this.subtests[0].nesting, kFilename, this.subtests.length);
694678
} else {
@@ -703,6 +687,10 @@ class Test extends AsyncResource {
703687
directive = this.reporter.getTodo(this.message);
704688
}
705689

690+
if (this.reportedType) {
691+
details.type = this.reportedType;
692+
}
693+
706694
if (this.passed) {
707695
this.reporter.ok(this.nesting, kFilename, this.testNumber, this.name, details, directive);
708696
} else {
@@ -746,6 +734,7 @@ class TestHook extends Test {
746734
}
747735

748736
class Suite extends Test {
737+
reportedType = 'suite';
749738
constructor(options) {
750739
super(options);
751740

lib/internal/test_runner/utils.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,33 @@ function parseCommandLine() {
223223
return globalTestOptions;
224224
}
225225

226+
function countCompletedTest(test, harness = test.root.harness) {
227+
if (test.nesting === 0) {
228+
harness.counters.planned++;
229+
}
230+
if (test.reportedType === 'suite') {
231+
harness.counters.suites++;
232+
return;
233+
}
234+
// Check SKIP and TODO tests first, as those should not be counted as
235+
// failures.
236+
if (test.skipped) {
237+
harness.counters.skipped++;
238+
} else if (test.isTodo) {
239+
harness.counters.todo++;
240+
} else if (test.cancelled) {
241+
harness.counters.cancelled++;
242+
} else if (!test.passed) {
243+
harness.counters.failed++;
244+
} else {
245+
harness.counters.passed++;
246+
}
247+
harness.counters.all++;
248+
}
249+
226250
module.exports = {
227251
convertStringToRegExp,
252+
countCompletedTest,
228253
createDeferredCallback,
229254
doesPathMatchFilter,
230255
isSupportedFileType,

test/message/test_runner_abort.out

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,11 @@ not ok 4 - callback abort signal
260260
*
261261
...
262262
1..4
263-
# tests 4
264-
# pass 0
263+
# tests 22
264+
# suites 0
265+
# pass 8
265266
# fail 0
266-
# cancelled 4
267+
# cancelled 14
267268
# skipped 0
268269
# todo 0
269270
# duration_ms *

test/message/test_runner_abort_suite.out

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ TAP version 13
6464
not ok 1 - describe timeout signal
6565
---
6666
duration_ms: *
67+
type: 'suite'
6768
failureType: 'testAborted'
6869
error: 'The operation was aborted due to timeout'
6970
code: 23
@@ -78,6 +79,7 @@ not ok 1 - describe timeout signal
7879
not ok 2 - describe abort signal
7980
---
8081
duration_ms: *
82+
type: 'suite'
8183
failureType: 'testAborted'
8284
error: 'This operation was aborted'
8385
code: 20
@@ -94,10 +96,11 @@ not ok 2 - describe abort signal
9496
*
9597
...
9698
1..2
97-
# tests 2
98-
# pass 0
99+
# tests 9
100+
# suites 2
101+
# pass 4
99102
# fail 0
100-
# cancelled 2
103+
# cancelled 5
101104
# skipped 0
102105
# todo 0
103106
# duration_ms *

0 commit comments

Comments
 (0)