@reporters/mocha 1.2.0 → 2.0.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/index.js +153 -66
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
/* eslint-disable class-methods-use-this */
|
|
2
2
|
/* eslint-disable no-underscore-dangle */
|
|
3
|
-
/* eslint-disable max-classes-per-file */
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const Mocha = require('mocha');
|
|
9
|
-
const { loadOptions } = require('mocha/lib/cli');
|
|
4
|
+
import { EventEmitter } from 'node:events';
|
|
5
|
+
import Mocha from 'mocha';
|
|
6
|
+
import { loadOptions } from 'mocha/lib/cli/options.js';
|
|
10
7
|
|
|
11
8
|
const {
|
|
12
9
|
EVENT_RUN_BEGIN,
|
|
@@ -39,6 +36,8 @@ class Test {
|
|
|
39
36
|
this.parent = parent;
|
|
40
37
|
this.root = !parent;
|
|
41
38
|
this.children = [];
|
|
39
|
+
this.kind = 'test';
|
|
40
|
+
this.started = false;
|
|
42
41
|
this.#mochaOptions = mochaOptions;
|
|
43
42
|
|
|
44
43
|
this.body = '';
|
|
@@ -48,15 +47,19 @@ class Test {
|
|
|
48
47
|
this._afterEach = [];
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
applyStartEvent(event) {
|
|
52
51
|
this.title = event.data.name;
|
|
53
52
|
this.file = event.data.file;
|
|
53
|
+
this.nesting = event.data.nesting;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
applyTestEvent(event, passed) {
|
|
57
|
+
this.applyStartEvent(event);
|
|
54
58
|
this.pending = Boolean(event.data.skip || event.data.todo);
|
|
55
59
|
this.duration = event.data.details?.duration_ms;
|
|
56
60
|
const error = event.data.details?.error;
|
|
57
61
|
this.err = error?.cause instanceof Error ? error.cause : error;
|
|
58
62
|
this.passed = passed;
|
|
59
|
-
this.nesting = event.data.nesting;
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
get state() {
|
|
@@ -90,17 +93,25 @@ class Test {
|
|
|
90
93
|
return this.titlePath().join(' ');
|
|
91
94
|
}
|
|
92
95
|
|
|
93
|
-
|
|
94
|
-
this.
|
|
95
|
-
|
|
96
|
+
markSuite() {
|
|
97
|
+
this.kind = 'suite';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
beginSuite() {
|
|
101
|
+
this.markSuite();
|
|
102
|
+
this.started = true;
|
|
96
103
|
}
|
|
97
104
|
|
|
98
|
-
get
|
|
99
|
-
return this.
|
|
105
|
+
get isSuite() {
|
|
106
|
+
return this.kind === 'suite';
|
|
100
107
|
}
|
|
101
108
|
|
|
102
|
-
get
|
|
103
|
-
return this.children.filter((child) => child.
|
|
109
|
+
get suites() {
|
|
110
|
+
return this.children.filter((child) => child.isSuite);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get tests() {
|
|
114
|
+
return this.children.filter((child) => !child.isSuite);
|
|
104
115
|
}
|
|
105
116
|
}
|
|
106
117
|
|
|
@@ -118,11 +129,16 @@ class Runner extends EventEmitter {
|
|
|
118
129
|
|
|
119
130
|
#reporter;
|
|
120
131
|
|
|
121
|
-
#
|
|
132
|
+
#mochaOptions = loadOptions([]);
|
|
133
|
+
|
|
134
|
+
#root = new Test(null, this.#mochaOptions);
|
|
122
135
|
|
|
123
|
-
#
|
|
136
|
+
#activeNodes = [];
|
|
124
137
|
|
|
125
|
-
|
|
138
|
+
constructor() {
|
|
139
|
+
super();
|
|
140
|
+
this.#root.markSuite();
|
|
141
|
+
}
|
|
126
142
|
|
|
127
143
|
async init() {
|
|
128
144
|
const reporterName = this.#mochaOptions.reporter ?? 'spec';
|
|
@@ -135,10 +151,12 @@ class Runner extends EventEmitter {
|
|
|
135
151
|
try {
|
|
136
152
|
Reporter = await import(reporterName).then((m) => m.default || m);
|
|
137
153
|
} catch (err) {
|
|
154
|
+
// eslint-disable-next-line no-console
|
|
138
155
|
console.error(err);
|
|
139
156
|
}
|
|
140
157
|
}
|
|
141
158
|
if (!Reporter) {
|
|
159
|
+
// eslint-disable-next-line no-console
|
|
142
160
|
console.error(new Error(`invalid reporter "${reporterName}"`));
|
|
143
161
|
return;
|
|
144
162
|
}
|
|
@@ -147,90 +165,159 @@ class Runner extends EventEmitter {
|
|
|
147
165
|
}
|
|
148
166
|
|
|
149
167
|
get suite() {
|
|
150
|
-
return this.#
|
|
168
|
+
return this.#root;
|
|
151
169
|
}
|
|
152
170
|
|
|
153
171
|
end() {
|
|
154
172
|
if (!this.#reporter) {
|
|
155
173
|
return;
|
|
156
174
|
}
|
|
175
|
+
this.#closeActiveSuites();
|
|
157
176
|
this.stats.end = new Date();
|
|
158
177
|
this.stats.duration = this.stats.end - this.stats.start;
|
|
159
|
-
this.#
|
|
178
|
+
this.#startRootSuite();
|
|
179
|
+
this.emit(EVENT_SUITE_END, this.#root);
|
|
160
180
|
this.emit(EVENT_RUN_END);
|
|
161
181
|
if (typeof this.#reporter.done === 'function') {
|
|
162
182
|
this.#reporter.done(this.stats.failures, () => {});
|
|
163
183
|
}
|
|
164
184
|
}
|
|
165
185
|
|
|
166
|
-
#
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
186
|
+
#startRootSuite() {
|
|
187
|
+
if (this.#root.started) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
this.#root.beginSuite();
|
|
191
|
+
this.emit(EVENT_SUITE_BEGIN, this.#root);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
#findParent(nesting) {
|
|
195
|
+
if (nesting === 0) {
|
|
196
|
+
return this.#root;
|
|
197
|
+
}
|
|
198
|
+
return this.#activeNodes[nesting - 1] ?? this.#root;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
#matchesNode(node, event) {
|
|
202
|
+
return node
|
|
203
|
+
&& node.nesting === event.data.nesting
|
|
204
|
+
&& node.title === event.data.name;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
#ensureNode(event) {
|
|
208
|
+
const { nesting } = event.data;
|
|
209
|
+
const existingNode = this.#activeNodes[nesting];
|
|
210
|
+
if (this.#matchesNode(existingNode, event)) {
|
|
211
|
+
return existingNode;
|
|
173
212
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
213
|
+
|
|
214
|
+
const parent = this.#findParent(nesting);
|
|
215
|
+
const node = new Test(parent, this.#mochaOptions);
|
|
216
|
+
node.applyStartEvent(event);
|
|
217
|
+
parent.children.push(node);
|
|
218
|
+
this.#activeNodes[nesting] = node;
|
|
219
|
+
this.#activeNodes.length = nesting + 1;
|
|
220
|
+
return node;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
#openSuite(node) {
|
|
224
|
+
if (node.started) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
node.beginSuite();
|
|
228
|
+
this.emit(EVENT_SUITE_BEGIN, node);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
#ensureOpenAncestors(nesting) {
|
|
232
|
+
for (let i = 0; i < nesting; i += 1) {
|
|
233
|
+
const node = this.#activeNodes[i];
|
|
234
|
+
if (node) {
|
|
235
|
+
this.#openSuite(node);
|
|
182
236
|
}
|
|
183
|
-
this.emit(EVENT_TEST_END, test);
|
|
184
237
|
}
|
|
185
|
-
this.emit(EVENT_SUITE_END, suite);
|
|
186
238
|
}
|
|
187
239
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
240
|
+
#trimActiveNodes() {
|
|
241
|
+
while (
|
|
242
|
+
this.#activeNodes.length > 0
|
|
243
|
+
&& this.#activeNodes[this.#activeNodes.length - 1] === undefined
|
|
244
|
+
) {
|
|
245
|
+
this.#activeNodes.pop();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
#reportTest(node) {
|
|
250
|
+
this.stats.tests += 1;
|
|
251
|
+
this.emit(EVENT_TEST_BEGIN, node);
|
|
252
|
+
if (node.pending) {
|
|
253
|
+
this.stats.pending += 1;
|
|
254
|
+
this.emit(EVENT_TEST_PENDING, node);
|
|
255
|
+
} else if (!node.passed) {
|
|
256
|
+
this.stats.failures += 1;
|
|
257
|
+
this.emit(EVENT_TEST_FAIL, node, node.err);
|
|
258
|
+
} else {
|
|
259
|
+
this.stats.passes += 1;
|
|
260
|
+
this.emit(EVENT_TEST_PASS, node);
|
|
261
|
+
}
|
|
262
|
+
this.emit(EVENT_TEST_END, node);
|
|
193
263
|
}
|
|
194
264
|
|
|
195
|
-
|
|
196
|
-
|
|
265
|
+
#closeSuite(node) {
|
|
266
|
+
this.stats.suites += 1;
|
|
267
|
+
this.#openSuite(node);
|
|
268
|
+
this.emit(EVENT_SUITE_END, node);
|
|
197
269
|
}
|
|
198
270
|
|
|
199
|
-
|
|
200
|
-
this.#
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
271
|
+
#completeNode(event, passed) {
|
|
272
|
+
const node = this.#ensureNode(event);
|
|
273
|
+
this.#ensureOpenAncestors(event.data.nesting);
|
|
274
|
+
node.applyTestEvent(event, passed);
|
|
275
|
+
|
|
276
|
+
if (event.data.details?.type === 'suite' || node.children.length > 0) {
|
|
277
|
+
this.#closeSuite(node);
|
|
278
|
+
} else {
|
|
279
|
+
this.#reportTest(node);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
this.#activeNodes[event.data.nesting] = undefined;
|
|
283
|
+
this.#trimActiveNodes();
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
onTestStart(event) {
|
|
287
|
+
this.#startRootSuite();
|
|
288
|
+
this.#ensureOpenAncestors(event.data.nesting);
|
|
289
|
+
this.#ensureNode(event);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
onTestComplete(event, passed) {
|
|
293
|
+
this.#startRootSuite();
|
|
294
|
+
this.#completeNode(event, passed);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
#closeActiveSuites() {
|
|
298
|
+
for (let i = this.#activeNodes.length - 1; i >= 0; i -= 1) {
|
|
299
|
+
const node = this.#activeNodes[i];
|
|
300
|
+
if (node && node.isSuite) {
|
|
301
|
+
this.#closeSuite(node);
|
|
302
|
+
this.#activeNodes[i] = undefined;
|
|
213
303
|
}
|
|
214
|
-
this.#current = this.#current.parent;
|
|
215
304
|
}
|
|
305
|
+
this.#trimActiveNodes();
|
|
216
306
|
}
|
|
217
307
|
}
|
|
218
308
|
|
|
219
|
-
|
|
309
|
+
export default async function mochaReporter(source) {
|
|
220
310
|
const runner = new Runner();
|
|
221
311
|
await runner.init();
|
|
222
312
|
|
|
223
313
|
for await (const event of source) {
|
|
224
314
|
switch (event.type) {
|
|
225
315
|
case 'test:start':
|
|
226
|
-
runner.
|
|
316
|
+
runner.onTestStart(event);
|
|
227
317
|
break;
|
|
228
318
|
case 'test:pass':
|
|
229
319
|
case 'test:fail': {
|
|
230
|
-
|
|
231
|
-
runner.addChild(event, event.type === 'test:pass');
|
|
232
|
-
}
|
|
233
|
-
runner.childCompleted(event, event.type === 'test:pass');
|
|
320
|
+
runner.onTestComplete(event, event.type === 'test:pass');
|
|
234
321
|
break;
|
|
235
322
|
}
|
|
236
323
|
default:
|
|
@@ -239,4 +326,4 @@ module.exports = async function mochaReporter(source) {
|
|
|
239
326
|
}
|
|
240
327
|
|
|
241
328
|
runner.end();
|
|
242
|
-
}
|
|
329
|
+
}
|