Skip to content

Commit 5e2a5d3

Browse files
committed
test_runner: add classname hierarchy for JUnit reporter
1 parent e105e82 commit 5e2a5d3

File tree

7 files changed

+75
-13
lines changed

7 files changed

+75
-13
lines changed

lib/internal/test_runner/test.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22
const {
3+
ArrayPrototypeJoin,
34
ArrayPrototypePush,
45
ArrayPrototypePushApply,
56
ArrayPrototypeShift,
@@ -1360,6 +1361,18 @@ class Test extends AsyncResource {
13601361
if (this.passedAttempt !== undefined) {
13611362
details.passed_on_attempt = this.passedAttempt;
13621363
}
1364+
1365+
// Generate classname from suite hierarchy for JUnit reporter
1366+
if (this.parent && this.parent !== this.root) {
1367+
const parts = [];
1368+
for (let t = this.parent; t !== t.root; t = t.parent) {
1369+
ArrayPrototypeUnshift(parts, t.name);
1370+
}
1371+
if (parts.length > 0) {
1372+
details.classname = ArrayPrototypeJoin(parts, '.');
1373+
}
1374+
}
1375+
13631376
return { __proto__: null, details, directive };
13641377
}
13651378

lib/internal/test_runner/tests_stream.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class TestsStream extends Readable {
4141
nesting,
4242
testNumber,
4343
details,
44+
...(details.classname && { __proto__: null, classname: details.classname }),
4445
...loc,
4546
...directive,
4647
});
@@ -53,6 +54,7 @@ class TestsStream extends Readable {
5354
nesting,
5455
testNumber,
5556
details,
57+
...(details.classname && { __proto__: null, classname: details.classname }),
5658
...loc,
5759
...directive,
5860
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use strict';
2+
require('../../../common');
3+
const { suite, test } = require('node:test');
4+
5+
suite('Math', () => {
6+
suite('Addition', () => {
7+
test('adds positive numbers', () => {});
8+
});
9+
10+
suite('Multiplication', () => {
11+
test('multiplies positive numbers', () => {});
12+
});
13+
});
14+
15+
suite('String', () => {
16+
test('concatenates strings', () => {});
17+
});
18+
19+
test('standalone test', () => {});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<testsuites>
3+
<testsuite name="Math" time="*" disabled="0" errors="0" tests="2" failures="0" skipped="0" hostname="HOSTNAME">
4+
<testsuite name="Addition" time="*" disabled="0" errors="0" tests="1" failures="0" skipped="0" hostname="HOSTNAME">
5+
<testcase name="adds positive numbers" time="*" classname="Math.Addition" file="*"/>
6+
</testsuite>
7+
<testsuite name="Multiplication" time="*" disabled="0" errors="0" tests="1" failures="0" skipped="0" hostname="HOSTNAME">
8+
<testcase name="multiplies positive numbers" time="*" classname="Math.Multiplication" file="*"/>
9+
</testsuite>
10+
</testsuite>
11+
<testsuite name="String" time="*" disabled="0" errors="0" tests="1" failures="0" skipped="0" hostname="HOSTNAME">
12+
<testcase name="concatenates strings" time="*" classname="String" file="*"/>
13+
</testsuite>
14+
<testcase name="standalone test" time="*" classname="test" file="*"/>
15+
<!-- tests 4 -->
16+
<!-- suites 4 -->
17+
<!-- pass 4 -->
18+
<!-- fail 0 -->
19+
<!-- cancelled 0 -->
20+
<!-- skipped 0 -->
21+
<!-- todo 0 -->
22+
<!-- duration_ms * -->
23+
</testsuites>

test/fixtures/test-runner/output/junit_reporter.snapshot

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ true !== false
153153
<testcase name="immediate reject - passes but warns" time="*" classname="test" file="*"/>
154154
<testcase name="immediate resolve pass" time="*" classname="test" file="*"/>
155155
<testsuite name="subtest sync throw fail" time="*" disabled="0" errors="0" tests="1" failures="1" skipped="0" hostname="HOSTNAME">
156-
<testcase name="+sync throw fail" time="*" classname="test" file="*" failure="thrown from subtest sync throw fail">
156+
<testcase name="+sync throw fail" time="*" classname="subtest sync throw fail" file="*" failure="thrown from subtest sync throw fail">
157157
<failure type="testCodeFailure" message="thrown from subtest sync throw fail">
158158
Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail
159159
*
@@ -182,15 +182,15 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail
182182
</failure>
183183
</testcase>
184184
<testsuite name="level 0a" time="*" disabled="0" errors="0" tests="4" failures="0" skipped="0" hostname="HOSTNAME">
185-
<testcase name="level 1a" time="*" classname="test" file="*"/>
186-
<testcase name="level 1b" time="*" classname="test" file="*"/>
187-
<testcase name="level 1c" time="*" classname="test" file="*"/>
188-
<testcase name="level 1d" time="*" classname="test" file="*"/>
185+
<testcase name="level 1a" time="*" classname="level 0a" file="*"/>
186+
<testcase name="level 1b" time="*" classname="level 0a" file="*"/>
187+
<testcase name="level 1c" time="*" classname="level 0a" file="*"/>
188+
<testcase name="level 1d" time="*" classname="level 0a" file="*"/>
189189
</testsuite>
190190
<testsuite name="top level" time="*" disabled="0" errors="0" tests="2" failures="0" skipped="0" hostname="HOSTNAME">
191-
<testcase name="+long running" time="*" classname="test" file="*"/>
191+
<testcase name="+long running" time="*" classname="top level" file="*"/>
192192
<testsuite name="+short running" time="*" disabled="0" errors="0" tests="1" failures="0" skipped="0" hostname="HOSTNAME">
193-
<testcase name="++short running" time="*" classname="test" file="*"/>
193+
<testcase name="++short running" time="*" classname="top level.+short running" file="*"/>
194194
</testsuite>
195195
</testsuite>
196196
<testcase name="invalid subtest - pass but subtest fails" time="*" classname="test" file="*"/>
@@ -307,9 +307,9 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw
307307
</testcase>
308308
<testcase name="callback async throw after done" time="*" classname="test" file="*"/>
309309
<testsuite name="only is set on subtests but not in only mode" time="*" disabled="0" errors="0" tests="3" failures="0" skipped="0" hostname="HOSTNAME">
310-
<testcase name="running subtest 1" time="*" classname="test" file="*"/>
311-
<testcase name="running subtest 3" time="*" classname="test" file="*"/>
312-
<testcase name="running subtest 4" time="*" classname="test" file="*"/>
310+
<testcase name="running subtest 1" time="*" classname="only is set on subtests but not in only mode" file="*"/>
311+
<testcase name="running subtest 3" time="*" classname="only is set on subtests but not in only mode" file="*"/>
312+
<testcase name="running subtest 4" time="*" classname="only is set on subtests but not in only mode" file="*"/>
313313
</testsuite>
314314
<testcase name="custom inspect symbol fail" time="*" classname="test" file="*" failure="customized">
315315
<failure type="testCodeFailure" message="customized">
@@ -329,7 +329,7 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw
329329
</failure>
330330
</testcase>
331331
<testsuite name="subtest sync throw fails" time="*" disabled="0" errors="0" tests="2" failures="2" skipped="0" hostname="HOSTNAME">
332-
<testcase name="sync throw fails at first" time="*" classname="test" file="*" failure="thrown from subtest sync throw fails at first">
332+
<testcase name="sync throw fails at first" time="*" classname="subtest sync throw fails" file="*" failure="thrown from subtest sync throw fails at first">
333333
<failure type="testCodeFailure" message="thrown from subtest sync throw fails at first">
334334
Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at first
335335
*
@@ -350,7 +350,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at first
350350
}
351351
</failure>
352352
</testcase>
353-
<testcase name="sync throw fails at second" time="*" classname="test" file="*" failure="thrown from subtest sync throw fails at second">
353+
<testcase name="sync throw fails at second" time="*" classname="subtest sync throw fails" file="*" failure="thrown from subtest sync throw fails at second">
354354
<failure type="testCodeFailure" message="thrown from subtest sync throw fails at second">
355355
Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at second
356356
* {

test/parallel/test-runner-output.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ const tests = [
181181
{ name: 'test-runner/output/only_tests.js', flags: ['--test-reporter=tap'] },
182182
{ name: 'test-runner/output/dot_reporter.js', transform: specTransform },
183183
{ name: 'test-runner/output/junit_reporter.js', transform: junitTransform },
184+
{
185+
name: 'test-runner/output/junit_classname_hierarchy.js',
186+
flags: ['--test-reporter=junit'],
187+
transform: junitTransform,
188+
},
184189
{ name: 'test-runner/output/spec_reporter_successful.js', transform: specTransform },
185190
{ name: 'test-runner/output/spec_reporter.js', transform: specTransform },
186191
{ name: 'test-runner/output/spec_reporter_cli.js', transform: specTransform },

test/parallel/test-runner-reporters.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ describe('node:test reporters', { concurrency: true }, () => {
201201
const fileContents = fs.readFileSync(file, 'utf8');
202202
assert.match(fileContents, /<testsuite .*name="nested".*tests="2".*failures="1".*skipped="0".*>/);
203203
assert.match(fileContents, /<testcase .*name="failing".*>\s*<failure .*type="testCodeFailure".*message="error".*>/);
204-
assert.match(fileContents, /<testcase .*name="ok".*classname="test".*\/>/);
204+
assert.match(fileContents, /<testcase .*name="ok".*classname="nested".*\/>/);
205205
assert.match(fileContents, /<testcase .*name="top level".*classname="test".*\/>/);
206206
});
207207
});

0 commit comments

Comments
 (0)