mocha 7.1.2 → 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/mocha.js CHANGED
@@ -54,6 +54,17 @@ process.removeListener = function(e, fn) {
54
54
  }
55
55
  };
56
56
 
57
+ /**
58
+ * Implements listenerCount for 'uncaughtException'.
59
+ */
60
+
61
+ process.listenerCount = function(name) {
62
+ if (name === 'uncaughtException') {
63
+ return uncaughtExceptionHandlers.length;
64
+ }
65
+ return 0;
66
+ };
67
+
57
68
  /**
58
69
  * Implements uncaughtException listener.
59
70
  */
@@ -608,12 +619,75 @@ Context.prototype.retries = function(n) {
608
619
 
609
620
  },{}],6:[function(require,module,exports){
610
621
  'use strict';
622
+
623
+ var format = require('util').format;
624
+
611
625
  /**
626
+ * Factory functions to create throwable error objects
612
627
  * @module Errors
613
628
  */
629
+
614
630
  /**
615
- * Factory functions to create throwable error objects
631
+ * When Mocha throw exceptions (or otherwise errors), it attempts to assign a
632
+ * `code` property to the `Error` object, for easier handling. These are the
633
+ * potential values of `code`.
616
634
  */
635
+ var constants = {
636
+ /**
637
+ * An unrecoverable error.
638
+ */
639
+ FATAL: 'ERR_MOCHA_FATAL',
640
+
641
+ /**
642
+ * The type of an argument to a function call is invalid
643
+ */
644
+ INVALID_ARG_TYPE: 'ERR_MOCHA_INVALID_ARG_TYPE',
645
+
646
+ /**
647
+ * The value of an argument to a function call is invalid
648
+ */
649
+ INVALID_ARG_VALUE: 'ERR_MOCHA_INVALID_ARG_VALUE',
650
+
651
+ /**
652
+ * Something was thrown, but it wasn't an `Error`
653
+ */
654
+ INVALID_EXCEPTION: 'ERR_MOCHA_INVALID_EXCEPTION',
655
+
656
+ /**
657
+ * An interface (e.g., `Mocha.interfaces`) is unknown or invalid
658
+ */
659
+ INVALID_INTERFACE: 'ERR_MOCHA_INVALID_INTERFACE',
660
+
661
+ /**
662
+ * A reporter (.e.g, `Mocha.reporters`) is unknown or invalid
663
+ */
664
+ INVALID_REPORTER: 'ERR_MOCHA_INVALID_REPORTER',
665
+
666
+ /**
667
+ * `done()` was called twice in a `Test` or `Hook` callback
668
+ */
669
+ MULTIPLE_DONE: 'ERR_MOCHA_MULTIPLE_DONE',
670
+
671
+ /**
672
+ * No files matched the pattern provided by the user
673
+ */
674
+ NO_FILES_MATCH_PATTERN: 'ERR_MOCHA_NO_FILES_MATCH_PATTERN',
675
+
676
+ /**
677
+ * Known, but unsupported behavior of some kind
678
+ */
679
+ UNSUPPORTED: 'ERR_MOCHA_UNSUPPORTED',
680
+
681
+ /**
682
+ * Invalid state transition occuring in `Mocha` instance
683
+ */
684
+ INSTANCE_ALREADY_RUNNING: 'ERR_MOCHA_INSTANCE_ALREADY_RUNNING',
685
+
686
+ /**
687
+ * Invalid state transition occuring in `Mocha` instance
688
+ */
689
+ INSTANCE_ALREADY_DISPOSED: 'ERR_MOCHA_INSTANCE_ALREADY_DISPOSED'
690
+ };
617
691
 
618
692
  /**
619
693
  * Creates an error object to be thrown when no files to be tested could be found using specified pattern.
@@ -625,7 +699,7 @@ Context.prototype.retries = function(n) {
625
699
  */
626
700
  function createNoFilesMatchPatternError(message, pattern) {
627
701
  var err = new Error(message);
628
- err.code = 'ERR_MOCHA_NO_FILES_MATCH_PATTERN';
702
+ err.code = constants.NO_FILES_MATCH_PATTERN;
629
703
  err.pattern = pattern;
630
704
  return err;
631
705
  }
@@ -640,7 +714,7 @@ function createNoFilesMatchPatternError(message, pattern) {
640
714
  */
641
715
  function createInvalidReporterError(message, reporter) {
642
716
  var err = new TypeError(message);
643
- err.code = 'ERR_MOCHA_INVALID_REPORTER';
717
+ err.code = constants.INVALID_REPORTER;
644
718
  err.reporter = reporter;
645
719
  return err;
646
720
  }
@@ -655,7 +729,7 @@ function createInvalidReporterError(message, reporter) {
655
729
  */
656
730
  function createInvalidInterfaceError(message, ui) {
657
731
  var err = new Error(message);
658
- err.code = 'ERR_MOCHA_INVALID_INTERFACE';
732
+ err.code = constants.INVALID_INTERFACE;
659
733
  err.interface = ui;
660
734
  return err;
661
735
  }
@@ -669,7 +743,7 @@ function createInvalidInterfaceError(message, ui) {
669
743
  */
670
744
  function createUnsupportedError(message) {
671
745
  var err = new Error(message);
672
- err.code = 'ERR_MOCHA_UNSUPPORTED';
746
+ err.code = constants.UNSUPPORTED;
673
747
  return err;
674
748
  }
675
749
 
@@ -697,7 +771,7 @@ function createMissingArgumentError(message, argument, expected) {
697
771
  */
698
772
  function createInvalidArgumentTypeError(message, argument, expected) {
699
773
  var err = new TypeError(message);
700
- err.code = 'ERR_MOCHA_INVALID_ARG_TYPE';
774
+ err.code = constants.INVALID_ARG_TYPE;
701
775
  err.argument = argument;
702
776
  err.expected = expected;
703
777
  err.actual = typeof argument;
@@ -716,7 +790,7 @@ function createInvalidArgumentTypeError(message, argument, expected) {
716
790
  */
717
791
  function createInvalidArgumentValueError(message, argument, value, reason) {
718
792
  var err = new TypeError(message);
719
- err.code = 'ERR_MOCHA_INVALID_ARG_VALUE';
793
+ err.code = constants.INVALID_ARG_VALUE;
720
794
  err.argument = argument;
721
795
  err.value = value;
722
796
  err.reason = typeof reason !== 'undefined' ? reason : 'is invalid';
@@ -732,12 +806,113 @@ function createInvalidArgumentValueError(message, argument, value, reason) {
732
806
  */
733
807
  function createInvalidExceptionError(message, value) {
734
808
  var err = new Error(message);
735
- err.code = 'ERR_MOCHA_INVALID_EXCEPTION';
809
+ err.code = constants.INVALID_EXCEPTION;
736
810
  err.valueType = typeof value;
737
811
  err.value = value;
738
812
  return err;
739
813
  }
740
814
 
815
+ /**
816
+ * Creates an error object to be thrown when an unrecoverable error occurs.
817
+ *
818
+ * @public
819
+ * @param {string} message - Error message to be displayed.
820
+ * @returns {Error} instance detailing the error condition
821
+ */
822
+ function createFatalError(message, value) {
823
+ var err = new Error(message);
824
+ err.code = constants.FATAL;
825
+ err.valueType = typeof value;
826
+ err.value = value;
827
+ return err;
828
+ }
829
+
830
+ /**
831
+ * Dynamically creates a plugin-type-specific error based on plugin type
832
+ * @param {string} message - Error message
833
+ * @param {"reporter"|"interface"} pluginType - Plugin type. Future: expand as needed
834
+ * @param {string} [pluginId] - Name/path of plugin, if any
835
+ * @throws When `pluginType` is not known
836
+ * @public
837
+ * @returns {Error}
838
+ */
839
+ function createInvalidPluginError(message, pluginType, pluginId) {
840
+ switch (pluginType) {
841
+ case 'reporter':
842
+ return createInvalidReporterError(message, pluginId);
843
+ case 'interface':
844
+ return createInvalidInterfaceError(message, pluginId);
845
+ default:
846
+ throw new Error('unknown pluginType "' + pluginType + '"');
847
+ }
848
+ }
849
+
850
+ /**
851
+ * Creates an error object to be thrown when a mocha object's `run` method is executed while it is already disposed.
852
+ * @param {string} message The error message to be displayed.
853
+ * @param {boolean} cleanReferencesAfterRun the value of `cleanReferencesAfterRun`
854
+ * @param {Mocha} instance the mocha instance that throw this error
855
+ */
856
+ function createMochaInstanceAlreadyDisposedError(
857
+ message,
858
+ cleanReferencesAfterRun,
859
+ instance
860
+ ) {
861
+ var err = new Error(message);
862
+ err.code = constants.INSTANCE_ALREADY_DISPOSED;
863
+ err.cleanReferencesAfterRun = cleanReferencesAfterRun;
864
+ err.instance = instance;
865
+ return err;
866
+ }
867
+
868
+ /**
869
+ * Creates an error object to be thrown when a mocha object's `run` method is called while a test run is in progress.
870
+ * @param {string} message The error message to be displayed.
871
+ */
872
+ function createMochaInstanceAlreadyRunningError(message, instance) {
873
+ var err = new Error(message);
874
+ err.code = constants.INSTANCE_ALREADY_RUNNING;
875
+ err.instance = instance;
876
+ return err;
877
+ }
878
+
879
+ /*
880
+ * Creates an error object to be thrown when done() is called multiple times in a test
881
+ *
882
+ * @public
883
+ * @param {Runnable} runnable - Original runnable
884
+ * @param {Error} [originalErr] - Original error, if any
885
+ * @returns {Error} instance detailing the error condition
886
+ */
887
+ function createMultipleDoneError(runnable, originalErr) {
888
+ var title;
889
+ try {
890
+ title = format('<%s>', runnable.fullTitle());
891
+ if (runnable.parent.root) {
892
+ title += ' (of root suite)';
893
+ }
894
+ } catch (ignored) {
895
+ title = format('<%s> (of unknown suite)', runnable.title);
896
+ }
897
+ var message = format(
898
+ 'done() called multiple times in %s %s',
899
+ runnable.type ? runnable.type : 'unknown runnable',
900
+ title
901
+ );
902
+ if (runnable.file) {
903
+ message += format(' of file %s', runnable.file);
904
+ }
905
+ if (originalErr) {
906
+ message += format('; in addition, done() received error: %s', originalErr);
907
+ }
908
+
909
+ var err = new Error(message);
910
+ err.code = constants.MULTIPLE_DONE;
911
+ err.valueType = typeof originalErr;
912
+ err.value = originalErr;
913
+ return err;
914
+ }
915
+
741
916
  module.exports = {
742
917
  createInvalidArgumentTypeError: createInvalidArgumentTypeError,
743
918
  createInvalidArgumentValueError: createInvalidArgumentValueError,
@@ -746,10 +921,16 @@ module.exports = {
746
921
  createInvalidReporterError: createInvalidReporterError,
747
922
  createMissingArgumentError: createMissingArgumentError,
748
923
  createNoFilesMatchPatternError: createNoFilesMatchPatternError,
749
- createUnsupportedError: createUnsupportedError
924
+ createUnsupportedError: createUnsupportedError,
925
+ createInvalidPluginError: createInvalidPluginError,
926
+ createMochaInstanceAlreadyDisposedError: createMochaInstanceAlreadyDisposedError,
927
+ createMochaInstanceAlreadyRunningError: createMochaInstanceAlreadyRunningError,
928
+ createFatalError: createFatalError,
929
+ createMultipleDoneError: createMultipleDoneError,
930
+ constants: constants
750
931
  };
751
932
 
752
- },{}],7:[function(require,module,exports){
933
+ },{"util":89}],7:[function(require,module,exports){
753
934
  'use strict';
754
935
 
755
936
  var Runnable = require('./runnable');
@@ -779,6 +960,14 @@ function Hook(title, fn) {
779
960
  */
780
961
  inherits(Hook, Runnable);
781
962
 
963
+ /**
964
+ * Resets the state for a next run.
965
+ */
966
+ Hook.prototype.reset = function() {
967
+ Runnable.prototype.reset.call(this);
968
+ delete this._error;
969
+ };
970
+
782
971
  /**
783
972
  * Get or set the test `err`.
784
973
  *
@@ -923,6 +1112,7 @@ module.exports.description = 'BDD or RSpec style [default]';
923
1112
  var Suite = require('../suite');
924
1113
  var errors = require('../errors');
925
1114
  var createMissingArgumentError = errors.createMissingArgumentError;
1115
+ var createUnsupportedError = errors.createUnsupportedError;
926
1116
 
927
1117
  /**
928
1118
  * Functions common to more than one interface.
@@ -1046,14 +1236,14 @@ module.exports = function(suites, context, mocha) {
1046
1236
  suites.unshift(suite);
1047
1237
  if (opts.isOnly) {
1048
1238
  if (mocha.options.forbidOnly && shouldBeTested(suite)) {
1049
- throw new Error('`.only` forbidden');
1239
+ throw createUnsupportedError('`.only` forbidden');
1050
1240
  }
1051
1241
 
1052
1242
  suite.parent.appendOnlySuite(suite);
1053
1243
  }
1054
1244
  if (suite.pending) {
1055
1245
  if (mocha.options.forbidPending && shouldBeTested(suite)) {
1056
- throw new Error('Pending test forbidden');
1246
+ throw createUnsupportedError('Pending test forbidden');
1057
1247
  }
1058
1248
  }
1059
1249
  if (typeof opts.fn === 'function') {
@@ -1085,7 +1275,9 @@ module.exports = function(suites, context, mocha) {
1085
1275
  * @returns {*}
1086
1276
  */
1087
1277
  only: function(mocha, test) {
1088
- test.parent.appendOnlyTest(test);
1278
+ if (mocha.options.forbidOnly)
1279
+ throw createUnsupportedError('`.only` forbidden');
1280
+ test.markOnly();
1089
1281
  return test;
1090
1282
  },
1091
1283
 
@@ -1412,6 +1604,10 @@ var esmUtils = utils.supportsEsModules() ? require('./esm-utils') : undefined;
1412
1604
  var createStatsCollector = require('./stats-collector');
1413
1605
  var createInvalidReporterError = errors.createInvalidReporterError;
1414
1606
  var createInvalidInterfaceError = errors.createInvalidInterfaceError;
1607
+ var createMochaInstanceAlreadyDisposedError =
1608
+ errors.createMochaInstanceAlreadyDisposedError;
1609
+ var createMochaInstanceAlreadyRunningError =
1610
+ errors.createMochaInstanceAlreadyRunningError;
1415
1611
  var EVENT_FILE_PRE_REQUIRE = Suite.constants.EVENT_FILE_PRE_REQUIRE;
1416
1612
  var EVENT_FILE_POST_REQUIRE = Suite.constants.EVENT_FILE_POST_REQUIRE;
1417
1613
  var EVENT_FILE_REQUIRE = Suite.constants.EVENT_FILE_REQUIRE;
@@ -1419,12 +1615,36 @@ var sQuote = utils.sQuote;
1419
1615
 
1420
1616
  exports = module.exports = Mocha;
1421
1617
 
1618
+ /**
1619
+ * A Mocha instance is a finite state machine.
1620
+ * These are the states it can be in.
1621
+ */
1622
+ var mochaStates = utils.defineConstants({
1623
+ /**
1624
+ * Initial state of the mocha instance
1625
+ */
1626
+ INIT: 'init',
1627
+ /**
1628
+ * Mocha instance is running tests
1629
+ */
1630
+ RUNNING: 'running',
1631
+ /**
1632
+ * Mocha instance is done running tests and references to test functions and hooks are cleaned.
1633
+ * You can reset this state by unloading the test files.
1634
+ */
1635
+ REFERENCES_CLEANED: 'referencesCleaned',
1636
+ /**
1637
+ * Mocha instance is disposed and can no longer be used.
1638
+ */
1639
+ DISPOSED: 'disposed'
1640
+ });
1641
+
1422
1642
  /**
1423
1643
  * To require local UIs and reporters when running in node.
1424
1644
  */
1425
1645
 
1426
- if (!process.browser) {
1427
- var cwd = process.cwd();
1646
+ if (!process.browser && typeof module.paths !== 'undefined') {
1647
+ var cwd = utils.cwd();
1428
1648
  module.paths.push(cwd, path.join(cwd, 'node_modules'));
1429
1649
  }
1430
1650
 
@@ -1484,6 +1704,8 @@ exports.Test = require('./test');
1484
1704
  * @param {number} [options.slow] - Slow threshold value.
1485
1705
  * @param {number|string} [options.timeout] - Timeout threshold value.
1486
1706
  * @param {string} [options.ui] - Interface name.
1707
+ * @param {MochaRootHookObject} [options.rootHooks] - Hooks to bootstrap the root
1708
+ * suite with
1487
1709
  */
1488
1710
  function Mocha(options) {
1489
1711
  options = utils.assign({}, mocharc, options || {});
@@ -1491,6 +1713,7 @@ function Mocha(options) {
1491
1713
  this.options = options;
1492
1714
  // root suite
1493
1715
  this.suite = new exports.Suite('', new exports.Context(), true);
1716
+ this._cleanReferencesAfterRun = true;
1494
1717
 
1495
1718
  this.grep(options.grep)
1496
1719
  .fgrep(options.fgrep)
@@ -1530,6 +1753,10 @@ function Mocha(options) {
1530
1753
  this[opt]();
1531
1754
  }
1532
1755
  }, this);
1756
+
1757
+ if (options.rootHooks) {
1758
+ this.rootHooks(options.rootHooks);
1759
+ }
1533
1760
  }
1534
1761
 
1535
1762
  /**
@@ -1596,24 +1823,24 @@ Mocha.prototype.reporter = function(reporter, reporterOptions) {
1596
1823
  _reporter = require(reporter);
1597
1824
  } catch (err) {
1598
1825
  if (
1599
- err.code !== 'MODULE_NOT_FOUND' ||
1600
- err.message.indexOf('Cannot find module') !== -1
1826
+ err.code === 'MODULE_NOT_FOUND' ||
1827
+ err.message.indexOf('Cannot find module') >= 0
1601
1828
  ) {
1602
1829
  // Try to load reporters from a path (absolute or relative)
1603
1830
  try {
1604
- _reporter = require(path.resolve(process.cwd(), reporter));
1831
+ _reporter = require(path.resolve(utils.cwd(), reporter));
1605
1832
  } catch (_err) {
1606
- _err.code !== 'MODULE_NOT_FOUND' ||
1607
- _err.message.indexOf('Cannot find module') !== -1
1608
- ? console.warn(sQuote(reporter) + ' reporter not found')
1609
- : console.warn(
1833
+ _err.code === 'MODULE_NOT_FOUND' ||
1834
+ _err.message.indexOf('Cannot find module') >= 0
1835
+ ? utils.warn(sQuote(reporter) + ' reporter not found')
1836
+ : utils.warn(
1610
1837
  sQuote(reporter) +
1611
1838
  ' reporter blew up with error:\n' +
1612
1839
  err.stack
1613
1840
  );
1614
1841
  }
1615
1842
  } else {
1616
- console.warn(
1843
+ utils.warn(
1617
1844
  sQuote(reporter) + ' reporter blew up with error:\n' + err.stack
1618
1845
  );
1619
1846
  }
@@ -1782,7 +2009,18 @@ Mocha.unloadFile = function(file) {
1782
2009
  * @chainable
1783
2010
  */
1784
2011
  Mocha.prototype.unloadFiles = function() {
1785
- this.files.forEach(Mocha.unloadFile);
2012
+ if (this._state === mochaStates.DISPOSED) {
2013
+ throw createMochaInstanceAlreadyDisposedError(
2014
+ 'Mocha instance is already disposed, it cannot be used again.',
2015
+ this._cleanReferencesAfterRun,
2016
+ this
2017
+ );
2018
+ }
2019
+
2020
+ this.files.forEach(function(file) {
2021
+ Mocha.unloadFile(file);
2022
+ });
2023
+ this._state = mochaStates.INIT;
1786
2024
  return this;
1787
2025
  };
1788
2026
 
@@ -1900,6 +2138,38 @@ Mocha.prototype.checkLeaks = function(checkLeaks) {
1900
2138
  return this;
1901
2139
  };
1902
2140
 
2141
+ /**
2142
+ * Enables or disables whether or not to dispose after each test run.
2143
+ * Disable this to ensure you can run the test suite multiple times.
2144
+ * If disabled, be sure to dispose mocha when you're done to prevent memory leaks.
2145
+ * @public
2146
+ * @see {@link Mocha#dispose}
2147
+ * @param {boolean} cleanReferencesAfterRun
2148
+ * @return {Mocha} this
2149
+ * @chainable
2150
+ */
2151
+ Mocha.prototype.cleanReferencesAfterRun = function(cleanReferencesAfterRun) {
2152
+ this._cleanReferencesAfterRun = cleanReferencesAfterRun !== false;
2153
+ return this;
2154
+ };
2155
+
2156
+ /**
2157
+ * Manually dispose this mocha instance. Mark this instance as `disposed` and unable to run more tests.
2158
+ * It also removes function references to tests functions and hooks, so variables trapped in closures can be cleaned by the garbage collector.
2159
+ * @public
2160
+ */
2161
+ Mocha.prototype.dispose = function() {
2162
+ if (this._state === mochaStates.RUNNING) {
2163
+ throw createMochaInstanceAlreadyRunningError(
2164
+ 'Cannot dispose while the mocha instance is still running tests.'
2165
+ );
2166
+ }
2167
+ this.unloadFiles();
2168
+ this._previousRunner && this._previousRunner.dispose();
2169
+ this.suite.dispose();
2170
+ this._state = mochaStates.DISPOSED;
2171
+ };
2172
+
1903
2173
  /**
1904
2174
  * Displays full stack trace upon test failure.
1905
2175
  *
@@ -2250,6 +2520,28 @@ Mocha.prototype.forbidPending = function(forbidPending) {
2250
2520
  return this;
2251
2521
  };
2252
2522
 
2523
+ /**
2524
+ * Throws an error if mocha is in the wrong state to be able to transition to a "running" state.
2525
+ */
2526
+ Mocha.prototype._guardRunningStateTransition = function() {
2527
+ if (this._state === mochaStates.RUNNING) {
2528
+ throw createMochaInstanceAlreadyRunningError(
2529
+ 'Mocha instance is currently running tests, cannot start a next test run until this one is done',
2530
+ this
2531
+ );
2532
+ }
2533
+ if (
2534
+ this._state === mochaStates.DISPOSED ||
2535
+ this._state === mochaStates.REFERENCES_CLEANED
2536
+ ) {
2537
+ throw createMochaInstanceAlreadyDisposedError(
2538
+ '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.',
2539
+ this._cleanReferencesAfterRun,
2540
+ this
2541
+ );
2542
+ }
2543
+ };
2544
+
2253
2545
  /**
2254
2546
  * Mocha version as specified by "package.json".
2255
2547
  *
@@ -2290,13 +2582,23 @@ Object.defineProperty(Mocha.prototype, 'version', {
2290
2582
  * mocha.run(failures => process.exitCode = failures ? 1 : 0);
2291
2583
  */
2292
2584
  Mocha.prototype.run = function(fn) {
2585
+ this._guardRunningStateTransition();
2586
+ this._state = mochaStates.RUNNING;
2587
+ if (this._previousRunner) {
2588
+ this._previousRunner.dispose();
2589
+ this.suite.reset();
2590
+ }
2293
2591
  if (this.files.length && !this.loadAsync) {
2294
2592
  this.loadFiles();
2295
2593
  }
2594
+ var self = this;
2296
2595
  var suite = this.suite;
2297
2596
  var options = this.options;
2298
2597
  options.files = this.files;
2299
- var runner = new exports.Runner(suite, options.delay);
2598
+ var runner = new exports.Runner(suite, {
2599
+ delay: options.delay,
2600
+ cleanReferencesAfterRun: this._cleanReferencesAfterRun
2601
+ });
2300
2602
  createStatsCollector(runner);
2301
2603
  var reporter = new this._reporter(runner, options);
2302
2604
  runner.checkLeaks = options.checkLeaks === true;
@@ -2321,6 +2623,12 @@ Mocha.prototype.run = function(fn) {
2321
2623
  exports.reporters.Base.hideDiff = !options.diff;
2322
2624
 
2323
2625
  function done(failures) {
2626
+ self._previousRunner = runner;
2627
+ if (self._cleanReferencesAfterRun) {
2628
+ self._state = mochaStates.REFERENCES_CLEANED;
2629
+ } else {
2630
+ self._state = mochaStates.INIT;
2631
+ }
2324
2632
  fn = fn || utils.noop;
2325
2633
  if (reporter.done) {
2326
2634
  reporter.done(failures, fn);
@@ -2332,6 +2640,49 @@ Mocha.prototype.run = function(fn) {
2332
2640
  return runner.run(done);
2333
2641
  };
2334
2642
 
2643
+ /**
2644
+ * Assigns hooks to the root suite
2645
+ * @param {MochaRootHookObject} [hooks] - Hooks to assign to root suite
2646
+ * @chainable
2647
+ */
2648
+ Mocha.prototype.rootHooks = function rootHooks(hooks) {
2649
+ if (utils.type(hooks) === 'object') {
2650
+ var beforeAll = [].concat(hooks.beforeAll || []);
2651
+ var beforeEach = [].concat(hooks.beforeEach || []);
2652
+ var afterAll = [].concat(hooks.afterAll || []);
2653
+ var afterEach = [].concat(hooks.afterEach || []);
2654
+ var rootSuite = this.suite;
2655
+ beforeAll.forEach(function(hook) {
2656
+ rootSuite.beforeAll(hook);
2657
+ });
2658
+ beforeEach.forEach(function(hook) {
2659
+ rootSuite.beforeEach(hook);
2660
+ });
2661
+ afterAll.forEach(function(hook) {
2662
+ rootSuite.afterAll(hook);
2663
+ });
2664
+ afterEach.forEach(function(hook) {
2665
+ rootSuite.afterEach(hook);
2666
+ });
2667
+ }
2668
+ return this;
2669
+ };
2670
+
2671
+ /**
2672
+ * An alternative way to define root hooks that works with parallel runs.
2673
+ * @typedef {Object} MochaRootHookObject
2674
+ * @property {Function|Function[]} [beforeAll] - "Before all" hook(s)
2675
+ * @property {Function|Function[]} [beforeEach] - "Before each" hook(s)
2676
+ * @property {Function|Function[]} [afterAll] - "After all" hook(s)
2677
+ * @property {Function|Function[]} [afterEach] - "After each" hook(s)
2678
+ */
2679
+
2680
+ /**
2681
+ * An function that returns a {@link MochaRootHookObject}, either sync or async.
2682
+ * @callback MochaRootHookFunction
2683
+ * @returns {MochaRootHookObject|Promise<MochaRootHookObject>}
2684
+ */
2685
+
2335
2686
  }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2336
2687
  },{"../package.json":90,"./context":5,"./errors":6,"./esm-utils":42,"./growl":2,"./hook":7,"./interfaces":11,"./mocharc.json":15,"./reporters":21,"./runnable":33,"./runner":34,"./stats-collector":35,"./suite":36,"./test":37,"./utils":38,"_process":69,"escape-string-regexp":49,"path":42}],15:[function(require,module,exports){
2337
2688
  module.exports={
@@ -2952,6 +3303,7 @@ function Doc(runner, options) {
2952
3303
 
2953
3304
  runner.on(EVENT_TEST_PASS, function(test) {
2954
3305
  Base.consoleLog('%s <dt>%s</dt>', indent(), utils.escape(test.title));
3306
+ Base.consoleLog('%s <dt>%s</dt>', indent(), utils.escape(test.file));
2955
3307
  var code = utils.escape(utils.clean(test.body));
2956
3308
  Base.consoleLog('%s <dd><pre><code>%s</code></pre></dd>', indent(), code);
2957
3309
  });
@@ -2962,6 +3314,11 @@ function Doc(runner, options) {
2962
3314
  indent(),
2963
3315
  utils.escape(test.title)
2964
3316
  );
3317
+ Base.consoleLog(
3318
+ '%s <dt class="error">%s</dt>',
3319
+ indent(),
3320
+ utils.escape(test.file)
3321
+ );
2965
3322
  var code = utils.escape(utils.clean(test.body));
2966
3323
  Base.consoleLog(
2967
3324
  '%s <dd class="error"><pre><code>%s</code></pre></dd>',
@@ -3564,6 +3921,7 @@ function clean(test) {
3564
3921
  return {
3565
3922
  title: test.title,
3566
3923
  fullTitle: test.fullTitle(),
3924
+ file: test.file,
3567
3925
  duration: test.duration,
3568
3926
  currentRetry: test.currentRetry()
3569
3927
  };
@@ -3663,6 +4021,7 @@ function clean(test) {
3663
4021
  return {
3664
4022
  title: test.title,
3665
4023
  fullTitle: test.fullTitle(),
4024
+ file: test.file,
3666
4025
  duration: test.duration,
3667
4026
  currentRetry: test.currentRetry(),
3668
4027
  err: cleanCycles(err)
@@ -3813,6 +4172,14 @@ function Landing(runner, options) {
3813
4172
  process.stdout.write('\n');
3814
4173
  self.epilogue();
3815
4174
  });
4175
+
4176
+ // if cursor is hidden when we ctrl-C, then it will remain hidden unless...
4177
+ process.once('SIGINT', function() {
4178
+ cursor.show();
4179
+ process.nextTick(function() {
4180
+ process.kill(process.pid, 'SIGINT');
4181
+ });
4182
+ });
3816
4183
  }
3817
4184
 
3818
4185
  /**
@@ -5093,8 +5460,9 @@ var Pending = require('./pending');
5093
5460
  var debug = require('debug')('mocha:runnable');
5094
5461
  var milliseconds = require('ms');
5095
5462
  var utils = require('./utils');
5096
- var createInvalidExceptionError = require('./errors')
5097
- .createInvalidExceptionError;
5463
+ var errors = require('./errors');
5464
+ var createInvalidExceptionError = errors.createInvalidExceptionError;
5465
+ var createMultipleDoneError = errors.createMultipleDoneError;
5098
5466
 
5099
5467
  /**
5100
5468
  * Save timer references to avoid Sinon interfering (see GH-237).
@@ -5124,10 +5492,8 @@ function Runnable(title, fn) {
5124
5492
  this._timeout = 2000;
5125
5493
  this._slow = 75;
5126
5494
  this._enableTimeouts = true;
5127
- this.timedOut = false;
5128
5495
  this._retries = -1;
5129
- this._currentRetry = 0;
5130
- this.pending = false;
5496
+ this.reset();
5131
5497
  }
5132
5498
 
5133
5499
  /**
@@ -5135,6 +5501,17 @@ function Runnable(title, fn) {
5135
5501
  */
5136
5502
  utils.inherits(Runnable, EventEmitter);
5137
5503
 
5504
+ /**
5505
+ * Resets the state initially or for a next run.
5506
+ */
5507
+ Runnable.prototype.reset = function() {
5508
+ this.timedOut = false;
5509
+ this._currentRetry = 0;
5510
+ this.pending = false;
5511
+ delete this.state;
5512
+ delete this.err;
5513
+ };
5514
+
5138
5515
  /**
5139
5516
  * Get current timeout value in msecs.
5140
5517
  *
@@ -5356,7 +5733,7 @@ Runnable.prototype.run = function(fn) {
5356
5733
  var start = new Date();
5357
5734
  var ctx = this.ctx;
5358
5735
  var finished;
5359
- var emitted;
5736
+ var errorWasHandled = false;
5360
5737
 
5361
5738
  // Sometimes the ctx exists, but it is not runnable
5362
5739
  if (ctx && ctx.runnable) {
@@ -5365,17 +5742,11 @@ Runnable.prototype.run = function(fn) {
5365
5742
 
5366
5743
  // called multiple times
5367
5744
  function multiple(err) {
5368
- if (emitted) {
5745
+ if (errorWasHandled) {
5369
5746
  return;
5370
5747
  }
5371
- emitted = true;
5372
- var msg = 'done() called multiple times';
5373
- if (err && err.message) {
5374
- err.message += " (and Mocha's " + msg + ')';
5375
- self.emit('error', err);
5376
- } else {
5377
- self.emit('error', new Error(msg));
5378
- }
5748
+ errorWasHandled = true;
5749
+ self.emit('error', createMultipleDoneError(self, err));
5379
5750
  }
5380
5751
 
5381
5752
  // finished
@@ -5426,7 +5797,7 @@ Runnable.prototype.run = function(fn) {
5426
5797
  callFnAsync(this.fn);
5427
5798
  } catch (err) {
5428
5799
  // handles async runnables which actually run synchronously
5429
- emitted = true;
5800
+ errorWasHandled = true;
5430
5801
  if (err instanceof Pending) {
5431
5802
  return; // done() is already called in this.skip()
5432
5803
  } else if (this.allowUncaught) {
@@ -5445,7 +5816,7 @@ Runnable.prototype.run = function(fn) {
5445
5816
  callFn(this.fn);
5446
5817
  }
5447
5818
  } catch (err) {
5448
- emitted = true;
5819
+ errorWasHandled = true;
5449
5820
  if (err instanceof Pending) {
5450
5821
  return done();
5451
5822
  } else if (this.allowUncaught) {
@@ -5597,6 +5968,7 @@ var type = utils.type;
5597
5968
  var errors = require('./errors');
5598
5969
  var createInvalidExceptionError = errors.createInvalidExceptionError;
5599
5970
  var createUnsupportedError = errors.createUnsupportedError;
5971
+ var createFatalError = errors.createFatalError;
5600
5972
 
5601
5973
  /**
5602
5974
  * Non-enumerable globals.
@@ -5679,7 +6051,19 @@ var constants = utils.defineConstants(
5679
6051
  /**
5680
6052
  * Emitted when {@link Test} execution has failed, but will retry
5681
6053
  */
5682
- EVENT_TEST_RETRY: 'retry'
6054
+ EVENT_TEST_RETRY: 'retry',
6055
+ /**
6056
+ * Initial state of Runner
6057
+ */
6058
+ STATE_IDLE: 'idle',
6059
+ /**
6060
+ * State set to this value when the Runner has started running
6061
+ */
6062
+ STATE_RUNNING: 'running',
6063
+ /**
6064
+ * State set to this value when the Runner has stopped
6065
+ */
6066
+ STATE_STOPPED: 'stopped'
5683
6067
  }
5684
6068
  );
5685
6069
 
@@ -5691,19 +6075,30 @@ module.exports = Runner;
5691
6075
  * @extends external:EventEmitter
5692
6076
  * @public
5693
6077
  * @class
5694
- * @param {Suite} suite Root suite
5695
- * @param {boolean} [delay] Whether or not to delay execution of root suite
5696
- * until ready.
5697
- */
5698
- function Runner(suite, delay) {
6078
+ * @param {Suite} suite - Root suite
6079
+ * @param {Object|boolean} [opts] - Options. If `boolean`, whether or not to delay execution of root suite until ready (for backwards compatibility).
6080
+ * @param {boolean} [opts.delay] - Whether to delay execution of root suite until ready.
6081
+ * @param {boolean} [opts.cleanReferencesAfterRun] - Whether to clean references to test fns and hooks when a suite is done.
6082
+ */
6083
+ function Runner(suite, opts) {
6084
+ if (opts === undefined) {
6085
+ opts = {};
6086
+ }
6087
+ if (typeof opts === 'boolean') {
6088
+ this._delay = opts;
6089
+ opts = {};
6090
+ } else {
6091
+ this._delay = opts.delay;
6092
+ }
5699
6093
  var self = this;
5700
6094
  this._globals = [];
5701
6095
  this._abort = false;
5702
- this._delay = delay;
5703
6096
  this.suite = suite;
5704
- this.started = false;
6097
+ this._opts = opts;
6098
+ this.state = constants.STATE_IDLE;
5705
6099
  this.total = suite.total();
5706
6100
  this.failures = 0;
6101
+ this._eventListeners = [];
5707
6102
  this.on(constants.EVENT_TEST_END, function(test) {
5708
6103
  if (test.type === 'test' && test.retriedTest() && test.parent) {
5709
6104
  var idx =
@@ -5718,6 +6113,8 @@ function Runner(suite, delay) {
5718
6113
  this._defaultGrep = /.*/;
5719
6114
  this.grep(this._defaultGrep);
5720
6115
  this.globals(this.globalProps());
6116
+
6117
+ this.uncaught = this._uncaught.bind(this);
5721
6118
  }
5722
6119
 
5723
6120
  /**
@@ -5733,6 +6130,56 @@ Runner.immediately = global.setImmediate || process.nextTick;
5733
6130
  */
5734
6131
  inherits(Runner, EventEmitter);
5735
6132
 
6133
+ /**
6134
+ * Replacement for `target.on(eventName, listener)` that does bookkeeping to remove them when this runner instance is disposed.
6135
+ * @param {EventEmitter} target - The `EventEmitter`
6136
+ * @param {string} eventName - The event name
6137
+ * @param {string} fn - Listener function
6138
+ */
6139
+ Runner.prototype._addEventListener = function(target, eventName, listener) {
6140
+ target.on(eventName, listener);
6141
+ this._eventListeners.push([target, eventName, listener]);
6142
+ };
6143
+
6144
+ /**
6145
+ * Replacement for `target.removeListener(eventName, listener)` that also updates the bookkeeping.
6146
+ * @param {EventEmitter} target - The `EventEmitter`
6147
+ * @param {string} eventName - The event anme
6148
+ * @param {function} listener - Listener function
6149
+ */
6150
+ Runner.prototype._removeEventListener = function(target, eventName, listener) {
6151
+ var eventListenerIndex = -1;
6152
+ for (var i = 0; i < this._eventListeners.length; i++) {
6153
+ var eventListenerDescriptor = this._eventListeners[i];
6154
+ if (
6155
+ eventListenerDescriptor[0] === target &&
6156
+ eventListenerDescriptor[1] === eventName &&
6157
+ eventListenerDescriptor[2] === listener
6158
+ ) {
6159
+ eventListenerIndex = i;
6160
+ break;
6161
+ }
6162
+ }
6163
+ if (eventListenerIndex !== -1) {
6164
+ var removedListener = this._eventListeners.splice(eventListenerIndex, 1)[0];
6165
+ removedListener[0].removeListener(removedListener[1], removedListener[2]);
6166
+ }
6167
+ };
6168
+
6169
+ /**
6170
+ * Removes all event handlers set during a run on this instance.
6171
+ * Remark: this does _not_ clean/dispose the tests or suites themselves.
6172
+ */
6173
+ Runner.prototype.dispose = function() {
6174
+ this.removeAllListeners();
6175
+ this._eventListeners.forEach(function(eventListenerDescriptor) {
6176
+ eventListenerDescriptor[0].removeListener(
6177
+ eventListenerDescriptor[1],
6178
+ eventListenerDescriptor[2]
6179
+ );
6180
+ });
6181
+ };
6182
+
5736
6183
  /**
5737
6184
  * Run tests with full titles matching `re`. Updates runner.total
5738
6185
  * with number of tests matched.
@@ -5744,7 +6191,7 @@ inherits(Runner, EventEmitter);
5744
6191
  * @return {Runner} Runner instance.
5745
6192
  */
5746
6193
  Runner.prototype.grep = function(re, invert) {
5747
- debug('grep %s', re);
6194
+ debug('grep(): setting to %s', re);
5748
6195
  this._grep = re;
5749
6196
  this._invert = invert;
5750
6197
  this.total = this.grepTotal(this.suite);
@@ -5809,7 +6256,7 @@ Runner.prototype.globals = function(arr) {
5809
6256
  if (!arguments.length) {
5810
6257
  return this._globals;
5811
6258
  }
5812
- debug('globals %j', arr);
6259
+ debug('globals(): setting to %O', arr);
5813
6260
  this._globals = this._globals.concat(arr);
5814
6261
  return this;
5815
6262
  };
@@ -5858,8 +6305,18 @@ Runner.prototype.fail = function(test, err) {
5858
6305
  if (test.isPending()) {
5859
6306
  return;
5860
6307
  }
6308
+ if (this.state === constants.STATE_STOPPED) {
6309
+ if (err.code === errors.constants.MULTIPLE_DONE) {
6310
+ throw err;
6311
+ }
6312
+ throw createFatalError(
6313
+ 'Test failed after root suite execution completed!',
6314
+ err
6315
+ );
6316
+ }
5861
6317
 
5862
6318
  ++this.failures;
6319
+ debug('total number of failures: %d', this.failures);
5863
6320
  test.state = STATE_FAILED;
5864
6321
 
5865
6322
  if (!isError(err)) {
@@ -5947,7 +6404,7 @@ Runner.prototype.hook = function(name, fn) {
5947
6404
  self.emit(constants.EVENT_HOOK_BEGIN, hook);
5948
6405
 
5949
6406
  if (!hook.listeners('error').length) {
5950
- hook.on('error', function(err) {
6407
+ self._addEventListener(hook, 'error', function(err) {
5951
6408
  self.failHook(hook, err);
5952
6409
  });
5953
6410
  }
@@ -6090,18 +6547,10 @@ Runner.prototype.runTest = function(fn) {
6090
6547
  return;
6091
6548
  }
6092
6549
 
6093
- var suite = this.parents().reverse()[0] || this.suite;
6094
- if (this.forbidOnly && suite.hasOnly()) {
6095
- fn(new Error('`.only` forbidden'));
6096
- return;
6097
- }
6098
6550
  if (this.asyncOnly) {
6099
6551
  test.asyncOnly = true;
6100
6552
  }
6101
- test.on('error', function(err) {
6102
- if (err instanceof Pending) {
6103
- return;
6104
- }
6553
+ this._addEventListener(test, 'error', function(err) {
6105
6554
  self.fail(test, err);
6106
6555
  });
6107
6556
  if (this.allowUncaught) {
@@ -6296,9 +6745,10 @@ Runner.prototype.runSuite = function(suite, fn) {
6296
6745
  var self = this;
6297
6746
  var total = this.grepTotal(suite);
6298
6747
 
6299
- debug('run suite %s', suite.fullTitle());
6748
+ debug('runSuite(): running %s', suite.fullTitle());
6300
6749
 
6301
6750
  if (!total || (self.failures && suite._bail)) {
6751
+ debug('runSuite(): bailing');
6302
6752
  return fn();
6303
6753
  }
6304
6754
 
@@ -6364,22 +6814,49 @@ Runner.prototype.runSuite = function(suite, fn) {
6364
6814
  /**
6365
6815
  * Handle uncaught exceptions within runner.
6366
6816
  *
6367
- * @param {Error} err
6817
+ * This function is bound to the instance as `Runner#uncaught` at instantiation
6818
+ * time. It's intended to be listening on the `Process.uncaughtException` event.
6819
+ * In order to not leak EE listeners, we need to ensure no more than a single
6820
+ * `uncaughtException` listener exists per `Runner`. The only way to do
6821
+ * this--because this function needs the context (and we don't have lambdas)--is
6822
+ * to use `Function.prototype.bind`. We need strict equality to unregister and
6823
+ * _only_ unregister the _one_ listener we set from the
6824
+ * `Process.uncaughtException` event; would be poor form to just remove
6825
+ * everything. See {@link Runner#run} for where the event listener is registered
6826
+ * and unregistered.
6827
+ * @param {Error} err - Some uncaught error
6368
6828
  * @private
6369
6829
  */
6370
- Runner.prototype.uncaught = function(err) {
6830
+ Runner.prototype._uncaught = function(err) {
6831
+ // this is defensive to prevent future developers from mis-calling this function.
6832
+ // it's more likely that it'd be called with the incorrect context--say, the global
6833
+ // `process` object--than it would to be called with a context that is not a "subclass"
6834
+ // of `Runner`.
6835
+ if (!(this instanceof Runner)) {
6836
+ throw createFatalError(
6837
+ 'Runner#uncaught() called with invalid context',
6838
+ this
6839
+ );
6840
+ }
6371
6841
  if (err instanceof Pending) {
6842
+ debug('uncaught(): caught a Pending');
6372
6843
  return;
6373
6844
  }
6374
6845
  // browser does not exit script when throwing in global.onerror()
6375
6846
  if (this.allowUncaught && !process.browser) {
6847
+ debug('uncaught(): bubbling exception due to --allow-uncaught');
6848
+ throw err;
6849
+ }
6850
+
6851
+ if (this.state === constants.STATE_STOPPED) {
6852
+ debug('uncaught(): throwing after run has completed!');
6376
6853
  throw err;
6377
6854
  }
6378
6855
 
6379
6856
  if (err) {
6380
- debug('uncaught exception %O', err);
6857
+ debug('uncaught(): got truthy exception %O', err);
6381
6858
  } else {
6382
- debug('uncaught undefined/falsy exception');
6859
+ debug('uncaught(): undefined/falsy exception');
6383
6860
  err = createInvalidExceptionError(
6384
6861
  'Caught falsy/undefined exception which would otherwise be uncaught. No stack trace found; try a debugger',
6385
6862
  err
@@ -6388,6 +6865,7 @@ Runner.prototype.uncaught = function(err) {
6388
6865
 
6389
6866
  if (!isError(err)) {
6390
6867
  err = thrown2Error(err);
6868
+ debug('uncaught(): converted "error" %o to Error', err);
6391
6869
  }
6392
6870
  err.uncaught = true;
6393
6871
 
@@ -6395,12 +6873,15 @@ Runner.prototype.uncaught = function(err) {
6395
6873
 
6396
6874
  if (!runnable) {
6397
6875
  runnable = new Runnable('Uncaught error outside test suite');
6876
+ debug('uncaught(): no current Runnable; created a phony one');
6398
6877
  runnable.parent = this.suite;
6399
6878
 
6400
- if (this.started) {
6879
+ if (this.state === constants.STATE_RUNNING) {
6880
+ debug('uncaught(): failing gracefully');
6401
6881
  this.fail(runnable, err);
6402
6882
  } else {
6403
6883
  // Can't recover from this failure
6884
+ debug('uncaught(): test run has not yet started; unrecoverable');
6404
6885
  this.emit(constants.EVENT_RUN_BEGIN);
6405
6886
  this.fail(runnable, err);
6406
6887
  this.emit(constants.EVENT_RUN_END);
@@ -6412,9 +6893,11 @@ Runner.prototype.uncaught = function(err) {
6412
6893
  runnable.clearTimeout();
6413
6894
 
6414
6895
  if (runnable.isFailed()) {
6896
+ debug('uncaught(): Runnable has already failed');
6415
6897
  // Ignore error if already failed
6416
6898
  return;
6417
6899
  } else if (runnable.isPending()) {
6900
+ debug('uncaught(): pending Runnable wound up failing!');
6418
6901
  // report 'pending test' retrospectively as failed
6419
6902
  runnable.isPending = alwaysFalse;
6420
6903
  this.fail(runnable, err);
@@ -6425,25 +6908,15 @@ Runner.prototype.uncaught = function(err) {
6425
6908
  // we cannot recover gracefully if a Runnable has already passed
6426
6909
  // then fails asynchronously
6427
6910
  if (runnable.isPassed()) {
6911
+ debug('uncaught(): Runnable has already passed; bailing gracefully');
6428
6912
  this.fail(runnable, err);
6429
6913
  this.abort();
6430
6914
  } else {
6431
- debug(runnable);
6915
+ debug('uncaught(): forcing Runnable to complete with Error');
6432
6916
  return runnable.callback(err);
6433
6917
  }
6434
6918
  };
6435
6919
 
6436
- /**
6437
- * Handle uncaught exceptions after runner's end event.
6438
- *
6439
- * @param {Error} err
6440
- * @private
6441
- */
6442
- Runner.prototype.uncaughtEnd = function uncaughtEnd(err) {
6443
- if (err instanceof Pending) return;
6444
- throw err;
6445
- };
6446
-
6447
6920
  /**
6448
6921
  * Run the root suite and invoke `fn(failures)`
6449
6922
  * on completion.
@@ -6459,51 +6932,56 @@ Runner.prototype.run = function(fn) {
6459
6932
 
6460
6933
  fn = fn || function() {};
6461
6934
 
6462
- function uncaught(err) {
6463
- self.uncaught(err);
6464
- }
6465
-
6466
6935
  function start() {
6936
+ debug('run(): starting');
6467
6937
  // If there is an `only` filter
6468
6938
  if (rootSuite.hasOnly()) {
6469
6939
  rootSuite.filterOnly();
6940
+ debug('run(): filtered exclusive Runnables');
6470
6941
  }
6471
- self.started = true;
6942
+ self.state = constants.STATE_RUNNING;
6472
6943
  if (self._delay) {
6473
6944
  self.emit(constants.EVENT_DELAY_END);
6945
+ debug('run(): "delay" ended');
6474
6946
  }
6947
+ debug('run(): emitting %s', constants.EVENT_RUN_BEGIN);
6475
6948
  self.emit(constants.EVENT_RUN_BEGIN);
6949
+ debug('run(): emitted %s', constants.EVENT_RUN_BEGIN);
6476
6950
 
6477
6951
  self.runSuite(rootSuite, function() {
6478
- debug('finished running');
6952
+ debug(
6953
+ 'run(): root suite completed; emitting %s',
6954
+ constants.EVENT_RUN_END
6955
+ );
6479
6956
  self.emit(constants.EVENT_RUN_END);
6957
+ debug('run(): emitted %s', constants.EVENT_RUN_END);
6480
6958
  });
6481
6959
  }
6482
6960
 
6483
- debug(constants.EVENT_RUN_BEGIN);
6484
-
6485
6961
  // references cleanup to avoid memory leaks
6486
- this.on(constants.EVENT_SUITE_END, function(suite) {
6487
- suite.cleanReferences();
6488
- });
6962
+ if (this._opts.cleanReferencesAfterRun) {
6963
+ this.on(constants.EVENT_SUITE_END, function(suite) {
6964
+ suite.cleanReferences();
6965
+ });
6966
+ }
6489
6967
 
6490
6968
  // callback
6491
6969
  this.on(constants.EVENT_RUN_END, function() {
6970
+ self.state = constants.STATE_STOPPED;
6492
6971
  debug(constants.EVENT_RUN_END);
6493
- process.removeListener('uncaughtException', uncaught);
6494
- process.on('uncaughtException', self.uncaughtEnd);
6972
+ debug('run(): emitted %s', constants.EVENT_RUN_END);
6495
6973
  fn(self.failures);
6496
6974
  });
6497
6975
 
6498
- // uncaught exception
6499
- process.removeListener('uncaughtException', self.uncaughtEnd);
6500
- process.on('uncaughtException', uncaught);
6976
+ self._removeEventListener(process, 'uncaughtException', self.uncaught);
6977
+ self._addEventListener(process, 'uncaughtException', self.uncaught);
6501
6978
 
6502
6979
  if (this._delay) {
6503
6980
  // for reporters, I guess.
6504
6981
  // might be nice to debounce some dots while we wait.
6505
6982
  this.emit(constants.EVENT_DELAY_BEGIN, rootSuite);
6506
6983
  rootSuite.once(EVENT_ROOT_SUITE_RUN, start);
6984
+ debug('run(): waiting for green light due to --delay');
6507
6985
  } else {
6508
6986
  Runner.immediately(function() {
6509
6987
  start();
@@ -6521,7 +6999,7 @@ Runner.prototype.run = function(fn) {
6521
6999
  * @return {Runner} Runner instance.
6522
7000
  */
6523
7001
  Runner.prototype.abort = function() {
6524
- debug('aborting');
7002
+ debug('abort(): aborting');
6525
7003
  this._abort = true;
6526
7004
 
6527
7005
  return this;
@@ -6756,20 +7234,20 @@ function Suite(title, parentContext, isRoot) {
6756
7234
  this.ctx = new Context();
6757
7235
  this.suites = [];
6758
7236
  this.tests = [];
7237
+ this.root = isRoot === true;
6759
7238
  this.pending = false;
7239
+ this._retries = -1;
6760
7240
  this._beforeEach = [];
6761
7241
  this._beforeAll = [];
6762
7242
  this._afterEach = [];
6763
7243
  this._afterAll = [];
6764
- this.root = isRoot === true;
6765
7244
  this._timeout = 2000;
6766
7245
  this._enableTimeouts = true;
6767
7246
  this._slow = 75;
6768
7247
  this._bail = false;
6769
- this._retries = -1;
6770
7248
  this._onlyTests = [];
6771
7249
  this._onlySuites = [];
6772
- this.delayed = false;
7250
+ this.reset();
6773
7251
 
6774
7252
  this.on('newListener', function(event) {
6775
7253
  if (deprecatedEvents[event]) {
@@ -6787,6 +7265,22 @@ function Suite(title, parentContext, isRoot) {
6787
7265
  */
6788
7266
  inherits(Suite, EventEmitter);
6789
7267
 
7268
+ /**
7269
+ * Resets the state initially or for a next run.
7270
+ */
7271
+ Suite.prototype.reset = function() {
7272
+ this.delayed = false;
7273
+ function doReset(thingToReset) {
7274
+ thingToReset.reset();
7275
+ }
7276
+ this.suites.forEach(doReset);
7277
+ this.tests.forEach(doReset);
7278
+ this._beforeEach.forEach(doReset);
7279
+ this._afterEach.forEach(doReset);
7280
+ this._beforeAll.forEach(doReset);
7281
+ this._afterAll.forEach(doReset);
7282
+ };
7283
+
6790
7284
  /**
6791
7285
  * Return a clone of this `Suite`.
6792
7286
  *
@@ -7206,6 +7700,16 @@ Suite.prototype.getHooks = function getHooks(name) {
7206
7700
  return this['_' + name];
7207
7701
  };
7208
7702
 
7703
+ /**
7704
+ * cleans all references from this suite and all child suites.
7705
+ */
7706
+ Suite.prototype.dispose = function() {
7707
+ this.suites.forEach(function(suite) {
7708
+ suite.dispose();
7709
+ });
7710
+ this.cleanReferences();
7711
+ };
7712
+
7209
7713
  /**
7210
7714
  * Cleans up the references to all the deferred functions
7211
7715
  * (before/after/beforeEach/afterEach) and tests of a Suite.
@@ -7365,9 +7869,9 @@ function Test(title, fn) {
7365
7869
  'string'
7366
7870
  );
7367
7871
  }
7368
- Runnable.call(this, title, fn);
7369
- this.pending = !fn;
7370
7872
  this.type = 'test';
7873
+ Runnable.call(this, title, fn);
7874
+ this.reset();
7371
7875
  }
7372
7876
 
7373
7877
  /**
@@ -7375,6 +7879,15 @@ function Test(title, fn) {
7375
7879
  */
7376
7880
  utils.inherits(Test, Runnable);
7377
7881
 
7882
+ /**
7883
+ * Resets the state initially or for a next run.
7884
+ */
7885
+ Test.prototype.reset = function() {
7886
+ Runnable.prototype.reset.call(this);
7887
+ this.pending = !this.fn;
7888
+ delete this.state;
7889
+ };
7890
+
7378
7891
  /**
7379
7892
  * Set or get retried test
7380
7893
  *
@@ -7387,6 +7900,15 @@ Test.prototype.retriedTest = function(n) {
7387
7900
  this._retriedTest = n;
7388
7901
  };
7389
7902
 
7903
+ /**
7904
+ * Add test to the list of tests marked `only`.
7905
+ *
7906
+ * @private
7907
+ */
7908
+ Test.prototype.markOnly = function() {
7909
+ this.parent.appendOnlyTest(this);
7910
+ };
7911
+
7390
7912
  Test.prototype.clone = function() {
7391
7913
  var test = new Test(this.title, this.fn);
7392
7914
  test.timeout(this.timeout());
@@ -7469,8 +7991,9 @@ exports.isString = function(obj) {
7469
7991
  exports.slug = function(str) {
7470
7992
  return str
7471
7993
  .toLowerCase()
7472
- .replace(/ +/g, '-')
7473
- .replace(/[^-\w]/g, '');
7994
+ .replace(/\s+/g, '-')
7995
+ .replace(/[^-\w]/g, '')
7996
+ .replace(/-{2,}/g, '-');
7474
7997
  };
7475
7998
 
7476
7999
  /**
@@ -8043,7 +8566,7 @@ exports.stackTraceFilter = function() {
8043
8566
  var slash = path.sep;
8044
8567
  var cwd;
8045
8568
  if (is.node) {
8046
- cwd = process.cwd() + slash;
8569
+ cwd = exports.cwd() + slash;
8047
8570
  } else {
8048
8571
  cwd = (typeof location === 'undefined'
8049
8572
  ? window.location
@@ -8228,6 +8751,16 @@ exports.supportsEsModules = function() {
8228
8751
  }
8229
8752
  };
8230
8753
 
8754
+ /**
8755
+ * Returns current working directory
8756
+ *
8757
+ * Wrapper around `process.cwd()` for isolation
8758
+ * @private
8759
+ */
8760
+ exports.cwd = function cwd() {
8761
+ return process.cwd();
8762
+ };
8763
+
8231
8764
  }).call(this,require('_process'),require("buffer").Buffer)
8232
8765
  },{"./errors":6,"_process":69,"buffer":43,"fs":42,"glob":42,"he":54,"object.assign":65,"path":42,"util":89}],39:[function(require,module,exports){
8233
8766
  'use strict'
@@ -18108,7 +18641,7 @@ function hasOwnProperty(obj, prop) {
18108
18641
  },{"./support/isBuffer":88,"_process":69,"inherits":56}],90:[function(require,module,exports){
18109
18642
  module.exports={
18110
18643
  "name": "mocha",
18111
- "version": "7.1.2",
18644
+ "version": "7.2.0",
18112
18645
  "homepage": "https://mochajs.org/",
18113
18646
  "notifyLogo": "https://ibin.co/4QuRuGjXvl36.png"
18114
18647
  }