forked from nodejs/node
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathspec.js
More file actions
107 lines (98 loc) · 3.48 KB
/
spec.js
File metadata and controls
107 lines (98 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
'use strict';
const {
ArrayPrototypeJoin,
ArrayPrototypePop,
ArrayPrototypeShift,
ArrayPrototypeUnshift,
hardenRegExp,
RegExpPrototypeSymbolSplit,
SafeMap,
StringPrototypeRepeat,
} = primordials;
const assert = require('assert');
const Transform = require('internal/streams/transform');
const { inspectWithNoCustomRetry } = require('internal/errors');
const { green, blue, red, white, gray } = require('internal/util/colors');
const inspectOptions = { __proto__: null, colors: true, breakLength: Infinity };
const colors = {
'__proto__': null,
'test:fail': red,
'test:pass': green,
'test:diagnostic': blue,
};
const symbols = {
'__proto__': null,
'test:fail': '\u2716 ',
'test:pass': '\u2714 ',
'test:diagnostic': '\u2139 ',
'arrow:right': '\u25B6 ',
};
class SpecReporter extends Transform {
#stack = [];
#reported = [];
#indentMemo = new SafeMap();
constructor() {
super({ writableObjectMode: true });
}
#indent(nesting) {
let value = this.#indentMemo.get(nesting);
if (value === undefined) {
value = StringPrototypeRepeat(' ', nesting);
this.#indentMemo.set(nesting, value);
}
return value;
}
#formatError(error, indent) {
if (!error) return '';
const err = error.code === 'ERR_TEST_FAILURE' ? error.cause : error;
const message = ArrayPrototypeJoin(
RegExpPrototypeSymbolSplit(
hardenRegExp(/\r?\n/),
inspectWithNoCustomRetry(err, inspectOptions),
), `\n${indent} `);
return `\n${indent} ${message}\n`;
}
#handleEvent({ type, data }) {
const color = colors[type] ?? white;
const symbol = symbols[type] ?? ' ';
switch (type) {
case 'test:fail':
case 'test:pass': {
const subtest = ArrayPrototypeShift(this.#stack); // This is the matching `test:start` event
if (subtest) {
assert(subtest.type === 'test:start');
assert(subtest.data.nesting === data.nesting);
assert(subtest.data.name === data.name);
}
let prefix = '';
while (this.#stack.length) {
// Report all the parent `test:start` events
const parent = ArrayPrototypePop(this.#stack);
assert(parent.type === 'test:start');
const msg = parent.data;
ArrayPrototypeUnshift(this.#reported, msg);
prefix += `${this.#indent(msg.nesting)}${symbols['arrow:right']}${msg.name}\n`;
}
const indent = this.#indent(data.nesting);
const duration_ms = data.details?.duration_ms ? ` ${gray}(${data.details.duration_ms}ms)${white}` : '';
const title = `${data.name}${duration_ms}`;
if (this.#reported[0] && this.#reported[0].nesting === data.nesting && this.#reported[0].name === data.name) {
// If this test has had children - it was already reporter, so slightly modify the output
ArrayPrototypeShift(this.#reported);
return `${prefix}${indent}${color}${symbols['arrow:right']}${white}${title}\n\n`;
}
const error = this.#formatError(data.details?.error, indent);
return `${prefix}${indent}${color}${symbol}${title}${error}${white}\n`;
}
case 'test:start':
ArrayPrototypeUnshift(this.#stack, { __proto__: null, data, type });
break;
case 'test:diagnostic':
return `${color}${this.#indent(data.nesting)}${symbol}${data.message}${white}\n`;
}
}
_transform({ type, data }, encoding, callback) {
callback(null, this.#handleEvent({ type, data }));
}
}
module.exports = SpecReporter;