Skip to content

Commit 175d312

Browse files
committed
test_runner: add classname hierarchy for JUnit reporter
1 parent 5e104c8 commit 175d312

File tree

7 files changed

+81
-13
lines changed

7 files changed

+81
-13
lines changed

lib/internal/test_runner/test.js

Lines changed: 12 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,
@@ -1366,6 +1367,17 @@ class Test extends AsyncResource {
13661367
details.passed_on_attempt = this.passedAttempt;
13671368
}
13681369

1370+
// Generate classname from suite hierarchy for JUnit reporter
1371+
if (this.parent && this.parent !== this.root) {
1372+
const parts = [];
1373+
for (let t = this.parent; t !== t.root; t = t.parent) {
1374+
ArrayPrototypeUnshift(parts, t.name);
1375+
}
1376+
if (parts.length > 0) {
1377+
details.classname = ArrayPrototypeJoin(parts, '.');
1378+
}
1379+
}
1380+
13691381
return { __proto__: null, details, directive };
13701382
}
13711383

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
@@ -163,7 +163,7 @@ true !== false
163163
<testcase name="immediate reject - passes but warns" time="*" classname="test" file="*"/>
164164
<testcase name="immediate resolve pass" time="*" classname="test" file="*"/>
165165
<testsuite name="subtest sync throw fail" time="*" disabled="0" errors="0" tests="1" failures="1" skipped="0" hostname="HOSTNAME">
166-
<testcase name="+sync throw fail" time="*" classname="test" file="*" failure="thrown from subtest sync throw fail">
166+
<testcase name="+sync throw fail" time="*" classname="subtest sync throw fail" file="*" failure="thrown from subtest sync throw fail">
167167
<failure type="testCodeFailure" message="thrown from subtest sync throw fail">
168168
Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail
169169
*
@@ -192,15 +192,15 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail
192192
</failure>
193193
</testcase>
194194
<testsuite name="level 0a" time="*" disabled="0" errors="0" tests="4" failures="0" skipped="0" hostname="HOSTNAME">
195-
<testcase name="level 1a" time="*" classname="test" file="*"/>
196-
<testcase name="level 1b" time="*" classname="test" file="*"/>
197-
<testcase name="level 1c" time="*" classname="test" file="*"/>
198-
<testcase name="level 1d" time="*" classname="test" file="*"/>
195+
<testcase name="level 1a" time="*" classname="level 0a" file="*"/>
196+
<testcase name="level 1b" time="*" classname="level 0a" file="*"/>
197+
<testcase name="level 1c" time="*" classname="level 0a" file="*"/>
198+
<testcase name="level 1d" time="*" classname="level 0a" file="*"/>
199199
</testsuite>
200200
<testsuite name="top level" time="*" disabled="0" errors="0" tests="2" failures="0" skipped="0" hostname="HOSTNAME">
201-
<testcase name="+long running" time="*" classname="test" file="*"/>
201+
<testcase name="+long running" time="*" classname="top level" file="*"/>
202202
<testsuite name="+short running" time="*" disabled="0" errors="0" tests="1" failures="0" skipped="0" hostname="HOSTNAME">
203-
<testcase name="++short running" time="*" classname="test" file="*"/>
203+
<testcase name="++short running" time="*" classname="top level.+short running" file="*"/>
204204
</testsuite>
205205
</testsuite>
206206
<testcase name="invalid subtest - pass but subtest fails" time="*" classname="test" file="*"/>
@@ -317,9 +317,9 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw
317317
</testcase>
318318
<testcase name="callback async throw after done" time="*" classname="test" file="*"/>
319319
<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">
320-
<testcase name="running subtest 1" time="*" classname="test" file="*"/>
321-
<testcase name="running subtest 3" time="*" classname="test" file="*"/>
322-
<testcase name="running subtest 4" time="*" classname="test" file="*"/>
320+
<testcase name="running subtest 1" time="*" classname="only is set on subtests but not in only mode" file="*"/>
321+
<testcase name="running subtest 3" time="*" classname="only is set on subtests but not in only mode" file="*"/>
322+
<testcase name="running subtest 4" time="*" classname="only is set on subtests but not in only mode" file="*"/>
323323
</testsuite>
324324
<testcase name="custom inspect symbol fail" time="*" classname="test" file="*" failure="customized">
325325
<failure type="testCodeFailure" message="customized">
@@ -339,7 +339,7 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw
339339
</failure>
340340
</testcase>
341341
<testsuite name="subtest sync throw fails" time="*" disabled="0" errors="0" tests="2" failures="2" skipped="0" hostname="HOSTNAME">
342-
<testcase name="sync throw fails at first" time="*" classname="test" file="*" failure="thrown from subtest sync throw fails at first">
342+
<testcase name="sync throw fails at first" time="*" classname="subtest sync throw fails" file="*" failure="thrown from subtest sync throw fails at first">
343343
<failure type="testCodeFailure" message="thrown from subtest sync throw fails at first">
344344
Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at first
345345
*
@@ -360,7 +360,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at first
360360
}
361361
</failure>
362362
</testcase>
363-
<testcase name="sync throw fails at second" time="*" classname="test" file="*" failure="thrown from subtest sync throw fails at second">
363+
<testcase name="sync throw fails at second" time="*" classname="subtest sync throw fails" file="*" failure="thrown from subtest sync throw fails at second">
364364
<failure type="testCodeFailure" message="thrown from subtest sync throw fails at second">
365365
Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at second
366366
* {

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
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Test that the output of test-runner/output/junit_classname_hierarchy.js matches
2+
// test-runner/output/junit_classname_hierarchy.snapshot
3+
import '../common/index.mjs';
4+
import * as fixtures from '../common/fixtures.mjs';
5+
import { spawnAndAssert, junitTransform, ensureCwdIsProjectRoot } from '../common/assertSnapshot.js';
6+
7+
ensureCwdIsProjectRoot();
8+
await spawnAndAssert(
9+
fixtures.path('test-runner/output/junit_classname_hierarchy.js'),
10+
junitTransform,
11+
{ flags: ['--test-reporter=junit'] },
12+
);

0 commit comments

Comments
 (0)