mocha 7.1.1 → 8.0.1

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.
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const debug = require('debug')('mocha:cli:watch');
3
4
  const path = require('path');
4
5
  const chokidar = require('chokidar');
5
6
  const Context = require('../context');
@@ -12,6 +13,64 @@ const collectFiles = require('./collect-files');
12
13
  * @private
13
14
  */
14
15
 
16
+ /**
17
+ * Run Mocha in parallel "watch" mode
18
+ * @param {Mocha} mocha - Mocha instance
19
+ * @param {Object} opts - Options
20
+ * @param {string[]} [opts.watchFiles] - List of paths and patterns to
21
+ * watch. If not provided all files with an extension included in
22
+ * `fileColletionParams.extension` are watched. See first argument of
23
+ * `chokidar.watch`.
24
+ * @param {string[]} opts.watchIgnore - List of paths and patterns to
25
+ * exclude from watching. See `ignored` option of `chokidar`.
26
+ * @param {FileCollectionOptions} fileCollectParams - Parameters that control test
27
+ * @private
28
+ */
29
+ exports.watchParallelRun = (
30
+ mocha,
31
+ {watchFiles, watchIgnore},
32
+ fileCollectParams
33
+ ) => {
34
+ debug('creating parallel watcher');
35
+ return createWatcher(mocha, {
36
+ watchFiles,
37
+ watchIgnore,
38
+ beforeRun({mocha}) {
39
+ // I don't know why we're cloning the root suite.
40
+ const rootSuite = mocha.suite.clone();
41
+
42
+ // this `require` is needed because the require cache has been cleared. the dynamic
43
+ // exports set via the below call to `mocha.ui()` won't work properly if a
44
+ // test depends on this module (see `required-tokens.spec.js`).
45
+ const Mocha = require('../mocha');
46
+
47
+ // ... and now that we've gotten a new module, we need to use it again due
48
+ // to `mocha.ui()` call
49
+ const newMocha = new Mocha(mocha.options);
50
+ // don't know why this is needed
51
+ newMocha.suite = rootSuite;
52
+ // nor this
53
+ newMocha.suite.ctx = new Context();
54
+
55
+ // reset the list of files
56
+ newMocha.files = collectFiles(fileCollectParams);
57
+
58
+ // because we've swapped out the root suite (see the `run` inner function
59
+ // in `createRerunner`), we need to call `mocha.ui()` again to set up the context/globals.
60
+ newMocha.ui(newMocha.options.ui);
61
+
62
+ // in parallel mode, the main Mocha process doesn't actually load the
63
+ // files. this flag prevents `mocha.run()` from autoloading.
64
+ newMocha.lazyLoadFiles(true);
65
+ return newMocha;
66
+ },
67
+ afterRun({watcher}) {
68
+ blastCache(watcher);
69
+ },
70
+ fileCollectParams
71
+ });
72
+ };
73
+
15
74
  /**
16
75
  * Run Mocha in "watch" mode
17
76
  * @param {Mocha} mocha - Mocha instance
@@ -22,27 +81,88 @@ const collectFiles = require('./collect-files');
22
81
  * `chokidar.watch`.
23
82
  * @param {string[]} opts.watchIgnore - List of paths and patterns to
24
83
  * exclude from watching. See `ignored` option of `chokidar`.
25
- * @param {Object} fileCollectParams - Parameters that control test
84
+ * @param {FileCollectionOptions} fileCollectParams - Parameters that control test
26
85
  * file collection. See `lib/cli/collect-files.js`.
27
- * @param {string[]} fileCollectParams.extension - List of extensions
28
- * to watch if `opts.watchFiles` is not given.
29
86
  * @private
30
87
  */
