mocha 8.1.3 → 8.2.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/lib/errors.js CHANGED
@@ -1,12 +1,57 @@
1
1
  'use strict';
2
2
 
3
- var format = require('util').format;
3
+ const {format} = require('util');
4
4
 
5
5
  /**
6
- * Factory functions to create throwable error objects
7
- * @module Errors
6
+ * Contains error codes, factory functions to create throwable error objects,
7
+ * and warning/deprecation functions.
8
+ * @module
8
9
  */
9
10
 
11
+ /**
12
+ * process.emitWarning or a polyfill
13
+ * @see https://nodejs.org/api/process.html#process_process_emitwarning_warning_options
14
+ * @ignore
15
+ */
16
+ const emitWarning = (msg, type) => {
17
+ if (process.emitWarning) {
18
+ process.emitWarning(msg, type);
19
+ } else {
20
+ process.nextTick(function() {
21
+ console.warn(type + ': ' + msg);
22
+ });
23
+ }
24
+ };
25
+
26
+ /**
27
+ * Show a deprecation warning. Each distinct message is only displayed once.
28
+ * Ignores empty messages.
29
+ *
30
+ * @param {string} [msg] - Warning to print
31
+ * @private
32
+ */
33
+ const deprecate = msg => {
34
+ msg = String(msg);
35
+ if (msg && !deprecate.cache[msg]) {
36
+ deprecate.cache[msg] = true;
37
+ emitWarning(msg, 'DeprecationWarning');
38
+ }
39
+ };
40
+ deprecate.cache = {};
41
+
42
+ /**
43
+ * Show a generic warning.
44
+ * Ignores empty messages.
45
+ *
46
+ * @param {string} [msg] - Warning to print
47
+ * @private
48
+ */
49
+ const warn = msg => {
50
+ if (msg) {
51
+ emitWarning(msg);
52
+ }
53
+ };
54
+
10
55
  /**
11
56
  * When Mocha throw exceptions (or otherwise errors), it attempts to assign a
12
57
  * `code` property to the `Error` object, for easier handling. These are the
@@ -71,7 +116,17 @@ var constants = {
71
116
  /**
72
117
  * Use of `only()` w/ `--forbid-only` results in this error.
73
118
  */
74
- FORBIDDEN_EXCLUSIVITY: 'ERR_MOCHA_FORBIDDEN_EXCLUSIVITY'
119
+ FORBIDDEN_EXCLUSIVITY: 'ERR_MOCHA_FORBIDDEN_EXCLUSIVITY',
120
+
121
+ /**
122
+ * To be thrown when a user-defined plugin implementation (e.g., `mochaHooks`) is invalid
123
+ */
124
+ INVALID_PLUGIN_IMPLEMENTATION: 'ERR_MOCHA_INVALID_PLUGIN_IMPLEMENTATION',
125
+
126
+ /**
127
+ * To be thrown when a builtin or third-party plugin definition (the _definition_ of `mochaHooks`) is invalid
128
+ */
129
+ INVALID_PLUGIN_DEFINITION: 'ERR_MOCHA_INVALID_PLUGIN_DEFINITION'
75
130
  };
76
131
 
77
132
  /**
@@ -221,7 +276,7 @@ function createFatalError(message, value) {
221
276
  * @public
222
277
  * @returns {Error}
223
278
  */
