mocha 8.1.2 → 8.3.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/cli/run.js CHANGED
@@ -19,8 +19,7 @@ const {
19
19
  const {
20
20
  list,
21
21
  handleRequires,
22
- validatePlugin,
23
- loadRootHooks,
22
+ validateLegacyPlugin,
24
23
  runMocha
25
24
  } = require('./run-helpers');
26
25
  const {ONE_AND_DONES, ONE_AND_DONE_ARGS} = require('./one-and-dones');
@@ -339,13 +338,10 @@ exports.builder = yargs =>
339
338
  // currently a failing middleware does not work nicely with yargs' `fail()`.
340
339
  try {
341
340
  // load requires first, because it can impact "plugin" validation
342
- const rawRootHooks = await handleRequires(argv.require);
343
- validatePlugin(argv, 'reporter', Mocha.reporters);
344
- validatePlugin(argv, 'ui', Mocha.interfaces);
345
-
346
- if (rawRootHooks && rawRootHooks.length) {
347
- argv.rootHooks = await loadRootHooks(rawRootHooks);
348
- }
341
+ const plugins = await handleRequires(argv.require);
342
+ validateLegacyPlugin(argv, 'reporter', Mocha.reporters);
343
+ validateLegacyPlugin(argv, 'ui', Mocha.interfaces);
344
+ Object.assign(argv, plugins);
349
345
  } catch (err) {
350
346
  // this could be a bad --require, bad reporter, ui, etc.
351
347
  console.error(`\n${symbols.error} ${ansi.red('ERROR:')}`, err);
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const logSymbols = require('log-symbols');
3
4
  const debug = require('debug')('mocha:cli:watch');
4
5
  const path = require('path');
5
6
  const chokidar = require('chokidar');
@@ -32,6 +33,7 @@ exports.watchParallelRun = (
32
33
  fileCollectParams
33
34
  ) => {
34
35
  debug('creating parallel watcher');
36
+
35
37
  return createWatcher(mocha, {
36
38
  watchFiles,
37
39
  watchIgnore,
@@ -39,6 +41,9 @@ exports.watchParallelRun = (
39
41
  // I don't know why we're cloning the root suite.
40
42
  const rootSuite = mocha.suite.clone();
41
43
 
44
+ // ensure we aren't leaking event listeners
45
+ mocha.dispose();
46
+
42
47
  // this `require` is needed because the require cache has been cleared. the dynamic
43
48
  // exports set via the below call to `mocha.ui()` won't work properly if a
44
49
  // test depends on this module (see `required-tokens.spec.js`).
@@ -68,9 +73,6 @@ exports.watchParallelRun = (
68
73
  newMocha.lazyLoadFiles(true);
69
74
  return newMocha;
70
75
  },
71
- afterRun({watcher}) {
72
- blastCache(watcher);
73
- },
74
76
  fileCollectParams
75
77
  });
76
78
  };
@@ -91,7 +93,6 @@ exports.watchParallelRun = (
91
93
  */
92
94
  exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
93
95
  debug('creating serial watcher');
94
- // list of all test files
95
96
 
96
97
  return createWatcher(mocha, {
97
98
  watchFiles,
@@ -102,6 +103,9 @@ exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
102
103
  // I don't know why we're cloning the root suite.
103
104
  const rootSuite = mocha.suite.clone();
104
105
 
106
+ // ensure we aren't leaking event listeners
107
+ mocha.dispose();
108
+
105
109
  // this `require` is needed because the require cache has been cleared. the dynamic
106
110
  // exports set via the below call to `mocha.ui()` won't work properly if a
107
111
  // test depends on this module (see `required-tokens.spec.js`).
@@ -128,9 +132,6 @@ exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
128
132
 
129
133
  return newMocha;
130
134
  },
131
- afterRun({watcher}) {
132
- blastCache(watcher);
133
- },
134
135
  fileCollectParams
135
136
  });
136
137
  };
@@ -141,7 +142,6 @@ exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
141
142
  * @param {Object} opts
142
143
  * @param {BeforeWatchRun} [opts.beforeRun] - Function to call before
143
144
  * `mocha.run()`
144
- * @param {AfterWatchRun} [opts.afterRun] - Function to call after `mocha.run()`
145
145
  * @param {string[]} [opts.watchFiles] - List of paths and patterns to watch. If
146
146
  * not provided all files with an extension included in
147
147
  * `fileCollectionParams.extension` are watched. See first argument of
@@ -155,13 +155,17 @@ exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
155
155
  */
156
156
  const createWatcher = (
157
157
  mocha,
158
- {watchFiles, watchIgnore, beforeRun, afterRun, fileCollectParams}
158
+ {watchFiles, watchIgnore, beforeRun, fileCollectParams}
159
159
  ) => {
160
160
  if (!watchFiles) {
161
161
  watchFiles = fileCollectParams.extension.map(ext => `**/*.${ext}`);
162
162
  }
163
163
 
164
164
  debug('ignoring files matching: %s', watchIgnore);
165
+ let globalFixtureContext;
166
+
167
+ // we handle global fixtures manually
168
+ mocha.enableGlobalSetup(false).enableGlobalTeardown(false);
165
169
 
166
170
  const watcher = chokidar.watch(watchFiles, {
167
171
  ignored: watchIgnore,
@@ -169,11 +173,14 @@ const createWatcher = (
169
173
  });
170
174
 
171
175
  const rerunner = createRerunner(mocha, watcher, {
172
- beforeRun,
173
- afterRun
176
+ beforeRun
174
177
  });
175
178
 
176
- watcher.on('ready', () => {
179
+ watcher.on('ready', async () => {
180
+ if (!globalFixtureContext) {
181
+ debug('triggering global setup');
182
+ globalFixtureContext = await mocha.runGlobalSetup();
183
+ }
177
184
  rerunner.run();
178
185
  });
179
186
 
@@ -185,10 +192,39 @@ const createWatcher = (
185
192
  process.on('exit', () => {
186
193
  showCursor();
187
194
  });
188
- process.on('SIGINT', () => {
195
+
196
+ // this is for testing.
197
+ // win32 cannot gracefully shutdown via a signal from a parent
198
+ // process; a `SIGINT` from a parent will cause the process
199
+ // to immediately exit. during normal course of operation, a user
200
+ // will type Ctrl-C and the listener will be invoked, but this
201
+ // is not possible in automated testing.
202
+ // there may be another way to solve this, but it too will be a hack.
203
+ // for our watch tests on win32 we must _fork_ mocha with an IPC channel
204
+ if (process.connected) {
205
+ process.on('message', msg => {
206
+ if (msg === 'SIGINT') {
207
+ process.emit('SIGINT');
208
+ }
209
+ });
210
+ }
211
+
212
+ let exiting = false;
213
+ process.on('SIGINT', async () => {
189
214
  showCursor();
190
- console.log('\n');
191
- process.exit(128 + 2);
215
+ console.error(`${logSymbols.warning} [mocha] cleaning up, please wait...`);
216
+ if (!exiting) {
217
+ exiting = true;
218
+ if (mocha.hasGlobalTeardownFixtures()) {
219
+ debug('running global teardown');
220
+ try {
221
+ await mocha.runGlobalTeardown(globalFixtureContext);
222
+ } catch (err) {
223
+ console.error(err);
224
+ }
225
+ }
226
+ process.exit(130);
227
+ }
192
228
  });
193
229
 
194
230
  // Keyboard shortcut for restarting when "rs\n" is typed (ala Nodemon)
@@ -212,12 +248,11 @@ const createWatcher = (
212
248
  * @param {FSWatcher} watcher - chokidar `FSWatcher` instance
213
249
  * @param {Object} [opts] - Options!
214
250
  * @param {BeforeWatchRun} [opts.beforeRun] - Function to call before `mocha.run()`
215
- * @param {AfterWatchRun} [opts.afterRun] - Function to call after `mocha.run()`
216
251
  * @returns {Rerunner}
217
252
  * @ignore
218
253
  * @private
219
254
  */
220
- const createRerunner = (mocha, watcher, {beforeRun, afterRun} = {}) => {
255
+ const createRerunner = (mocha, watcher, {beforeRun} = {}) => {
221
256
  // Set to a `Runner` when mocha is running. Set to `null` when mocha is not
222
257
  // running.
223
258
  let runner = null;
@@ -226,16 +261,15 @@ const createRerunner = (mocha, watcher, {beforeRun, afterRun} = {}) => {
226
261
  let rerunScheduled = false;
227
262
 
228
263
  const run = () => {
229
- mocha = beforeRun ? beforeRun({mocha, watcher}) : mocha;
230
-
264
+ mocha = beforeRun ? beforeRun({mocha, watcher}) || mocha : mocha;
231
265
  runner = mocha.run(() => {
232
266
  debug('finished watch run');
233
267
  runner = null;
234
- afterRun && afterRun({mocha, watcher});
268
+ blastCache(watcher);
235
269
  if (rerunScheduled) {
236
270
  rerun();
237
271
  } else {
238
- debug('waiting for changes...');
272
+ console.error(`${logSymbols.info} [mocha] waiting for changes...`);
239
273
  }
240
274
  });
241
275
  };
@@ -333,15 +367,6 @@ const blastCache = watcher => {
333
367
  * @returns {Mocha}
334
368
  */
335
369
 
336
- /**
337
- * Callback to be run after `mocha.run()` completes. Typically used to clear
338
- * require cache.
339
- * @callback AfterWatchRun
340
- * @private
341
- * @param {{mocha: Mocha, watcher: FSWatcher}} options
342
- * @returns {void}
343
- */
344
-
345
370
  /**
346
371
  * Object containing run control methods
347
372
  * @typedef {Object} Rerunner
package/lib/errors.js CHANGED
@@ -1,83 +1,182 @@
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
 
10
11
  /**
11
- * When Mocha throw exceptions (or otherwise errors), it attempts to assign a
12
- * `code` property to the `Error` object, for easier handling. These are the
13
- * potential values of `code`.
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
+ /* istanbul ignore next */
21
+ process.nextTick(function() {
22
+ console.warn(type + ': ' + msg);
23
+ });
24
+ }
25
+ };
26
+
27
+ /**
28
+ * Show a deprecation warning. Each distinct message is only displayed once.
29
+ * Ignores empty messages.
30
+ *
31
+ * @param {string} [msg] - Warning to print
32
+ * @private
33
+ */
34
+ const deprecate = msg => {
35
+ msg = String(msg);
36
+ if (msg && !deprecate.cache[msg]) {
37
+ deprecate.cache[msg] = true;
38
+ emitWarning(msg, 'DeprecationWarning');
39
+ }
40
+ };
41
+ deprecate.cache = {};
42
+
43
+ /**
44
+ * Show a generic warning.
45
+ * Ignores empty messages.
46
+ *
47
+ * @param {string} [msg] - Warning to print
48
+ * @private
49
+ */
50
+ const warn = msg => {
51
+ if (msg) {
52
+ emitWarning(msg);
53
+ }
54
+ };
55
+
56
+ /**
57
+ * When Mocha throws exceptions (or rejects `Promise`s), it attempts to assign a `code` property to the `Error` object, for easier handling. These are the potential values of `code`.
58
+ * @public
59
+ * @namespace
60
+ * @memberof module:lib/errors
14
61
  */
15
62
  var constants = {
16
63
  /**
17
64
  * An unrecoverable error.
65
+ * @constant
66
+ * @default
18
67
  */
19
68
  FATAL: 'ERR_MOCHA_FATAL',
20
69
 
21
70
  /**
22
71
  * The type of an argument to a function call is invalid
72
+ * @constant
73
+ * @default
23
74
  */
24
75
  INVALID_ARG_TYPE: 'ERR_MOCHA_INVALID_ARG_TYPE',
25
76
 
26
77
  /**
27
78
  * The value of an argument to a function call is invalid
79
+ * @constant
80
+ * @default
28
81
  */
29
82
  INVALID_ARG_VALUE: 'ERR_MOCHA_INVALID_ARG_VALUE',
30
83
 
31
84
  /**
32
85
  * Something was thrown, but it wasn't an `Error`
86
+ * @constant
87
+ * @default
33
88
  */
34
89
  INVALID_EXCEPTION: 'ERR_MOCHA_INVALID_EXCEPTION',
35
90
 
36
91
  /**
37
92
  * An interface (e.g., `Mocha.interfaces`) is unknown or invalid
93
+ * @constant
94
+ * @default
38
95
  */
39
96
  INVALID_INTERFACE: 'ERR_MOCHA_INVALID_INTERFACE',
40
97
 
41
98
  /**
42
99
  * A reporter (.e.g, `Mocha.reporters`) is unknown or invalid
100
+ * @constant
101
+ * @default
43
102
  */
44
103
  INVALID_REPORTER: 'ERR_MOCHA_INVALID_REPORTER',
45
104
 
46
105
  /**
47
106
  * `done()` was called twice in a `Test` or `Hook` callback
107
+ * @constant
108
+ * @default
48
109
  */
49
110
  MULTIPLE_DONE: 'ERR_MOCHA_MULTIPLE_DONE',
50
111
 
51
112
  /**
52
113
  * No files matched the pattern provided by the user
114
+ * @constant
115
+ * @default
53
116
  */
54
117
  NO_FILES_MATCH_PATTERN: 'ERR_MOCHA_NO_FILES_MATCH_PATTERN',
55
118
 
56
119
  /**
57
120
  * Known, but unsupported behavior of some kind
121
+ * @constant
122
+ * @default
58
123
  */
59
124
  UNSUPPORTED: 'ERR_MOCHA_UNSUPPORTED',
60
125
 
61
126
  /**
62
127
  * Invalid state transition occurring in `Mocha` instance
128
+ * @constant
129
+ * @default
63
130
  */
64
131
  INSTANCE_ALREADY_RUNNING: 'ERR_MOCHA_INSTANCE_ALREADY_RUNNING',
65
132
 
66
133
  /**
67
134
  * Invalid state transition occurring in `Mocha` instance
135
+ * @constant
136
+ * @default
68
137
  */
69
138
  INSTANCE_ALREADY_DISPOSED: 'ERR_MOCHA_INSTANCE_ALREADY_DISPOSED',
70
139
 
71
140
  /**
72
141
  * Use of `only()` w/ `--forbid-only` results in this error.
142
+ * @constant
143
+ * @default
73
144
  */
74
- FORBIDDEN_EXCLUSIVITY: 'ERR_MOCHA_FORBIDDEN_EXCLUSIVITY'
145
+ FORBIDDEN_EXCLUSIVITY: 'ERR_MOCHA_FORBIDDEN_EXCLUSIVITY',
146
+
147
+ /**
148
+ * To be thrown when a user-defined plugin implementation (e.g., `mochaHooks`) is invalid
149
+ * @constant
150
+ * @default
151
+ */
152
+ INVALID_PLUGIN_IMPLEMENTATION: 'ERR_MOCHA_INVALID_PLUGIN_IMPLEMENTATION',
153
+
154
+ /**
155
+ * To be thrown when a builtin or third-party plugin definition (the _definition_ of `mochaHooks`) is invalid
156
+ * @constant
157
+ * @default
158
+ */
159
+ INVALID_PLUGIN_DEFINITION: 'ERR_MOCHA_INVALID_PLUGIN_DEFINITION',
160
+
161
+ /**
162
+ * When a runnable exceeds its allowed run time.
163
+ * @constant
164
+ * @default
165
+ */
166
+ TIMEOUT: 'ERR_MOCHA_TIMEOUT'
75
167
  };
76
168
 
169
+ /**
170
+ * A set containing all string values of all Mocha error constants, for use by {@link isMochaError}.
171
+ * @private
172
+ */
173
+ const MOCHA_ERRORS = new Set(Object.values(constants));
174
+
77
175
  /**
78
176
  * Creates an error object to be thrown when no files to be tested could be found using specified pattern.
79
177
  *
80
178
  * @public
179
+ * @static
81
180
  * @param {string} message - Error message to be displayed.
82
181
  * @param {string} pattern - User-specified argument value.
83
182
  * @returns {Error} instance detailing the error condition
@@ -108,6 +207,7 @@ function createInvalidReporterError(message, reporter) {
108
207
  * Creates an error object to be thrown when the interface specified in the options was not found.
109
208
  *
110
209
  * @public
210
+ * @static
111
211
  * @param {string} message - Error message to be displayed.
112
212
  * @param {string} ui - User-specified interface value.
113
213
  * @returns {Error} instance detailing the error condition
@@ -123,6 +223,7 @@ function createInvalidInterfaceError(message, ui) {
123
223
  * Creates an error object to be thrown when a behavior, option, or parameter is unsupported.
124
224
  *
125
225
  * @public
226
+ * @static
126
227
  * @param {string} message - Error message to be displayed.
127
228
  * @returns {Error} instance detailing the error condition
128
229
  */
@@ -136,6 +237,7 @@ function createUnsupportedError(message) {
136
237
  * Creates an error object to be thrown when an argument is missing.
137
238
  *
138
239
  * @public
240
+ * @static
139
241
  * @param {string} message - Error message to be displayed.
140
242
  * @param {string} argument - Argument name.
141
243
  * @param {string} expected - Expected argument datatype.
@@ -149,6 +251,7 @@ function createMissingArgumentError(message, argument, expected) {
149
251
  * Creates an error object to be thrown when an argument did not use the supported type
150
252
  *
151
253
  * @public
254
+ * @static
152
255
  * @param {string} message - Error message to be displayed.
153
256
  * @param {string} argument - Argument name.
154
257
  * @param {string} expected - Expected argument datatype.
@@ -167,6 +270,7 @@ function createInvalidArgumentTypeError(message, argument, expected) {
167
270
  * Creates an error object to be thrown when an argument did not use the supported value
168
271
  *
169
272
  * @public
273
+ * @static
170
274
  * @param {string} message - Error message to be displayed.
171
275
  * @param {string} argument - Argument name.
172
276
  * @param {string} value - Argument value.
@@ -186,6 +290,7 @@ function createInvalidArgumentValueError(message, argument, value, reason) {
186
290
  * Creates an error object to be thrown when an exception was caught, but the `Error` is falsy or undefined.
187
291
  *
188
292
  * @public
293
+ * @static
189
294
  * @param {string} message - Error message to be displayed.
190
295
  * @returns {Error} instance detailing the error condition
191
296
  */
@@ -201,6 +306,7 @@ function createInvalidExceptionError(message, value) {
201
306
  * Creates an error object to be thrown when an unrecoverable error occurs.
202
307
  *
203
308
  * @public
309
+ * @static
204
310
  * @param {string} message - Error message to be displayed.
205
311
  * @returns {Error} instance detailing the error condition
206
312
  */
@@ -219,9 +325,10 @@ function createFatalError(message, value) {
219
325
  * @param {string} [pluginId] - Name/path of plugin, if any
220
326
  * @throws When `pluginType` is not known
221
327
  * @public
328
+ * @static
222
329
  * @returns {Error}
223
330
  */
224
- function createInvalidPluginError(message, pluginType, pluginId) {
331
+ function createInvalidLegacyPluginError(message, pluginType, pluginId) {
225
332
  switch (pluginType) {
226
333
  case 'reporter':
227
334
  return createInvalidReporterError(message, pluginId);
@@ -232,11 +339,28 @@ function createInvalidPluginError(message, pluginType, pluginId) {
232
339
  }
233
340
  }
234
341
 
342
+ /**
343
+ * **DEPRECATED**. Use {@link createInvalidLegacyPluginError} instead Dynamically creates a plugin-type-specific error based on plugin type
344
+ * @deprecated
345
+ * @param {string} message - Error message
346
+ * @param {"reporter"|"interface"} pluginType - Plugin type. Future: expand as needed
347
+ * @param {string} [pluginId] - Name/path of plugin, if any
348
+ * @throws When `pluginType` is not known
349
+ * @public
350
+ * @static
351
+ * @returns {Error}
352
+ */
353
+ function createInvalidPluginError(...args) {
354
+ deprecate('Use createInvalidLegacyPluginError() instead');
355
+ return createInvalidLegacyPluginError(...args);
356
+ }
357
+
235
358
  /**
236
359
  * Creates an error object to be thrown when a mocha object's `run` method is executed while it is already disposed.
237
360
  * @param {string} message The error message to be displayed.
238
361
  * @param {boolean} cleanReferencesAfterRun the value of `cleanReferencesAfterRun`
239
362
  * @param {Mocha} instance the mocha instance that throw this error
363
+ * @static
240
364
  */
241
365
  function createMochaInstanceAlreadyDisposedError(
242
366
  message,
@@ -253,6 +377,8 @@ function createMochaInstanceAlreadyDisposedError(
253
377
  /**
254
378
  * Creates an error object to be thrown when a mocha object's `run` method is called while a test run is in progress.
255
379
  * @param {string} message The error message to be displayed.
380
+ * @static
381
+ * @public
256
382
  */
257
383
  function createMochaInstanceAlreadyRunningError(message, instance) {
258
384
  var err = new Error(message);
@@ -261,13 +387,14 @@ function createMochaInstanceAlreadyRunningError(message, instance) {
261
387
  return err;
262
388
  }
263
389
 
264
- /*
390
+ /**
265
391
  * Creates an error object to be thrown when done() is called multiple times in a test
266
392
  *
267
393
  * @public
268
394
  * @param {Runnable} runnable - Original runnable
269
395
  * @param {Error} [originalErr] - Original error, if any
270
396
  * @returns {Error} instance detailing the error condition
397
+ * @static
271
398
  */
272
399
  function createMultipleDoneError(runnable, originalErr) {
273
400
  var title;
@@ -301,6 +428,7 @@ function createMultipleDoneError(runnable, originalErr) {
301
428
  /**
302
429
  * Creates an error object to be thrown when `.only()` is used with
303
430
  * `--forbid-only`.
431
+ * @static
304
432
  * @public
305
433
  * @param {Mocha} mocha - Mocha instance
306
434
  * @returns {Error} Error with code {@link constants.FORBIDDEN_EXCLUSIVITY}
@@ -315,20 +443,99 @@ function createForbiddenExclusivityError(mocha) {
315
443
  return err;
316
444
  }
317
445
 
446
+ /**
447
+ * Creates an error object to be thrown when a plugin definition is invalid
448
+ * @static
449
+ * @param {string} msg - Error message
450
+ * @param {PluginDefinition} [pluginDef] - Problematic plugin definition
451
+ * @public
452
+ * @returns {Error} Error with code {@link constants.INVALID_PLUGIN_DEFINITION}
453
+ */
454
+ function createInvalidPluginDefinitionError(msg, pluginDef) {
455
+ const err = new Error(msg);
456
+ err.code = constants.INVALID_PLUGIN_DEFINITION;
457
+ err.pluginDef = pluginDef;
458
+ return err;
459
+ }
460
+
461
+ /**
462
+ * Creates an error object to be thrown when a plugin implementation (user code) is invalid
463
+ * @static
464
+ * @param {string} msg - Error message
465
+ * @param {Object} [opts] - Plugin definition and user-supplied implementation
466
+ * @param {PluginDefinition} [opts.pluginDef] - Plugin Definition
467
+ * @param {*} [opts.pluginImpl] - Plugin Implementation (user-supplied)
468
+ * @public
469
+ * @returns {Error} Error with code {@link constants.INVALID_PLUGIN_DEFINITION}
470
+ */
471
+ function createInvalidPluginImplementationError(
472
+ msg,
473
+ {pluginDef, pluginImpl} = {}
474
+ ) {
475
+ const err = new Error(msg);
476
+ err.code = constants.INVALID_PLUGIN_IMPLEMENTATION;
477
+ err.pluginDef = pluginDef;
478
+ err.pluginImpl = pluginImpl;
479
+ return err;
480
+ }
481
+
482
+ /**
483
+ * Creates an error object to be thrown when a runnable exceeds its allowed run time.
484
+ * @static
485
+ * @param {string} msg - Error message
486
+ * @param {number} [timeout] - Timeout in ms
487
+ * @param {string} [file] - File, if given
488
+ * @returns {MochaTimeoutError}
489
+ */
490
+ function createTimeoutError(msg, timeout, file) {
491
+ const err = new Error(msg);
492
+ err.code = constants.TIMEOUT;
493
+ err.timeout = timeout;
494
+ err.file = file;
495
+ return err;
496
+ }
497
+
498
+ /**
499
+ * Returns `true` if an error came out of Mocha.
500
+ * _Can suffer from false negatives, but not false positives._
501
+ * @static
502
+ * @public
503
+ * @param {*} err - Error, or anything
504
+ * @returns {boolean}
505
+ */
506
+ const isMochaError = err =>
507
+ Boolean(err && typeof err === 'object' && MOCHA_ERRORS.has(err.code));
508
+
318
509
  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
510
+ constants,
511
+ createFatalError,
512
+ createForbiddenExclusivityError,
513
+ createInvalidArgumentTypeError,
514
+ createInvalidArgumentValueError,
515
+ createInvalidExceptionError,
516
+ createInvalidInterfaceError,
517
+ createInvalidLegacyPluginError,
518
+ createInvalidPluginDefinitionError,
519
+ createInvalidPluginError,
520
+ createInvalidPluginImplementationError,
521
+ createInvalidReporterError,
522
+ createMissingArgumentError,
523
+ createMochaInstanceAlreadyDisposedError,
524
+ createMochaInstanceAlreadyRunningError,
525
+ createMultipleDoneError,
526
+ createNoFilesMatchPatternError,
527
+ createTimeoutError,
528
+ createUnsupportedError,
529
+ deprecate,
530
+ isMochaError,
531
+ warn
334
532
  };
533
+
534
+ /**
535
+ * The error thrown when a Runnable times out
536
+ * @memberof module:lib/errors
537
+ * @typedef {Error} MochaTimeoutError
538
+ * @property {constants.TIMEOUT} code - Error code
539
+ * @property {number?} timeout Timeout in ms
540
+ * @property {string?} file Filepath, if given
541
+ */
package/lib/esm-utils.js CHANGED
@@ -3,7 +3,29 @@ const url = require('url');
3
3
 
4
4
  const formattedImport = async file => {
5
5
  if (path.isAbsolute(file)) {
6
- return import(url.pathToFileURL(file));
6
+ try {
7
+ return await import(url.pathToFileURL(file));
8
+ } catch (err) {
9
+ // This is a hack created because ESM in Node.js (at least in Node v15.5.1) does not emit
10
+ // the location of the syntax error in the error thrown.
11
+ // This is problematic because the user can't see what file has the problem,
12
+ // so we add the file location to the error.
13
+ // This `if` should be removed once Node.js fixes the problem.
14
+ if (
15
+ err instanceof SyntaxError &&
16
+ err.message &&
17
+ err.stack &&
18
+ !err.stack.includes(file)
19
+ ) {
20
+ const newErrorWithFilename = new SyntaxError(err.message);
21
+ newErrorWithFilename.stack = err.stack.replace(
22
+ /^SyntaxError/,
23
+ `SyntaxError[ @${file} ]`
24
+ );
25
+ throw newErrorWithFilename;
26
+ }
27
+ throw err;
28
+ }
7
29
  }
8
30
  return import(file);
9
31
  };