mocha 7.1.2 → 8.1.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +143 -2
  2. package/bin/mocha +24 -4
  3. package/browser-entry.js +37 -9
  4. package/lib/browser/growl.js +2 -1
  5. package/lib/browser/highlight-tags.js +39 -0
  6. package/lib/browser/parse-query.js +24 -0
  7. package/lib/browser/progress.js +4 -0
  8. package/lib/browser/template.html +7 -5
  9. package/lib/cli/cli.js +6 -3
  10. package/lib/cli/collect-files.js +17 -10
  11. package/lib/cli/config.js +6 -6
  12. package/lib/cli/init.js +1 -2
  13. package/lib/cli/lookup-files.js +145 -0
  14. package/lib/cli/node-flags.js +2 -2
  15. package/lib/cli/options.js +14 -90
  16. package/lib/cli/run-helpers.js +133 -36
  17. package/lib/cli/run-option-metadata.js +4 -2
  18. package/lib/cli/run.js +71 -11
  19. package/lib/cli/watch-run.js +211 -51
  20. package/lib/context.js +0 -15
  21. package/lib/errors.js +202 -9
  22. package/lib/esm-utils.js +11 -6
  23. package/lib/hook.js +32 -0
  24. package/lib/interfaces/common.js +21 -10
  25. package/lib/mocha.js +301 -126
  26. package/lib/mocharc.json +0 -1
  27. package/lib/nodejs/buffered-worker-pool.js +174 -0
  28. package/lib/{growl.js → nodejs/growl.js} +3 -2
  29. package/lib/nodejs/parallel-buffered-runner.js +295 -0
  30. package/lib/nodejs/reporters/parallel-buffered.js +133 -0
  31. package/lib/nodejs/serializer.js +404 -0
  32. package/lib/nodejs/worker.js +154 -0
  33. package/lib/pending.js +4 -0
  34. package/lib/reporters/base.js +25 -12
  35. package/lib/reporters/doc.js +6 -0
  36. package/lib/reporters/json-stream.js +1 -0
  37. package/lib/reporters/json.js +1 -0
  38. package/lib/reporters/landing.js +11 -3
  39. package/lib/reporters/tap.js +1 -2
  40. package/lib/reporters/xunit.js +3 -2
  41. package/lib/runnable.js +39 -47
  42. package/lib/runner.js +219 -118
  43. package/lib/suite.js +61 -27
  44. package/lib/test.js +48 -3
  45. package/lib/utils.js +33 -209
  46. package/mocha.js +25522 -17715
  47. package/mocha.js.map +1 -0
  48. package/package.json +87 -68
  49. package/lib/browser/tty.js +0 -13
package/lib/mocha.js CHANGED
@@ -9,40 +9,72 @@
9
9
  var escapeRe = require('escape-string-regexp');
10
10
  var path = require('path');
11
11
  var builtinReporters = require('./reporters');
12
- var growl = require('./growl');
12
+ var growl = require('./nodejs/growl');
13
13
  var utils = require('./utils');
14
14
  var mocharc = require('./mocharc.json');
15
15
  var errors = require('./errors');
16
16
  var Suite = require('./suite');
17
- var esmUtils = utils.supportsEsModules() ? require('./esm-utils') : undefined;
17
+ var esmUtils = utils.supportsEsModules(true)
18
+ ? require('./esm-utils')
19
+ : undefined;
18
20
  var createStatsCollector = require('./stats-collector');
19
21
  var createInvalidReporterError = errors.createInvalidReporterError;
20
22
  var createInvalidInterfaceError = errors.createInvalidInterfaceError;
23
+ var createMochaInstanceAlreadyDisposedError =
24
+ errors.createMochaInstanceAlreadyDisposedError;
25
+ var createMochaInstanceAlreadyRunningError =
26
+ errors.createMochaInstanceAlreadyRunningError;
21
27
  var EVENT_FILE_PRE_REQUIRE = Suite.constants.EVENT_FILE_PRE_REQUIRE;
22
28
  var EVENT_FILE_POST_REQUIRE = Suite.constants.EVENT_FILE_POST_REQUIRE;
23
29
  var EVENT_FILE_REQUIRE = Suite.constants.EVENT_FILE_REQUIRE;
24
30
  var sQuote = utils.sQuote;
31
+ var debug = require('debug')('mocha:mocha');
25
32
 