224
- function createInvalidPluginError(message, pluginType, pluginId) {
279
+ function createInvalidLegacyPluginError(message, pluginType, pluginId) {
225
280
  switch (pluginType) {
226
281
  case 'reporter':
227
282
  return createInvalidReporterError(message, pluginId);
@@ -232,6 +287,21 @@ function createInvalidPluginError(message, pluginType, pluginId) {
232
287
  }
233
288
  }
234
289
 
290
+ /**
291
+ * **DEPRECATED**. Use {@link createInvalidLegacyPluginError} instead Dynamically creates a plugin-type-specific error based on plugin type
292
+ * @deprecated
293
+ * @param {string} message - Error message
294
+ * @param {"reporter"|"interface"} pluginType - Plugin type. Future: expand as needed
295
+ * @param {string} [pluginId] - Name/path of plugin, if any
296
+ * @throws When `pluginType` is not known
297
+ * @public
298
+ * @returns {Error}
299
+ */
300
+ function createInvalidPluginError(...args) {
301
+ deprecate('Use createInvalidLegacyPluginError() instead');
302
+ return createInvalidLegacyPluginError(...args);
303
+ }
304
+
235
305
  /**
236
306
  * Creates an error object to be thrown when a mocha object's `run` method is executed while it is already disposed.
237
307
  * @param {string} message The error message to be displayed.
@@ -315,20 +385,59 @@ function createForbiddenExclusivityError(mocha) {
315
385
  return err;
316
386
  }
317
387
 
388
+ /**
389
+ * Creates an error object to be thrown when a plugin definition is invalid
390
+ * @param {string} msg - Error message
391
+ * @param {PluginDefinition} [pluginDef] - Problematic plugin definition
392
+ * @public
393
+ * @returns {Error} Error with code {@link constants.INVALID_PLUGIN_DEFINITION}
394
+ */
395
+ function createInvalidPluginDefinitionError(msg, pluginDef) {
396
+ const err = new Error(msg);
397
+ err.code = constants.INVALID_PLUGIN_DEFINITION;
398
+ err.pluginDef = pluginDef;
399
+ return err;
400
+ }
401
+
402
+ /**
403
+ * Creates an error object to be thrown when a plugin implementation (user code) is invalid
404
+ * @param {string} msg - Error message
405
+ * @param {Object} [opts] - Plugin definition and user-supplied implementation
406
+ * @param {PluginDefinition} [opts.pluginDef] - Plugin Definition
407
+ * @param {*} [opts.pluginImpl] - Plugin Implementation (user-supplied)
408
+ * @public
409
+ * @returns {Error} Error with code {@link constants.INVALID_PLUGIN_DEFINITION}
410
+ */
411
+ function createInvalidPluginImplementationError(
412
+ msg,
413
+ {pluginDef, pluginImpl} = {}
414
+ ) {
415
+ const err = new Error(msg);
416
+ err.code = constants.INVALID_PLUGIN_IMPLEMENTATION;
417
+ err.pluginDef = pluginDef;
418
+ err.pluginImpl = pluginImpl;
419
+ return err;
420
+ }
421
+
318
422
  module.exports = {
319
- createInvalidArgumentTypeError: createInvalidArgumentTypeError,
320
- createInvalidArgumentValueError: createInvalidArgumentValueError,
321
- createInvalidExceptionError: createInvalidExceptionError,
322
- createInvalidInterfaceError: createInvalidInterfaceError,
323
- createInvalidReporterError: createInvalidReporterError,
324
- createMissingArgumentError: createMissingArgumentError,
325
- createNoFilesMatchPatternError: createNoFilesMatchPatternError,
326
- createUnsupportedError: createUnsupportedError,
327
- createInvalidPluginError: createInvalidPluginError,
328
- createMochaInstanceAlreadyDisposedError: createMochaInstanceAlreadyDisposedError,
329
- createMochaInstanceAlreadyRunningError: createMochaInstanceAlreadyRunningError,
330
- createFatalError: createFatalError,
331
- createMultipleDoneError: createMultipleDoneError,
332
- createForbiddenExclusivityError: createForbiddenExclusivityError,
333
- constants: constants
423
+ constants,
424
+ createFatalError,
425
+ createForbiddenExclusivityError,
426
+ createInvalidArgumentTypeError,
427
+ createInvalidArgumentValueError,
428
+ createInvalidExceptionError,
429
+ createInvalidInterfaceError,
430
+ createInvalidLegacyPluginError,
431
+ createInvalidPluginDefinitionError,
432
+ createInvalidPluginError,
433
+ createInvalidPluginImplementationError,
434
+ createInvalidReporterError,
435
+ createMissingArgumentError,
436
+ createMochaInstanceAlreadyDisposedError,
437
+ createMochaInstanceAlreadyRunningError,
438
+ createMultipleDoneError,
439
+ createNoFilesMatchPatternError,
440
+ createUnsupportedError,
441
+ deprecate,
442
+ warn
334
443
  };
package/lib/hook.js CHANGED
@@ -1,7 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var Runnable = require('./runnable');
4
- var inherits = require('./utils').inherits;
4
+ const {inherits, constants} = require('./utils');
5
+ const {MOCHA_ID_PROP_NAME} = constants;
5
6
 
6
7
  /**
7
8
  * Expose `Hook`.
@@ -63,16 +64,20 @@ Hook.prototype.serialize = function serialize() {
63
64
  return {
64
65
  $$isPending: this.isPending(),
65
66
  $$titlePath: this.titlePath(),
66
- ctx: {
67
- currentTest: {
68
- title: this.ctx && this.ctx.currentTest && this.ctx.currentTest.title
69
- }
70
- },
67
+ ctx:
68
+ this.ctx && this.ctx.currentTest
69
+ ? {
70
+ currentTest: {
71
+ title: this.ctx.currentTest.title,
72
+ [MOCHA_ID_PROP_NAME]: this.ctx.currentTest.id
73
+ }
74
+ }
75
+ : {},
71
76
  parent: {
72
- root: this.parent.root,
73
- title: this.parent.title
77
+ [MOCHA_ID_PROP_NAME]: this.parent.id
74
78
  },
75
79
  title: this.title,
76
- type: this.type
80
+ type: this.type,
81
+ [MOCHA_ID_PROP_NAME]: this.id
77
82
  };
78
83
  };
package/lib/mocha.js CHANGED
@@ -18,15 +18,18 @@ var esmUtils = utils.supportsEsModules(true)
18
18
  : undefined;
19
19
  var createStatsCollector = require('./stats-collector');
20
20
  const {
21
- createUnsupportedError,
22
- createInvalidInterfaceError,
21
+ warn,
23
22
  createInvalidReporterError,
23
+ createInvalidInterfaceError,
24
24
  createMochaInstanceAlreadyDisposedError,
25
- createMochaInstanceAlreadyRunningError
25
+ createMochaInstanceAlreadyRunningError,
26
+ createUnsupportedError
26
27
  } = require('./errors');
27
- var EVENT_FILE_PRE_REQUIRE = Suite.constants.EVENT_FILE_PRE_REQUIRE;
28
- var EVENT_FILE_POST_REQUIRE = Suite.constants.EVENT_FILE_POST_REQUIRE;
29
- var EVENT_FILE_REQUIRE = Suite.constants.EVENT_FILE_REQUIRE;
28
+ const {
29
+ EVENT_FILE_PRE_REQUIRE,
30
+ EVENT_FILE_POST_REQUIRE,
31
+ EVENT_FILE_REQUIRE
32
+ } = Suite.constants;
30
33
  var sQuote = utils.sQuote;
31
34
  var debug = require('debug')('mocha:mocha');
32
35
 
@@ -128,8 +131,8 @@ exports.Test = require('./test');
128
131
  * suite with
129
132
  * @param {boolean} [options.isWorker] - Should be `true` if `Mocha` process is running in a worker process.
130
133
  */
131
- function Mocha(options) {
132
- options = utils.assign({}, mocharc, options || {});
134
+ function Mocha(options = {}) {
135
+ options = {...mocharc, ...options};
133
136
  this.files = [];
134
137
  this.options = options;
135
138
  // root suite
@@ -205,6 +208,11 @@ function Mocha(options) {
205
208
  */
206
209
  this.isWorker = Boolean(options.isWorker);
207
210
 
211
+ this.globalSetup(options.globalSetup)
212
+ .globalTeardown(options.globalTeardown)
213
+ .enableGlobalSetup(options.enableGlobalSetup)
214
+ .enableGlobalTeardown(options.enableGlobalTeardown);
215
+
208
216
  if (
209
217
  options.parallel &&
210
218
  (typeof options.jobs === 'undefined' || options.jobs > 1)
@@ -277,25 +285,21 @@ Mocha.prototype.reporter = function(reporterName, reporterOptions) {
277
285
  try {
278
286
  reporter = require(reporterName);
279
287
  } catch (err) {
280
- if (
281
- err.code === 'MODULE_NOT_FOUND' ||
282
- err.message.indexOf('Cannot find module') >= 0
283
- ) {
288
+ if (err.code === 'MODULE_NOT_FOUND') {
284
289
  // Try to load reporters from a path (absolute or relative)
285
290
  try {
286
291
  reporter = require(path.resolve(utils.cwd(), reporterName));
287
292
  } catch (_err) {
288
- _err.code === 'MODULE_NOT_FOUND' ||
289
- _err.message.indexOf('Cannot find module') >= 0
290
- ? utils.warn(sQuote(reporterName) + ' reporter not found')
291
- : utils.warn(
293
+ _err.code === 'MODULE_NOT_FOUND'
294
+ ? warn(sQuote(reporterName) + ' reporter not found')
295
+ : warn(
292
296
  sQuote(reporterName) +
293
297
  ' reporter blew up with error:\n' +
294
298
  err.stack
295
299
  );
296
300
  }
297
301
  } else {
298
- utils.warn(
302
+ warn(
299
303
  sQuote(reporterName) + ' reporter blew up with error:\n' + err.stack
300
304
  );
301
305
  }
@@ -965,11 +969,10 @@ Mocha.prototype.run = function(fn) {
965
969
  if (this.files.length && !this._lazyLoadFiles) {
966
970
  this.loadFiles();
967
971
  }
968
- var self = this;
969
972
  var suite = this.suite;
970
973
  var options = this.options;
971
974
  options.files = this.files;
972
- var runner = new this._runnerClass(suite, {
975
+ const runner = new this._runnerClass(suite, {
973
976
  delay: options.delay,
974
977
  cleanReferencesAfterRun: this._cleanReferencesAfterRun
975
978
  });
@@ -996,22 +999,42 @@ Mocha.prototype.run = function(fn) {
996
999
  exports.reporters.Base.inlineDiffs = options.inlineDiffs;
997
1000
  exports.reporters.Base.hideDiff = !options.diff;
998
1001
 
999
- function done(failures) {
1000
- self._previousRunner = runner;
1001
- if (self._cleanReferencesAfterRun) {
1002
- self._state = mochaStates.REFERENCES_CLEANED;
1003
- } else {
1004
- self._state = mochaStates.INIT;
1005
- }
1002
+ const done = failures => {
1003
+ this._previousRunner = runner;
1004
+ this._state = this._cleanReferencesAfterRun
1005
+ ? mochaStates.REFERENCES_CLEANED
1006
+ : mochaStates.INIT;
1006
1007
  fn = fn || utils.noop;
1007
- if (reporter.done) {
1008
+ if (typeof reporter.done === 'function') {
1008
1009
  reporter.done(failures, fn);
1009
1010
  } else {
1010
1011
  fn(failures);
1011
1012
  }
1012
- }
1013
+ };
1014
+
1015
+ const runAsync = async runner => {
1016
+ const context =
1017
+ this.options.enableGlobalSetup && this.hasGlobalSetupFixtures()
1018
+ ? await this.runGlobalSetup(runner)
1019
+ : {};
1020
+ const failureCount = await runner.runAsync({
1021
+ files: this.files,
1022
+ options
1023
+ });
1024
+ if (this.options.enableGlobalTeardown && this.hasGlobalTeardownFixtures()) {
1025
+ await this.runGlobalTeardown(runner, {context});
1026
+ }
1027
+ return failureCount;
1028
+ };
1013
1029
 
1014
- return runner.run(done, {files: this.files, options: options});
1030
+ // no "catch" here is intentional. errors coming out of
1031
+ // Runner#run are considered uncaught/unhandled and caught
1032
+ // by the `process` event listeners.
1033
+ // also: returning anything other than `runner` would be a breaking
1034
+ // change
1035
+ runAsync(runner).then(done);
1036
+
1037
+ return runner;
1015
1038
  };
1016
1039
 
1017
1040
  /**
@@ -1019,26 +1042,28 @@ Mocha.prototype.run = function(fn) {
1019
1042
  * @param {MochaRootHookObject} [hooks] - Hooks to assign to root suite
1020
1043
  * @chainable
1021
1044
  */
1022
- Mocha.prototype.rootHooks = function rootHooks(hooks) {
1023
- if (utils.type(hooks) === 'object') {
1024
- var beforeAll = [].concat(hooks.beforeAll || []);
1025
- var beforeEach = [].concat(hooks.beforeEach || []);
1026
- var afterAll = [].concat(hooks.afterAll || []);
1027
- var afterEach = [].concat(hooks.afterEach || []);
1028
- var rootSuite = this.suite;
1029
- beforeAll.forEach(function(hook) {
1030
- rootSuite.beforeAll(hook);
1031
- });
1032
- beforeEach.forEach(function(hook) {
1033
- rootSuite.beforeEach(hook);
1034
- });
1035
- afterAll.forEach(function(hook) {
1036
- rootSuite.afterAll(hook);
1037
- });
1038
- afterEach.forEach(function(hook) {
1039
- rootSuite.afterEach(hook);
1040
- });
1041
- }
1045
+ Mocha.prototype.rootHooks = function rootHooks({
1046
+ beforeAll = [],
1047
+ beforeEach = [],
1048
+ afterAll = [],
1049
+ afterEach = []
1050
+ } = {}) {
1051
+ beforeAll = utils.castArray(beforeAll);
1052
+ beforeEach = utils.castArray(beforeEach);
1053
+ afterAll = utils.castArray(afterAll);
1054
+ afterEach = utils.castArray(afterEach);
1055
+ beforeAll.forEach(hook => {
1056
+ this.suite.beforeAll(hook);
1057
+ });
1058
+ beforeEach.forEach(hook => {
1059
+ this.suite.beforeEach(hook);
1060
+ });
1061
+ afterAll.forEach(hook => {
1062
+ this.suite.afterAll(hook);
1063
+ });
1064
+ afterEach.forEach(hook => {
1065
+ this.suite.afterEach(hook);
1066
+ });
1042
1067
  return this;
1043
1068
  };
1044
1069
 
@@ -1047,18 +1072,21 @@ Mocha.prototype.rootHooks = function rootHooks(hooks) {
1047
1072
  *
1048
1073
  * Must be run before calling {@link Mocha#run}. Changes the `Runner` class to
1049
1074
  * use; also enables lazy file loading if not already done so.
1075
+ *
1076
+ * Warning: when passed `false` and lazy loading has been enabled _via any means_ (including calling `parallelMode(true)`), this method will _not_ disable lazy loading. Lazy loading is a prerequisite for parallel
1077
+ * mode, but parallel mode is _not_ a prerequisite for lazy loading!
1050
1078
  * @param {boolean} [enable] - If `true`, enable; otherwise disable.
1051
1079
  * @throws If run in browser
1052
- * @throws If Mocha not in "INIT" state
1080
+ * @throws If Mocha not in `INIT` state
1053
1081
  * @returns {Mocha}
1054
1082
  * @chainable
1055
1083
  * @public
1056
1084
  */
1057
- Mocha.prototype.parallelMode = function parallelMode(enable) {
1085
+ Mocha.prototype.parallelMode = function parallelMode(enable = true) {
1058
1086
  if (utils.isBrowser()) {
1059
1087
  throw createUnsupportedError('parallel mode is only supported in Node.js');
1060
1088
  }
1061
- var parallel = enable === true;
1089
+ const parallel = Boolean(enable);
1062
1090
  if (
1063
1091
  parallel === this.options.parallel &&
1064
1092
  this._lazyLoadFiles &&
@@ -1100,8 +1128,144 @@ Mocha.prototype.lazyLoadFiles = function lazyLoadFiles(enable) {
1100
1128
  };
1101
1129
 
1102
1130
  /**
1103
- * An alternative way to define root hooks that works with parallel runs.
1131
+ * Configures one or more global setup fixtures.
1132
+ *
1133
+ * If given no parameters, _unsets_ any previously-set fixtures.
1134
+ * @chainable
1135
+ * @public
1136
+ * @param {MochaGlobalFixture|MochaGlobalFixture[]} [setupFns] - Global setup fixture(s)
1137
+ * @returns {Mocha}
1138
+ */
1139
+ Mocha.prototype.globalSetup = function globalSetup(setupFns = []) {
1140
+ setupFns = utils.castArray(setupFns);
1141
+ this.options.globalSetup = setupFns;
1142
+ debug('configured %d global setup functions', setupFns.length);
1143
+ return this;
1144
+ };
1145
+
1146
+ /**
1147
+ * Configures one or more global teardown fixtures.
1148
+ *
1149
+ * If given no parameters, _unsets_ any previously-set fixtures.
1150
+ * @chainable
1151
+ * @public
1152
+ * @param {MochaGlobalFixture|MochaGlobalFixture[]} [teardownFns] - Global teardown fixture(s)
1153
+ * @returns {Mocha}
1154
+ */
1155
+ Mocha.prototype.globalTeardown = function globalTeardown(teardownFns = []) {
1156
+ teardownFns = utils.castArray(teardownFns);
1157
+ this.options.globalTeardown = teardownFns;
1158
+ debug('configured %d global teardown functions', teardownFns.length);
1159
+ return this;
1160
+ };
1161
+
1162
+ /**
1163
+ * Run any global setup fixtures sequentially, if any.
1164
+ *
1165
+ * This is _automatically called_ by {@link Mocha#run} _unless_ the `runGlobalSetup` option is `false`; see {@link Mocha#enableGlobalSetup}.
1166
+ *
1167
+ * The context object this function resolves with should be consumed by {@link Mocha#runGlobalTeardown}.
1168
+ * @param {object} [context] - Context object if already have one
1169
+ * @public
1170
+ * @returns {Promise<object>} Context object
1171
+ */
1172
+ Mocha.prototype.runGlobalSetup = async function runGlobalSetup(context = {}) {
1173
+ const {globalSetup} = this.options;
1174
+ if (globalSetup && globalSetup.length) {
1175
+ debug('run(): global setup starting');
1176
+ await this._runGlobalFixtures(globalSetup, context);
1177
+ debug('run(): global setup complete');
1178
+ }
1179
+ return context;
1180
+ };
1181
+
1182
+ /**
1183
+ * Run any global teardown fixtures sequentially, if any.
1184
+ *
1185
+ * This is _automatically called_ by {@link Mocha#run} _unless_ the `runGlobalTeardown` option is `false`; see {@link Mocha#enableGlobalTeardown}.
1186
+ *
1187
+ * Should be called with context object returned by {@link Mocha#runGlobalSetup}, if applicable.
1188
+ * @param {object} [context] - Context object if already have one
1189
+ * @public
1190
+ * @returns {Promise<object>} Context object
1191
+ */
1192
+ Mocha.prototype.runGlobalTeardown = async function runGlobalTeardown(
1193
+ context = {}
1194
+ ) {
1195
+ const {globalTeardown} = this.options;
1196
+ if (globalTeardown && globalTeardown.length) {
1197
+ debug('run(): global teardown starting');
1198
+ await this._runGlobalFixtures(globalTeardown, context);
1199
+ }
1200
+ debug('run(): global teardown complete');
1201
+ return context;
1202
+ };
1203
+
1204
+ /**
1205
+ * Run global fixtures sequentially with context `context`
1104
1206
  * @private
1207
+ * @param {MochaGlobalFixture[]} [fixtureFns] - Fixtures to run
1208
+ * @param {object} [context] - context object
1209
+ * @returns {Promise<object>} context object
1210
+ */
1211
+ Mocha.prototype._runGlobalFixtures = async function _runGlobalFixtures(
1212
+ fixtureFns = [],
1213
+ context = {}
1214
+ ) {
1215
+ for await (const fixtureFn of fixtureFns) {
1216
+ await fixtureFn.call(context);
1217
+ }
1218
+ return context;
1219
+ };
1220
+
1221
+ /**
1222
+ * Toggle execution of any global setup fixture(s)
1223
+ *
1224
+ * @chainable
1225
+ * @public
1226
+ * @param {boolean } [enabled=true] - If `false`, do not run global setup fixture
1227
+ * @returns {Mocha}
1228
+ */
1229
+ Mocha.prototype.enableGlobalSetup = function enableGlobalSetup(enabled = true) {
1230
+ this.options.enableGlobalSetup = Boolean(enabled);
1231
+ return this;
1232
+ };
1233
+
1234
+ /**
1235
+ * Toggle execution of any global teardown fixture(s)
1236
+ *
1237
+ * @chainable
1238
+ * @public
1239
+ * @param {boolean } [enabled=true] - If `false`, do not run global teardown fixture
1240
+ * @returns {Mocha}
1241
+ */
1242
+ Mocha.prototype.enableGlobalTeardown = function enableGlobalTeardown(
1243
+ enabled = true
1244
+ ) {
1245
+ this.options.enableGlobalTeardown = Boolean(enabled);
1246
+ return this;
1247
+ };
1248
+
1249
+ /**
1250
+ * Returns `true` if one or more global setup fixtures have been supplied.
1251
+ * @public
1252
+ * @returns {boolean}
1253
+ */
1254
+ Mocha.prototype.hasGlobalSetupFixtures = function hasGlobalSetupFixtures() {
1255
+ return Boolean(this.options.globalSetup.length);
1256
+ };
1257
+
1258
+ /**
1259
+ * Returns `true` if one or more global teardown fixtures have been supplied.
1260
+ * @public
1261
+ * @returns {boolean}
1262
+ */
1263
+ Mocha.prototype.hasGlobalTeardownFixtures = function hasGlobalTeardownFixtures() {
1264
+ return Boolean(this.options.globalTeardown.length);
1265
+ };
1266
+
1267
+ /**
1268
+ * An alternative way to define root hooks that works with parallel runs.
1105
1269
  * @typedef {Object} MochaRootHookObject
1106
1270
  * @property {Function|Function[]} [beforeAll] - "Before all" hook(s)
1107
1271
  * @property {Function|Function[]} [beforeEach] - "Before each" hook(s)
@@ -1111,7 +1275,40 @@ Mocha.prototype.lazyLoadFiles = function lazyLoadFiles(enable) {
1111
1275
 
1112
1276
  /**
1113
1277
  * An function that returns a {@link MochaRootHookObject}, either sync or async.
1114
- * @private
1115
- * @callback MochaRootHookFunction
1278
+ @callback MochaRootHookFunction
1116
1279
  * @returns {MochaRootHookObject|Promise<MochaRootHookObject>}
1117
1280
  */
1281
+
1282
+ /**
1283
+ * A function that's invoked _once_ which is either sync or async.
1284
+ * Can be a "teardown" or "setup". These will all share the same context.
1285
+ * @callback MochaGlobalFixture
1286
+ * @returns {void|Promise<void>}
1287
+ */
1288
+
1289
+ /**
1290
+ * An object making up all necessary parts of a plugin loader and aggregator
1291
+ * @typedef {Object} PluginDefinition
1292
+ * @property {string} exportName - Named export to use
1293
+ * @property {string} [optionName] - Option name for Mocha constructor (use `exportName` if omitted)
1294
+ * @property {PluginValidator} [validate] - Validator function
1295
+ * @property {PluginFinalizer} [finalize] - Finalizer/aggregator function
1296
+ */
1297
+
1298
+ /**
1299
+ * A (sync) function to assert a user-supplied plugin implementation is valid.
1300
+ *
1301
+ * Defined in a {@link PluginDefinition}.
1302
+
1303
+ * @callback PluginValidator
1304
+ * @param {*} value - Value to check
1305
+ * @this {PluginDefinition}
1306
+ * @returns {void}
1307
+ */
1308
+
1309
+ /**
1310
+ * A function to finalize plugins impls of a particular ilk
1311
+ * @callback PluginFinalizer
1312
+ * @param {Array<*>} impls - User-supplied implementations
1313
+ * @returns {Promise<*>|*}
1314
+ */
@@ -75,9 +75,7 @@ class BufferedWorkerPool {
75
75
  process.execArgv.join(' ')
76
76
  );
77
77
 
78
- this.options = Object.assign({}, WORKER_POOL_DEFAULT_OPTS, opts, {
79
- maxWorkers
80
- });
78
+ this.options = {...WORKER_POOL_DEFAULT_OPTS, opts, maxWorkers};
81
79
  this._pool = workerpool.pool(WORKER_PATH, this.options);
82
80
  }
83
81