Skip to content

Commit 79b7813

Browse files
committed
test_runner: parse yaml
1 parent 43f9bb3 commit 79b7813

File tree

6 files changed

+775
-16
lines changed

6 files changed

+775
-16
lines changed

lib/internal/test_runner/runner.js

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ const {
44
ArrayPrototypeFilter,
55
ArrayPrototypeForEach,
66
ArrayPrototypeIncludes,
7-
ArrayPrototypeJoin,
87
ArrayPrototypePush,
98
ArrayPrototypeSlice,
109
ArrayPrototypeSort,
@@ -35,6 +34,7 @@ const { kEmptyObject } = require('internal/util');
3534
const { createTestTree } = require('internal/test_runner/harness');
3635
const { kDefaultIndent, kSubtestsFailed, Test } = require('internal/test_runner/test');
3736
const { TapParser } = require('internal/test_runner/tap_parser');
37+
const { parseYAML } = require('internal/test_runner/yaml_parser');
3838
const { TokenKind } = require('internal/test_runner/tap_lexer');
3939

4040
const {
@@ -130,17 +130,7 @@ class FileTest extends Test {
130130
#handleReportItem({ kind, node, nesting = 0 }) {
131131
const indent = StringPrototypeRepeat(kDefaultIndent, nesting + 1);
132132

133-
const details = (diagnostic) => {
134-
return (
135-
diagnostic && {
136-
__proto__: null,
137-
yaml:
138-
`${indent} ` +
139-
ArrayPrototypeJoin(diagnostic, `\n${indent} `) +
140-
'\n',
141-
}
142-
);
143-
};
133+
const details = (diagnostic) => diagnostic && parseYAML(diagnostic);
144134

145135
switch (kind) {
146136
case TokenKind.TAP_VERSION:

lib/internal/test_runner/tap_stream.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,10 @@ class TapStream extends Readable {
8383
}
8484

8585
#details(indent, data = kEmptyObject) {
86-
const { error, duration, yaml } = data;
86+
const { error, duration_ms } = data;
8787
let details = `${indent} ---\n`;
8888

89-
details += `${yaml ? yaml : ''}`;
90-
details += jsToYaml(indent, 'duration_ms', duration);
89+
details += jsToYaml(indent, 'duration_ms', duration_ms);
9190
details += jsToYaml(indent, null, error);
9291
details += `${indent} ...\n`;
9392
this.#tryPush(details);

lib/internal/test_runner/test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ class Test extends AsyncResource {
676676
this.reportSubtest();
677677
}
678678
let directive;
679-
const details = { __proto__: null, duration: this.#duration() };
679+
const details = { __proto__: null, duration_ms: this.#duration() };
680680

681681
if (this.skipped) {
682682
directive = this.reporter.getSkip(this.message);
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
'use strict';
2+
const {
3+
codes: {
4+
ERR_TEST_FAILURE,
5+
}
6+
} = require('internal/errors');
7+
const AssertionError = require('internal/assert/assertion_error');
8+
const {
9+
ArrayPrototypeJoin,
10+
Error,
11+
Number,
12+
NumberIsNaN,
13+
RegExpPrototypeExec,
14+
StringPrototypeEndsWith,
15+
StringPrototypeRepeat,
16+
StringPrototypeSlice,
17+
StringPrototypeStartsWith,
18+
StringPrototypeSubstring,
19+
} = primordials;
20+
21+
const kYamlKeyRegex = /^(\s+)?(\w+):(\s)+([>|][-+])?(.*)$/;
22+
const kStackDelimiter = ' at ';
23+
24+
function reConstructError(parsedYaml) {
25+
if (!('error' in parsedYaml)) {
26+
return parsedYaml;
27+
}
28+
const isAssertionError = parsedYaml.code === 'ERR_ASSERTION' ||
29+
'actual' in parsedYaml || 'expected' in parsedYaml || 'operator' in parsedYaml;
30+
const isTestFauilure = parsedYaml.code === 'ERR_TEST_FAILURE' || 'failureType' in parsedYaml;
31+
const stack = parsedYaml.stack ? kStackDelimiter + ArrayPrototypeJoin(parsedYaml.stack, `\n${kStackDelimiter}`) : '';
32+
33+
// eslint-disable-next-line no-restricted-syntax
34+
let error = new Error(parsedYaml.error);
35+
error.stack = stack;
36+
error.code = parsedYaml.code;
37+
38+
if (isAssertionError) {
39+
error = new AssertionError({
40+
message: parsedYaml.error,
41+
actual: parsedYaml.actual,
42+
expected: parsedYaml.expected,
43+
operator: parsedYaml.operator
44+
});
45+
error.stack = stack;
46+
}
47+
48+
if (isTestFauilure) {
49+
error = new ERR_TEST_FAILURE(error, parsedYaml.failureType);
50+
error.stack = stack;
51+
}
52+
53+
parsedYaml.error = error;
54+
delete parsedYaml.stack;
55+
delete parsedYaml.code;
56+
delete parsedYaml.failureType;
57+
delete parsedYaml.actual;
58+
delete parsedYaml.expected;
59+
delete parsedYaml.operator;
60+
61+
return parsedYaml;
62+
}
63+
64+
function getYamlValue(value, key) {
65+
if (StringPrototypeStartsWith(value, "'") && StringPrototypeEndsWith(value, "'")) {
66+
return StringPrototypeSlice(value, 1, -1);
67+
}
68+
if (value === 'true') {
69+
return true;
70+
}
71+
if (value === 'false') {
72+
return false;
73+
}
74+
if (value && !NumberIsNaN(value)) {
75+
return Number(value);
76+
}
77+
return value;
78+
}
79+
80+
function parseYAML(lines) {
81+
const result = {};
82+
let isInYamlBlock = false;
83+
for (const line of lines) {
84+
if (isInYamlBlock && !StringPrototypeStartsWith(line, StringPrototypeRepeat(' ', isInYamlBlock.indent))) {
85+
result[isInYamlBlock.key] = isInYamlBlock.key === 'stack' ?
86+
result[isInYamlBlock.key] : ArrayPrototypeJoin(result[isInYamlBlock.key], '\n');
87+
isInYamlBlock = false;
88+
}
89+
if (isInYamlBlock) {
90+
const blockLine = StringPrototypeSubstring(line, isInYamlBlock.indent);
91+
result[isInYamlBlock.key].push(blockLine);
92+
continue;
93+
}
94+
const match = RegExpPrototypeExec(kYamlKeyRegex, line);
95+
if (match !== null) {
96+
const { 1: leadingSpaces, 2: key, 4: block, 5: value } = match;
97+
if (block) {
98+
isInYamlBlock = { key, indent: (leadingSpaces?.length ?? 0) + 2 };
99+
result[key] = [];
100+
} else {
101+
result[key] = getYamlValue(value, key);
102+
}
103+
}
104+
}
105+
return reConstructError(result);
106+
}
107+
108+
module.exports = {
109+
parseYAML,
110+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Flags: --no-warnings
2+
'use strict';
3+
require('../common');
4+
const spawn = require('node:child_process').spawn;
5+
spawn(process.execPath,
6+
['--no-warnings', '--test', 'test/message/test_runner_output.js'], { stdio: 'inherit' });

0 commit comments

Comments
 (0)