26
33
  exports = module.exports = Mocha;
27
34
 
35
+ /**
36
+ * A Mocha instance is a finite state machine.
37
+ * These are the states it can be in.
38
+ * @private
39
+ */
40
+ var mochaStates = utils.defineConstants({
41
+ /**
42
+ * Initial state of the mocha instance
43
+ * @private
44
+ */
45
+ INIT: 'init',
46
+ /**
47
+ * Mocha instance is running tests
48
+ * @private
49
+ */
50
+ RUNNING: 'running',
51
+ /**
52
+ * Mocha instance is done running tests and references to test functions and hooks are cleaned.
53
+ * You can reset this state by unloading the test files.
54
+ * @private
55
+ */
56
+ REFERENCES_CLEANED: 'referencesCleaned',
57
+ /**
58
+ * Mocha instance is disposed and can no longer be used.
59
+ * @private
60
+ */
61
+ DISPOSED: 'disposed'
62
+ });
63
+
28
64
  /**
29
65
  * To require local UIs and reporters when running in node.
30
66
  */
31
67
 
32
- if (!process.browser) {
33
- var cwd = process.cwd();
68
+ if (!utils.isBrowser() && typeof module.paths !== 'undefined') {
69
+ var cwd = utils.cwd();
34
70
  module.paths.push(cwd, path.join(cwd, 'node_modules'));
35
71
  }
36
72
 
37
73
  /**
38
74
  * Expose internals.
75
+ * @private
39
76
  */
40
77
 
41
- /**
42
- * @public
43
- * @class utils
44
- * @memberof Mocha
45
- */
46
78
  exports.utils = utils;
47
79
  exports.interfaces = require('./interfaces');
48
80
  /**
@@ -90,6 +122,11 @@ exports.Test = require('./test');
90
122
  * @param {number} [options.slow] - Slow threshold value.
91
123
  * @param {number|string} [options.timeout] - Timeout threshold value.
92
124
  * @param {string} [options.ui] - Interface name.
125
+ * @param {boolean} [options.parallel] - Run jobs in parallel
126
+ * @param {number} [options.jobs] - Max number of worker processes for parallel runs
127
+ * @param {MochaRootHookObject} [options.rootHooks] - Hooks to bootstrap the root
128
+ * suite with
129
+ * @param {boolean} [options.isWorker] - Should be `true` if `Mocha` process is running in a worker process.
93
130
  */
94
131
  function Mocha(options) {
95
132
  options = utils.assign({}, mocharc, options || {});
@@ -97,6 +134,8 @@ function Mocha(options) {
97
134
  this.options = options;
98
135
  // root suite
99
136
  this.suite = new exports.Suite('', new exports.Context(), true);
137
+ this._cleanReferencesAfterRun = true;
138
+ this._state = mochaStates.INIT;
100
139
 
101
140
  this.grep(options.grep)
102
141
  .fgrep(options.fgrep)
@@ -136,6 +175,43 @@ function Mocha(options) {
136
175
  this[opt]();
137
176
  }
138
177
  }, this);
178
+
179
+ if (options.rootHooks) {
180
+ this.rootHooks(options.rootHooks);
181
+ }
182
+
183
+ /**
184
+ * The class which we'll instantiate in {@link Mocha#run}. Defaults to
185
+ * {@link Runner} in serial mode; changes in parallel mode.
186
+ * @memberof Mocha
187
+ * @private
188
+ */
189
+ this._runnerClass = exports.Runner;
190
+
191
+ /**
192
+ * Whether or not to call {@link Mocha#loadFiles} implicitly when calling
193
+ * {@link Mocha#run}. If this is `true`, then it's up to the consumer to call
194
+ * {@link Mocha#loadFiles} _or_ {@link Mocha#loadFilesAsync}.
195
+ * @private
196
+ * @memberof Mocha
197
+ */
198
+ this._lazyLoadFiles = false;
199
+
200
+ /**
201
+ * It's useful for a Mocha instance to know if it's running in a worker process.
202
+ * We could derive this via other means, but it's helpful to have a flag to refer to.
203
+ * @memberof Mocha
204
+ * @private
205
+ */
206
+ this.isWorker = Boolean(options.isWorker);
207
+
208
+ if (
209
+ options.parallel &&
210
+ (typeof options.jobs === 'undefined' || options.jobs > 1)
211
+ ) {
212
+ debug('attempting to enable parallel mode');
213
+ this.parallelMode(true);
214
+ }
139
215
  }
