@reporters/junit 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +2 -1
- package/index.js +41 -25
- package/package.json +2 -2
- package/tests/index.test.js +2 -1
- package/tests/output.v18.js +29 -0
- package/tests/output.v19.js +31 -0
- package/tests/output.js +0 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.0.4](https://github.com/MoLow/reporters/compare/junit-v1.0.3...junit-v1.0.4) (2023-04-03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* allow multiple roots ([590df94](https://github.com/MoLow/reporters/commit/590df948f8a4626fc29e8ce185e08d2226a307ba))
|
|
9
|
+
|
|
10
|
+
## [1.0.3](https://github.com/MoLow/reporters/compare/junit-v1.0.2...junit-v1.0.3) (2023-03-12)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **junit:** support more usecases ([72359c3](https://github.com/MoLow/reporters/commit/72359c3983334d7712c4d404a0ae297b9ef9e859))
|
|
16
|
+
|
|
3
17
|
## [1.0.2](https://github.com/MoLow/reporters/compare/junit-v1.0.1...junit-v1.0.2) (2022-12-25)
|
|
4
18
|
|
|
5
19
|
|
package/README.md
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
[](https://www.npmjs.com/package/@reporters/junit)  [](https://codecov.io/gh/MoLow/reporters)
|
|
2
|
+
|
|
2
3
|
# Junit Reporter
|
|
3
4
|
A Junit reporter for `node:test`.
|
|
4
5
|
intendend for use with major CI tools like Jenkins, CircleCI, etc that consume Junit reports.
|
package/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const assert = require('node:assert');
|
|
2
1
|
const util = require('node:util');
|
|
3
2
|
const { hostname } = require('node:os');
|
|
4
3
|
|
|
@@ -14,7 +13,7 @@ function escapeContent(s = '') {
|
|
|
14
13
|
|
|
15
14
|
function treeToXML(tree) {
|
|
16
15
|
if (typeof tree === 'string') {
|
|
17
|
-
return escapeContent(tree)
|
|
16
|
+
return `${escapeContent(tree)}\n`;
|
|
18
17
|
}
|
|
19
18
|
const {
|
|
20
19
|
tag, props, nesting, children,
|
|
@@ -22,12 +21,12 @@ function treeToXML(tree) {
|
|
|
22
21
|
const propsString = Object.entries(props)
|
|
23
22
|
.map(([key, value]) => `${key}="${escapeProperty(String(value))}"`)
|
|
24
23
|
.join(' ');
|
|
25
|
-
const indent = '
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const childrenString = `${
|
|
30
|
-
return `${indent}<${tag} ${propsString}
|
|
24
|
+
const indent = '\t'.repeat(nesting + 1);
|
|
25
|
+
if (!children?.length) {
|
|
26
|
+
return `${indent}<${tag} ${propsString}/>\n`;
|
|
27
|
+
}
|
|
28
|
+
const childrenString = `${(children ?? []).map(treeToXML).join('')}`;
|
|
29
|
+
return `${indent}<${tag} ${propsString}>\n${childrenString}${indent}</${tag}>\n`;
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
function isFailure(node) {
|
|
@@ -42,27 +41,42 @@ module.exports = async function* junitReporter(source) {
|
|
|
42
41
|
yield '<?xml version="1.0" encoding="utf-8"?>\n';
|
|
43
42
|
yield '<testsuites>\n';
|
|
44
43
|
let currentSuite = null;
|
|
44
|
+
const roots = [];
|
|
45
|
+
|
|
46
|
+
function startTest(event) {
|
|
47
|
+
const originalSuite = currentSuite;
|
|
48
|
+
currentSuite = {
|
|
49
|
+
props: { name: event.data.name },
|
|
50
|
+
nesting: event.data.nesting,
|
|
51
|
+
parent: currentSuite,
|
|
52
|
+
children: [],
|
|
53
|
+
};
|
|
54
|
+
originalSuite?.children.push(currentSuite);
|
|
55
|
+
if (!currentSuite.parent) {
|
|
56
|
+
roots.push(currentSuite);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
45
60
|
for await (const event of source) {
|
|
46
61
|
switch (event.type) {
|
|
47
62
|
case 'test:start': {
|
|
48
|
-
|
|
49
|
-
currentSuite = {
|
|
50
|
-
props: { name: event.data.name },
|
|
51
|
-
nesting: event.data.nesting,
|
|
52
|
-
parent: currentSuite,
|
|
53
|
-
children: [],
|
|
54
|
-
};
|
|
55
|
-
originalSuite?.children.push(currentSuite);
|
|
63
|
+
startTest(event);
|
|
56
64
|
break;
|
|
57
65
|
}
|
|
58
66
|
case 'test:pass':
|
|
59
67
|
case 'test:fail': {
|
|
68
|
+
if (!currentSuite) {
|
|
69
|
+
startTest({ data: { name: 'root', nesting: 0 } });
|
|
70
|
+
}
|
|
71
|
+
if (currentSuite.props.name !== event.data.name
|
|
72
|
+
|| currentSuite.nesting !== event.data.nesting) {
|
|
73
|
+
startTest(event);
|
|
74
|
+
}
|
|
60
75
|
const currentTest = currentSuite;
|
|
61
|
-
if (currentSuite?.nesting === event.data.nesting
|
|
76
|
+
if (currentSuite?.nesting === event.data.nesting) {
|
|
62
77
|
currentSuite = currentSuite.parent;
|
|
63
78
|
}
|
|
64
|
-
|
|
65
|
-
currentTest.props.time = (event.data.details.duration_ms / 1000).toFixed(5);
|
|
79
|
+
currentTest.props.time = (event.data.details.duration_ms / 1000).toFixed(6);
|
|
66
80
|
if (currentTest.children.length > 0) {
|
|
67
81
|
currentTest.tag = 'testsuite';
|
|
68
82
|
currentTest.props.disabled = 0;
|
|
@@ -73,19 +87,19 @@ module.exports = async function* junitReporter(source) {
|
|
|
73
87
|
currentTest.props.hostname = HOSTNAME;
|
|
74
88
|
} else {
|
|
75
89
|
currentTest.tag = 'testcase';
|
|
76
|
-
currentTest.props.classname = 'test';
|
|
90
|
+
currentTest.props.classname = event.data.classname ?? 'test';
|
|
77
91
|
if (event.data.skip) {
|
|
78
|
-
currentTest.children.push({ nesting: event.data.nesting + 1, tag: 'skipped', props: { message: event.data.skip } });
|
|
92
|
+
currentTest.children.push({ nesting: event.data.nesting + 1, tag: 'skipped', props: { type: 'skipped', message: event.data.skip } });
|
|
79
93
|
}
|
|
80
94
|
if (event.data.todo) {
|
|
81
|
-
currentTest.children.push({ nesting: event.data.nesting + 1, tag: 'skipped', props: { message: event.data.todo } });
|
|
95
|
+
currentTest.children.push({ nesting: event.data.nesting + 1, tag: 'skipped', props: { type: 'todo', message: event.data.todo } });
|
|
82
96
|
}
|
|
83
97
|
if (event.type === 'test:fail') {
|
|
84
98
|
const error = event.data.details?.error;
|
|
85
99
|
currentTest.children.push({
|
|
86
100
|
nesting: event.data.nesting + 1,
|
|
87
101
|
tag: 'failure',
|
|
88
|
-
props: {
|
|
102
|
+
props: { type: error?.failureType || error?.code, message: error?.message ?? '' },
|
|
89
103
|
children: [util.inspect(
|
|
90
104
|
event.data.details?.error,
|
|
91
105
|
{ colors: false, breakLength: Infinity },
|
|
@@ -103,6 +117,8 @@ module.exports = async function* junitReporter(source) {
|
|
|
103
117
|
break;
|
|
104
118
|
}
|
|
105
119
|
}
|
|
106
|
-
|
|
107
|
-
|
|
120
|
+
for (const suite of roots) {
|
|
121
|
+
yield treeToXML(suite);
|
|
122
|
+
}
|
|
123
|
+
yield '</testsuites>\n';
|
|
108
124
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reporters/junit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "A jUnit reporter for `node:test`",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"junit",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"reporters"
|
|
11
11
|
],
|
|
12
12
|
"scripts": {
|
|
13
|
-
"test": "
|
|
13
|
+
"test": "node --test-reporter=spec --test-reporter-destination=stdout --test-reporter=../github/index.js --test-reporter-destination=stdout --test"
|
|
14
14
|
},
|
|
15
15
|
"bugs": {
|
|
16
16
|
"url": "https://github.com/MoLow/reporters/issues"
|
package/tests/index.test.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
const { spawnSync } = require('child_process');
|
|
2
2
|
const assert = require('assert');
|
|
3
3
|
const { compareLines } = require('../../../tests/utils');
|
|
4
|
-
|
|
4
|
+
// eslint-disable-next-line import/no-dynamic-require
|
|
5
|
+
const output = require(`./output.${process.version.split('.')[0]}`);
|
|
5
6
|
|
|
6
7
|
const child = spawnSync(process.execPath, ['--test-reporter', './index.js', '../../tests/example']);
|
|
7
8
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
stdout: `<\\?xml version="1.0" encoding="utf-8"\\?>
|
|
3
|
+
<testsuites>
|
|
4
|
+
\t<testsuite name="tests" time=".*" disabled="0" errors="0" tests="3" failures="1" skipped="0" hostname=".*">
|
|
5
|
+
\t\t<testcase name="is ok" time=".*" classname="test"/>
|
|
6
|
+
\t\t<testcase name="fails" time=".*" classname="test" failure="this is an error">
|
|
7
|
+
\t\t\t<failure type="testCodeFailure" message="this is an error">
|
|
8
|
+
\\[Error \\[ERR_TEST_FAILURE\\]: this is an error\\] {
|
|
9
|
+
failureType: 'testCodeFailure',
|
|
10
|
+
cause: Error: this is an error
|
|
11
|
+
at Object.<anonymous> (.*)
|
|
12
|
+
.*
|
|
13
|
+
.*
|
|
14
|
+
.*
|
|
15
|
+
.*
|
|
16
|
+
.*
|
|
17
|
+
.*
|
|
18
|
+
code: 'ERR_TEST_FAILURE'
|
|
19
|
+
}
|
|
20
|
+
\t\t\t</failure>
|
|
21
|
+
\t\t</testcase>
|
|
22
|
+
\t\t<testcase name="is a diagnostic" time=".*" classname="test"/>
|
|
23
|
+
\t</testsuite>
|
|
24
|
+
\t<testsuite name="more tests" time=".*" disabled="0" errors="0" tests="1" failures="0" skipped="0" hostname=".*">
|
|
25
|
+
\t\t<testcase name="is ok" time=".*" classname="test"/>
|
|
26
|
+
\t</testsuite>
|
|
27
|
+
</testsuites>
|
|
28
|
+
`,
|
|
29
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
stdout: `<\\?xml version="1.0" encoding="utf-8"\\?>
|
|
3
|
+
<testsuites>
|
|
4
|
+
\t<testsuite name="tests" time=".*" disabled="0" errors="0" tests="3" failures="1" skipped="0" hostname=".*">
|
|
5
|
+
\t\t<testcase name="is ok" time=".*" classname="test"/>
|
|
6
|
+
\t\t<testcase name="fails" time=".*" classname="test" failure="this is an error">
|
|
7
|
+
\t\t\t<failure type="testCodeFailure" message="this is an error">
|
|
8
|
+
\\[Error \\[ERR_TEST_FAILURE\\]: this is an error\\] {
|
|
9
|
+
failureType: 'testCodeFailure',
|
|
10
|
+
cause: Error: this is an error
|
|
11
|
+
.*
|
|
12
|
+
.*
|
|
13
|
+
.*
|
|
14
|
+
.*
|
|
15
|
+
.*
|
|
16
|
+
.*
|
|
17
|
+
.*
|
|
18
|
+
.*
|
|
19
|
+
.*
|
|
20
|
+
code: 'ERR_TEST_FAILURE'
|
|
21
|
+
}
|
|
22
|
+
\t\t\t</failure>
|
|
23
|
+
\t\t</testcase>
|
|
24
|
+
\t\t<testcase name="is a diagnostic" time=".*" classname="test"/>
|
|
25
|
+
\t</testsuite>
|
|
26
|
+
\t<testsuite name="more tests" time=".*" disabled="0" errors="0" tests="1" failures="0" skipped="0" hostname=".*">
|
|
27
|
+
\t\t<testcase name="is ok" time=".*" classname="test"/>
|
|
28
|
+
\t</testsuite>
|
|
29
|
+
</testsuites>
|
|
30
|
+
`,
|
|
31
|
+
};
|
package/tests/output.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
stdout: `<\\?xml version="1.0" encoding="utf-8"\\?>
|
|
3
|
-
<testsuites>
|
|
4
|
-
<testsuite name="tests" time=".*" disabled="0" errors="0" tests="2" failures="1" skipped="0" hostname=".*">
|
|
5
|
-
<testcase name="is ok" time=".*" classname="test"></testcase>
|
|
6
|
-
<testcase name="fails" time=".*" classname="test" failure="this is an error">
|
|
7
|
-
<failure message="this is an error" type="testCodeFailure">
|
|
8
|
-
\\[Error \\[ERR_TEST_FAILURE\\]: this is an error\\] {
|
|
9
|
-
failureType: 'testCodeFailure',
|
|
10
|
-
cause: Error: this is an error
|
|
11
|
-
at Object.<anonymous> (.*)
|
|
12
|
-
.*
|
|
13
|
-
.*
|
|
14
|
-
.*
|
|
15
|
-
.*
|
|
16
|
-
.*
|
|
17
|
-
.*
|
|
18
|
-
.*
|
|
19
|
-
code: 'ERR_TEST_FAILURE'
|
|
20
|
-
}
|
|
21
|
-
</failure>
|
|
22
|
-
</testcase>
|
|
23
|
-
</testsuite>
|
|
24
|
-
</testsuites>
|
|
25
|
-
`,
|
|
26
|
-
};
|