mocha 9.1.2

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.
Files changed (76) hide show
  1. package/CHANGELOG.md +1015 -0
  2. package/LICENSE +22 -0
  3. package/README.md +70 -0
  4. package/assets/growl/error.png +0 -0
  5. package/assets/growl/ok.png +0 -0
  6. package/bin/_mocha +10 -0
  7. package/bin/mocha +142 -0
  8. package/browser-entry.js +216 -0
  9. package/index.js +3 -0
  10. package/lib/browser/growl.js +169 -0
  11. package/lib/browser/highlight-tags.js +39 -0
  12. package/lib/browser/parse-query.js +24 -0
  13. package/lib/browser/progress.js +123 -0
  14. package/lib/browser/template.html +20 -0
  15. package/lib/cli/cli.js +89 -0
  16. package/lib/cli/collect-files.js +92 -0
  17. package/lib/cli/commands.js +13 -0
  18. package/lib/cli/config.js +105 -0
  19. package/lib/cli/index.js +3 -0
  20. package/lib/cli/init.js +36 -0
  21. package/lib/cli/lookup-files.js +145 -0
  22. package/lib/cli/node-flags.js +85 -0
  23. package/lib/cli/one-and-dones.js +69 -0
  24. package/lib/cli/options.js +261 -0
  25. package/lib/cli/run-helpers.js +243 -0
  26. package/lib/cli/run-option-metadata.js +117 -0
  27. package/lib/cli/run.js +379 -0
  28. package/lib/cli/watch-run.js +380 -0
  29. package/lib/context.js +86 -0
  30. package/lib/errors.js +563 -0
  31. package/lib/hook.js +89 -0
  32. package/lib/interfaces/bdd.js +111 -0
  33. package/lib/interfaces/common.js +193 -0
  34. package/lib/interfaces/exports.js +60 -0
  35. package/lib/interfaces/index.js +6 -0
  36. package/lib/interfaces/qunit.js +98 -0
  37. package/lib/interfaces/tdd.js +106 -0
  38. package/lib/mocha.js +1374 -0
  39. package/lib/mocharc.json +10 -0
  40. package/lib/nodejs/buffered-worker-pool.js +172 -0
  41. package/lib/nodejs/esm-utils.js +109 -0
  42. package/lib/nodejs/file-unloader.js +15 -0
  43. package/lib/nodejs/growl.js +137 -0
  44. package/lib/nodejs/parallel-buffered-runner.js +433 -0
  45. package/lib/nodejs/reporters/parallel-buffered.js +165 -0
  46. package/lib/nodejs/serializer.js +412 -0
  47. package/lib/nodejs/worker.js +151 -0
  48. package/lib/pending.js +16 -0
  49. package/lib/plugin-loader.js +286 -0
  50. package/lib/reporters/base.js +537 -0
  51. package/lib/reporters/doc.js +95 -0
  52. package/lib/reporters/dot.js +81 -0
  53. package/lib/reporters/html.js +390 -0
  54. package/lib/reporters/index.js +19 -0
  55. package/lib/reporters/json-stream.js +92 -0
  56. package/lib/reporters/json.js +162 -0
  57. package/lib/reporters/landing.js +116 -0
  58. package/lib/reporters/list.js +78 -0
  59. package/lib/reporters/markdown.js +112 -0
  60. package/lib/reporters/min.js +52 -0
  61. package/lib/reporters/nyan.js +276 -0
  62. package/lib/reporters/progress.js +104 -0
  63. package/lib/reporters/spec.js +99 -0
  64. package/lib/reporters/tap.js +293 -0
  65. package/lib/reporters/xunit.js +217 -0
  66. package/lib/runnable.js +476 -0
  67. package/lib/runner.js +1269 -0
  68. package/lib/stats-collector.js +83 -0
  69. package/lib/suite.js +695 -0
  70. package/lib/test.js +113 -0
  71. package/lib/utils.js +641 -0
  72. package/mocha-es2018.js +19816 -0
  73. package/mocha.css +325 -0
  74. package/mocha.js +30844 -0
  75. package/mocha.js.map +1 -0
  76. package/package.json +200 -0