140
216
 
141
217
  /**
@@ -176,7 +252,7 @@ Mocha.prototype.addFile = function(file) {
176
252
  * @public
177
253
  * @see [CLI option](../#-reporter-name-r-name)
178
254
  * @see [Reporters](../#reporters)
179
- * @param {String|Function} reporter - Reporter name or constructor.
255
+ * @param {String|Function} reporterName - Reporter name or constructor.
180
256
  * @param {Object} [reporterOptions] - Options used to configure the reporter.
181
257
  * @returns {Mocha} this
182
258
  * @chainable
@@ -186,52 +262,52 @@ Mocha.prototype.addFile = function(file) {
186
262
  * // Use XUnit reporter and direct its output to file
187
263
  * mocha.reporter('xunit', { output: '/path/to/testspec.xunit.xml' });
188
264
  */
189
- Mocha.prototype.reporter = function(reporter, reporterOptions) {
190
- if (typeof reporter === 'function') {
191
- this._reporter = reporter;
265
+ Mocha.prototype.reporter = function(reporterName, reporterOptions) {
266
+ if (typeof reporterName === 'function') {
267
+ this._reporter = reporterName;
192
268
  } else {
193
- reporter = reporter || 'spec';
194
- var _reporter;
269
+ reporterName = reporterName || 'spec';
270
+ var reporter;
195
271
  // Try to load a built-in reporter.
196
- if (builtinReporters[reporter]) {
197
- _reporter = builtinReporters[reporter];
272
+ if (builtinReporters[reporterName]) {
273
+ reporter = builtinReporters[reporterName];
198
274
  }
199
275
  // Try to load reporters from process.cwd() and node_modules
200
- if (!_reporter) {
276
+ if (!reporter) {
201
277
  try {
202
- _reporter = require(reporter);
278
+ reporter = require(reporterName);
203
279
  } catch (err) {
204
280
  if (
205
- err.code !== 'MODULE_NOT_FOUND' ||
206
- err.message.indexOf('Cannot find module') !== -1
281
+ err.code === 'MODULE_NOT_FOUND' ||
282
+ err.message.indexOf('Cannot find module') >= 0
207
283
  ) {
208
284
  // Try to load reporters from a path (absolute or relative)
209
285
  try {
210
- _reporter = require(path.resolve(process.cwd(), reporter));
286
+ reporter = require(path.resolve(utils.cwd(), reporterName));
211
287
  } catch (_err) {
212
- _err.code !== 'MODULE_NOT_FOUND' ||
213
- _err.message.indexOf('Cannot find module') !== -1
214
- ? console.warn(sQuote(reporter) + ' reporter not found')
215
- : console.warn(
216
- sQuote(reporter) +
288
+ _err.code === 'MODULE_NOT_FOUND' ||
289
+ _err.message.indexOf('Cannot find module') >= 0
290
+ ? utils.warn(sQuote(reporterName) + ' reporter not found')
291
+ : utils.warn(
292
+ sQuote(reporterName) +
217
293
  ' reporter blew up with error:\n' +
218
294
  err.stack
219
295
  );
220
296
  }
221
297
  } else {
222
- console.warn(
223
- sQuote(reporter) + ' reporter blew up with error:\n' + err.stack
298
+ utils.warn(
299
+ sQuote(reporterName) + ' reporter blew up with error:\n' + err.stack
224
300
  );
225
301
  }
226
302
  }
227
303
  }
228
- if (!_reporter) {
304
+ if (!reporter) {
229
305
  throw createInvalidReporterError(
230
- 'invalid reporter ' + sQuote(reporter),
231
- reporter
306
+ 'invalid reporter ' + sQuote(reporterName),
307
+ reporterName
232
308
  );
233
309
  }
234
- this._reporter = _reporter;
310
+ this._reporter = reporter;
235
311
  }
236
312
  this.options.reporterOption = reporterOptions;
237
313
  // alias option name is used in public reporters xunit/tap/progress
@@ -340,7 +416,7 @@ Mocha.prototype.loadFiles = function(fn) {
340
416
  Mocha.prototype.loadFilesAsync = function() {
341
417
  var self = this;
342
418
  var suite = this.suite;
343
- this.loadAsync = true;
419
+ this.lazyLoadFiles(true);
344
420
 
345
421
  if (!esmUtils) {
346
422
  return new Promise(function(resolve) {
@@ -388,7 +464,18 @@ Mocha.unloadFile = function(file) {
388
464
  * @chainable
389
465
  */
390
466
  Mocha.prototype.unloadFiles = function() {
391
- this.files.forEach(Mocha.unloadFile);
467
+ if (this._state === mochaStates.DISPOSED) {
468
+ throw createMochaInstanceAlreadyDisposedError(
469
+ 'Mocha instance is already disposed, it cannot be used again.',
470
+ this._cleanReferencesAfterRun,
471
+ this
472
+ );
473
+ }
474
+
475
+ this.files.forEach(function(file) {
476
+ Mocha.unloadFile(file);
477
+ });
478
+ this._state = mochaStates.INIT;
392
479
  return this;
393
480
  };
394
481
 
@@ -475,37 +562,51 @@ Mocha.prototype.invert = function() {
475
562
  };
476
563
 
477
564
  /**
478
- * Enables or disables ignoring global leaks.
565
+ * Enables or disables checking for global variables leaked while running tests.
479
566
  *
480
- * @deprecated since v7.0.0
481
567
  * @public
482
- * @see {@link Mocha#checkLeaks}
483
- * @param {boolean} [ignoreLeaks=false] - Whether to ignore global leaks.
568
+ * @see [CLI option](../#-check-leaks)
569
+ * @param {boolean} [checkLeaks=true] - Whether to check for global variable leaks.
484
570
  * @return {Mocha} this
485
571
  * @chainable
486
572
  */
487
- Mocha.prototype.ignoreLeaks = function(ignoreLeaks) {
488
- utils.deprecate(
489
- '"ignoreLeaks()" is DEPRECATED, please use "checkLeaks()" instead.'
490
- );
491
- this.options.checkLeaks = !ignoreLeaks;
573
+ Mocha.prototype.checkLeaks = function(checkLeaks) {
574
+ this.options.checkLeaks = checkLeaks !== false;
492
575
  return this;
493
576
  };
494
577
 
495
578
  /**
496
- * Enables or disables checking for global variables leaked while running tests.
497
- *
579
+ * Enables or disables whether or not to dispose after each test run.
580
+ * Disable this to ensure you can run the test suite multiple times.
581
+ * If disabled, be sure to dispose mocha when you're done to prevent memory leaks.
498
582
  * @public
499
- * @see [CLI option](../#-check-leaks)
500
- * @param {boolean} [checkLeaks=true] - Whether to check for global variable leaks.
583
+ * @see {@link Mocha#dispose}
584
+ * @param {boolean} cleanReferencesAfterRun
501
585
  * @return {Mocha} this
502
586
  * @chainable
503
587
  */
504
- Mocha.prototype.checkLeaks = function(checkLeaks) {
505
- this.options.checkLeaks = checkLeaks !== false;
588
+ Mocha.prototype.cleanReferencesAfterRun = function(cleanReferencesAfterRun) {
589
+ this._cleanReferencesAfterRun = cleanReferencesAfterRun !== false;
506
590
  return this;
507
591
  };
508
592
 
593
+ /**
594
+ * Manually dispose this mocha instance. Mark this instance as `disposed` and unable to run more tests.
595
+ * It also removes function references to tests functions and hooks, so variables trapped in closures can be cleaned by the garbage collector.
596
+ * @public
597
+ */
598
+ Mocha.prototype.dispose = function() {
599
+ if (this._state === mochaStates.RUNNING) {
600
+ throw createMochaInstanceAlreadyRunningError(
601
+ 'Cannot dispose while the mocha instance is still running tests.'
602
+ );
603
+ }
604
+ this.unloadFiles();
605
+ this._previousRunner && this._previousRunner.dispose();
606
+ this.suite.dispose();
607
+ this._state = mochaStates.DISPOSED;
608
+ };
609
+
509
610
  /**
510
611
  * Displays full stack trace upon test failure.
511
612
  *
@@ -531,7 +632,7 @@ Mocha.prototype.fullTrace = function(fullTrace) {
531
632
  Mocha.prototype.growl = function() {
532
633
  this.options.growl = this.isGrowlCapable();
533
634
  if (!this.options.growl) {
534
- var detail = process.browser
635
+ var detail = utils.isBrowser()
535
636
  ? 'notification support not available in this browser...'
536
637
  : 'notification support prerequisites not installed...';
537
638
  console.error(detail + ' cannot enable!');
@@ -589,24 +690,6 @@ Mocha.prototype.global = function(global) {
589
690
  // for backwards compability, 'globals' is an alias of 'global'
590
691
  Mocha.prototype.globals = Mocha.prototype.global;
591
692
 
592
- /**
593
- * Enables or disables TTY color output by screen-oriented reporters.
594
- *
595
- * @deprecated since v7.0.0
596
- * @public
597
- * @see {@link Mocha#color}
598
- * @param {boolean} colors - Whether to enable color output.
599
- * @return {Mocha} this
600
- * @chainable
601
- */
602
- Mocha.prototype.useColors = function(colors) {
603
- utils.deprecate('"useColors()" is DEPRECATED, please use "color()" instead.');
604
- if (colors !== undefined) {
605
- this.options.color = colors;
606
- }
607
- return this;
608
- };
609
-
610
693
  /**
611
694
  * Enables or disables TTY color output by screen-oriented reporters.
612
695
  *
@@ -621,25 +704,6 @@ Mocha.prototype.color = function(color) {
621
704
  return this;
622
705
  };
623
706
 
624
- /**
625
- * Determines if reporter should use inline diffs (rather than +/-)
626
- * in test failure output.
627
- *
628
- * @deprecated since v7.0.0
629
- * @public
630
- * @see {@link Mocha#inlineDiffs}
631
- * @param {boolean} [inlineDiffs=false] - Whether to use inline diffs.
632
- * @return {Mocha} this
633
- * @chainable
634
- */
635
- Mocha.prototype.useInlineDiffs = function(inlineDiffs) {
636
- utils.deprecate(
637
- '"useInlineDiffs()" is DEPRECATED, please use "inlineDiffs()" instead.'
638
- );
639
- this.options.inlineDiffs = inlineDiffs !== undefined && inlineDiffs;
640
- return this;
641
- };
642
-
643
707
  /**
644
708
  * Enables or disables reporter to use inline diffs (rather than +/-)
645
709
  * in test failure output.
@@ -655,22 +719,6 @@ Mocha.prototype.inlineDiffs = function(inlineDiffs) {
655
719
  return this;
656
720
  };
657
721
 
658
- /**
659
- * Determines if reporter should include diffs in test failure output.
660
- *
661
- * @deprecated since v7.0.0
662
- * @public
663
- * @see {@link Mocha#diff}
664
- * @param {boolean} [hideDiff=false] - Whether to hide diffs.
665
- * @return {Mocha} this
666
- * @chainable
667
- */
668
- Mocha.prototype.hideDiff = function(hideDiff) {
669
- utils.deprecate('"hideDiff()" is DEPRECATED, please use "diff()" instead.');
670
- this.options.diff = !(hideDiff === true);
671
- return this;
672
- };
673
-
674
722
  /**
675
723
  * Enables or disables reporter to include diff in test failure output.
676
724
  *
@@ -696,7 +744,6 @@ Mocha.prototype.diff = function(diff) {
696
744
  * @public
697
745
  * @see [CLI option](../#-timeout-ms-t-ms)
698
746
  * @see [Timeouts](../#timeouts)
699
- * @see {@link Mocha#enableTimeouts}
700
747
  * @param {number|string} msecs - Timeout threshold value.
701
748
  * @return {Mocha} this
702
749
  * @chainable
@@ -728,8 +775,8 @@ Mocha.prototype.timeout = function(msecs) {
728
775
  * // Allow any failed test to retry one more time
729
776
  * mocha.retries(1);
730
777
  */
731
- Mocha.prototype.retries = function(n) {
732
- this.suite.retries(n);
778
+ Mocha.prototype.retries = function(retry) {
779
+ this.suite.retries(retry);
733
780
  return this;
734
781
  };
735
782
 
@@ -755,22 +802,6 @@ Mocha.prototype.slow = function(msecs) {
755
802
  return this;
756
803
  };
757
804
 
758
- /**
759
- * Enables or disables timeouts.
760
- *
761
- * @public
762
- * @see [CLI option](../#-timeout-ms-t-ms)
763
- * @param {boolean} enableTimeouts - Whether to enable timeouts.
764
- * @return {Mocha} this
765
- * @chainable
766
- */
767
- Mocha.prototype.enableTimeouts = function(enableTimeouts) {
768
- this.suite.enableTimeouts(
769
- arguments.length && enableTimeouts !== undefined ? enableTimeouts : true
770
- );
771
- return this;
772
- };
773
-
774
805
  /**
775
806
  * Forces all tests to either accept a `done` callback or return a promise.
776
807
  *
@@ -856,6 +887,29 @@ Mocha.prototype.forbidPending = function(forbidPending) {
856
887
  return this;
857
888
  };
858
889
 
890
+ /**
891
+ * Throws an error if mocha is in the wrong state to be able to transition to a "running" state.
892
+ * @private
893
+ */
894
+ Mocha.prototype._guardRunningStateTransition = function() {
895
+ if (this._state === mochaStates.RUNNING) {
896
+ throw createMochaInstanceAlreadyRunningError(
897
+ 'Mocha instance is currently running tests, cannot start a next test run until this one is done',
898
+ this
899
+ );
900
+ }
901
+ if (
902
+ this._state === mochaStates.DISPOSED ||
903
+ this._state === mochaStates.REFERENCES_CLEANED
904
+ ) {
905
+ throw createMochaInstanceAlreadyDisposedError(
906
+ '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.',
907
+ this._cleanReferencesAfterRun,
908
+ this
909
+ );
910
+ }
911
+ };
912
+
859
913
  /**
860
914
  * Mocha version as specified by "package.json".
861
915
  *
@@ -873,6 +927,7 @@ Object.defineProperty(Mocha.prototype, 'version', {
873
927
  /**
874
928
  * Callback to be invoked when test execution is complete.
875
929
  *
930
+ * @private
876
931
  * @callback DoneCB
877
932
  * @param {number} failures - Number of failures that occurred.
878
933
  */
@@ -896,13 +951,23 @@ Object.defineProperty(Mocha.prototype, 'version', {
896
951
  * mocha.run(failures => process.exitCode = failures ? 1 : 0);
897
952
  */
898
953
  Mocha.prototype.run = function(fn) {
899
- if (this.files.length && !this.loadAsync) {
954
+ this._guardRunningStateTransition();
955
+ this._state = mochaStates.RUNNING;
956
+ if (this._previousRunner) {
957
+ this._previousRunner.dispose();
958
+ this.suite.reset();
959
+ }
960
+ if (this.files.length && !this._lazyLoadFiles) {
900
961
  this.loadFiles();
901
962
  }
963
+ var self = this;
902
964
  var suite = this.suite;
903
965
  var options = this.options;
904
966
  options.files = this.files;
905
- var runner = new exports.Runner(suite, options.delay);
967
+ var runner = new this._runnerClass(suite, {
968
+ delay: options.delay,
969
+ cleanReferencesAfterRun: this._cleanReferencesAfterRun
970
+ });
906
971
  createStatsCollector(runner);
907
972
  var reporter = new this._reporter(runner, options);
908
973
  runner.checkLeaks = options.checkLeaks === true;
@@ -927,6 +992,12 @@ Mocha.prototype.run = function(fn) {
927
992
  exports.reporters.Base.hideDiff = !options.diff;
928
993
 
929
994
  function done(failures) {
995
+ self._previousRunner = runner;
996
+ if (self._cleanReferencesAfterRun) {
997
+ self._state = mochaStates.REFERENCES_CLEANED;
998
+ } else {
999
+ self._state = mochaStates.INIT;
1000
+ }
930
1001
  fn = fn || utils.noop;
931
1002
  if (reporter.done) {
932
1003
  reporter.done(failures, fn);
@@ -935,5 +1006,109 @@ Mocha.prototype.run = function(fn) {
935
1006
  }
936
1007
  }
937
1008
 
938
- return runner.run(done);
1009
+ return runner.run(done, {files: this.files, options: options});
1010
+ };
1011
+
1012
+ /**
1013
+ * Assigns hooks to the root suite
1014
+ * @param {MochaRootHookObject} [hooks] - Hooks to assign to root suite
1015
+ * @chainable
1016
+ */
1017
+ Mocha.prototype.rootHooks = function rootHooks(hooks) {
1018
+ if (utils.type(hooks) === 'object') {
1019
+ var beforeAll = [].concat(hooks.beforeAll || []);
1020
+ var beforeEach = [].concat(hooks.beforeEach || []);
1021
+ var afterAll = [].concat(hooks.afterAll || []);
1022
+ var afterEach = [].concat(hooks.afterEach || []);
1023
+ var rootSuite = this.suite;
1024
+ beforeAll.forEach(function(hook) {
1025
+ rootSuite.beforeAll(hook);
1026
+ });
1027
+ beforeEach.forEach(function(hook) {
1028
+ rootSuite.beforeEach(hook);
1029
+ });
1030
+ afterAll.forEach(function(hook) {
1031
+ rootSuite.afterAll(hook);
1032
+ });
1033
+ afterEach.forEach(function(hook) {
1034
+ rootSuite.afterEach(hook);
1035
+ });
1036
+ }
1037
+ return this;
1038
+ };
1039
+
1040
+ /**
1041
+ * Toggles parallel mode.
1042
+ *
1043
+ * Must be run before calling {@link Mocha#run}. Changes the `Runner` class to
1044
+ * use; also enables lazy file loading if not already done so.
1045
+ * @param {boolean} [enable] - If `true`, enable; otherwise disable.
1046
+ * @throws If run in browser
1047
+ * @throws If Mocha not in "INIT" state
1048
+ * @returns {Mocha}
1049
+ * @chainable
1050
+ * @public
1051
+ */
1052
+ Mocha.prototype.parallelMode = function parallelMode(enable) {
1053
+ if (utils.isBrowser()) {
1054
+ throw errors.createUnsupportedError(
1055
+ 'parallel mode is only supported in Node.js'
1056
+ );
1057
+ }
1058
+ var parallel = enable === true;
1059
+ if (
1060
+ parallel === this.options.parallel &&
1061
+ this._lazyLoadFiles &&
1062
+ this._runnerClass !== exports.Runner
1063
+ ) {
1064
+ return this;
1065
+ }
1066
+ if (this._state !== mochaStates.INIT) {
1067
+ throw errors.createUnsupportedError(
1068
+ 'cannot change parallel mode after having called run()'
1069
+ );
1070
+ }
1071
+ this.options.parallel = parallel;
1072
+
1073
+ // swap Runner class
1074
+ this._runnerClass = parallel
1075
+ ? require('./nodejs/parallel-buffered-runner')
1076
+ : exports.Runner;
1077
+
1078
+ // lazyLoadFiles may have been set `true` otherwise (for ESM loading),
1079
+ // so keep `true` if so.
1080
+ return this.lazyLoadFiles(this._lazyLoadFiles || parallel);
1081
+ };
1082
+
1083
+ /**
1084
+ * Disables implicit call to {@link Mocha#loadFiles} in {@link Mocha#run}. This
1085
+ * setting is used by watch mode, parallel mode, and for loading ESM files.
1086
+ * @todo This should throw if we've already loaded files; such behavior
1087
+ * necessitates adding a new state.
1088
+ * @param {boolean} [enable] - If `true`, disable eager loading of files in
1089
+ * {@link Mocha#run}
1090
+ * @chainable
1091
+ * @public
1092
+ */
1093
+ Mocha.prototype.lazyLoadFiles = function lazyLoadFiles(enable) {
1094
+ this._lazyLoadFiles = enable === true;
1095
+ debug('set lazy load to %s', enable);
1096
+ return this;
939
1097
  };
1098
+
1099
+ /**
1100
+ * An alternative way to define root hooks that works with parallel runs.
1101
+ * @private
1102
+ * @typedef {Object} MochaRootHookObject
1103
+ * @property {Function|Function[]} [beforeAll] - "Before all" hook(s)
1104
+ * @property {Function|Function[]} [beforeEach] - "Before each" hook(s)
1105
+ * @property {Function|Function[]} [afterAll] - "After all" hook(s)
1106
+ * @property {Function|Function[]} [afterEach] - "After each" hook(s)
1107
+ */
1108
+
1109
+ /**
1110
+ * An function that returns a {@link MochaRootHookObject}, either sync or async.
1111
+ * @private
1112
+ * @callback MochaRootHookFunction
1113
+ * @returns {MochaRootHookObject|Promise<MochaRootHookObject>}
1114
+ */
package/lib/mocharc.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "diff": true,
3
3
  "extension": ["js", "cjs", "mjs"],
4
- "opts": "./test/mocha.opts",
5
4
  "package": "./package.json",
6
5
  "reporter": "spec",
7
6
  "slow": 75,