mocha-compat 3.6.4 → 10.8.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 (92) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +61 -110
  3. package/bin/_mocha +10 -0
  4. package/bin/mocha.js +142 -0
  5. package/browser-entry.js +61 -22
  6. package/lib/browser/highlight-tags.js +39 -0
  7. package/lib/browser/parse-query.js +24 -0
  8. package/lib/{template.html → browser/template.html} +7 -5
  9. package/lib/cli/cli.js +89 -0
  10. package/lib/cli/collect-files.js +137 -0
  11. package/lib/cli/commands.js +14 -0
  12. package/lib/cli/config.js +100 -0
  13. package/lib/cli/index.js +3 -0
  14. package/lib/cli/init.js +36 -0
  15. package/lib/cli/lookup-files.js +150 -0
  16. package/lib/cli/node-flags.js +85 -0
  17. package/lib/cli/one-and-dones.js +69 -0
  18. package/lib/cli/options.js +284 -0
  19. package/lib/cli/run-helpers.js +304 -0
  20. package/lib/cli/run-option-metadata.js +116 -0
  21. package/lib/cli/run.js +380 -0
  22. package/lib/cli/watch-run.js +377 -0
  23. package/lib/context.js +16 -42
  24. package/lib/errors.js +563 -0
  25. package/lib/hook.js +50 -9
  26. package/lib/interfaces/bdd.js +28 -29
  27. package/lib/interfaces/common.js +56 -21
  28. package/lib/interfaces/exports.js +4 -7
  29. package/lib/interfaces/qunit.js +10 -11
  30. package/lib/interfaces/tdd.js +15 -15
  31. package/lib/mocha.js +1073 -292
  32. package/lib/mocharc.json +10 -0
  33. package/lib/nodejs/buffered-worker-pool.js +188 -0
  34. package/lib/nodejs/esm-utils.js +106 -0
  35. package/lib/nodejs/file-unloader.js +15 -0
  36. package/lib/nodejs/parallel-buffered-runner.js +433 -0
  37. package/lib/nodejs/reporters/parallel-buffered.js +165 -0
  38. package/lib/nodejs/serializer.js +414 -0
  39. package/lib/nodejs/worker.js +151 -0
  40. package/lib/pending.js +3 -3
  41. package/lib/plugin-loader.js +286 -0
  42. package/lib/reporters/base.js +305 -205
  43. package/lib/reporters/doc.js +52 -21
  44. package/lib/reporters/dot.js +31 -18
  45. package/lib/reporters/html.js +153 -81
  46. package/lib/reporters/json-stream.js +53 -24
  47. package/lib/reporters/json.js +88 -18
  48. package/lib/reporters/landing.js +38 -16
  49. package/lib/reporters/list.js +34 -19
  50. package/lib/reporters/markdown.js +28 -15
  51. package/lib/reporters/min.js +22 -8
  52. package/lib/reporters/nyan.js +62 -58
  53. package/lib/reporters/progress.js +32 -19
  54. package/lib/reporters/spec.js +41 -23
  55. package/lib/reporters/tap.js +255 -32
  56. package/lib/reporters/xunit.js +89 -39
  57. package/lib/runnable.js +233 -148
  58. package/lib/runner.js +679 -380
  59. package/lib/stats-collector.js +83 -0
  60. package/lib/suite.js +376 -112
  61. package/lib/test.js +82 -21
  62. package/lib/utils.js +364 -477
  63. package/mocha.css +183 -54
  64. package/mocha.js +19840 -15846
  65. package/mocha.js.map +1 -0
  66. package/package.json +163 -336
  67. package/{lib/to-iso-string → vendor/serialize-javascript}/LICENSE +8 -6
  68. package/vendor/serialize-javascript/README.md +10 -0
  69. package/vendor/serialize-javascript/index.js +349 -0
  70. package/bin/_mocha-compat +0 -572
  71. package/bin/mocha-compat +0 -87
  72. package/bin/options.js +0 -41
  73. package/bower.json +0 -38
  74. package/images/error.png +0 -0
  75. package/images/ok.png +0 -0
  76. package/lib/browser/.eslintrc.yaml +0 -4
  77. package/lib/browser/debug.js +0 -7
  78. package/lib/browser/events.js +0 -195
  79. package/lib/browser/progress.js +0 -119
  80. package/lib/browser/tty.js +0 -13
  81. package/lib/ms.js +0 -130
  82. package/lib/to-iso-string/index.js +0 -37
  83. package/vendor/glob/LICENSE +0 -15
  84. package/vendor/glob/README.md +0 -399
  85. package/vendor/glob/common.js +0 -244
  86. package/vendor/glob/glob.js +0 -788
  87. package/vendor/glob/package.json +0 -55
  88. package/vendor/glob/sync.js +0 -486
  89. package/vendor/inflight/LICENSE +0 -15
  90. package/vendor/inflight/README.md +0 -37
  91. package/vendor/inflight/inflight.js +0 -54
  92. package/vendor/inflight/package.json +0 -29
package/lib/mocha.js CHANGED
@@ -6,122 +6,299 @@
6
6
  * MIT Licensed
7
7
  */
8
8
 
9
- /**
10
- * Module dependencies.
11
- */
12
-
13
9
  var escapeRe = require('escape-string-regexp');
14
10
  var path = require('path');
15
- var reporters = require('./reporters');
11
+ var builtinReporters = require('./reporters');
16
12
  var utils = require('./utils');
13
+ var mocharc = require('./mocharc.json');
14
+ var Suite = require('./suite');
15
+ var esmUtils = require('./nodejs/esm-utils');
16
+ var createStatsCollector = require('./stats-collector');
17
+ const {
18
+ createInvalidReporterError,
19
+ createInvalidInterfaceError,
20
+ createMochaInstanceAlreadyDisposedError,
21
+ createMochaInstanceAlreadyRunningError,
22
+ createUnsupportedError
23
+ } = require('./errors');
24
+ const {EVENT_FILE_PRE_REQUIRE, EVENT_FILE_POST_REQUIRE, EVENT_FILE_REQUIRE} =
25
+ Suite.constants;
26
+ var debug = require('debug')('mocha:mocha');
27
+
28
+ exports = module.exports = Mocha;
17
29
 
18
30
  /**
19
- * Expose `Mocha`.
31
+ * A Mocha instance is a finite state machine.
32
+ * These are the states it can be in.
33
+ * @private
20
34
  */
21
-
22
- exports = module.exports = Mocha;
35
+ var mochaStates = utils.defineConstants({
36
+ /**
37
+ * Initial state of the mocha instance
38
+ * @private
39
+ */
40
+ INIT: 'init',
41
+ /**
42
+ * Mocha instance is running tests
43
+ * @private
44
+ */
45
+ RUNNING: 'running',
46
+ /**
47
+ * Mocha instance is done running tests and references to test functions and hooks are cleaned.
48
+ * You can reset this state by unloading the test files.
49
+ * @private
50
+ */
51
+ REFERENCES_CLEANED: 'referencesCleaned',
52
+ /**
53
+ * Mocha instance is disposed and can no longer be used.
54
+ * @private
55
+ */
56
+ DISPOSED: 'disposed'
57
+ });
23
58
 
24
59
  /**
25
60
  * To require local UIs and reporters when running in node.
26
61
  */
27
62
 