@@ -0,0 +1,433 @@
1
+ /**
2
+ * A test Runner that uses a {@link module:buffered-worker-pool}.
3
+ * @module parallel-buffered-runner
4
+ * @private
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const allSettled = require('@ungap/promise-all-settled').bind(Promise);
10
+ const Runner = require('../runner');
11
+ const {EVENT_RUN_BEGIN, EVENT_RUN_END} = Runner.constants;
12
+ const debug = require('debug')('mocha:parallel:parallel-buffered-runner');
13
+ const {BufferedWorkerPool} = require('./buffered-worker-pool');
14
+ const {setInterval, clearInterval} = global;
15
+ const {createMap, constants} = require('../utils');
16
+ const {MOCHA_ID_PROP_NAME} = constants;
17
+ const {createFatalError} = require('../errors');
18
+
19
+ const DEFAULT_WORKER_REPORTER = require.resolve(
20
+ './reporters/parallel-buffered'
21
+ );
22
+
23
+ /**
24
+ * List of options to _not_ serialize for transmission to workers
25
+ */
26
+ const DENY_OPTIONS = [
27
+ 'globalSetup',
28
+ 'globalTeardown',
29
+ 'parallel',
30
+ 'p',
31
+ 'jobs',
32
+ 'j'
33
+ ];
34
+
35
+ /**
36
+ * Outputs a debug statement with worker stats
37
+ * @param {BufferedWorkerPool} pool - Worker pool
38
+ */
39
+ /* istanbul ignore next */
40
+ const debugStats = pool => {
41
+ const {totalWorkers, busyWorkers, idleWorkers, pendingTasks} = pool.stats();
42
+ debug(
43
+ '%d/%d busy workers; %d idle; %d tasks queued',
44
+ busyWorkers,
45
+ totalWorkers,
46
+ idleWorkers,
47
+ pendingTasks
48
+ );
49
+ };
50
+
51
+ /**
52
+ * The interval at which we will display stats for worker processes in debug mode
53
+ */
54
+ const DEBUG_STATS_INTERVAL = 5000;
55
+
56
+ const ABORTED = 'ABORTED';
57
+ const IDLE = 'IDLE';
58
+ const ABORTING = 'ABORTING';
59
+ const RUNNING = 'RUNNING';
60
+ const BAILING = 'BAILING';
61
+ const BAILED = 'BAILED';
62
+ const COMPLETE = 'COMPLETE';
63
+
64
+ const states = createMap({
65
+ [IDLE]: new Set([RUNNING, ABORTING]),
66
+ [RUNNING]: new Set([COMPLETE, BAILING, ABORTING]),
67
+ [COMPLETE]: new Set(),
68
+ [ABORTED]: new Set(),
69
+ [ABORTING]: new Set([ABORTED]),
70
+ [BAILING]: new Set([BAILED, ABORTING]),
71
+ [BAILED]: new Set([COMPLETE, ABORTING])
72
+ });
73
+
74
+ /**
75
+ * This `Runner` delegates tests runs to worker threads. Does not execute any
76
+ * {@link Runnable}s by itself!
77
+ * @public
78
+ */
79
+ class ParallelBufferedRunner extends Runner {
80
+ constructor(...args) {
81
+ super(...args);
82
+
83
+ let state = IDLE;
84
+ Object.defineProperty(this, '_state', {
85
+ get() {
86
+ return state;
87
+ },
88
+ set(newState) {
89
+ if (states[state].has(newState)) {
90
+ state = newState;
91
+ } else {
92
+ throw new Error(`invalid state transition: ${state} => ${newState}`);
93
+ }
94
+ }
95
+ });
96
+
97
+ this._workerReporter = DEFAULT_WORKER_REPORTER;
98
+ this._linkPartialObjects = false;
99
+ this._linkedObjectMap = new Map();
100
+
101
+ this.once(Runner.constants.EVENT_RUN_END, () => {
102
+ this._state = COMPLETE;
103
+ });
104
+ }
105
+
106
+ /**
107
+ * Returns a mapping function to enqueue a file in the worker pool and return results of its execution.
108
+ * @param {BufferedWorkerPool} pool - Worker pool
109
+ * @param {Options} options - Mocha options
110
+ * @returns {FileRunner} Mapping function
111
+ * @private
112
+ */
113
+ _createFileRunner(pool, options) {
114
+ /**
115
+ * Emits event and sets `BAILING` state, if necessary.
116
+ * @param {Object} event - Event having `eventName`, maybe `data` and maybe `error`
117
+ * @param {number} failureCount - Failure count
118
+ */
119
+ const emitEvent = (event, failureCount) => {
120
+ this.emit(event.eventName, event.data, event.error);
121
+ if (
122
+ this._state !== BAILING &&
123
+ event.data &&
124
+ event.data._bail &&
125
+ (failureCount || event.error)
126
+ ) {
127
+ debug('run(): nonzero failure count & found bail flag');
128
+ // we need to let the events complete for this file, as the worker
129
+ // should run any cleanup hooks
130
+ this._state = BAILING;
131
+ }
132
+ };
133
+
134
+ /**
135
+ * Given an event, recursively find any objects in its data that have ID's, and create object references to already-seen objects.
136
+ * @param {Object} event - Event having `eventName`, maybe `data` and maybe `error`
137
+ */
138
+ const linkEvent = event => {
139
+ const stack = [{parent: event, prop: 'data'}];
140
+ while (stack.length) {
141
+ const {parent, prop} = stack.pop();
142
+ const obj = parent[prop];
143
+ let newObj;
144
+ if (obj && typeof obj === 'object') {
145
+ if (obj[MOCHA_ID_PROP_NAME]) {
146
+ const id = obj[MOCHA_ID_PROP_NAME];
147
+ newObj = this._linkedObjectMap.has(id)
148
+ ? Object.assign(this._linkedObjectMap.get(id), obj)
149
+ : obj;
150
+ this._linkedObjectMap.set(id, newObj);
151
+ parent[prop] = newObj;
152
+ } else {
153
+ throw createFatalError(
154
+ 'Object missing ID received in event data',
155
+ obj
156
+ );
157
+ }
158
+ }
159
+ Object.keys(newObj).forEach(key => {
160
+ const value = obj[key];
161
+ if (value && typeof value === 'object' && value[MOCHA_ID_PROP_NAME]) {
162
+ stack.push({obj: value, parent: newObj, prop: key});
163
+ }
164
+ });
165
+ }
166
+ };
167
+
168
+ return async file => {
169
+ debug('run(): enqueueing test file %s', file);
170
+ try {
171
+ const {failureCount, events} = await pool.run(file, options);
172
+
173
+ if (this._state === BAILED) {
174
+ // short-circuit after a graceful bail. if this happens,
175
+ // some other worker has bailed.
176
+ // TODO: determine if this is the desired behavior, or if we
177
+ // should report the events of this run anyway.
178
+ return;
179
+ }
180
+ debug(
181
+ 'run(): completed run of file %s; %d failures / %d events',
182
+ file,
183
+ failureCount,
184
+ events.length
185
+ );
186
+ this.failures += failureCount; // can this ever be non-numeric?
187
+ let event = events.shift();
188
+
189
+ if (this._linkPartialObjects) {
190
+ while (event) {
191
+ linkEvent(event);
192
+ emitEvent(event, failureCount);
193
+ event = events.shift();
194
+ }
195
+ } else {
196
+ while (event) {
197
+ emitEvent(event, failureCount);
198
+ event = events.shift();
199
+ }
200
+ }
201
+ if (this._state === BAILING) {
202
+ debug('run(): terminating pool due to "bail" flag');
203
+ this._state = BAILED;
204
+ await pool.terminate();
205
+ }
206
+ } catch (err) {
207
+ if (this._state === BAILED || this._state === ABORTING) {
208
+ debug(
209
+ 'run(): worker pool terminated with intent; skipping file %s',
210
+ file
211
+ );
212
+ } else {
213
+ // this is an uncaught exception
214
+ debug('run(): encountered uncaught exception: %O', err);
215
+ if (this.allowUncaught) {
216
+ // still have to clean up
217
+ this._state = ABORTING;
218
+ await pool.terminate(true);
219
+ }
220
+ throw err;
221
+ }
222
+ } finally {
223
+ debug('run(): done running file %s', file);
224
+ }
225
+ };
226
+ }
227
+
228
+ /**
229
+ * Listen on `Process.SIGINT`; terminate pool if caught.
230
+ * Returns the listener for later call to `process.removeListener()`.
231
+ * @param {BufferedWorkerPool} pool - Worker pool
232
+ * @returns {SigIntListener} Listener
233
+ * @private
234
+ */
235
+ _bindSigIntListener(pool) {
236
+ const sigIntListener = async () => {
237
+ debug('run(): caught a SIGINT');
238
+ this._state = ABORTING;
239
+
240
+ try {
241
+ debug('run(): force-terminating worker pool');
242
+ await pool.terminate(true);
243
+ } catch (err) {
244
+ console.error(
245
+ `Error while attempting to force-terminate worker pool: ${err}`
246
+ );
247
+ process.exitCode = 1;
248
+ } finally {
249
+ process.nextTick(() => {
250
+ debug('run(): imminent death');
251
+ this._state = ABORTED;
252
+ process.kill(process.pid, 'SIGINT');
253
+ });
254
+ }
255
+ };
256
+
257
+ process.once('SIGINT', sigIntListener);
258
+
259
+ return sigIntListener;
260
+ }
261
+
262
+ /**
263
+ * Runs Mocha tests by creating a thread pool, then delegating work to the
264
+ * worker threads.
265
+ *
266
+ * Each worker receives one file, and as workers become available, they take a
267
+ * file from the queue and run it. The worker thread execution is treated like
268
+ * an RPC--it returns a `Promise` containing serialized information about the
269
+ * run. The information is processed as it's received, and emitted to a
270
+ * {@link Reporter}, which is likely listening for these events.
271
+ *
272
+ * @param {Function} callback - Called with an exit code corresponding to
273
+ * number of test failures.
274
+ * @param {{files: string[], options: Options}} opts - Files to run and
275
+ * command-line options, respectively.
276
+ */
277
+ run(callback, {files, options = {}} = {}) {
278
+ /**
279
+ * Listener on `Process.SIGINT` which tries to cleanly terminate the worker pool.
280
+ */
281
+ let sigIntListener;
282
+
283
+ // assign the reporter the worker will use, which will be different than the
284
+ // main process' reporter
285
+ options = {...options, reporter: this._workerReporter};
286
+
287
+ // This function should _not_ return a `Promise`; its parent (`Runner#run`)
288
+ // returns this instance, so this should do the same. However, we want to make
289
+ // use of `async`/`await`, so we use this IIFE.
290
+ (async () => {
291
+ /**
292
+ * This is an interval that outputs stats about the worker pool every so often
293
+ */
294
+ let debugInterval;
295
+
296
+ /**
297
+ * @type {BufferedWorkerPool}
298
+ */
299
+ let pool;
300
+
301
+ try {
302
+ pool = BufferedWorkerPool.create({maxWorkers: options.jobs});
303
+
304
+ sigIntListener = this._bindSigIntListener(pool);
305
+
306
+ /* istanbul ignore next */
307
+ debugInterval = setInterval(
308
+ () => debugStats(pool),
309
+ DEBUG_STATS_INTERVAL
310
+ ).unref();
311
+
312
+ // this is set for uncaught exception handling in `Runner#uncaught`
313
+ // TODO: `Runner` should be using a state machine instead.
314
+ this.started = true;
315
+ this._state = RUNNING;
316
+
317
+ this.emit(EVENT_RUN_BEGIN);
318
+
319
+ options = {...options};
320
+ DENY_OPTIONS.forEach(opt => {
321
+ delete options[opt];
322
+ });
323
+
324
+ const results = await allSettled(
325
+ files.map(this._createFileRunner(pool, options))
326
+ );
327
+
328
+ // note that pool may already be terminated due to --bail
329
+ await pool.terminate();
330
+
331
+ results
332
+ .filter(({status}) => status === 'rejected')
333
+ .forEach(({reason}) => {
334
+ if (this.allowUncaught) {
335
+ // yep, just the first one.
336
+ throw reason;
337
+ }
338
+ // "rejected" will correspond to uncaught exceptions.
339
+ // unlike the serial runner, the parallel runner can always recover.
340
+ this.uncaught(reason);
341
+ });
342
+
343
+ if (this._state === ABORTING) {
344
+ return;
345
+ }
346
+
347
+ this.emit(EVENT_RUN_END);
348
+ debug('run(): completing with failure count %d', this.failures);
349
+ callback(this.failures);
350
+ } catch (err) {
351
+ // this `nextTick` takes us out of the `Promise` scope, so the
352
+ // exception will not be caught and returned as a rejected `Promise`,
353
+ // which would lead to an `unhandledRejection` event.
354
+ process.nextTick(() => {
355
+ debug('run(): re-throwing uncaught exception');
356
+ throw err;
357
+ });
358
+ } finally {
359
+ clearInterval(debugInterval);
360
+ process.removeListener('SIGINT', sigIntListener);
361
+ }
362
+ })();
363
+ return this;
364
+ }
365
+
366
+ /**
367
+ * Toggle partial object linking behavior; used for building object references from
368
+ * unique ID's.
369
+ * @param {boolean} [value] - If `true`, enable partial object linking, otherwise disable
370
+ * @returns {Runner}
371
+ * @chainable
372
+ * @public
373
+ * @example
374
+ * // this reporter needs proper object references when run in parallel mode
375
+ * class MyReporter() {
376
+ * constructor(runner) {
377
+ * this.runner.linkPartialObjects(true)
378
+ * .on(EVENT_SUITE_BEGIN, suite => {
379
+ // this Suite may be the same object...
380
+ * })
381
+ * .on(EVENT_TEST_BEGIN, test => {
382
+ * // ...as the `test.parent` property
383
+ * });
384
+ * }
385
+ * }
386
+ */
387
+ linkPartialObjects(value) {
388
+ this._linkPartialObjects = Boolean(value);
389
+ return super.linkPartialObjects(value);
390
+ }
391
+
392
+ /**
393
+ * If this class is the `Runner` in use, then this is going to return `true`.
394
+ *
395
+ * For use by reporters.
396
+ * @returns {true}
397
+ * @public
398
+ */
399
+ isParallelMode() {
400
+ return true;
401
+ }
402
+
403
+ /**
404
+ * Configures an alternate reporter for worker processes to use. Subclasses
405
+ * using worker processes should implement this.
406
+ * @public
407
+ * @param {string} path - Absolute path to alternate reporter for worker processes to use
408
+ * @returns {Runner}
409
+ * @throws When in serial mode
410
+ * @chainable
411
+ */
412
+ workerReporter(reporter) {
413
+ this._workerReporter = reporter;
414
+ return this;
415
+ }
416
+ }
417
+
418
+ module.exports = ParallelBufferedRunner;
419
+
420
+ /**
421
+ * Listener function intended to be bound to `Process.SIGINT` event
422
+ * @private
423
+ * @callback SigIntListener
424
+ * @returns {Promise<void>}
425
+ */
426
+
427
+ /**
428
+ * A function accepting a test file path and returning the results of a test run
429
+ * @private
430
+ * @callback FileRunner
431
+ * @param {string} filename - File to run
432
+ * @returns {Promise<SerializedWorkerResult>}
433
+ */
@@ -0,0 +1,165 @@
1
+ /**
2
+ * "Buffered" reporter used internally by a worker process when running in parallel mode.
3
+ * @module nodejs/reporters/parallel-buffered
4
+ * @public
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ /**
10
+ * Module dependencies.
11
+ */
12
+
13
+ const {
14
+ EVENT_SUITE_BEGIN,
15
+ EVENT_SUITE_END,
16
+ EVENT_TEST_FAIL,
17
+ EVENT_TEST_PASS,
18
+ EVENT_TEST_PENDING,
19
+ EVENT_TEST_BEGIN,
20
+ EVENT_TEST_END,
21
+ EVENT_TEST_RETRY,
22
+ EVENT_DELAY_BEGIN,
23
+ EVENT_DELAY_END,
24
+ EVENT_HOOK_BEGIN,
25
+ EVENT_HOOK_END,
26
+ EVENT_RUN_END
27
+ } = require('../../runner').constants;
28
+ const {SerializableEvent, SerializableWorkerResult} = require('../serializer');
29
+ const debug = require('debug')('mocha:reporters:buffered');
30
+ const Base = require('../../reporters/base');
31
+
32
+ /**
33
+ * List of events to listen to; these will be buffered and sent
34
+ * when `Mocha#run` is complete (via {@link ParallelBuffered#done}).
35
+ */
36
+ const EVENT_NAMES = [
37
+ EVENT_SUITE_BEGIN,
38
+ EVENT_SUITE_END,
39
+ EVENT_TEST_BEGIN,
40
+ EVENT_TEST_PENDING,
41
+ EVENT_TEST_FAIL,
42
+ EVENT_TEST_PASS,
43
+ EVENT_TEST_RETRY,
44
+ EVENT_TEST_END,
45
+ EVENT_HOOK_BEGIN,
46
+ EVENT_HOOK_END
47
+ ];
48
+
49
+ /**
50
+ * Like {@link EVENT_NAMES}, except we expect these events to only be emitted
51
+ * by the `Runner` once.
52
+ */
53
+ const ONCE_EVENT_NAMES = [EVENT_DELAY_BEGIN, EVENT_DELAY_END];
54
+
55
+ /**
56
+ * The `ParallelBuffered` reporter is used by each worker process in "parallel"
57
+ * mode, by default. Instead of reporting to to `STDOUT`, etc., it retains a
58
+ * list of events it receives and hands these off to the callback passed into
59
+ * {@link Mocha#run}. That callback will then return the data to the main
60
+ * process.
61
+ * @public
62
+ */
63
+ class ParallelBuffered extends Base {
64
+ /**
65
+ * Calls {@link ParallelBuffered#createListeners}
66
+ * @param {Runner} runner
67
+ */
68
+ constructor(runner, opts) {
69
+ super(runner, opts);
70
+
71
+ /**
72
+ * Retained list of events emitted from the {@link Runner} instance.
73
+ * @type {BufferedEvent[]}
74
+ * @public
75
+ */
76
+ this.events = [];
77
+
78
+ /**
79
+ * Map of `Runner` event names to listeners (for later teardown)
80
+ * @public
81
+ * @type {Map<string,EventListener>}
82
+ */
83
+ this.listeners = new Map();
84
+
85
+ this.createListeners(runner);
86
+ }
87
+
88
+ /**
89
+ * Returns a new listener which saves event data in memory to
90
+ * {@link ParallelBuffered#events}. Listeners are indexed by `eventName` and stored
91
+ * in {@link ParallelBuffered#listeners}. This is a defensive measure, so that we
92
+ * don't a) leak memory or b) remove _other_ listeners that may not be
93
+ * associated with this reporter.
94
+ *
95
+ * Subclasses could override this behavior.
96
+ *
97
+ * @public
98
+ * @param {string} eventName - Name of event to create listener for
99
+ * @returns {EventListener}
100
+ */
101
+ createListener(eventName) {
102
+ const listener = (runnable, err) => {
103
+ this.events.push(SerializableEvent.create(eventName, runnable, err));
104
+ };
105
+ return this.listeners.set(eventName, listener).get(eventName);
106
+ }
107
+
108
+ /**
109
+ * Creates event listeners (using {@link ParallelBuffered#createListener}) for each
110
+ * reporter-relevant event emitted by a {@link Runner}. This array is drained when
111
+ * {@link ParallelBuffered#done} is called by {@link Runner#run}.
112
+ *
113
+ * Subclasses could override this behavior.
114
+ * @public
115
+ * @param {Runner} runner - Runner instance
116
+ * @returns {ParallelBuffered}
117
+ * @chainable
118
+ */
119
+ createListeners(runner) {
120
+ EVENT_NAMES.forEach(evt => {
121
+ runner.on(evt, this.createListener(evt));
122
+ });
123
+ ONCE_EVENT_NAMES.forEach(evt => {
124
+ runner.once(evt, this.createListener(evt));
125
+ });
126
+
127
+ runner.once(EVENT_RUN_END, () => {
128
+ debug('received EVENT_RUN_END');
129
+ this.listeners.forEach((listener, evt) => {
130
+ runner.removeListener(evt, listener);
131
+ this.listeners.delete(evt);
132
+ });
133
+ });
134
+
135
+ return this;
136
+ }
137
+
138
+ /**
139
+ * Calls the {@link Mocha#run} callback (`callback`) with the test failure
140
+ * count and the array of {@link BufferedEvent} objects. Resets the array.
141
+ *
142
+ * This is called directly by `Runner#run` and should not be called by any other consumer.
143
+ *
144
+ * Subclasses could override this.
145
+ *
146
+ * @param {number} failures - Number of failed tests
147
+ * @param {Function} callback - The callback passed to {@link Mocha#run}.
148
+ * @public
149
+ */
150
+ done(failures, callback) {
151
+ callback(SerializableWorkerResult.create(this.events, failures));
152
+ this.events = []; // defensive
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Serializable event data from a `Runner`. Keys of the `data` property
158
+ * beginning with `__` will be converted into a function which returns the value
159
+ * upon deserialization.
160
+ * @typedef {Object} BufferedEvent
161
+ * @property {string} name - Event name
162
+ * @property {object} data - Event parameters
163
+ */
164
+
165
+ module.exports = ParallelBuffered;