31
- module.exports = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
88
+ exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
89
+ debug('creating serial watcher');
90
+ // list of all test files
91
+
92
+ return createWatcher(mocha, {
93
+ watchFiles,
94
+ watchIgnore,
95
+ beforeRun({mocha}) {
96
+ mocha.unloadFiles();
97
+
98
+ // I don't know why we're cloning the root suite.
99
+ const rootSuite = mocha.suite.clone();
100
+
101
+ // this `require` is needed because the require cache has been cleared. the dynamic
102
+ // exports set via the below call to `mocha.ui()` won't work properly if a
103
+ // test depends on this module (see `required-tokens.spec.js`).
104
+ const Mocha = require('../mocha');
105
+
106
+ // ... and now that we've gotten a new module, we need to use it again due
107
+ // to `mocha.ui()` call
108
+ const newMocha = new Mocha(mocha.options);
109
+ // don't know why this is needed
110
+ newMocha.suite = rootSuite;
111
+ // nor this
112
+ newMocha.suite.ctx = new Context();
113
+
114
+ // reset the list of files
115
+ newMocha.files = collectFiles(fileCollectParams);
116
+
117
+ // because we've swapped out the root suite (see the `run` inner function
118
+ // in `createRerunner`), we need to call `mocha.ui()` again to set up the context/globals.
119
+ newMocha.ui(newMocha.options.ui);
120
+
121
+ return newMocha;
122
+ },
123
+ afterRun({watcher}) {
124
+ blastCache(watcher);
125
+ },
126
+ fileCollectParams
127
+ });
128
+ };
129
+
130
+ /**
131
+ * Bootstraps a chokidar watcher. Handles keyboard input & signals
132
+ * @param {Mocha} mocha - Mocha instance
133
+ * @param {Object} opts
134
+ * @param {BeforeWatchRun} [opts.beforeRun] - Function to call before
135
+ * `mocha.run()`
136
+ * @param {AfterWatchRun} [opts.afterRun] - Function to call after `mocha.run()`
137
+ * @param {string[]} [opts.watchFiles] - List of paths and patterns to watch. If
138
+ * not provided all files with an extension included in
139
+ * `fileColletionParams.extension` are watched. See first argument of
140
+ * `chokidar.watch`.
141
+ * @param {string[]} [opts.watchIgnore] - List of paths and patterns to exclude
142
+ * from watching. See `ignored` option of `chokidar`.
143
+ * @param {FileCollectionOptions} opts.fileCollectParams - List of extensions to watch if `opts.watchFiles` is not given.
144
+ * @returns {FSWatcher}
145
+ * @ignore
146
+ * @private
147
+ */
148
+ const createWatcher = (
149
+ mocha,
150
+ {watchFiles, watchIgnore, beforeRun, afterRun, fileCollectParams}
151
+ ) => {
32
152
  if (!watchFiles) {
33
153
  watchFiles = fileCollectParams.extension.map(ext => `**/*.${ext}`);
34
154
  }
35
155
 
156
+ debug('ignoring files matching: %s', watchIgnore);
157
+
36
158
  const watcher = chokidar.watch(watchFiles, {
37
159
  ignored: watchIgnore,
38
160
  ignoreInitial: true
39
161
  });
40
162
 
41
- const rerunner = createRerunner(mocha, () => {
42
- getWatchedFiles(watcher).forEach(file => {
43
- delete require.cache[file];
44
- });
45
- mocha.files = collectFiles(fileCollectParams);
163
+ const rerunner = createRerunner(mocha, watcher, {
164
+ beforeRun,
165
+ afterRun
46
166
  });
47
167
 
48
168
  watcher.on('ready', () => {
@@ -53,7 +173,6 @@ module.exports = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
53
173
  rerunner.scheduleRun();
54
174
  });
55
175
 
56
- console.log();
57
176
  hideCursor();
58
177
  process.on('exit', () => {
59
178
  showCursor();
@@ -74,36 +193,43 @@ module.exports = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
74
193
  .toLowerCase();
75
194
  if (str === 'rs') rerunner.scheduleRun();
76
195
  });
196
+
197
+ return watcher;
77
198
  };
78
199
 
79
200
  /**
80
- * Create an object that allows you to rerun tests on the mocha
81
- * instance. `beforeRun` is called everytime before `mocha.run()` is
82
- * called.
201
+ * Create an object that allows you to rerun tests on the mocha instance.
83
202
  *
84
203
  * @param {Mocha} mocha - Mocha instance
85
- * @param {function} beforeRun - Called just before `mocha.run()`
204
+ * @param {FSWatcher} watcher - chokidar `FSWatcher` instance
205
+ * @param {Object} [opts] - Options!
206
+ * @param {BeforeWatchRun} [opts.beforeRun] - Function to call before `mocha.run()`
207
+ * @param {AfterWatchRun} [opts.afterRun] - Function to call after `mocha.run()`
208
+ * @returns {Rerunner}
209
+ * @ignore
210
+ * @private
86
211
  */
87
- const createRerunner = (mocha, beforeRun) => {
212
+ const createRerunner = (mocha, watcher, {beforeRun, afterRun} = {}) => {
88
213
  // Set to a `Runner` when mocha is running. Set to `null` when mocha is not
89
214
  // running.
90
215
  let runner = null;
91
216
 
217
+ // true if a file has changed during a test run
92
218
  let rerunScheduled = false;
93
219
 
94
220
  const run = () => {
95
- try {
96
- beforeRun();
97
- resetMocha(mocha);
98
- runner = mocha.run(() => {
99
- runner = null;
100
- if (rerunScheduled) {
101
- rerun();
102
- }
103
- });
104
- } catch (e) {
105
- console.log(e.stack);
106
- }
221
+ mocha = beforeRun ? beforeRun({mocha, watcher}) : mocha;
222
+
223
+ runner = mocha.run(() => {
224
+ debug('finished watch run');
225
+ runner = null;
226
+ afterRun && afterRun({mocha, watcher});
227
+ if (rerunScheduled) {
228
+ rerun();
229
+ } else {
230
+ debug('waiting for changes...');
231
+ }
232
+ });
107
233
  };
108
234
 
109
235
  const scheduleRun = () => {
@@ -136,32 +262,18 @@ const createRerunner = (mocha, beforeRun) => {
136
262
  *
137
263
  * @param watcher - Instance of a chokidar watcher
138
264
  * @return {string[]} - List of absolute paths
265
+ * @ignore
266
+ * @private
139
267
  */
140
268
  const getWatchedFiles = watcher => {
141
269
  const watchedDirs = watcher.getWatched();
142
- let watchedFiles = [];
143
- Object.keys(watchedDirs).forEach(dir => {
144
- watchedFiles = watchedFiles.concat(
145
- watchedDirs[dir].map(file => path.join(dir, file))
146
- );
147
- });
148
- return watchedFiles;
149
- };
150
-
151
- /**
152
- * Reset the internal state of the mocha instance so that tests can be rerun.
153
- *
154
- * @param {Mocha} mocha - Mocha instance
155
- * @private
156
- */
157
- const resetMocha = mocha => {
158
- mocha.unloadFiles();
159
- mocha.suite = mocha.suite.clone();
160
- mocha.suite.ctx = new Context();
161
- // Registers a callback on `mocha.suite` that wires new context to the DSL
162
- // (e.g. `describe`) that is exposed as globals when the test files are
163
- // reloaded.
164
- mocha.ui(mocha.options.ui);
270
+ return Object.keys(watchedDirs).reduce(
271
+ (acc, dir) => [
272
+ ...acc,
273
+ ...watchedDirs[dir].map(file => path.join(dir, file))
274
+ ],
275
+ []
276
+ );
165
277
  };
166
278
 
167
279
  /**
@@ -189,3 +301,43 @@ const showCursor = () => {
189
301
  const eraseLine = () => {
190
302
  process.stdout.write('\u001b[2K');
191
303
  };
304
+
305
+ /**
306
+ * Blast all of the watched files out of `require.cache`
307
+ * @param {FSWatcher} watcher - chokidar FSWatcher
308
+ * @ignore
309
+ * @private
310
+ */
311
+ const blastCache = watcher => {
312
+ const files = getWatchedFiles(watcher);
313
+ files.forEach(file => {
314
+ delete require.cache[file];
315
+ });
316
+ debug('deleted %d file(s) from the require cache', files.length);
317
+ };
318
+
319
+ /**
320
+ * Callback to be run before `mocha.run()` is called.
321
+ * Optionally, it can return a new `Mocha` instance.
322
+ * @callback BeforeWatchRun
323
+ * @private
324
+ * @param {{mocha: Mocha, watcher: FSWatcher}} options
325
+ * @returns {Mocha}
326
+ */
327
+
328
+ /**
329
+ * Callback to be run after `mocha.run()` completes. Typically used to clear
330
+ * require cache.
331
+ * @callback AfterWatchRun
332
+ * @private
333
+ * @param {{mocha: Mocha, watcher: FSWatcher}} options
334
+ * @returns {void}
335
+ */
336
+
337
+ /**
338
+ * Object containing run control methods
339
+ * @typedef {Object} Rerunner
340
+ * @private
341
+ * @property {Function} run - Calls `mocha.run()`
342
+ * @property {Function} scheduleRun - Schedules another call to `run`
343
+ */
package/lib/context.js CHANGED
@@ -45,21 +45,6 @@ Context.prototype.timeout = function(ms) {
45
45
  return this;
46
46
  };
47
47
 
48
- /**
49
- * Set test timeout `enabled`.
50
- *
51
- * @private
52
- * @param {boolean} enabled
53
- * @return {Context} self
54
- */
55
- Context.prototype.enableTimeouts = function(enabled) {
56
- if (!arguments.length) {
57
- return this.runnable().enableTimeouts();
58
- }
59
- this.runnable().enableTimeouts(enabled);
60
- return this;
61
- };
62
-
63
48
  /**
64
49
  * Set or get test slowness threshold `ms`.
65
50
  *
package/lib/errors.js CHANGED
@@ -1,10 +1,78 @@
1
1
  'use strict';
2
+
3
+ var format = require('util').format;
4
+
2
5
  /**
6
+ * Factory functions to create throwable error objects
3
7
  * @module Errors
4
8
  */
9
+
5
10
  /**
6
- * Factory functions to create throwable error objects
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`.
7
14
  */
15
+ var constants = {
16
+ /**
17
+ * An unrecoverable error.
18
+ */
19
+ FATAL: 'ERR_MOCHA_FATAL',
20
+
21
+ /**
22
+ * The type of an argument to a function call is invalid
23
+ */
24
+ INVALID_ARG_TYPE: 'ERR_MOCHA_INVALID_ARG_TYPE',
25
+
26
+ /**
27
+ * The value of an argument to a function call is invalid
28
+ */
29
+ INVALID_ARG_VALUE: 'ERR_MOCHA_INVALID_ARG_VALUE',
30
+
31
+ /**
32
+ * Something was thrown, but it wasn't an `Error`
33
+ */
34
+ INVALID_EXCEPTION: 'ERR_MOCHA_INVALID_EXCEPTION',
35
+
36
+ /**
37
+ * An interface (e.g., `Mocha.interfaces`) is unknown or invalid
38
+ */
39
+ INVALID_INTERFACE: 'ERR_MOCHA_INVALID_INTERFACE',
40
+
41
+ /**
42
+ * A reporter (.e.g, `Mocha.reporters`) is unknown or invalid
43
+ */
44
+ INVALID_REPORTER: 'ERR_MOCHA_INVALID_REPORTER',
45
+
46
+ /**
47
+ * `done()` was called twice in a `Test` or `Hook` callback
48
+ */
49
+ MULTIPLE_DONE: 'ERR_MOCHA_MULTIPLE_DONE',
50
+
51
+ /**
52
+ * No files matched the pattern provided by the user
53
+ */
54
+ NO_FILES_MATCH_PATTERN: 'ERR_MOCHA_NO_FILES_MATCH_PATTERN',
55
+
56
+ /**
57
+ * Known, but unsupported behavior of some kind
58
+ */
59
+ UNSUPPORTED: 'ERR_MOCHA_UNSUPPORTED',
60
+
61
+ /**
62
+ * Invalid state transition occuring in `Mocha` instance
63
+ */
64
+ INSTANCE_ALREADY_RUNNING: 'ERR_MOCHA_INSTANCE_ALREADY_RUNNING',
65
+
66
+ /**
67
+ * Invalid state transition occuring in `Mocha` instance
68
+ */
69
+ INSTANCE_ALREADY_DISPOSED: 'ERR_MOCHA_INSTANCE_ALREADY_DISPOSED',
70
+
71
+ /**
72
+ * Use of `only()` w/ `--forbid-only` results in this error.
73
+ */
74
+ FORBIDDEN_EXCLUSIVITY: 'ERR_MOCHA_FORBIDDEN_EXCLUSIVITY'
75
+ };
8
76
 
9
77
  /**
10
78
  * Creates an error object to be thrown when no files to be tested could be found using specified pattern.
@@ -16,7 +84,7 @@
16
84
  */
17
85
  function createNoFilesMatchPatternError(message, pattern) {
18
86
  var err = new Error(message);
19
- err.code = 'ERR_MOCHA_NO_FILES_MATCH_PATTERN';
87
+ err.code = constants.NO_FILES_MATCH_PATTERN;
20
88
  err.pattern = pattern;
21
89
  return err;
22
90
  }
@@ -31,7 +99,7 @@ function createNoFilesMatchPatternError(message, pattern) {
31
99
  */
32
100
  function createInvalidReporterError(message, reporter) {
33
101
  var err = new TypeError(message);
34
- err.code = 'ERR_MOCHA_INVALID_REPORTER';
102
+ err.code = constants.INVALID_REPORTER;
35
103
  err.reporter = reporter;
36
104
  return err;
37
105
  }
@@ -46,7 +114,7 @@ function createInvalidReporterError(message, reporter) {
46
114
  */
47
115
  function createInvalidInterfaceError(message, ui) {
48
116
  var err = new Error(message);
49
- err.code = 'ERR_MOCHA_INVALID_INTERFACE';
117
+ err.code = constants.INVALID_INTERFACE;
50
118
  err.interface = ui;
51
119
  return err;
52
120
  }
@@ -60,7 +128,7 @@ function createInvalidInterfaceError(message, ui) {
60
128
  */
61
129
  function createUnsupportedError(message) {
62
130
  var err = new Error(message);
63
- err.code = 'ERR_MOCHA_UNSUPPORTED';
131
+ err.code = constants.UNSUPPORTED;
64
132
  return err;
65
133
  }
66
134
 
@@ -88,7 +156,7 @@ function createMissingArgumentError(message, argument, expected) {
88
156
  */
89
157
  function createInvalidArgumentTypeError(message, argument, expected) {
90
158
  var err = new TypeError(message);
91
- err.code = 'ERR_MOCHA_INVALID_ARG_TYPE';
159
+ err.code = constants.INVALID_ARG_TYPE;
92
160
  err.argument = argument;
93
161
  err.expected = expected;
94
162
  err.actual = typeof argument;
@@ -107,7 +175,7 @@ function createInvalidArgumentTypeError(message, argument, expected) {
107
175
  */
108
176
  function createInvalidArgumentValueError(message, argument, value, reason) {
109
177
  var err = new TypeError(message);
110
- err.code = 'ERR_MOCHA_INVALID_ARG_VALUE';
178
+ err.code = constants.INVALID_ARG_VALUE;
111
179
  err.argument = argument;
112
180
  err.value = value;
113
181
  err.reason = typeof reason !== 'undefined' ? reason : 'is invalid';
@@ -123,12 +191,130 @@ function createInvalidArgumentValueError(message, argument, value, reason) {
123
191
  */
124
192
  function createInvalidExceptionError(message, value) {
125
193
  var err = new Error(message);
126
- err.code = 'ERR_MOCHA_INVALID_EXCEPTION';
194
+ err.code = constants.INVALID_EXCEPTION;
127
195
  err.valueType = typeof value;
128
196
  err.value = value;
129
197
  return err;
130
198
  }
131
199
 
200
+ /**
201
+ * Creates an error object to be thrown when an unrecoverable error occurs.
202
+ *
203
+ * @public
204
+ * @param {string} message - Error message to be displayed.
205
+ * @returns {Error} instance detailing the error condition
206
+ */
207
+ function createFatalError(message, value) {
208
+ var err = new Error(message);
209
+ err.code = constants.FATAL;
210
+ err.valueType = typeof value;
211
+ err.value = value;
212
+ return err;
213
+ }
214
+
215
+ /**
216
+ * Dynamically creates a plugin-type-specific error based on plugin type
217
+ * @param {string} message - Error message
218
+ * @param {"reporter"|"interface"} pluginType - Plugin type. Future: expand as needed
219
+ * @param {string} [pluginId] - Name/path of plugin, if any
220
+ * @throws When `pluginType` is not known
221
+ * @public
222
+ * @returns {Error}
223
+ */
224
+ function createInvalidPluginError(message, pluginType, pluginId) {
225
+ switch (pluginType) {
226
+ case 'reporter':
227
+ return createInvalidReporterError(message, pluginId);
228
+ case 'interface':
229
+ return createInvalidInterfaceError(message, pluginId);
230
+ default:
231
+ throw new Error('unknown pluginType "' + pluginType + '"');
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Creates an error object to be thrown when a mocha object's `run` method is executed while it is already disposed.
237
+ * @param {string} message The error message to be displayed.
238
+ * @param {boolean} cleanReferencesAfterRun the value of `cleanReferencesAfterRun`
239
+ * @param {Mocha} instance the mocha instance that throw this error
240
+ */
241
+ function createMochaInstanceAlreadyDisposedError(
242
+ message,
243
+ cleanReferencesAfterRun,
244
+ instance
245
+ ) {
246
+ var err = new Error(message);
247
+ err.code = constants.INSTANCE_ALREADY_DISPOSED;
248
+ err.cleanReferencesAfterRun = cleanReferencesAfterRun;
249
+ err.instance = instance;
250
+ return err;
251
+ }
252
+
253
+ /**
254
+ * Creates an error object to be thrown when a mocha object's `run` method is called while a test run is in progress.
255
+ * @param {string} message The error message to be displayed.
256
+ */
257
+ function createMochaInstanceAlreadyRunningError(message, instance) {
258
+ var err = new Error(message);
259
+ err.code = constants.INSTANCE_ALREADY_RUNNING;
260
+ err.instance = instance;
261
+ return err;
262
+ }
263
+
264
+ /*
265
+ * Creates an error object to be thrown when done() is called multiple times in a test
266
+ *
267
+ * @public
268
+ * @param {Runnable} runnable - Original runnable
269
+ * @param {Error} [originalErr] - Original error, if any
270
+ * @returns {Error} instance detailing the error condition
271
+ */
272
+ function createMultipleDoneError(runnable, originalErr) {
273
+ var title;
274
+ try {
275
+ title = format('<%s>', runnable.fullTitle());
276
+ if (runnable.parent.root) {
277
+ title += ' (of root suite)';
278
+ }
279
+ } catch (ignored) {
280
+ title = format('<%s> (of unknown suite)', runnable.title);
281
+ }
282
+ var message = format(
283
+ 'done() called multiple times in %s %s',
284
+ runnable.type ? runnable.type : 'unknown runnable',
285
+ title
286
+ );
287
+ if (runnable.file) {
288
+ message += format(' of file %s', runnable.file);
289
+ }
290
+ if (originalErr) {
291
+ message += format('; in addition, done() received error: %s', originalErr);
292
+ }
293
+
294
+ var err = new Error(message);
295
+ err.code = constants.MULTIPLE_DONE;
296
+ err.valueType = typeof originalErr;
297
+ err.value = originalErr;
298
+ return err;
299
+ }
300
+
301
+ /**
302
+ * Creates an error object to be thrown when `.only()` is used with
303
+ * `--forbid-only`.
304
+ * @public
305
+ * @param {Mocha} mocha - Mocha instance
306
+ * @returns {Error} Error with code {@link constants.FORBIDDEN_EXCLUSIVITY}
307
+ */
308
+ function createForbiddenExclusivityError(mocha) {
309
+ var err = new Error(
310
+ mocha.isWorker
311
+ ? '`.only` is not supported in parallel mode'
312
+ : '`.only` forbidden by --forbid-only'
313
+ );
314
+ err.code = constants.FORBIDDEN_EXCLUSIVITY;
315
+ return err;
316
+ }
317
+
132
318
  module.exports = {
133
319
  createInvalidArgumentTypeError: createInvalidArgumentTypeError,
134
320
  createInvalidArgumentValueError: createInvalidArgumentValueError,
@@ -137,5 +323,12 @@ module.exports = {
137
323
  createInvalidReporterError: createInvalidReporterError,
138
324
  createMissingArgumentError: createMissingArgumentError,
139
325
  createNoFilesMatchPatternError: createNoFilesMatchPatternError,
140
- createUnsupportedError: createUnsupportedError
326
+ createUnsupportedError: createUnsupportedError,
327
+ createInvalidPluginError: createInvalidPluginError,
328
+ createMochaInstanceAlreadyDisposedError: createMochaInstanceAlreadyDisposedError,
329
+ createMochaInstanceAlreadyRunningError: createMochaInstanceAlreadyRunningError,
330
+ createFatalError: createFatalError,
331
+ createMultipleDoneError: createMultipleDoneError,
332
+ createForbiddenExclusivityError: createForbiddenExclusivityError,
333
+ constants: constants
141
334
  };
package/lib/esm-utils.js CHANGED
@@ -1,11 +1,16 @@
1
- const url = require('url');
2
1
  const path = require('path');
2
+ const url = require('url');
3
3
 
4
- const requireOrImport = async file => {
5
- file = path.resolve(file);
4
+ const formattedImport = async file => {
5
+ if (path.isAbsolute(file)) {
6
+ return import(url.pathToFileURL(file));
7
+ }
8
+ return import(file);
9
+ };
6
10
 
11
+ exports.requireOrImport = async file => {
7
12
  if (path.extname(file) === '.mjs') {
8
- return import(url.pathToFileURL(file));
13
+ return formattedImport(file);
9
14
  }
10
15
  // This is currently the only known way of figuring out whether a file is CJS or ESM.
11
16
  // If Node.js or the community establish a better procedure for that, we can fix this code.
@@ -15,7 +20,7 @@ const requireOrImport = async file => {
15
20
  return require(file);
16
21
  } catch (err) {
17
22
  if (err.code === 'ERR_REQUIRE_ESM') {
18
- return import(url.pathToFileURL(file));
23
+ return formattedImport(file);
19
24
  } else {
20
25
  throw err;
21
26
  }
@@ -25,7 +30,7 @@ const requireOrImport = async file => {
25
30
  exports.loadFilesAsync = async (files, preLoadFunc, postLoadFunc) => {
26
31
  for (const file of files) {
27
32
  preLoadFunc(file);
28
- const result = await requireOrImport(file);
33
+ const result = await exports.requireOrImport(path.resolve(file));
29
34
  postLoadFunc(file, result);
30
35
  }
31
36
  };
package/lib/hook.js CHANGED
@@ -27,6 +27,14 @@ function Hook(title, fn) {
27
27
  */
28
28
  inherits(Hook, Runnable);
29
29
 
30
+ /**
31
+ * Resets the state for a next run.
32
+ */
33
+ Hook.prototype.reset = function() {
34
+ Runnable.prototype.reset.call(this);
35
+ delete this._error;
36
+ };
37
+
30
38
  /**
31
39
  * Get or set the test `err`.
32
40
  *
@@ -44,3 +52,27 @@ Hook.prototype.error = function(err) {
44
52
 
45
53
  this._error = err;
46
54
  };
55
+
56
+ /**
57
+ * Returns an object suitable for IPC.
58
+ * Functions are represented by keys beginning with `$$`.
59
+ * @private
60
+ * @returns {Object}
61
+ */
62
+ Hook.prototype.serialize = function serialize() {
63
+ return {
64
+ $$isPending: this.isPending(),
65
+ $$titlePath: this.titlePath(),
66
+ ctx: {
67
+ currentTest: {
68
+ title: this.ctx && this.ctx.currentTest && this.ctx.currentTest.title
69
+ }
70
+ },
71
+ parent: {
72
+ root: this.parent.root,
73
+ title: this.parent.title
74
+ },
75
+ title: this.title,
76
+ type: this.type
77
+ };
78
+ };