risei 2.0.1 → 3.1.0
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/README.md +50 -28
- package/index.js +18 -66
- package/package.json +7 -6
- package/system/CallTypes.js +10 -0
- package/system/Choices.js +92 -0
- package/system/ClassTestGroup.js +8 -8
- package/system/LocalCaller.js +47 -7
- package/system/MethodSpoofer.js +2 -2
- package/system/MethodTestGroup.js +8 -8
- package/system/Moment.js +29 -29
- package/system/NameAnalyzer.js +26 -26
- package/system/ObjectAnalyzer.js +36 -0
- package/system/PropertySpoofer.js +1 -1
- package/system/SpoofDef.js +73 -63
- package/system/TerminalReporter.js +102 -25
- package/system/TestDef.js +75 -17
- package/system/TestFinder.js +31 -29
- package/system/TestFrame.js +21 -12
- package/system/TestGroup.js +25 -25
- package/system/TestResult.js +63 -13
- package/system/TestRunner.js +44 -16
- package/system/TestStages.js +85 -26
- package/system/TestSummary.js +38 -37
- package/system/TotalComparer.js +54 -17
- package/system/TotalDisplayer.js +29 -6
- package/system/TypeAnalyzer.js +117 -26
- package/system/TypeIdentifier.js +10 -6
- package/system/Types.js +1 -0
- package/system/ATestCaller.js +0 -61
- package/system/ATestFinder.js +0 -38
- package/system/ATestReporter.js +0 -26
- package/system/ChosenTestFinder.js +0 -31
- package/system/Risei.js +0 -118
package/system/NameAnalyzer.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
/**/
|
|
2
|
-
|
|
3
|
-
export default class NameAnalyzer {
|
|
4
|
-
// region Definitions
|
|
5
|
-
|
|
6
|
-
static dotOperator = ".";
|
|
7
|
-
static colonOperator = ":";
|
|
8
|
-
static parensOperator = "()";
|
|
9
|
-
static operatorsRegExp = /\.|:|\(\)/g;
|
|
10
|
-
|
|
11
|
-
// endregion Definitions
|
|
12
|
-
|
|
13
|
-
static hasPropertySigil(name) /* passed */ {
|
|
14
|
-
return name.startsWith(NameAnalyzer.dotOperator) || name.endsWith(NameAnalyzer.colonOperator);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
static hasMethodSigil(name) /* passed */ {
|
|
18
|
-
return name.endsWith(NameAnalyzer.parensOperator);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
static plainNameOf(name) /* passed */ {
|
|
22
|
-
let plain = name.replaceAll(NameAnalyzer.operatorsRegExp, "");
|
|
23
|
-
return plain;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
1
|
+
/**/
|
|
2
|
+
|
|
3
|
+
export default class NameAnalyzer {
|
|
4
|
+
// region Definitions
|
|
5
|
+
|
|
6
|
+
static dotOperator = ".";
|
|
7
|
+
static colonOperator = ":";
|
|
8
|
+
static parensOperator = "()";
|
|
9
|
+
static operatorsRegExp = /\.|:|\(\)/g;
|
|
10
|
+
|
|
11
|
+
// endregion Definitions
|
|
12
|
+
|
|
13
|
+
static hasPropertySigil(name) /* passed */ {
|
|
14
|
+
return name.startsWith(NameAnalyzer.dotOperator) || name.endsWith(NameAnalyzer.colonOperator);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static hasMethodSigil(name) /* passed */ {
|
|
18
|
+
return name.endsWith(NameAnalyzer.parensOperator);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static plainNameOf(name) /* passed */ {
|
|
22
|
+
let plain = name.replaceAll(NameAnalyzer.operatorsRegExp, "");
|
|
23
|
+
return plain;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**/
|
|
2
|
+
|
|
3
|
+
import TypeAnalyzer from "./TypeAnalyzer.js";
|
|
4
|
+
|
|
5
|
+
export default class ObjectAnalyzer {
|
|
6
|
+
/* Retrieves names of all properties, both values
|
|
7
|
+
and accessors, including all in superclasses. */
|
|
8
|
+
static allProperties(topic) /* passed */ {
|
|
9
|
+
let proto = Object.getPrototypeOf(topic);
|
|
10
|
+
|
|
11
|
+
let getters = [];
|
|
12
|
+
|
|
13
|
+
// Accessors, including in superclasses.
|
|
14
|
+
// Nonce object has no prototype / type.
|
|
15
|
+
if (proto !== null) {
|
|
16
|
+
let type = proto.constructor;
|
|
17
|
+
getters = TypeAnalyzer.allGetters(type);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let names = [];
|
|
21
|
+
|
|
22
|
+
// All value names, including inherited ones.
|
|
23
|
+
for (let name in topic) {
|
|
24
|
+
names.push(name);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Concat good enough since sorting needed after anyway.
|
|
28
|
+
let output = names.concat(getters);
|
|
29
|
+
|
|
30
|
+
// Instead of mixed two sets in order coded,
|
|
31
|
+
// accessors backwards up prototype chain.
|
|
32
|
+
output.sort();
|
|
33
|
+
|
|
34
|
+
return output;
|
|
35
|
+
}
|
|
36
|
+
}
|
package/system/SpoofDef.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import TypeAnalyzer from "./TypeAnalyzer.js";
|
|
4
4
|
import NameAnalyzer from "./NameAnalyzer.js";
|
|
5
|
+
import TotalDisplayer from "./TotalDisplayer.js";
|
|
5
6
|
|
|
6
7
|
/* Defines what is found in a spoof definition, typically as
|
|
7
8
|
a nonce object rather than an instance of this class. */
|
|
@@ -20,11 +21,6 @@ export default class SpoofDef {
|
|
|
20
21
|
SpoofDef.#asNames
|
|
21
22
|
]);
|
|
22
23
|
|
|
23
|
-
/* &cruft, remove these after spoofing in .with and .in is removed */
|
|
24
|
-
/* Objects with either of these property names aren't
|
|
25
|
-
converted to spoofDefs by from-nonce methods. */
|
|
26
|
-
static skipNames = [ "not", "skip" ];
|
|
27
|
-
|
|
28
24
|
// endregion Static fields
|
|
29
25
|
|
|
30
26
|
// region Public fields (long names)
|
|
@@ -135,14 +131,14 @@ export default class SpoofDef {
|
|
|
135
131
|
|
|
136
132
|
// region Initing, including constructor() and statics
|
|
137
133
|
|
|
138
|
-
/*
|
|
139
|
-
|
|
134
|
+
/* Long names used, just in case. */
|
|
140
135
|
constructor(target, method, output) /* passed */ {
|
|
141
136
|
this.target = target;
|
|
142
137
|
this.method = method;
|
|
143
138
|
this.output = output;
|
|
144
139
|
}
|
|
145
140
|
|
|
141
|
+
/* Arg 'type' should be test.type if present. */
|
|
146
142
|
static fromNonceTuples(nonces, type) /* passed */ {
|
|
147
143
|
// Throughput and output.
|
|
148
144
|
let full = new SpoofDef();
|
|
@@ -159,82 +155,102 @@ export default class SpoofDef {
|
|
|
159
155
|
return output;
|
|
160
156
|
}
|
|
161
157
|
|
|
158
|
+
/* Arg 'type' should be test.type if present. */
|
|
162
159
|
static fromNonceTuple(nonce, type) /* passed */ {
|
|
163
|
-
|
|
160
|
+
// No spoof-def to output.
|
|
164
161
|
if (SpoofDef.isNotASpoof(nonce)) {
|
|
165
162
|
return [ ];
|
|
166
163
|
}
|
|
167
164
|
|
|
168
|
-
|
|
169
|
-
|
|
165
|
+
let defs = [ ];
|
|
166
|
+
|
|
167
|
+
// Nonce defines one spoof.
|
|
168
|
+
if (SpoofDef.#isMonoSpoof(nonce)) {
|
|
169
|
+
let def = SpoofDef.#fromMonoNonce(nonce, type);
|
|
170
|
+
defs.push(def);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Nonce defines more than one spoof: Recursion.
|
|
174
|
+
if (SpoofDef.#isPolySpoof(nonce)) {
|
|
175
|
+
let locals = SpoofDef.#fromPolyNonce(nonce, type);
|
|
176
|
+
defs.push(...locals);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return defs;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// region Dependencies of nonce-tuple initing methods
|
|
183
|
+
|
|
184
|
+
static #isMonoSpoof(nonce) /* verified */ {
|
|
185
|
+
return SpoofDef.#hasEitherName(nonce, SpoofDef.#ofNames);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
static #isPolySpoof(nonce) /* verified */ {
|
|
189
|
+
return !SpoofDef.#isMonoSpoof(nonce);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* Arg 'type' should be test.type if present. */
|
|
193
|
+
static #fromMonoNonce(nonce, type) /* verified */ {
|
|
194
|
+
// Empty, since each prop can
|
|
195
|
+
// have either of two names.
|
|
170
196
|
let def = new SpoofDef();
|
|
171
197
|
|
|
172
198
|
let shortNames = SpoofDef.#longsByShort.keys();
|
|
173
199
|
|
|
174
|
-
|
|
175
|
-
recurse internally using it without inner arrays, for a cleaner algorithm */
|
|
176
|
-
|
|
177
|
-
// Traversing matching pairs of names and applying
|
|
178
|
-
// whichever one is present as the tuple property;
|
|
200
|
+
// Traversing name pairs to use whichever one is present;
|
|
179
201
|
// if neither is present, the property is undefined.
|
|
180
202
|
for (let shortName of shortNames) {
|
|
181
203
|
let longName = SpoofDef.#longsByShort.get(shortName);
|
|
182
|
-
|
|
204
|
+
|
|
205
|
+
def[shortName]
|
|
206
|
+
= nonce[shortName] !== undefined
|
|
207
|
+
? nonce[shortName]
|
|
208
|
+
: nonce[longName];
|
|
183
209
|
}
|
|
184
210
|
|
|
185
|
-
//
|
|
186
|
-
|
|
187
|
-
|
|
211
|
+
// Adding test target's type, if no type provided.
|
|
212
|
+
if (def.target === undefined) {
|
|
213
|
+
def.target = type;
|
|
214
|
+
}
|
|
188
215
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
let locals = [ ];
|
|
216
|
+
return def;
|
|
217
|
+
}
|
|
192
218
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
219
|
+
/* Arg 'type' should be test.type if present. */
|
|
220
|
+
static #fromPolyNonce(nonce, type) /* verified */ {
|
|
221
|
+
let defs = [ ];
|
|
196
222
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
223
|
+
// Poly-nonce's .on applies to all its partial spoofs.
|
|
224
|
+
let on = nonce.on !== undefined ? nonce.on : nonce.target;
|
|
200
225
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
defs = locals;
|
|
204
|
-
}
|
|
226
|
+
// Poly-nonce's .as is an array of partial-spoof nonces.
|
|
227
|
+
let pairs = nonce.as !== undefined ? nonce.as : nonce.output;
|
|
205
228
|
|
|
206
|
-
//
|
|
207
|
-
|
|
229
|
+
// Traversing partial-spoof nonces (.of and .as only).
|
|
230
|
+
for (let pair of pairs) {
|
|
231
|
+
// Either name (or neither) may exist on nonce partial.
|
|
232
|
+
let of = pair.of !== undefined ? pair.of : pair.method;
|
|
233
|
+
let as = pair.as !== undefined ? pair.as : pair.output;
|
|
234
|
+
|
|
235
|
+
// Only one level of recursion.
|
|
236
|
+
let passer = SpoofDef.#fromMonoNonce({ on, of, as }, type);
|
|
237
|
+
|
|
238
|
+
defs.push(passer);
|
|
239
|
+
}
|
|
208
240
|
|
|
209
|
-
// Back to caller.
|
|
210
241
|
return defs;
|
|
211
242
|
}
|
|
212
243
|
|
|
213
|
-
// region Dependencies of nonce-tuple initing methods
|
|
214
|
-
|
|
215
244
|
static #hasEitherName(nonce, names) /* verified */ {
|
|
216
245
|
let hasEither = false;
|
|
217
246
|
|
|
218
247
|
for (let name of names) {
|
|
219
|
-
hasEither ||=
|
|
248
|
+
hasEither ||= nonce[name] !== undefined;
|
|
220
249
|
}
|
|
221
250
|
|
|
222
251
|
return hasEither;
|
|
223
252
|
}
|
|
224
253
|
|
|
225
|
-
static #hasName(nonce, name) /* verified */ {
|
|
226
|
-
return nonce[name] !== undefined;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
static #setAnyMissingTypes(defs, type) /* verified */ {
|
|
230
|
-
// Adding test target's type, if no type provided.
|
|
231
|
-
for (let def of defs) {
|
|
232
|
-
if (def.target === undefined) {
|
|
233
|
-
def.target = type;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
254
|
// endregion Dependencies of nonce-tuple initing methods
|
|
239
255
|
|
|
240
256
|
// endregion Initing, including constructor() and statics
|
|
@@ -242,19 +258,13 @@ export default class SpoofDef {
|
|
|
242
258
|
// region Overrides and dependencies
|
|
243
259
|
|
|
244
260
|
toString() /* passed */ {
|
|
245
|
-
let
|
|
246
|
-
|
|
247
|
-
|
|
261
|
+
let displayer = new TotalDisplayer();
|
|
262
|
+
|
|
263
|
+
let text = `SpoofDef{ on:${ displayer.display(this.target) }, `
|
|
264
|
+
+ `of:${ displayer.display(this.method) }, `
|
|
265
|
+
+ `as:${ displayer.display(this.output) } }`;
|
|
248
266
|
return text;
|
|
249
267
|
}
|
|
250
|
-
|
|
251
|
-
#asRawOrString(value) /* verified */ {
|
|
252
|
-
if (typeof value === "string") {
|
|
253
|
-
return `"${ value }"`;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
return value;
|
|
257
|
-
}
|
|
258
|
-
|
|
268
|
+
|
|
259
269
|
// endregion Overrides and dependencies
|
|
260
270
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**/
|
|
2
2
|
|
|
3
|
-
/* TerminalReporter
|
|
3
|
+
/* TerminalReporter displays each test result in the terminal / console window. */
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import Moment from "./Moment.js";
|
|
6
6
|
import TestGroup from "./TestGroup.js";
|
|
7
7
|
import ClassTestGroup from "./ClassTestGroup.js";
|
|
8
8
|
import MethodTestGroup from "./MethodTestGroup.js";
|
|
@@ -11,8 +11,12 @@ import TestSummary from "./TestSummary.js";
|
|
|
11
11
|
|
|
12
12
|
import chalk from "chalk";
|
|
13
13
|
|
|
14
|
-
export default class TerminalReporter
|
|
15
|
-
// region
|
|
14
|
+
export default class TerminalReporter {
|
|
15
|
+
// region Fields
|
|
16
|
+
|
|
17
|
+
/* Display styles for the start title and other general needs. */
|
|
18
|
+
#title = chalk.hex("FFFFFF").bgHex("191970").bold;
|
|
19
|
+
#fails = chalk.hex("000000").bgHex("FFD700").bold;
|
|
16
20
|
|
|
17
21
|
/* Foreground-colors using dependency calls and hex. */
|
|
18
22
|
#trueWhite = chalk.hex("FFFFFF");
|
|
@@ -31,22 +35,53 @@ export default class TerminalReporter extends ATestReporter {
|
|
|
31
35
|
#methodGroup = this.#trueWhite.bgHex(this.#aqua).bold;
|
|
32
36
|
#passed = this.#trueBlack.bgHex(this.#paleGreen);
|
|
33
37
|
#failed = this.#trueBlack.bgHex(this.#paleRed);
|
|
38
|
+
#problems = chalk.hex("000000").bgHex("FFD700").bold;
|
|
39
|
+
|
|
34
40
|
#passedSummary = this.#trueBlack.bgHex(this.#paleGreen).bold;
|
|
35
41
|
#failedSummary = this.#trueBlack.bgHex(this.#paleRed).bold;
|
|
36
42
|
#summary = chalk.hex("000080").bgHex("FAFAD2").bold;
|
|
37
43
|
|
|
44
|
+
|
|
38
45
|
// Count of characters used for indent
|
|
39
46
|
// and text to the left of each test.
|
|
40
47
|
#preUsedWidth = 20;
|
|
41
48
|
|
|
42
|
-
// endregion
|
|
49
|
+
// endregion Fields
|
|
50
|
+
|
|
51
|
+
reportTitle() {
|
|
52
|
+
// This moment, ready for use in title.
|
|
53
|
+
let now = new Date();
|
|
54
|
+
now = new Moment(now);
|
|
55
|
+
|
|
56
|
+
// Top of screen and leading color stripe.
|
|
57
|
+
console.clear();
|
|
58
|
+
console.log();
|
|
59
|
+
console.log(this.#title(this.#wide()));
|
|
60
|
+
|
|
61
|
+
// Actually reporting title.
|
|
62
|
+
console.log(this.#title(this.#wide(` Risei tests run on ${ now.asReadable() } local time.`)));
|
|
63
|
+
|
|
64
|
+
// Trailing color stripe and blank line.
|
|
65
|
+
console.log(this.#title(this.#wide()));
|
|
66
|
+
console.log();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// region Dependencies of reportTitle()
|
|
70
|
+
|
|
71
|
+
/* Styling for color stripes. */
|
|
72
|
+
#wide(text) {
|
|
73
|
+
let width = process.stdout.columns;
|
|
74
|
+
text = text || "";
|
|
75
|
+
|
|
76
|
+
return text.padEnd(width, "\u00A0");
|
|
77
|
+
};
|
|
43
78
|
|
|
44
|
-
//
|
|
79
|
+
// endregion Dependencies of reportTitle()
|
|
45
80
|
|
|
46
81
|
reportNext(result) {
|
|
47
82
|
// The next result introduces a group of tests.
|
|
48
83
|
if (result instanceof TestGroup) {
|
|
49
|
-
this
|
|
84
|
+
this.#reportGroup(result);
|
|
50
85
|
return;
|
|
51
86
|
}
|
|
52
87
|
|
|
@@ -58,12 +93,14 @@ export default class TerminalReporter extends ATestReporter {
|
|
|
58
93
|
|
|
59
94
|
// The next result is the summary of all tests.
|
|
60
95
|
if (result instanceof TestSummary) {
|
|
61
|
-
this
|
|
96
|
+
this.#reportSummary(result);
|
|
62
97
|
return;
|
|
63
98
|
}
|
|
64
99
|
}
|
|
65
100
|
|
|
66
|
-
|
|
101
|
+
// region Direct dependencies of reportNext(), except summary
|
|
102
|
+
|
|
103
|
+
#reportGroup(result) {
|
|
67
104
|
if (result instanceof ClassTestGroup) {
|
|
68
105
|
console.log(this.#classGroup(` ${ result.group }: `));
|
|
69
106
|
}
|
|
@@ -73,32 +110,44 @@ export default class TerminalReporter extends ATestReporter {
|
|
|
73
110
|
}
|
|
74
111
|
}
|
|
75
112
|
|
|
76
|
-
// region Private dependencies of reportNext()
|
|
77
|
-
|
|
78
113
|
#reportTestResult(result) {
|
|
114
|
+
if (result.doesHaveThrow) {
|
|
115
|
+
this.#reportThrew(result.anyThrow.stack);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (result.doesHaveTrouble) {
|
|
119
|
+
this.#reportThrew(result.anyTrouble.stack);
|
|
120
|
+
}
|
|
121
|
+
|
|
79
122
|
if (result.didPass) {
|
|
80
|
-
this
|
|
123
|
+
this.#reportPassed(result);
|
|
81
124
|
}
|
|
82
125
|
|
|
83
126
|
if (!result.didPass) {
|
|
84
|
-
this
|
|
127
|
+
this.#reportFailed(result);
|
|
85
128
|
}
|
|
86
129
|
}
|
|
87
130
|
|
|
88
|
-
// endregion
|
|
131
|
+
// endregion Direct dependencies of reportNext(), except summary
|
|
132
|
+
|
|
133
|
+
// region Direct dependencies of #reportTestResult()
|
|
134
|
+
|
|
135
|
+
#reportThrew(threw) {
|
|
136
|
+
console.log(this.#problems(threw));
|
|
137
|
+
}
|
|
89
138
|
|
|
90
|
-
reportPassed(result) {
|
|
139
|
+
#reportPassed(result) {
|
|
91
140
|
this.#reportOneTestResult(result, "Passed", this.#passed);
|
|
92
141
|
}
|
|
93
142
|
|
|
94
|
-
reportFailed(result) {
|
|
143
|
+
#reportFailed(result) {
|
|
95
144
|
this.#reportOneTestResult(result, "Failed", this.#failed);
|
|
96
145
|
}
|
|
97
146
|
|
|
98
|
-
//
|
|
147
|
+
// endregion Direct dependencies of #reportTestResult()
|
|
148
|
+
|
|
149
|
+
// region Dependencies of #reportPassed() and #reportFailed()
|
|
99
150
|
|
|
100
|
-
/* &cruft, changes here / in dependencies
|
|
101
|
-
for better splitting to multiple lines */
|
|
102
151
|
#reportOneTestResult(result, net, styler) {
|
|
103
152
|
let { lineOne, lineTwo, lineThree, lineFour } = this.#calculateResultDisplay(result);
|
|
104
153
|
|
|
@@ -166,7 +215,7 @@ export default class TerminalReporter extends ATestReporter {
|
|
|
166
215
|
return this.#oneLineTactic(identityText, inputsText, expectedText, actualText);
|
|
167
216
|
}
|
|
168
217
|
|
|
169
|
-
// region
|
|
218
|
+
// region Dependencies of #calculateResultDisplay()
|
|
170
219
|
|
|
171
220
|
#fourLineTactic(identityText, inputsText, expectedText, actualText) {
|
|
172
221
|
// Each line on its own.
|
|
@@ -218,13 +267,17 @@ export default class TerminalReporter extends ATestReporter {
|
|
|
218
267
|
return { lineOne, lineTwo, lineThree, lineFour };
|
|
219
268
|
}
|
|
220
269
|
|
|
221
|
-
// endregion
|
|
270
|
+
// endregion Dependencies of #calculateResultDisplay()
|
|
271
|
+
|
|
272
|
+
// endregion Dependencies of #reportPassed() and #reportFailed()
|
|
222
273
|
|
|
223
|
-
//
|
|
274
|
+
// region Summary dependency of reportNext()
|
|
224
275
|
|
|
225
|
-
reportSummary(summary) {
|
|
276
|
+
#reportSummary(summary) {
|
|
226
277
|
console.log();
|
|
227
278
|
|
|
279
|
+
/* Actual summary. */
|
|
280
|
+
|
|
228
281
|
if (summary.anyWereRun) {
|
|
229
282
|
if (summary.allDidPass) {
|
|
230
283
|
console.log(this.#passedSummary(this.#toFullWidth(" Test run succeeded.")));
|
|
@@ -235,7 +288,24 @@ export default class TerminalReporter extends ATestReporter {
|
|
|
235
288
|
}
|
|
236
289
|
|
|
237
290
|
console.log(this.#summary(this.#toFullWidth(` ${ summary.summary }`)));
|
|
238
|
-
|
|
291
|
+
|
|
292
|
+
/* Post-summary reporting of unsought throws. */
|
|
293
|
+
|
|
294
|
+
if (summary.anyThrows.length !== 0) {
|
|
295
|
+
console.log();
|
|
296
|
+
console.log(this.#problems(summary.anyThrows.join("\n")));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// And/or reporting of outer-scope throws.
|
|
300
|
+
if (summary.anyTroubles.length !== 0) {
|
|
301
|
+
console.log();
|
|
302
|
+
console.log(this.#problems(summary.anyTroubles.join("\n")));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// endregion Summary dependency of reportNext()
|
|
307
|
+
|
|
308
|
+
// region Dependencies of #reportSummary()
|
|
239
309
|
|
|
240
310
|
#toFullWidth(text) {
|
|
241
311
|
text = text || "";
|
|
@@ -244,6 +314,13 @@ export default class TerminalReporter extends ATestReporter {
|
|
|
244
314
|
return text.padEnd(width, "\u00A0");
|
|
245
315
|
}
|
|
246
316
|
|
|
247
|
-
// endregion
|
|
317
|
+
// endregion Dependencies of #reportSummary()
|
|
248
318
|
|
|
319
|
+
blankLine() {
|
|
320
|
+
console.log();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
reportLoadFail(fail) {
|
|
324
|
+
console.log(this.#fails(this.#wide(` ${ fail }`)));
|
|
325
|
+
}
|
|
249
326
|
}
|