28
- if (!process.browser) {
29
- var cwd = process.cwd();
63
+ if (!utils.isBrowser() && typeof module.paths !== 'undefined') {
64
+ var cwd = utils.cwd();
30
65
  module.paths.push(cwd, path.join(cwd, 'node_modules'));
31
66
  }
32
67
 
33
68
  /**
34
69
  * Expose internals.
70
+ * @private
35
71
  */
36
72
 
37
73
  exports.utils = utils;
38
74
  exports.interfaces = require('./interfaces');
39
- exports.reporters = reporters;
75
+ /**
76
+ * @public
77
+ * @memberof Mocha
78
+ */
79
+ exports.reporters = builtinReporters;
40
80
  exports.Runnable = require('./runnable');
41
81
  exports.Context = require('./context');
82
+ /**
83
+ *
84
+ * @memberof Mocha
85
+ */
42
86
  exports.Runner = require('./runner');
43
- exports.Suite = require('./suite');
87
+ exports.Suite = Suite;
44
88
  exports.Hook = require('./hook');
45
89
  exports.Test = require('./test');
46
90
 
47
- /**
48
- * Return image `name` path.
49
- *
50
- * @api private
51
- * @param {string} name
52
- * @return {string}
53
- */
54
- function image (name) {
55
- return path.join(__dirname, '../images', name + '.png');
56
- }
91
+ let currentContext;
92
+ exports.afterEach = function (...args) {
93
+ return (currentContext.afterEach || currentContext.teardown).apply(
94
+ this,
95
+ args
96
+ );
97
+ };
98
+ exports.after = function (...args) {
99
+ return (currentContext.after || currentContext.suiteTeardown).apply(
100
+ this,
101
+ args
102
+ );
103
+ };
104
+ exports.beforeEach = function (...args) {
105
+ return (currentContext.beforeEach || currentContext.setup).apply(this, args);
106
+ };
107
+ exports.before = function (...args) {
108
+ return (currentContext.before || currentContext.suiteSetup).apply(this, args);
109
+ };
110
+ exports.describe = function (...args) {
111
+ return (currentContext.describe || currentContext.suite).apply(this, args);
112
+ };
113
+ exports.describe.only = function (...args) {
114
+ return (currentContext.describe || currentContext.suite).only.apply(
115
+ this,
116
+ args
117
+ );
118
+ };
119
+ exports.describe.skip = function (...args) {
120
+ return (currentContext.describe || currentContext.suite).skip.apply(
121
+ this,
122
+ args
123
+ );
124
+ };
125
+ exports.it = function (...args) {
126
+ return (currentContext.it || currentContext.test).apply(this, args);
127
+ };
128
+ exports.it.only = function (...args) {
129
+ return (currentContext.it || currentContext.test).only.apply(this, args);
130
+ };
131
+ exports.it.skip = function (...args) {
132
+ return (currentContext.it || currentContext.test).skip.apply(this, args);
133
+ };
134
+ exports.xdescribe = exports.describe.skip;
135
+ exports.xit = exports.it.skip;
136
+ exports.setup = exports.beforeEach;
137
+ exports.suiteSetup = exports.before;
138
+ exports.suiteTeardown = exports.after;
139
+ exports.suite = exports.describe;
140
+ exports.teardown = exports.afterEach;
141
+ exports.test = exports.it;
142
+ exports.run = function (...args) {
143
+ return currentContext.run.apply(this, args);
144
+ };
57
145
 
58
146
  /**
59
- * Set up mocha with `options`.
60
- *
61
- * Options:
147
+ * Constructs a new Mocha instance with `options`.
62
148
  *
63
- * - `ui` name "bdd", "tdd", "exports" etc
64
- * - `reporter` reporter instance, defaults to `mocha.reporters.spec`
65
- * - `globals` array of accepted globals
66
- * - `timeout` timeout in milliseconds
67
- * - `retries` number of times to retry failed tests
68
- * - `bail` bail on the first test failure
69
- * - `slow` milliseconds to wait before considering a test slow
70
- * - `ignoreLeaks` ignore global leaks
71
- * - `fullTrace` display the full stack-trace on failing
72
- * - `grep` string or regexp to filter tests with
73
- *
74
- * @param {Object} options
75
- * @api public
149
+ * @public
150
+ * @class Mocha
151
+ * @param {Object} [options] - Settings object.
152
+ * @param {boolean} [options.allowUncaught] - Propagate uncaught errors?
153
+ * @param {boolean} [options.asyncOnly] - Force `done` callback or promise?
154
+ * @param {boolean} [options.bail] - Bail after first test failure?
155
+ * @param {boolean} [options.checkLeaks] - Check for global variable leaks?
156
+ * @param {boolean} [options.color] - Color TTY output from reporter?
157
+ * @param {boolean} [options.delay] - Delay root suite execution?
158
+ * @param {boolean} [options.diff] - Show diff on failure?
159
+ * @param {boolean} [options.dryRun] - Report tests without running them?
160
+ * @param {boolean} [options.passOnFailingTestSuite] - Fail test run if tests were failed?
161
+ * @param {boolean} [options.failZero] - Fail test run if zero tests?
162
+ * @param {string} [options.fgrep] - Test filter given string.
163
+ * @param {boolean} [options.forbidOnly] - Tests marked `only` fail the suite?
164
+ * @param {boolean} [options.forbidPending] - Pending tests fail the suite?
165
+ * @param {boolean} [options.fullTrace] - Full stacktrace upon failure?
166
+ * @param {string[]} [options.global] - Variables expected in global scope.
167
+ * @param {RegExp|string} [options.grep] - Test filter given regular expression.
168
+ * @param {boolean} [options.inlineDiffs] - Display inline diffs?
169
+ * @param {boolean} [options.invert] - Invert test filter matches?
170
+ * @param {boolean} [options.noHighlighting] - Disable syntax highlighting?
171
+ * @param {string|constructor} [options.reporter] - Reporter name or constructor.
172
+ * @param {Object} [options.reporterOption] - Reporter settings object.
173
+ * @param {number} [options.retries] - Number of times to retry failed tests.
174
+ * @param {number} [options.slow] - Slow threshold value.
175
+ * @param {number|string} [options.timeout] - Timeout threshold value.
176
+ * @param {string} [options.ui] - Interface name.
177
+ * @param {boolean} [options.parallel] - Run jobs in parallel.
178
+ * @param {number} [options.jobs] - Max number of worker processes for parallel runs.
179
+ * @param {MochaRootHookObject} [options.rootHooks] - Hooks to bootstrap the root suite with.
180
+ * @param {string[]} [options.require] - Pathname of `rootHooks` plugin for parallel runs.
181
+ * @param {boolean} [options.isWorker] - Should be `true` if `Mocha` process is running in a worker process.
76
182
  */
77
- function Mocha (options) {
78
- options = options || {};
183
+ function Mocha(options = {}) {
184
+ options = {...mocharc, ...options};
79
185
  this.files = [];
80
186
  this.options = options;
81
- if (options.grep) {
82
- this.grep(new RegExp(options.grep));
83
- }
84
- if (options.fgrep) {
85
- this.fgrep(options.fgrep);
86
- }
87
- this.suite = new exports.Suite('', new exports.Context());
88
- this.ui(options.ui);
89
- this.bail(options.bail);
90
- this.reporter(options.reporter, options.reporterOptions);
91
- if (typeof options.timeout !== 'undefined' && options.timeout !== null) {
92
- this.timeout(options.timeout);
187
+ // root suite
188
+ this.suite = new exports.Suite('', new exports.Context(), true);
189
+ this._cleanReferencesAfterRun = true;
190
+ this._state = mochaStates.INIT;
191
+
192
+ this.grep(options.grep)
193
+ .fgrep(options.fgrep)
194
+ .ui(options.ui)
195
+ .reporter(
196
+ options.reporter,
197
+ options.reporterOption || options.reporterOptions // for backwards compatibility
198
+ )
199
+ .slow(options.slow)
200
+ .global(options.global);
201
+
202
+ // this guard exists because Suite#timeout does not consider `undefined` to be valid input
203
+ if (typeof options.timeout !== 'undefined') {
204
+ this.timeout(options.timeout === false ? 0 : options.timeout);
93
205
  }
94
- if (typeof options.retries !== 'undefined' && options.retries !== null) {
206
+
207
+ if ('retries' in options) {
95
208
  this.retries(options.retries);
96
209
  }
97
- this.useColors(options.useColors);
98
- if (options.enableTimeouts !== null) {
99
- this.enableTimeouts(options.enableTimeouts);
210
+
211
+ [
212
+ 'allowUncaught',
213
+ 'asyncOnly',
214
+ 'bail',
215
+ 'checkLeaks',
216
+ 'color',
217
+ 'delay',
218
+ 'diff',
219
+ 'dryRun',
220
+ 'passOnFailingTestSuite',
221
+ 'failZero',
222
+ 'forbidOnly',
223
+ 'forbidPending',
224
+ 'fullTrace',
225
+ 'inlineDiffs',
226
+ 'invert'
227
+ ].forEach(function (opt) {
228
+ if (options[opt]) {
229
+ this[opt]();
230
+ }
231
+ }, this);
232
+
233
+ if (options.rootHooks) {
234
+ this.rootHooks(options.rootHooks);
100
235
  }
101
- if (options.slow) {
102
- this.slow(options.slow);
236
+
237
+ /**
238
+ * The class which we'll instantiate in {@link Mocha#run}. Defaults to
239
+ * {@link Runner} in serial mode; changes in parallel mode.
240
+ * @memberof Mocha
241
+ * @private
242
+ */
243
+ this._runnerClass = exports.Runner;
244
+
245
+ /**
246
+ * Whether or not to call {@link Mocha#loadFiles} implicitly when calling
247
+ * {@link Mocha#run}. If this is `true`, then it's up to the consumer to call
248
+ * {@link Mocha#loadFiles} _or_ {@link Mocha#loadFilesAsync}.
249
+ * @private
250
+ * @memberof Mocha
251
+ */
252
+ this._lazyLoadFiles = false;
253
+
254
+ /**
255
+ * It's useful for a Mocha instance to know if it's running in a worker process.
256
+ * We could derive this via other means, but it's helpful to have a flag to refer to.
257
+ * @memberof Mocha
258
+ * @private
259
+ */
260
+ this.isWorker = Boolean(options.isWorker);
261
+
262
+ this.globalSetup(options.globalSetup)
263
+ .globalTeardown(options.globalTeardown)
264
+ .enableGlobalSetup(options.enableGlobalSetup)
265
+ .enableGlobalTeardown(options.enableGlobalTeardown);
266
+
267
+ if (
268
+ options.parallel &&
269
+ (typeof options.jobs === 'undefined' || options.jobs > 1)
270
+ ) {
271
+ debug('attempting to enable parallel mode');
272
+ this.parallelMode(true);
103
273
  }
104
274
  }
105
275
 
106
276
  /**
107
- * Enable or disable bailing on the first failure.
277
+ * Enables or disables bailing on the first failure.
108
278
  *
109
- * @api public
110
- * @param {boolean} [bail]
279
+ * @public
280
+ * @see [CLI option](../#-bail-b)
281
+ * @param {boolean} [bail=true] - Whether to bail on first error.
282
+ * @returns {Mocha} this
283
+ * @chainable
111
284
  */
112
285
  Mocha.prototype.bail = function (bail) {
113
- if (!arguments.length) {
114
- bail = true;
115
- }
116
- this.suite.bail(bail);
286
+ this.suite.bail(bail !== false);
117
287
  return this;
118
288
  };
119
289
 
120
290
  /**
121
- * Add test `file`.
291
+ * @summary
292
+ * Adds `file` to be loaded for execution.
293
+ *
294
+ * @description
295
+ * Useful for generic setup code that must be included within test suite.
122
296
  *
123
- * @api public
124
- * @param {string} file
297
+ * @public
298
+ * @see [CLI option](../#-file-filedirectoryglob)
299
+ * @param {string} file - Pathname of file to be loaded.
300
+ * @returns {Mocha} this
301
+ * @chainable
125
302
  */
126
303
  Mocha.prototype.addFile = function (file) {
127
304
  this.files.push(file);
@@ -129,169 +306,283 @@ Mocha.prototype.addFile = function (file) {
129
306
  };
130
307
 
131
308
  /**
132
- * Set reporter to `reporter`, defaults to "spec".
309
+ * Sets reporter to `reporter`, defaults to "spec".
133
310
  *
134
- * @param {String|Function} reporter name or constructor
135
- * @param {Object} reporterOptions optional options
136
- * @api public
137
- * @param {string|Function} reporter name or constructor
138
- * @param {Object} reporterOptions optional options
311
+ * @public
312
+ * @see [CLI option](../#-reporter-name-r-name)
313
+ * @see [Reporters](../#reporters)
314
+ * @param {String|Function} reporterName - Reporter name or constructor.
315
+ * @param {Object} [reporterOptions] - Options used to configure the reporter.
316
+ * @returns {Mocha} this
317
+ * @chainable
318
+ * @throws {Error} if requested reporter cannot be loaded
319
+ * @example
320
+ *
321
+ * // Use XUnit reporter and direct its output to file
322
+ * mocha.reporter('xunit', { output: '/path/to/testspec.xunit.xml' });
139
323
  */
140
- Mocha.prototype.reporter = function (reporter, reporterOptions) {
141
- if (typeof reporter === 'function') {
142
- this._reporter = reporter;
324
+ Mocha.prototype.reporter = function (reporterName, reporterOptions) {
325
+ if (typeof reporterName === 'function') {
326
+ this._reporter = reporterName;
143
327
  } else {
144
- reporter = reporter || 'spec';
145
- var _reporter;
328
+ reporterName = reporterName || 'spec';
329
+ var reporter;
146
330
  // Try to load a built-in reporter.
147
- if (reporters[reporter]) {
148
- _reporter = reporters[reporter];
331
+ if (builtinReporters[reporterName]) {
332
+ reporter = builtinReporters[reporterName];
149
333
  }
150
334
  // Try to load reporters from process.cwd() and node_modules
151
- if (!_reporter) {
335
+ if (!reporter) {
336
+ let foundReporter;
152
337
  try {
153
- _reporter = require(reporter);
338
+ foundReporter = require.resolve(reporterName);
339
+ reporter = require(foundReporter);
154
340
  } catch (err) {
155
- if (err.message.indexOf('Cannot find module') !== -1) {
156
- // Try to load reporters from a path (absolute or relative)
157
- try {
158
- _reporter = require(path.resolve(process.cwd(), reporter));
159
- } catch (_err) {
160
- err.message.indexOf('Cannot find module') !== -1 ? console.warn('"' + reporter + '" reporter not found')
161
- : console.warn('"' + reporter + '" reporter blew up with error:\n' + err.stack);
162
- }
163
- } else {
164
- console.warn('"' + reporter + '" reporter blew up with error:\n' + err.stack);
341
+ if (foundReporter) {
342
+ throw createInvalidReporterError(err.message, foundReporter);
343
+ }
344
+ // Try to load reporters from a cwd-relative path
345
+ try {
346
+ reporter = require(path.resolve(reporterName));
347
+ } catch (e) {
348
+ throw createInvalidReporterError(e.message, reporterName);
165
349
  }
166
350
  }
167
351
  }
168
- if (!_reporter && reporter === 'teamcity') {
169
- console.warn('The Teamcity reporter was moved to a package named ' +
170
- 'mocha-teamcity-reporter ' +
171
- '(https://npmjs.org/package/mocha-teamcity-reporter).');
172
- }
173
- if (!_reporter) {
174
- throw new Error('invalid reporter "' + reporter + '"');
175
- }
176
- this._reporter = _reporter;
352
+ this._reporter = reporter;
177
353
  }
354
+ this.options.reporterOption = reporterOptions;
355
+ // alias option name is used in built-in reporters xunit/tap/progress
178
356
  this.options.reporterOptions = reporterOptions;
179
357
  return this;
180
358
  };
181
359
 
182
360
  /**
183
- * Set test UI `name`, defaults to "bdd".
361
+ * Sets test UI `name`, defaults to "bdd".
184
362
  *
185
- * @api public
186
- * @param {string} bdd
363
+ * @public
364
+ * @see [CLI option](../#-ui-name-u-name)
365
+ * @see [Interface DSLs](../#interfaces)
366
+ * @param {string|Function} [ui=bdd] - Interface name or class.
367
+ * @returns {Mocha} this
368
+ * @chainable
369
+ * @throws {Error} if requested interface cannot be loaded
187
370
  */
188
- Mocha.prototype.ui = function (name) {
189
- name = name || 'bdd';
190
- this._ui = exports.interfaces[name];
191
- if (!this._ui) {
192
- try {
193
- this._ui = require(name);
194
- } catch (err) {
195
- throw new Error('invalid interface "' + name + '"');
371
+ Mocha.prototype.ui = function (ui) {
372
+ var bindInterface;
373
+ if (typeof ui === 'function') {
374
+ bindInterface = ui;
375
+ } else {
376
+ ui = ui || 'bdd';
377
+ bindInterface = exports.interfaces[ui];
378
+ if (!bindInterface) {
379
+ try {
380
+ bindInterface = require(ui);
381
+ } catch (err) {
382
+ throw createInvalidInterfaceError(`invalid interface '${ui}'`, ui);
383
+ }
196
384
  }
197
385
  }
198
- this._ui = this._ui(this.suite);
199
-
200
- this.suite.on('pre-require', function (context) {
201
- exports.afterEach = context.afterEach || context.teardown;
202
- exports.after = context.after || context.suiteTeardown;
203
- exports.beforeEach = context.beforeEach || context.setup;
204
- exports.before = context.before || context.suiteSetup;
205
- exports.describe = context.describe || context.suite;
206
- exports.it = context.it || context.test;
207
- exports.xit = context.xit || context.test.skip;
208
- exports.setup = context.setup || context.beforeEach;
209
- exports.suiteSetup = context.suiteSetup || context.before;
210
- exports.suiteTeardown = context.suiteTeardown || context.after;
211
- exports.suite = context.suite || context.describe;
212
- exports.teardown = context.teardown || context.afterEach;
213
- exports.test = context.test || context.it;
214
- exports.run = context.run;
386
+ bindInterface(this.suite);
387
+
388
+ this.suite.on(EVENT_FILE_PRE_REQUIRE, function (context) {
389
+ currentContext = context;
215
390
  });
216
391
 
217
392
  return this;
218
393
  };
219
394
 
220
395
  /**
221
- * Load registered files.
396
+ * Loads `files` prior to execution. Does not support ES Modules.
397
+ *
398
+ * @description
399
+ * The implementation relies on Node's `require` to execute
400
+ * the test interface functions and will be subject to its cache.
401
+ * Supports only CommonJS modules. To load ES modules, use Mocha#loadFilesAsync.
222
402
  *
223
- * @api private
403
+ * @private
404
+ * @see {@link Mocha#addFile}
405
+ * @see {@link Mocha#run}
406
+ * @see {@link Mocha#unloadFiles}
407
+ * @see {@link Mocha#loadFilesAsync}
408
+ * @param {Function} [fn] - Callback invoked upon completion.
224
409
  */
225
410
  Mocha.prototype.loadFiles = function (fn) {
226
411
  var self = this;
227
412
  var suite = this.suite;
228
413
  this.files.forEach(function (file) {
229
414
  file = path.resolve(file);
230
- suite.emit('pre-require', global, file, self);
231
- suite.emit('require', require(file), file, self);
232
- suite.emit('post-require', global, file, self);
415
+ suite.emit(EVENT_FILE_PRE_REQUIRE, global, file, self);
416
+ suite.emit(EVENT_FILE_REQUIRE, require(file), file, self);
417
+ suite.emit(EVENT_FILE_POST_REQUIRE, global, file, self);
233
418
  });
234
419
  fn && fn();
235
420
  };
236
421
 
237
422
  /**
238
- * Enable growl support.
423
+ * Loads `files` prior to execution. Supports Node ES Modules.
424
+ *
425
+ * @description
426
+ * The implementation relies on Node's `require` and `import` to execute
427
+ * the test interface functions and will be subject to its cache.
428
+ * Supports both CJS and ESM modules.
429
+ *
430
+ * @public
431
+ * @see {@link Mocha#addFile}
432
+ * @see {@link Mocha#run}
433
+ * @see {@link Mocha#unloadFiles}
434
+ * @param {Object} [options] - Settings object.
435
+ * @param {Function} [options.esmDecorator] - Function invoked on esm module name right before importing it. By default will passthrough as is.
436
+ * @returns {Promise}
437
+ * @example
239
438
  *
240
- * @api private
439
+ * // loads ESM (and CJS) test files asynchronously, then runs root suite
440
+ * mocha.loadFilesAsync()
441
+ * .then(() => mocha.run(failures => process.exitCode = failures ? 1 : 0))
442
+ * .catch(() => process.exitCode = 1);
241
443
  */
242
- Mocha.prototype._growl = function (runner, reporter) {
243
- // var notify = require('growl');
444
+ Mocha.prototype.loadFilesAsync = function ({esmDecorator} = {}) {
445
+ var self = this;
446
+ var suite = this.suite;
447
+ this.lazyLoadFiles(true);
244
448
 
245
- // runner.on('end', function () {
246
- // var stats = reporter.stats;
247
- // if (stats.failures) {
248
- // var msg = stats.failures + ' of ' + runner.total + ' tests failed';
249
- // notify(msg, { name: 'mocha', title: 'Failed', image: image('error') });
250
- // } else {
251
- // notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {
252
- // name: 'mocha',
253
- // title: 'Passed',
254
- // image: image('ok')
255
- // });
256
- // }
257
- // });
449
+ return esmUtils.loadFilesAsync(
450
+ this.files,
451
+ function (file) {
452
+ suite.emit(EVENT_FILE_PRE_REQUIRE, global, file, self);
453
+ },
454
+ function (file, resultModule) {
455
+ suite.emit(EVENT_FILE_REQUIRE, resultModule, file, self);
456
+ suite.emit(EVENT_FILE_POST_REQUIRE, global, file, self);
457
+ },
458
+ esmDecorator
459
+ );
258
460
  };
259
461
 
260
462
  /**
261
- * Escape string and add it to grep as a regexp.
463
+ * Removes a previously loaded file from Node's `require` cache.
262
464
  *
263
- * @api public
264
- * @param str
265
- * @returns {Mocha}
465
+ * @private
466
+ * @static
467
+ * @see {@link Mocha#unloadFiles}
468
+ * @param {string} file - Pathname of file to be unloaded.
469
+ */
470
+ Mocha.unloadFile = function (file) {
471
+ if (utils.isBrowser()) {
472
+ throw createUnsupportedError(
473
+ 'unloadFile() is only supported in a Node.js environment'
474
+ );
475
+ }
476
+ return require('./nodejs/file-unloader').unloadFile(file);
477
+ };
478
+
479
+ /**
480
+ * Unloads `files` from Node's `require` cache.
481
+ *
482
+ * @description
483
+ * This allows required files to be "freshly" reloaded, providing the ability
484
+ * to reuse a Mocha instance programmatically.
485
+ * Note: does not clear ESM module files from the cache
486
+ *
487
+ * <strong>Intended for consumers &mdash; not used internally</strong>
488
+ *
489
+ * @public
490
+ * @see {@link Mocha#run}
491
+ * @returns {Mocha} this
492
+ * @chainable
493
+ */
494
+ Mocha.prototype.unloadFiles = function () {
495
+ if (this._state === mochaStates.DISPOSED) {
496
+ throw createMochaInstanceAlreadyDisposedError(
497
+ 'Mocha instance is already disposed, it cannot be used again.',
498
+ this._cleanReferencesAfterRun,
499
+ this
500
+ );
501
+ }
502
+
503
+ this.files.forEach(function (file) {
504
+ Mocha.unloadFile(file);
505
+ });
506
+ this._state = mochaStates.INIT;
507
+ return this;
508
+ };
509
+
510
+ /**
511
+ * Sets `grep` filter after escaping RegExp special characters.
512
+ *
513
+ * @public
514
+ * @see {@link Mocha#grep}
515
+ * @param {string} str - Value to be converted to a regexp.
516
+ * @returns {Mocha} this
517
+ * @chainable
518
+ * @example
519
+ *
520
+ * // Select tests whose full title begins with `"foo"` followed by a period
521
+ * mocha.fgrep('foo.');
266
522
  */
267
523
  Mocha.prototype.fgrep = function (str) {
524
+ if (!str) {
525
+ return this;
526
+ }
268
527
  return this.grep(new RegExp(escapeRe(str)));
269
528
  };
270
529
 
271
530
  /**
272
- * Add regexp to grep, if `re` is a string it is escaped.
531
+ * @summary
532
+ * Sets `grep` filter used to select specific tests for execution.
533
+ *
534
+ * @description
535
+ * If `re` is a regexp-like string, it will be converted to regexp.
536
+ * The regexp is tested against the full title of each test (i.e., the
537
+ * name of the test preceded by titles of each its ancestral suites).
538
+ * As such, using an <em>exact-match</em> fixed pattern against the
539
+ * test name itself will not yield any matches.
540
+ * <br>
541
+ * <strong>Previous filter value will be overwritten on each call!</strong>
542
+ *
543
+ * @public
544
+ * @see [CLI option](../#-grep-regexp-g-regexp)
545
+ * @see {@link Mocha#fgrep}
546
+ * @see {@link Mocha#invert}
547
+ * @param {RegExp|String} re - Regular expression used to select tests.
548
+ * @return {Mocha} this
549
+ * @chainable
550
+ * @example
551
+ *
552
+ * // Select tests whose full title contains `"match"`, ignoring case
553
+ * mocha.grep(/match/i);
554
+ * @example
555
+ *
556
+ * // Same as above but with regexp-like string argument
557
+ * mocha.grep('/match/i');
558
+ * @example
273
559
  *
274
- * @param {RegExp|String} re
275
- * @return {Mocha}
276
- * @api public
277
- * @param {RegExp|string} re
278
- * @return {Mocha}
560
+ * // ## Anti-example
561
+ * // Given embedded test `it('only-this-test')`...
562
+ * mocha.grep('/^only-this-test$/'); // NO! Use `.only()` to do this!
279
563
  */
280
564
  Mocha.prototype.grep = function (re) {
281
565
  if (utils.isString(re)) {
282
566
  // extract args if it's regex-like, i.e: [string, pattern, flag]
283
- var arg = re.match(/^\/(.*)\/(g|i|)$|.*/);
567
+ var arg = re.match(/^\/(.*)\/([gimy]{0,4})$|.*/);
284
568
  this.options.grep = new RegExp(arg[1] || arg[0], arg[2]);
285
569
  } else {
286
570
  this.options.grep = re;
287
571
  }
288
572
  return this;
289
573
  };
574
+
290
575
  /**
291
- * Invert `.grep()` matches.
576
+ * Inverts `grep` matches.
577
+ *
578
+ * @public
579
+ * @see {@link Mocha#grep}
580
+ * @return {Mocha} this
581
+ * @chainable
582
+ * @example
292
583
  *
293
- * @return {Mocha}
294
- * @api public
584
+ * // Select tests whose full title does *not* contain `"match"`, ignoring case
585
+ * mocha.grep(/match/i).invert();
295
586
  */
296
587
  Mocha.prototype.invert = function () {
297
588
  this.options.invert = true;
@@ -299,165 +590,223 @@ Mocha.prototype.invert = function () {
299
590
  };
300
591
 
301
592
  /**
302
- * Ignore global leaks.
593
+ * Enables or disables checking for global variables leaked while running tests.
303
594
  *
304
- * @param {Boolean} ignore
305
- * @return {Mocha}
306
- * @api public
307
- * @param {boolean} ignore
308
- * @return {Mocha}
595
+ * @public
596
+ * @see [CLI option](../#-check-leaks)
597
+ * @param {boolean} [checkLeaks=true] - Whether to check for global variable leaks.
598
+ * @return {Mocha} this
599
+ * @chainable
309
600
  */
310
- Mocha.prototype.ignoreLeaks = function (ignore) {
311
- this.options.ignoreLeaks = Boolean(ignore);
601
+ Mocha.prototype.checkLeaks = function (checkLeaks) {
602
+ this.options.checkLeaks = checkLeaks !== false;
312
603
  return this;
313
604
  };
314
605
 
315
606
  /**
316
- * Enable global leak checking.
317
- *
318
- * @return {Mocha}
319
- * @api public
607
+ * Enables or disables whether or not to dispose after each test run.
608
+ * Disable this to ensure you can run the test suite multiple times.
609
+ * If disabled, be sure to dispose mocha when you're done to prevent memory leaks.
610
+ * @public
611
+ * @see {@link Mocha#dispose}
612
+ * @param {boolean} cleanReferencesAfterRun
613
+ * @return {Mocha} this
614
+ * @chainable
320
615
  */
321
- Mocha.prototype.checkLeaks = function () {
322
- this.options.ignoreLeaks = false;
616
+ Mocha.prototype.cleanReferencesAfterRun = function (cleanReferencesAfterRun) {
617
+ this._cleanReferencesAfterRun = cleanReferencesAfterRun !== false;
323
618
  return this;
324
619
  };
325
620
 
326
621
  /**
327
- * Display long stack-trace on failing
328
- *
329
- * @return {Mocha}
330
- * @api public
622
+ * Manually dispose this mocha instance. Mark this instance as `disposed` and unable to run more tests.
623
+ * It also removes function references to tests functions and hooks, so variables trapped in closures can be cleaned by the garbage collector.
624
+ * @public
331
625
  */
332
- Mocha.prototype.fullTrace = function () {
333
- this.options.fullStackTrace = true;
334
- return this;
626
+ Mocha.prototype.dispose = function () {
627
+ if (this._state === mochaStates.RUNNING) {
628
+ throw createMochaInstanceAlreadyRunningError(
629
+ 'Cannot dispose while the mocha instance is still running tests.'
630
+ );
631
+ }
632
+ this.unloadFiles();
633
+ this._previousRunner && this._previousRunner.dispose();
634
+ this.suite.dispose();
635
+ this._state = mochaStates.DISPOSED;
335
636
  };
336
637
 
337
638
  /**
338
- * Enable growl support.
639
+ * Displays full stack trace upon test failure.
339
640
  *
340
- * @return {Mocha}
341
- * @api public
641
+ * @public
642
+ * @see [CLI option](../#-full-trace)
643
+ * @param {boolean} [fullTrace=true] - Whether to print full stacktrace upon failure.
644
+ * @return {Mocha} this
645
+ * @chainable
342
646
  */
343
- Mocha.prototype.growl = function () {
344
- this.options.growl = true;
647
+ Mocha.prototype.fullTrace = function (fullTrace) {
648
+ this.options.fullTrace = fullTrace !== false;
345
649
  return this;
346
650
  };
347
651
 
348
652
  /**
349
- * Ignore `globals` array or string.
653
+ * Specifies whitelist of variable names to be expected in global scope.
654
+ *
655
+ * @public
656
+ * @see [CLI option](../#-global-variable-name)
657
+ * @see {@link Mocha#checkLeaks}
658
+ * @param {String[]|String} global - Accepted global variable name(s).
659
+ * @return {Mocha} this
660
+ * @chainable
661
+ * @example
350
662
  *
351
- * @param {Array|String} globals
352
- * @return {Mocha}
353
- * @api public
354
- * @param {Array|string} globals
355
- * @return {Mocha}
663
+ * // Specify variables to be expected in global scope
664
+ * mocha.global(['jQuery', 'MyLib']);
356
665
  */
357
- Mocha.prototype.globals = function (globals) {
358
- this.options.globals = (this.options.globals || []).concat(globals);
666
+ Mocha.prototype.global = function (global) {
667
+ this.options.global = (this.options.global || [])
668
+ .concat(global)
669
+ .filter(Boolean)
670
+ .filter(function (elt, idx, arr) {
671
+ return arr.indexOf(elt) === idx;
672
+ });
359
673
  return this;
360
674
  };
675
+ // for backwards compatibility, 'globals' is an alias of 'global'
676
+ Mocha.prototype.globals = Mocha.prototype.global;
361
677
 
362
678
  /**
363
- * Emit color output.
679
+ * Enables or disables TTY color output by screen-oriented reporters.
364
680
  *
365
- * @param {Boolean} colors
366
- * @return {Mocha}
367
- * @api public
368
- * @param {boolean} colors
369
- * @return {Mocha}
681
+ * @public
682
+ * @see [CLI option](../#-color-c-colors)
683
+ * @param {boolean} [color=true] - Whether to enable color output.
684
+ * @return {Mocha} this
685
+ * @chainable
370
686
  */
371
- Mocha.prototype.useColors = function (colors) {
372
- if (colors !== undefined) {
373
- this.options.useColors = colors;
374
- }
687
+ Mocha.prototype.color = function (color) {
688
+ this.options.color = color !== false;
375
689
  return this;
376
690
  };
377
691
 
378
692
  /**
379
- * Use inline diffs rather than +/-.
693
+ * Enables or disables reporter to use inline diffs (rather than +/-)
694
+ * in test failure output.
380
695
  *
381
- * @param {Boolean} inlineDiffs
382
- * @return {Mocha}
383
- * @api public
384
- * @param {boolean} inlineDiffs
385
- * @return {Mocha}
696
+ * @public
697
+ * @see [CLI option](../#-inline-diffs)
698
+ * @param {boolean} [inlineDiffs=true] - Whether to use inline diffs.
699
+ * @return {Mocha} this
700
+ * @chainable
386
701
  */
387
- Mocha.prototype.useInlineDiffs = function (inlineDiffs) {
388
- this.options.useInlineDiffs = inlineDiffs !== undefined && inlineDiffs;
702
+ Mocha.prototype.inlineDiffs = function (inlineDiffs) {
703
+ this.options.inlineDiffs = inlineDiffs !== false;
389
704
  return this;
390
705
  };
391
706
 
392
707
  /**
393
- * Set the timeout in milliseconds.
708
+ * Enables or disables reporter to include diff in test failure output.
394
709
  *
395
- * @param {Number} timeout
396
- * @return {Mocha}
397
- * @api public
398
- * @param {number} timeout
399
- * @return {Mocha}
710
+ * @public
711
+ * @see [CLI option](../#-diff)
712
+ * @param {boolean} [diff=true] - Whether to show diff on failure.
713
+ * @return {Mocha} this
714
+ * @chainable
400
715
  */
401
- Mocha.prototype.timeout = function (timeout) {
402
- this.suite.timeout(timeout);
716
+ Mocha.prototype.diff = function (diff) {
717
+ this.options.diff = diff !== false;
403
718
  return this;
404
719
  };
405
720
 
406
721
  /**
407
- * Set the number of times to retry failed tests.
722
+ * @summary
723
+ * Sets timeout threshold value.
724
+ *
725
+ * @description
726
+ * A string argument can use shorthand (such as "2s") and will be converted.
727
+ * If the value is `0`, timeouts will be disabled.
728
+ *
729
+ * @public
730
+ * @see [CLI option](../#-timeout-ms-t-ms)
731
+ * @see [Timeouts](../#timeouts)
732
+ * @param {number|string} msecs - Timeout threshold value.
733
+ * @return {Mocha} this
734
+ * @chainable
735
+ * @example
736
+ *
737
+ * // Sets timeout to one second
738
+ * mocha.timeout(1000);
739
+ * @example
408
740
  *
409
- * @param {Number} retry times
410
- * @return {Mocha}
411
- * @api public
741
+ * // Same as above but using string argument
742
+ * mocha.timeout('1s');
412
743
  */
413
- Mocha.prototype.retries = function (n) {
414
- this.suite.retries(n);
744
+ Mocha.prototype.timeout = function (msecs) {
745
+ this.suite.timeout(msecs);
415
746
  return this;
416
747
  };
417
748
 
418
749
  /**
419
- * Set slowness threshold in milliseconds.
750
+ * Sets the number of times to retry failed tests.
420
751
  *
421
- * @param {Number} slow
422
- * @return {Mocha}
423
- * @api public
424
- * @param {number} slow
425
- * @return {Mocha}
752
+ * @public
753
+ * @see [CLI option](../#-retries-n)
754
+ * @see [Retry Tests](../#retry-tests)
755
+ * @param {number} retry - Number of times to retry failed tests.
756
+ * @return {Mocha} this
757
+ * @chainable
758
+ * @example
759
+ *
760
+ * // Allow any failed test to retry one more time
761
+ * mocha.retries(1);
426
762
  */
427
- Mocha.prototype.slow = function (slow) {
428
- this.suite.slow(slow);
763
+ Mocha.prototype.retries = function (retry) {
764
+ this.suite.retries(retry);
429
765
  return this;
430
766
  };
431
767
 
432
768
  /**
433
- * Enable timeouts.
769
+ * Sets slowness threshold value.
770
+ *
771
+ * @public
772
+ * @see [CLI option](../#-slow-ms-s-ms)
773
+ * @param {number} msecs - Slowness threshold value.
774
+ * @return {Mocha} this
775
+ * @chainable
776
+ * @example
434
777
  *
435
- * @param {Boolean} enabled
436
- * @return {Mocha}
437
- * @api public
438
- * @param {boolean} enabled
439
- * @return {Mocha}
778
+ * // Sets "slow" threshold to half a second
779
+ * mocha.slow(500);
780
+ * @example
781
+ *
782
+ * // Same as above but using string argument
783
+ * mocha.slow('0.5s');
440
784
  */
441
- Mocha.prototype.enableTimeouts = function (enabled) {
442
- this.suite.enableTimeouts(arguments.length && enabled !== undefined ? enabled : true);
785
+ Mocha.prototype.slow = function (msecs) {
786
+ this.suite.slow(msecs);
443
787
  return this;
444
788
  };
445
789
 
446
790
  /**
447
- * Makes all tests async (accepting a callback)
791
+ * Forces all tests to either accept a `done` callback or return a promise.
448
792
  *
449
- * @return {Mocha}
450
- * @api public
793
+ * @public
794
+ * @see [CLI option](../#-async-only-a)
795
+ * @param {boolean} [asyncOnly=true] - Whether to force `done` callback or promise.
796
+ * @return {Mocha} this
797
+ * @chainable
451
798
  */
452
- Mocha.prototype.asyncOnly = function () {
453
- this.options.asyncOnly = true;
799
+ Mocha.prototype.asyncOnly = function (asyncOnly) {
800
+ this.options.asyncOnly = asyncOnly !== false;
454
801
  return this;
455
802
  };
456
803
 
457
804
  /**
458
- * Disable syntax highlighting (in browser).
805
+ * Disables syntax highlighting (in browser).
459
806
  *
460
- * @api public
807
+ * @public
808
+ * @return {Mocha} this
809
+ * @chainable
461
810
  */
462
811
  Mocha.prototype.noHighlighting = function () {
463
812
  this.options.noHighlighting = true;
@@ -465,62 +814,192 @@ Mocha.prototype.noHighlighting = function () {
465
814
  };
466
815
 
467
816
  /**
468
- * Enable uncaught errors to propagate (in browser).
817
+ * Enables or disables uncaught errors to propagate.
469
818
  *
470
- * @return {Mocha}
471
- * @api public
819
+ * @public
820
+ * @see [CLI option](../#-allow-uncaught)
821
+ * @param {boolean} [allowUncaught=true] - Whether to propagate uncaught errors.
822
+ * @return {Mocha} this
823
+ * @chainable
472
824
  */
473
- Mocha.prototype.allowUncaught = function () {
474
- this.options.allowUncaught = true;
825
+ Mocha.prototype.allowUncaught = function (allowUncaught) {
826
+ this.options.allowUncaught = allowUncaught !== false;
475
827
  return this;
476
828
  };
477
829
 
478
830
  /**
479
- * Delay root suite execution.
480
- * @returns {Mocha}
831
+ * @summary
832
+ * Delays root suite execution.
833
+ *
834
+ * @description
835
+ * Used to perform async operations before any suites are run.
836
+ *
837
+ * @public
838
+ * @see [delayed root suite](../#delayed-root-suite)
839
+ * @returns {Mocha} this
840
+ * @chainable
481
841
  */
482
- Mocha.prototype.delay = function delay () {
842
+ Mocha.prototype.delay = function delay() {
483
843
  this.options.delay = true;
484
844
  return this;
485
845
  };
486
846
 
487
847
  /**
488
- * Tests marked only fail the suite
489
- * @returns {Mocha}
848
+ * Enables or disables running tests in dry-run mode.
849
+ *
850
+ * @public
851
+ * @see [CLI option](../#-dry-run)
852
+ * @param {boolean} [dryRun=true] - Whether to activate dry-run mode.
853
+ * @return {Mocha} this
854
+ * @chainable
490
855
  */
491
- Mocha.prototype.forbidOnly = function () {
492
- this.options.forbidOnly = true;
856
+ Mocha.prototype.dryRun = function (dryRun) {
857
+ this.options.dryRun = dryRun !== false;
493
858
  return this;
494
859
  };
495
860
 
496
861
  /**
497
- * Pending tests and tests marked skip fail the suite
498
- * @returns {Mocha}
862
+ * Fails test run if no tests encountered with exit-code 1.
863
+ *
864
+ * @public
865
+ * @see [CLI option](../#-fail-zero)
866
+ * @param {boolean} [failZero=true] - Whether to fail test run.
867
+ * @return {Mocha} this
868
+ * @chainable
869
+ */
870
+ Mocha.prototype.failZero = function (failZero) {
871
+ this.options.failZero = failZero !== false;
872
+ return this;
873
+ };
874
+
875
+ /**
876
+ * Fail test run if tests were failed.
877
+ *
878
+ * @public
879
+ * @see [CLI option](../#-pass-on-failing-test-suite)
880
+ * @param {boolean} [passOnFailingTestSuite=false] - Whether to fail test run.
881
+ * @return {Mocha} this
882
+ * @chainable
883
+ */
884
+ Mocha.prototype.passOnFailingTestSuite = function(passOnFailingTestSuite) {
885
+ this.options.passOnFailingTestSuite = passOnFailingTestSuite === true;
886
+ return this;
887
+ };
888
+
889
+ /**
890
+ * Causes tests marked `only` to fail the suite.
891
+ *
892
+ * @public
893
+ * @see [CLI option](../#-forbid-only)
894
+ * @param {boolean} [forbidOnly=true] - Whether tests marked `only` fail the suite.
895
+ * @returns {Mocha} this
896
+ * @chainable
897
+ */
898
+ Mocha.prototype.forbidOnly = function (forbidOnly) {
899
+ this.options.forbidOnly = forbidOnly !== false;
900
+ return this;
901
+ };
902
+
903
+ /**
904
+ * Causes pending tests and tests marked `skip` to fail the suite.
905
+ *
906
+ * @public
907
+ * @see [CLI option](../#-forbid-pending)
908
+ * @param {boolean} [forbidPending=true] - Whether pending tests fail the suite.
909
+ * @returns {Mocha} this
910
+ * @chainable
499
911
  */
500
- Mocha.prototype.forbidPending = function () {
501
- this.options.forbidPending = true;
912
+ Mocha.prototype.forbidPending = function (forbidPending) {
913
+ this.options.forbidPending = forbidPending !== false;
502
914
  return this;
503
915
  };
504
916
 
505
917
  /**
506
- * Run tests and invoke `fn()` when complete.
918
+ * Throws an error if mocha is in the wrong state to be able to transition to a "running" state.
919
+ * @private
920
+ */
921
+ Mocha.prototype._guardRunningStateTransition = function () {
922
+ if (this._state === mochaStates.RUNNING) {
923
+ throw createMochaInstanceAlreadyRunningError(
924
+ 'Mocha instance is currently running tests, cannot start a next test run until this one is done',
925
+ this
926
+ );
927
+ }
928
+ if (
929
+ this._state === mochaStates.DISPOSED ||
930
+ this._state === mochaStates.REFERENCES_CLEANED
931
+ ) {
932
+ throw createMochaInstanceAlreadyDisposedError(
933
+ 'Mocha instance is already disposed, cannot start a new test run. Please create a new mocha instance. Be sure to set disable `cleanReferencesAfterRun` when you want to reuse the same mocha instance for multiple test runs.',
934
+ this._cleanReferencesAfterRun,
935
+ this
936
+ );
937
+ }
938
+ };
939
+
940
+ /**
941
+ * Mocha version as specified by "package.json".
507
942
  *
508
- * @api public
509
- * @param {Function} fn
510
- * @return {Runner}
943
+ * @name Mocha#version
944
+ * @type string
945
+ * @readonly
946
+ */
947
+ Object.defineProperty(Mocha.prototype, 'version', {
948
+ value: require('../package.json').version,
949
+ configurable: false,
950
+ enumerable: true,
951
+ writable: false
952
+ });
953
+
954
+ /**
955
+ * Callback to be invoked when test execution is complete.
956
+ *
957
+ * @private
958
+ * @callback DoneCB
959
+ * @param {number} failures - Number of failures that occurred.
960
+ */
961
+
962
+ /**
963
+ * Runs root suite and invokes `fn()` when complete.
964
+ *
965
+ * @description
966
+ * To run tests multiple times (or to run tests in files that are
967
+ * already in the `require` cache), make sure to clear them from
968
+ * the cache first!
969
+ *
970
+ * @public
971
+ * @see {@link Mocha#unloadFiles}
972
+ * @see {@link Runner#run}
973
+ * @param {DoneCB} [fn] - Callback invoked when test execution completed.
974
+ * @returns {Runner} runner instance
975
+ * @example
976
+ *
977
+ * // exit with non-zero status if there were test failures
978
+ * mocha.run(failures => process.exitCode = failures ? 1 : 0);
511
979
  */
512
980
  Mocha.prototype.run = function (fn) {
513
- if (this.files.length) {
981
+ this._guardRunningStateTransition();
982
+ this._state = mochaStates.RUNNING;
983
+ if (this._previousRunner) {
984
+ this._previousRunner.dispose();
985
+ this.suite.reset();
986
+ }
987
+ if (this.files.length && !this._lazyLoadFiles) {
514
988
  this.loadFiles();
515
989
  }
516
990
  var suite = this.suite;
517
991
  var options = this.options;
518
992
  options.files = this.files;
519
- var runner = new exports.Runner(suite, options.delay);
993
+ const runner = new this._runnerClass(suite, {
994
+ cleanReferencesAfterRun: this._cleanReferencesAfterRun,
995
+ delay: options.delay,
996
+ dryRun: options.dryRun,
997
+ failZero: options.failZero
998
+ });
999
+ createStatsCollector(runner);
520
1000
  var reporter = new this._reporter(runner, options);
521
- runner.ignoreLeaks = options.ignoreLeaks !== false;
522
- runner.fullStackTrace = options.fullStackTrace;
523
- runner.hasOnly = options.hasOnly;
1001
+ runner.checkLeaks = options.checkLeaks === true;
1002
+ runner.fullStackTrace = options.fullTrace;
524
1003
  runner.asyncOnly = options.asyncOnly;
525
1004
  runner.allowUncaught = options.allowUncaught;
526
1005
  runner.forbidOnly = options.forbidOnly;
@@ -528,24 +1007,326 @@ Mocha.prototype.run = function (fn) {
528
1007
  if (options.grep) {
529
1008
  runner.grep(options.grep, options.invert);
530
1009
  }
531
- if (options.globals) {
532
- runner.globals(options.globals);
1010
+ if (options.global) {
1011
+ runner.globals(options.global);
533
1012
  }
534
- if (options.growl) {
535
- this._growl(runner, reporter);
1013
+ if (options.color !== undefined) {
1014
+ exports.reporters.Base.useColors = options.color;
536
1015
  }
537
- if (options.useColors !== undefined) {
538
- exports.reporters.Base.useColors = options.useColors;
539
- }
540
- exports.reporters.Base.inlineDiffs = options.useInlineDiffs;
1016
+ exports.reporters.Base.inlineDiffs = options.inlineDiffs;
1017
+ exports.reporters.Base.hideDiff = !options.diff;
541
1018
 
542
- function done (failures) {
543
- if (reporter.done) {
1019
+ const done = failures => {
1020
+ this._previousRunner = runner;
1021
+ this._state = this._cleanReferencesAfterRun
1022
+ ? mochaStates.REFERENCES_CLEANED
1023
+ : mochaStates.INIT;
1024
+ fn = fn || utils.noop;
1025
+ if (typeof reporter.done === 'function') {
544
1026
  reporter.done(failures, fn);
545
1027
  } else {
546
- fn && fn(failures);
1028
+ fn(failures);
1029
+ }
1030
+ };
1031
+
1032
+ const runAsync = async runner => {
1033
+ const context =
1034
+ this.options.enableGlobalSetup && this.hasGlobalSetupFixtures()
1035
+ ? await this.runGlobalSetup(runner)
1036
+ : {};
1037
+ const failureCount = await runner.runAsync({
1038
+ files: this.files,
1039
+ options
1040
+ });
1041
+ if (this.options.enableGlobalTeardown && this.hasGlobalTeardownFixtures()) {
1042
+ await this.runGlobalTeardown(runner, {context});
547
1043
  }
1044
+ return failureCount;
1045
+ };
1046
+
1047
+ // no "catch" here is intentional. errors coming out of
1048
+ // Runner#run are considered uncaught/unhandled and caught
1049
+ // by the `process` event listeners.
1050
+ // also: returning anything other than `runner` would be a breaking
1051
+ // change
1052
+ runAsync(runner).then(done);
1053
+
1054
+ return runner;
1055
+ };
1056
+
1057
+ /**
1058
+ * Assigns hooks to the root suite
1059
+ * @param {MochaRootHookObject} [hooks] - Hooks to assign to root suite
1060
+ * @chainable
1061
+ */
1062
+ Mocha.prototype.rootHooks = function rootHooks({
1063
+ beforeAll = [],
1064
+ beforeEach = [],
1065
+ afterAll = [],
1066
+ afterEach = []
1067
+ } = {}) {
1068
+ beforeAll = utils.castArray(beforeAll);
1069
+ beforeEach = utils.castArray(beforeEach);
1070
+ afterAll = utils.castArray(afterAll);
1071
+ afterEach = utils.castArray(afterEach);
1072
+ beforeAll.forEach(hook => {
1073
+ this.suite.beforeAll(hook);
1074
+ });
1075
+ beforeEach.forEach(hook => {
1076
+ this.suite.beforeEach(hook);
1077
+ });
1078
+ afterAll.forEach(hook => {
1079
+ this.suite.afterAll(hook);
1080
+ });
1081
+ afterEach.forEach(hook => {
1082
+ this.suite.afterEach(hook);
1083
+ });
1084
+ return this;
1085
+ };
1086
+
1087
+ /**
1088
+ * Toggles parallel mode.
1089
+ *
1090
+ * Must be run before calling {@link Mocha#run}. Changes the `Runner` class to
1091
+ * use; also enables lazy file loading if not already done so.
1092
+ *
1093
+ * 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
1094
+ * mode, but parallel mode is _not_ a prerequisite for lazy loading!
1095
+ * @param {boolean} [enable] - If `true`, enable; otherwise disable.
1096
+ * @throws If run in browser
1097
+ * @throws If Mocha not in `INIT` state
1098
+ * @returns {Mocha}
1099
+ * @chainable
1100
+ * @public
1101
+ */
1102
+ Mocha.prototype.parallelMode = function parallelMode(enable = true) {
1103
+ if (utils.isBrowser()) {
1104
+ throw createUnsupportedError('parallel mode is only supported in Node.js');
1105
+ }
1106
+ const parallel = Boolean(enable);
1107
+ if (
1108
+ parallel === this.options.parallel &&
1109
+ this._lazyLoadFiles &&
1110
+ this._runnerClass !== exports.Runner
1111
+ ) {
1112
+ return this;
1113
+ }
1114
+ if (this._state !== mochaStates.INIT) {
1115
+ throw createUnsupportedError(
1116
+ 'cannot change parallel mode after having called run()'
1117
+ );
548
1118
  }
1119
+ this.options.parallel = parallel;
549
1120
 
550
- return runner.run(done);
1121
+ // swap Runner class
1122
+ this._runnerClass = parallel
1123
+ ? require('./nodejs/parallel-buffered-runner')
1124
+ : exports.Runner;
1125
+
1126
+ // lazyLoadFiles may have been set `true` otherwise (for ESM loading),
1127
+ // so keep `true` if so.
1128
+ return this.lazyLoadFiles(this._lazyLoadFiles || parallel);
551
1129
  };
1130
+
1131
+ /**
1132
+ * Disables implicit call to {@link Mocha#loadFiles} in {@link Mocha#run}. This
1133
+ * setting is used by watch mode, parallel mode, and for loading ESM files.
1134
+ * @todo This should throw if we've already loaded files; such behavior
1135
+ * necessitates adding a new state.
1136
+ * @param {boolean} [enable] - If `true`, disable eager loading of files in
1137
+ * {@link Mocha#run}
1138
+ * @chainable
1139
+ * @public
1140
+ */
1141
+ Mocha.prototype.lazyLoadFiles = function lazyLoadFiles(enable) {
1142
+ this._lazyLoadFiles = enable === true;
1143
+ debug('set lazy load to %s', enable);
1144
+ return this;
1145
+ };
1146
+
1147
+ /**
1148
+ * Configures one or more global setup fixtures.
1149
+ *
1150
+ * If given no parameters, _unsets_ any previously-set fixtures.
1151
+ * @chainable
1152
+ * @public
1153
+ * @param {MochaGlobalFixture|MochaGlobalFixture[]} [setupFns] - Global setup fixture(s)
1154
+ * @returns {Mocha}
1155
+ */
1156
+ Mocha.prototype.globalSetup = function globalSetup(setupFns = []) {
1157
+ setupFns = utils.castArray(setupFns);
1158
+ this.options.globalSetup = setupFns;
1159
+ debug('configured %d global setup functions', setupFns.length);
1160
+ return this;
1161
+ };
1162
+
1163
+ /**
1164
+ * Configures one or more global teardown fixtures.
1165
+ *
1166
+ * If given no parameters, _unsets_ any previously-set fixtures.
1167
+ * @chainable
1168
+ * @public
1169
+ * @param {MochaGlobalFixture|MochaGlobalFixture[]} [teardownFns] - Global teardown fixture(s)
1170
+ * @returns {Mocha}
1171
+ */
1172
+ Mocha.prototype.globalTeardown = function globalTeardown(teardownFns = []) {
1173
+ teardownFns = utils.castArray(teardownFns);
1174
+ this.options.globalTeardown = teardownFns;
1175
+ debug('configured %d global teardown functions', teardownFns.length);
1176
+ return this;
1177
+ };
1178
+
1179
+ /**
1180
+ * Run any global setup fixtures sequentially, if any.
1181
+ *
1182
+ * This is _automatically called_ by {@link Mocha#run} _unless_ the `runGlobalSetup` option is `false`; see {@link Mocha#enableGlobalSetup}.
1183
+ *
1184
+ * The context object this function resolves with should be consumed by {@link Mocha#runGlobalTeardown}.
1185
+ * @param {object} [context] - Context object if already have one
1186
+ * @public
1187
+ * @returns {Promise<object>} Context object
1188
+ */
1189
+ Mocha.prototype.runGlobalSetup = async function runGlobalSetup(context = {}) {
1190
+ const {globalSetup} = this.options;
1191
+ if (globalSetup && globalSetup.length) {
1192
+ debug('run(): global setup starting');
1193
+ await this._runGlobalFixtures(globalSetup, context);
1194
+ debug('run(): global setup complete');
1195
+ }
1196
+ return context;
1197
+ };
1198
+
1199
+ /**
1200
+ * Run any global teardown fixtures sequentially, if any.
1201
+ *
1202
+ * This is _automatically called_ by {@link Mocha#run} _unless_ the `runGlobalTeardown` option is `false`; see {@link Mocha#enableGlobalTeardown}.
1203
+ *
1204
+ * Should be called with context object returned by {@link Mocha#runGlobalSetup}, if applicable.
1205
+ * @param {object} [context] - Context object if already have one
1206
+ * @public
1207
+ * @returns {Promise<object>} Context object
1208
+ */
1209
+ Mocha.prototype.runGlobalTeardown = async function runGlobalTeardown(
1210
+ context = {}
1211
+ ) {
1212
+ const {globalTeardown} = this.options;
1213
+ if (globalTeardown && globalTeardown.length) {
1214
+ debug('run(): global teardown starting');
1215
+ await this._runGlobalFixtures(globalTeardown, context);
1216
+ }
1217
+ debug('run(): global teardown complete');
1218
+ return context;
1219
+ };
1220
+
1221
+ /**
1222
+ * Run global fixtures sequentially with context `context`
1223
+ * @private
1224
+ * @param {MochaGlobalFixture[]} [fixtureFns] - Fixtures to run
1225
+ * @param {object} [context] - context object
1226
+ * @returns {Promise<object>} context object
1227
+ */
1228
+ Mocha.prototype._runGlobalFixtures = async function _runGlobalFixtures(
1229
+ fixtureFns = [],
1230
+ context = {}
1231
+ ) {
1232
+ for await (const fixtureFn of fixtureFns) {
1233
+ await fixtureFn.call(context);
1234
+ }
1235
+ return context;
1236
+ };
1237
+
1238
+ /**
1239
+ * Toggle execution of any global setup fixture(s)
1240
+ *
1241
+ * @chainable
1242
+ * @public
1243
+ * @param {boolean } [enabled=true] - If `false`, do not run global setup fixture
1244
+ * @returns {Mocha}
1245
+ */
1246
+ Mocha.prototype.enableGlobalSetup = function enableGlobalSetup(enabled = true) {
1247
+ this.options.enableGlobalSetup = Boolean(enabled);
1248
+ return this;
1249
+ };
1250
+
1251
+ /**
1252
+ * Toggle execution of any global teardown fixture(s)
1253
+ *
1254
+ * @chainable
1255
+ * @public
1256
+ * @param {boolean } [enabled=true] - If `false`, do not run global teardown fixture
1257
+ * @returns {Mocha}
1258
+ */
1259
+ Mocha.prototype.enableGlobalTeardown = function enableGlobalTeardown(
1260
+ enabled = true
1261
+ ) {
1262
+ this.options.enableGlobalTeardown = Boolean(enabled);
1263
+ return this;
1264
+ };
1265
+
1266
+ /**
1267
+ * Returns `true` if one or more global setup fixtures have been supplied.
1268
+ * @public
1269
+ * @returns {boolean}
1270
+ */
1271
+ Mocha.prototype.hasGlobalSetupFixtures = function hasGlobalSetupFixtures() {
1272
+ return Boolean(this.options.globalSetup.length);
1273
+ };
1274
+
1275
+ /**
1276
+ * Returns `true` if one or more global teardown fixtures have been supplied.
1277
+ * @public
1278
+ * @returns {boolean}
1279
+ */
1280
+ Mocha.prototype.hasGlobalTeardownFixtures =
1281
+ function hasGlobalTeardownFixtures() {
1282
+ return Boolean(this.options.globalTeardown.length);
1283
+ };
1284
+
1285
+ /**
1286
+ * An alternative way to define root hooks that works with parallel runs.
1287
+ * @typedef {Object} MochaRootHookObject
1288
+ * @property {Function|Function[]} [beforeAll] - "Before all" hook(s)
1289
+ * @property {Function|Function[]} [beforeEach] - "Before each" hook(s)
1290
+ * @property {Function|Function[]} [afterAll] - "After all" hook(s)
1291
+ * @property {Function|Function[]} [afterEach] - "After each" hook(s)
1292
+ */
1293
+
1294
+ /**
1295
+ * An function that returns a {@link MochaRootHookObject}, either sync or async.
1296
+ @callback MochaRootHookFunction
1297
+ * @returns {MochaRootHookObject|Promise<MochaRootHookObject>}
1298
+ */
1299
+
1300
+ /**
1301
+ * A function that's invoked _once_ which is either sync or async.
1302
+ * Can be a "teardown" or "setup". These will all share the same context.
1303
+ * @callback MochaGlobalFixture
1304
+ * @returns {void|Promise<void>}
1305
+ */
1306
+
1307
+ /**
1308
+ * An object making up all necessary parts of a plugin loader and aggregator
1309
+ * @typedef {Object} PluginDefinition
1310
+ * @property {string} exportName - Named export to use
1311
+ * @property {string} [optionName] - Option name for Mocha constructor (use `exportName` if omitted)
1312
+ * @property {PluginValidator} [validate] - Validator function
1313
+ * @property {PluginFinalizer} [finalize] - Finalizer/aggregator function
1314
+ */
1315
+
1316
+ /**
1317
+ * A (sync) function to assert a user-supplied plugin implementation is valid.
1318
+ *
1319
+ * Defined in a {@link PluginDefinition}.
1320
+
1321
+ * @callback PluginValidator
1322
+ * @param {*} value - Value to check
1323
+ * @this {PluginDefinition}
1324
+ * @returns {void}
1325
+ */
1326
+
1327
+ /**
1328
+ * A function to finalize plugins impls of a particular ilk
1329
+ * @callback PluginFinalizer
1330
+ * @param {Array<*>} impls - User-supplied implementations
1331
+ * @returns {Promise<*>|*}
1332
+ */