mocha 7.0.1 → 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
  */
@@ -62,7 +73,7 @@ process.on = function(e, fn) {
62
73
  if (e === 'uncaughtException') {
63
74
  global.onerror = function(err, url, line) {
64
75
  fn(new Error(err + ' (' + url + ':' + line + ')'));
65
- return !mocha.allowUncaught;
76
+ return !mocha.options.allowUncaught;
66
77
  };
67
78
  uncaughtExceptionHandlers.push(fn);
68
79
  }
@@ -131,7 +142,7 @@ mocha.setup = function(opts) {
131
142
  opts = {ui: opts};
132
143
  }
133
144
  for (var opt in opts) {
134
- if (opts.hasOwnProperty(opt)) {
145
+ if (Object.prototype.hasOwnProperty.call(opts, opt)) {
135
146
  this[opt](opts[opt]);
136
147
  }
137
148
  }
@@ -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
 
@@ -1408,9 +1600,14 @@ var utils = require('./utils');
1408
1600
  var mocharc = require('./mocharc.json');
1409
1601
  var errors = require('./errors');
1410
1602
  var Suite = require('./suite');
1603
+ var esmUtils = utils.supportsEsModules() ? require('./esm-utils') : undefined;
1411
1604
  var createStatsCollector = require('./stats-collector');
1412
1605
  var createInvalidReporterError = errors.createInvalidReporterError;
1413
1606
  var createInvalidInterfaceError = errors.createInvalidInterfaceError;
1607
+ var createMochaInstanceAlreadyDisposedError =
1608
+ errors.createMochaInstanceAlreadyDisposedError;
1609
+ var createMochaInstanceAlreadyRunningError =
1610
+ errors.createMochaInstanceAlreadyRunningError;
1414
1611
  var EVENT_FILE_PRE_REQUIRE = Suite.constants.EVENT_FILE_PRE_REQUIRE;
1415
1612
  var EVENT_FILE_POST_REQUIRE = Suite.constants.EVENT_FILE_POST_REQUIRE;
1416
1613
  var EVENT_FILE_REQUIRE = Suite.constants.EVENT_FILE_REQUIRE;
@@ -1418,12 +1615,36 @@ var sQuote = utils.sQuote;
1418
1615
 
1419
1616
  exports = module.exports = Mocha;
1420
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
+
1421
1642
  /**
1422
1643
  * To require local UIs and reporters when running in node.
1423
1644
  */
1424
1645
 
1425
- if (!process.browser) {
1426
- var cwd = process.cwd();
1646
+ if (!process.browser && typeof module.paths !== 'undefined') {
1647
+ var cwd = utils.cwd();
1427
1648
  module.paths.push(cwd, path.join(cwd, 'node_modules'));
1428
1649
  }
1429
1650
 
@@ -1483,6 +1704,8 @@ exports.Test = require('./test');
1483
1704
  * @param {number} [options.slow] - Slow threshold value.
1484
1705
  * @param {number|string} [options.timeout] - Timeout threshold value.
1485
1706
  * @param {string} [options.ui] - Interface name.
1707
+ * @param {MochaRootHookObject} [options.rootHooks] - Hooks to bootstrap the root
1708
+ * suite with
1486
1709
  */
1487
1710
  function Mocha(options) {
1488
1711
  options = utils.assign({}, mocharc, options || {});
@@ -1490,6 +1713,7 @@ function Mocha(options) {
1490
1713
  this.options = options;
1491
1714
  // root suite
1492
1715
  this.suite = new exports.Suite('', new exports.Context(), true);
1716
+ this._cleanReferencesAfterRun = true;
1493
1717
 
1494
1718
  this.grep(options.grep)
1495
1719
  .fgrep(options.fgrep)
@@ -1529,6 +1753,10 @@ function Mocha(options) {
1529
1753
  this[opt]();
1530
1754
  }
1531
1755
  }, this);
1756
+
1757
+ if (options.rootHooks) {
1758
+ this.rootHooks(options.rootHooks);
1759
+ }
1532
1760
  }
1533
1761
 
1534
1762
  /**
@@ -1595,24 +1823,24 @@ Mocha.prototype.reporter = function(reporter, reporterOptions) {
1595
1823
  _reporter = require(reporter);
1596
1824
  } catch (err) {
1597
1825
  if (
1598
- err.code !== 'MODULE_NOT_FOUND' ||
1599
- err.message.indexOf('Cannot find module') !== -1
1826
+ err.code === 'MODULE_NOT_FOUND' ||
1827
+ err.message.indexOf('Cannot find module') >= 0
1600
1828
  ) {
1601
1829
  // Try to load reporters from a path (absolute or relative)
1602
1830
  try {
1603
- _reporter = require(path.resolve(process.cwd(), reporter));
1831
+ _reporter = require(path.resolve(utils.cwd(), reporter));
1604
1832
  } catch (_err) {
1605
- _err.code !== 'MODULE_NOT_FOUND' ||
1606
- _err.message.indexOf('Cannot find module') !== -1
1607
- ? console.warn(sQuote(reporter) + ' reporter not found')
1608
- : 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(
1609
1837
  sQuote(reporter) +
1610
1838
  ' reporter blew up with error:\n' +
1611
1839
  err.stack
1612
1840
  );
1613
1841
  }
1614
1842
  } else {
1615
- console.warn(
1843
+ utils.warn(
1616
1844
  sQuote(reporter) + ' reporter blew up with error:\n' + err.stack
1617
1845
  );
1618
1846
  }
@@ -1684,16 +1912,18 @@ Mocha.prototype.ui = function(ui) {
1684
1912
  };
1685
1913
 
1686
1914
  /**
1687
- * Loads `files` prior to execution.
1915
+ * Loads `files` prior to execution. Does not support ES Modules.
1688
1916
  *
1689
1917
  * @description
1690
1918
  * The implementation relies on Node's `require` to execute
1691
1919
  * the test interface functions and will be subject to its cache.
1920
+ * Supports only CommonJS modules. To load ES modules, use Mocha#loadFilesAsync.
1692
1921
  *
1693
1922
  * @private
1694
1923
  * @see {@link Mocha#addFile}
1695
1924
  * @see {@link Mocha#run}
1696
1925
  * @see {@link Mocha#unloadFiles}
1926
+ * @see {@link Mocha#loadFilesAsync}
1697
1927
  * @param {Function} [fn] - Callback invoked upon completion.
1698
1928
  */
1699
1929
  Mocha.prototype.loadFiles = function(fn) {
@@ -1708,6 +1938,49 @@ Mocha.prototype.loadFiles = function(fn) {
1708
1938
  fn && fn();
1709
1939
  };
1710
1940
 
1941
+ /**
1942
+ * Loads `files` prior to execution. Supports Node ES Modules.
1943
+ *
1944
+ * @description
1945
+ * The implementation relies on Node's `require` and `import` to execute
1946
+ * the test interface functions and will be subject to its cache.
1947
+ * Supports both CJS and ESM modules.
1948
+ *
1949
+ * @public
1950
+ * @see {@link Mocha#addFile}
1951
+ * @see {@link Mocha#run}
1952
+ * @see {@link Mocha#unloadFiles}
1953
+ * @returns {Promise}
1954
+ * @example
1955
+ *
1956
+ * // loads ESM (and CJS) test files asynchronously, then runs root suite
1957
+ * mocha.loadFilesAsync()
1958
+ * .then(() => mocha.run(failures => process.exitCode = failures ? 1 : 0))
1959
+ * .catch(() => process.exitCode = 1);
1960
+ */
1961
+ Mocha.prototype.loadFilesAsync = function() {
1962
+ var self = this;
1963
+ var suite = this.suite;
1964
+ this.loadAsync = true;
1965
+
1966
+ if (!esmUtils) {
1967
+ return new Promise(function(resolve) {
1968
+ self.loadFiles(resolve);
1969
+ });
1970
+ }
1971
+
1972
+ return esmUtils.loadFilesAsync(
1973
+ this.files,
1974
+ function(file) {
1975
+ suite.emit(EVENT_FILE_PRE_REQUIRE, global, file, self);
1976
+ },
1977
+ function(file, resultModule) {
1978
+ suite.emit(EVENT_FILE_REQUIRE, resultModule, file, self);
1979
+ suite.emit(EVENT_FILE_POST_REQUIRE, global, file, self);
1980
+ }
1981
+ );
1982
+ };
1983
+
1711
1984
  /**
1712
1985
  * Removes a previously loaded file from Node's `require` cache.
1713
1986
  *
@@ -1724,8 +1997,9 @@ Mocha.unloadFile = function(file) {
1724
1997
  * Unloads `files` from Node's `require` cache.
1725
1998
  *
1726
1999
  * @description
1727
- * This allows files to be "freshly" reloaded, providing the ability
2000
+ * This allows required files to be "freshly" reloaded, providing the ability
1728
2001
  * to reuse a Mocha instance programmatically.
2002
+ * Note: does not clear ESM module files from the cache
1729
2003
  *
1730
2004
  * <strong>Intended for consumers &mdash; not used internally</strong>
1731
2005
  *
@@ -1735,7 +2009,18 @@ Mocha.unloadFile = function(file) {
1735
2009
  * @chainable
1736
2010
  */
1737
2011
  Mocha.prototype.unloadFiles = function() {
1738
- 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;
1739
2024
  return this;
1740
2025
  };
1741
2026
 
@@ -1853,6 +2138,38 @@ Mocha.prototype.checkLeaks = function(checkLeaks) {
1853
2138
  return this;
1854
2139
  };
1855
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
+
1856
2173
  /**
1857
2174
  * Displays full stack trace upon test failure.
1858
2175
  *
@@ -2203,6 +2520,28 @@ Mocha.prototype.forbidPending = function(forbidPending) {
2203
2520
  return this;
2204
2521
  };
2205
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
+
2206
2545
  /**
2207
2546
  * Mocha version as specified by "package.json".
2208
2547
  *
@@ -2236,16 +2575,30 @@ Object.defineProperty(Mocha.prototype, 'version', {
2236
2575
  * @see {@link Mocha#unloadFiles}
2237
2576
  * @see {@link Runner#run}
2238
2577
  * @param {DoneCB} [fn] - Callback invoked when test execution completed.
2239
- * @return {Runner} runner instance
2578
+ * @returns {Runner} runner instance
2579
+ * @example
2580
+ *
2581
+ * // exit with non-zero status if there were test failures
2582
+ * mocha.run(failures => process.exitCode = failures ? 1 : 0);
2240
2583
  */
2241
2584
  Mocha.prototype.run = function(fn) {
2242
- if (this.files.length) {
2585
+ this._guardRunningStateTransition();
2586
+ this._state = mochaStates.RUNNING;
2587
+ if (this._previousRunner) {
2588
+ this._previousRunner.dispose();
2589
+ this.suite.reset();
2590
+ }
2591
+ if (this.files.length && !this.loadAsync) {
2243
2592
  this.loadFiles();
2244
2593
  }
2594
+ var self = this;
2245
2595
  var suite = this.suite;
2246
2596
  var options = this.options;
2247
2597
  options.files = this.files;
2248
- var runner = new exports.Runner(suite, options.delay);
2598
+ var runner = new exports.Runner(suite, {
2599
+ delay: options.delay,
2600
+ cleanReferencesAfterRun: this._cleanReferencesAfterRun
2601
+ });
2249
2602
  createStatsCollector(runner);
2250
2603
  var reporter = new this._reporter(runner, options);
2251
2604
  runner.checkLeaks = options.checkLeaks === true;
@@ -2270,6 +2623,12 @@ Mocha.prototype.run = function(fn) {
2270
2623
  exports.reporters.Base.hideDiff = !options.diff;
2271
2624
 
2272
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
+ }
2273
2632
  fn = fn || utils.noop;
2274
2633
  if (reporter.done) {
2275
2634
  reporter.done(failures, fn);
@@ -2281,11 +2640,54 @@ Mocha.prototype.run = function(fn) {
2281
2640
  return runner.run(done);
2282
2641
  };
2283
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
+
2284
2686
  }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2285
- },{"../package.json":90,"./context":5,"./errors":6,"./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){
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){
2286
2688
  module.exports={
2287
2689
  "diff": true,
2288
- "extension": ["js"],
2690
+ "extension": ["js", "cjs", "mjs"],
2289
2691
  "opts": "./test/mocha.opts",
2290
2692
  "package": "./package.json",
2291
2693
  "reporter": "spec",
@@ -2901,6 +3303,7 @@ function Doc(runner, options) {
2901
3303
 
2902
3304
  runner.on(EVENT_TEST_PASS, function(test) {
2903
3305
  Base.consoleLog('%s <dt>%s</dt>', indent(), utils.escape(test.title));
3306
+ Base.consoleLog('%s <dt>%s</dt>', indent(), utils.escape(test.file));
2904
3307
  var code = utils.escape(utils.clean(test.body));
2905
3308
  Base.consoleLog('%s <dd><pre><code>%s</code></pre></dd>', indent(), code);
2906
3309
  });
@@ -2911,6 +3314,11 @@ function Doc(runner, options) {
2911
3314
  indent(),
2912
3315
  utils.escape(test.title)
2913
3316
  );
3317
+ Base.consoleLog(
3318
+ '%s <dt class="error">%s</dt>',
3319
+ indent(),
3320
+ utils.escape(test.file)
3321
+ );
2914
3322
  var code = utils.escape(utils.clean(test.body));
2915
3323
  Base.consoleLog(
2916
3324
  '%s <dd class="error"><pre><code>%s</code></pre></dd>',
@@ -3513,6 +3921,7 @@ function clean(test) {
3513
3921
  return {
3514
3922
  title: test.title,
3515
3923
  fullTitle: test.fullTitle(),
3924
+ file: test.file,
3516
3925
  duration: test.duration,
3517
3926
  currentRetry: test.currentRetry()
3518
3927
  };
@@ -3612,6 +4021,7 @@ function clean(test) {
3612
4021
  return {
3613
4022
  title: test.title,
3614
4023
  fullTitle: test.fullTitle(),
4024
+ file: test.file,
3615
4025
  duration: test.duration,
3616
4026
  currentRetry: test.currentRetry(),
3617
4027
  err: cleanCycles(err)
@@ -3762,6 +4172,14 @@ function Landing(runner, options) {
3762
4172
  process.stdout.write('\n');
3763
4173
  self.epilogue();
3764
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
+ });
3765
4183
  }
3766
4184
 
3767
4185
  /**
@@ -5042,8 +5460,9 @@ var Pending = require('./pending');
5042
5460
  var debug = require('debug')('mocha:runnable');
5043
5461
  var milliseconds = require('ms');
5044
5462
  var utils = require('./utils');
5045
- var createInvalidExceptionError = require('./errors')
5046
- .createInvalidExceptionError;
5463
+ var errors = require('./errors');
5464
+ var createInvalidExceptionError = errors.createInvalidExceptionError;
5465
+ var createMultipleDoneError = errors.createMultipleDoneError;
5047
5466
 
5048
5467
  /**
5049
5468
  * Save timer references to avoid Sinon interfering (see GH-237).
@@ -5073,10 +5492,8 @@ function Runnable(title, fn) {
5073
5492
  this._timeout = 2000;
5074
5493
  this._slow = 75;
5075
5494
  this._enableTimeouts = true;
5076
- this.timedOut = false;
5077
5495
  this._retries = -1;
5078
- this._currentRetry = 0;
5079
- this.pending = false;
5496
+ this.reset();
5080
5497
  }
5081
5498
 
5082
5499
  /**
@@ -5084,6 +5501,17 @@ function Runnable(title, fn) {
5084
5501
  */
5085
5502
  utils.inherits(Runnable, EventEmitter);
5086
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
+
5087
5515
  /**
5088
5516
  * Get current timeout value in msecs.
5089
5517
  *
@@ -5259,31 +5687,6 @@ Runnable.prototype.clearTimeout = function() {
5259
5687
  clearTimeout(this.timer);
5260
5688
  };
5261
5689
 
5262
- /**
5263
- * Inspect the runnable void of private properties.
5264
- *
5265
- * @private
5266
- * @return {string}
5267
- */
5268
- Runnable.prototype.inspect = function() {
5269
- return JSON.stringify(
5270
- this,
5271
- function(key, val) {
5272
- if (key[0] === '_') {
5273
- return;
5274
- }
5275
- if (key === 'parent') {
5276
- return '#<Suite>';
5277
- }
5278
- if (key === 'ctx') {
5279
- return '#<Context>';
5280
- }
5281
- return val;
5282
- },
5283
- 2
5284
- );
5285
- };
5286
-
5287
5690
  /**
5288
5691
  * Reset the timeout.
5289
5692
  *
@@ -5330,7 +5733,7 @@ Runnable.prototype.run = function(fn) {
5330
5733
  var start = new Date();
5331
5734
  var ctx = this.ctx;
5332
5735
  var finished;
5333
- var emitted;
5736
+ var errorWasHandled = false;
5334
5737
 
5335
5738
  // Sometimes the ctx exists, but it is not runnable
5336
5739
  if (ctx && ctx.runnable) {
@@ -5339,17 +5742,11 @@ Runnable.prototype.run = function(fn) {
5339
5742
 
5340
5743
  // called multiple times
5341
5744
  function multiple(err) {
5342
- if (emitted) {
5745
+ if (errorWasHandled) {
5343
5746
  return;
5344
5747
  }
5345
- emitted = true;
5346
- var msg = 'done() called multiple times';
5347
- if (err && err.message) {
5348
- err.message += " (and Mocha's " + msg + ')';
5349
- self.emit('error', err);
5350
- } else {
5351
- self.emit('error', new Error(msg));
5352
- }
5748
+ errorWasHandled = true;
5749
+ self.emit('error', createMultipleDoneError(self, err));
5353
5750
  }
5354
5751
 
5355
5752
  // finished
@@ -5400,7 +5797,7 @@ Runnable.prototype.run = function(fn) {
5400
5797
  callFnAsync(this.fn);
5401
5798
  } catch (err) {
5402
5799
  // handles async runnables which actually run synchronously
5403
- emitted = true;
5800
+ errorWasHandled = true;
5404
5801
  if (err instanceof Pending) {
5405
5802
  return; // done() is already called in this.skip()
5406
5803
  } else if (this.allowUncaught) {
@@ -5419,7 +5816,7 @@ Runnable.prototype.run = function(fn) {
5419
5816
  callFn(this.fn);
5420
5817
  }
5421
5818
  } catch (err) {
5422
- emitted = true;
5819
+ errorWasHandled = true;
5423
5820
  if (err instanceof Pending) {
5424
5821
  return done();
5425
5822
  } else if (this.allowUncaught) {
@@ -5564,7 +5961,6 @@ var EVENT_ROOT_SUITE_RUN = Suite.constants.EVENT_ROOT_SUITE_RUN;
5564
5961
  var STATE_FAILED = Runnable.constants.STATE_FAILED;
5565
5962
  var STATE_PASSED = Runnable.constants.STATE_PASSED;
5566
5963
  var dQuote = utils.dQuote;
5567
- var ngettext = utils.ngettext;
5568
5964
  var sQuote = utils.sQuote;
5569
5965
  var stackFilter = utils.stackTraceFilter();
5570
5966
  var stringify = utils.stringify;
@@ -5572,6 +5968,7 @@ var type = utils.type;
5572
5968
  var errors = require('./errors');
5573
5969
  var createInvalidExceptionError = errors.createInvalidExceptionError;
5574
5970
  var createUnsupportedError = errors.createUnsupportedError;
5971
+ var createFatalError = errors.createFatalError;
5575
5972
 
5576
5973
  /**
5577
5974
  * Non-enumerable globals.
@@ -5654,7 +6051,19 @@ var constants = utils.defineConstants(
5654
6051
  /**
5655
6052
  * Emitted when {@link Test} execution has failed, but will retry
5656
6053
  */
5657
- 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'
5658
6067
  }
5659
6068
  );
5660
6069
 
@@ -5666,20 +6075,36 @@ module.exports = Runner;
5666
6075
  * @extends external:EventEmitter
5667
6076
  * @public
5668
6077
  * @class
5669
- * @param {Suite} suite Root suite
5670
- * @param {boolean} [delay] Whether or not to delay execution of root suite
5671
- * until ready.
5672
- */
5673
- 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
+ }
5674
6093
  var self = this;
5675
6094
  this._globals = [];
5676
6095
  this._abort = false;
5677
- this._delay = delay;
5678
6096
  this.suite = suite;
5679
- this.started = false;
6097
+ this._opts = opts;
6098
+ this.state = constants.STATE_IDLE;
5680
6099
  this.total = suite.total();
5681
6100
  this.failures = 0;
6101
+ this._eventListeners = [];
5682
6102
  this.on(constants.EVENT_TEST_END, function(test) {
6103
+ if (test.type === 'test' && test.retriedTest() && test.parent) {
6104
+ var idx =
6105
+ test.parent.tests && test.parent.tests.indexOf(test.retriedTest());
6106
+ if (idx > -1) test.parent.tests[idx] = test;
6107
+ }
5683
6108
  self.checkGlobals(test);
5684
6109
  });
5685
6110
  this.on(constants.EVENT_HOOK_END, function(hook) {
@@ -5688,6 +6113,8 @@ function Runner(suite, delay) {
5688
6113
  this._defaultGrep = /.*/;
5689
6114
  this.grep(this._defaultGrep);
5690
6115
  this.globals(this.globalProps());
6116
+
6117
+ this.uncaught = this._uncaught.bind(this);
5691
6118
  }
5692
6119
 
5693
6120
  /**
@@ -5703,6 +6130,56 @@ Runner.immediately = global.setImmediate || process.nextTick;
5703
6130
  */
5704
6131
  inherits(Runner, EventEmitter);
5705
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
+
5706
6183
  /**
5707
6184
  * Run tests with full titles matching `re`. Updates runner.total
5708
6185
  * with number of tests matched.
@@ -5714,7 +6191,7 @@ inherits(Runner, EventEmitter);
5714
6191
  * @return {Runner} Runner instance.
5715
6192
  */
5716
6193
  Runner.prototype.grep = function(re, invert) {
5717
- debug('grep %s', re);
6194
+ debug('grep(): setting to %s', re);
5718
6195
  this._grep = re;
5719
6196
  this._invert = invert;
5720
6197
  this.total = this.grepTotal(this.suite);
@@ -5779,7 +6256,7 @@ Runner.prototype.globals = function(arr) {
5779
6256
  if (!arguments.length) {
5780
6257
  return this._globals;
5781
6258
  }
5782
- debug('globals %j', arr);
6259
+ debug('globals(): setting to %O', arr);
5783
6260
  this._globals = this._globals.concat(arr);
5784
6261
  return this;
5785
6262
  };
@@ -5811,12 +6288,8 @@ Runner.prototype.checkGlobals = function(test) {
5811
6288
  this._globals = this._globals.concat(leaks);
5812
6289
 
5813
6290
  if (leaks.length) {
5814
- var format = ngettext(
5815
- leaks.length,
5816
- 'global leak detected: %s',
5817
- 'global leaks detected: %s'
5818
- );
5819
- var error = new Error(util.format(format, leaks.map(sQuote).join(', ')));
6291
+ var msg = 'global leak(s) detected: %s';
6292
+ var error = new Error(util.format(msg, leaks.map(sQuote).join(', ')));
5820
6293
  this.fail(test, error);
5821
6294
  }
5822
6295
  };
@@ -5832,8 +6305,18 @@ Runner.prototype.fail = function(test, err) {
5832
6305
  if (test.isPending()) {
5833
6306
  return;
5834
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
+ }
5835
6317
 
5836
6318
  ++this.failures;
6319
+ debug('total number of failures: %d', this.failures);
5837
6320
  test.state = STATE_FAILED;
5838
6321
 
5839
6322
  if (!isError(err)) {
@@ -5921,7 +6404,7 @@ Runner.prototype.hook = function(name, fn) {
5921
6404
  self.emit(constants.EVENT_HOOK_BEGIN, hook);
5922
6405
 
5923
6406
  if (!hook.listeners('error').length) {
5924
- hook.on('error', function(err) {
6407
+ self._addEventListener(hook, 'error', function(err) {
5925
6408
  self.failHook(hook, err);
5926
6409
  });
5927
6410
  }
@@ -6064,18 +6547,10 @@ Runner.prototype.runTest = function(fn) {
6064
6547
  return;
6065
6548
  }
6066
6549
 
6067
- var suite = this.parents().reverse()[0] || this.suite;
6068
- if (this.forbidOnly && suite.hasOnly()) {
6069
- fn(new Error('`.only` forbidden'));
6070
- return;
6071
- }
6072
6550
  if (this.asyncOnly) {
6073
6551
  test.asyncOnly = true;
6074
6552
  }
6075
- test.on('error', function(err) {
6076
- if (err instanceof Pending) {
6077
- return;
6078
- }
6553
+ this._addEventListener(test, 'error', function(err) {
6079
6554
  self.fail(test, err);
6080
6555
  });
6081
6556
  if (this.allowUncaught) {
@@ -6270,9 +6745,10 @@ Runner.prototype.runSuite = function(suite, fn) {
6270
6745
  var self = this;
6271
6746
  var total = this.grepTotal(suite);
6272
6747
 
6273
- debug('run suite %s', suite.fullTitle());
6748
+ debug('runSuite(): running %s', suite.fullTitle());
6274
6749
 
6275
6750
  if (!total || (self.failures && suite._bail)) {
6751
+ debug('runSuite(): bailing');
6276
6752
  return fn();
6277
6753
  }
6278
6754
 
@@ -6338,21 +6814,49 @@ Runner.prototype.runSuite = function(suite, fn) {
6338
6814
  /**
6339
6815
  * Handle uncaught exceptions within runner.
6340
6816
  *
6341
- * @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
6342
6828
  * @private
6343
6829
  */
6344
- 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
+ }
6345
6841
  if (err instanceof Pending) {
6842
+ debug('uncaught(): caught a Pending');
6346
6843
  return;
6347
6844
  }
6348
- if (this.allowUncaught) {
6845
+ // browser does not exit script when throwing in global.onerror()
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!');
6349
6853
  throw err;
6350
6854
  }
6351
6855
 
6352
6856
  if (err) {
6353
- debug('uncaught exception %O', err);
6857
+ debug('uncaught(): got truthy exception %O', err);
6354
6858
  } else {
6355
- debug('uncaught undefined/falsy exception');
6859
+ debug('uncaught(): undefined/falsy exception');
6356
6860
  err = createInvalidExceptionError(
6357
6861
  'Caught falsy/undefined exception which would otherwise be uncaught. No stack trace found; try a debugger',
6358
6862
  err
@@ -6361,6 +6865,7 @@ Runner.prototype.uncaught = function(err) {
6361
6865
 
6362
6866
  if (!isError(err)) {
6363
6867
  err = thrown2Error(err);
6868
+ debug('uncaught(): converted "error" %o to Error', err);
6364
6869
  }
6365
6870
  err.uncaught = true;
6366
6871
 
@@ -6368,12 +6873,15 @@ Runner.prototype.uncaught = function(err) {
6368
6873
 
6369
6874
  if (!runnable) {
6370
6875
  runnable = new Runnable('Uncaught error outside test suite');
6876
+ debug('uncaught(): no current Runnable; created a phony one');
6371
6877
  runnable.parent = this.suite;
6372
6878
 
6373
- if (this.started) {
6879
+ if (this.state === constants.STATE_RUNNING) {
6880
+ debug('uncaught(): failing gracefully');
6374
6881
  this.fail(runnable, err);
6375
6882
  } else {
6376
6883
  // Can't recover from this failure
6884
+ debug('uncaught(): test run has not yet started; unrecoverable');
6377
6885
  this.emit(constants.EVENT_RUN_BEGIN);
6378
6886
  this.fail(runnable, err);
6379
6887
  this.emit(constants.EVENT_RUN_END);
@@ -6385,9 +6893,11 @@ Runner.prototype.uncaught = function(err) {
6385
6893
  runnable.clearTimeout();
6386
6894
 
6387
6895
  if (runnable.isFailed()) {
6896
+ debug('uncaught(): Runnable has already failed');
6388
6897
  // Ignore error if already failed
6389
6898
  return;
6390
6899
  } else if (runnable.isPending()) {
6900
+ debug('uncaught(): pending Runnable wound up failing!');
6391
6901
  // report 'pending test' retrospectively as failed
6392
6902
  runnable.isPending = alwaysFalse;
6393
6903
  this.fail(runnable, err);
@@ -6398,25 +6908,15 @@ Runner.prototype.uncaught = function(err) {
6398
6908
  // we cannot recover gracefully if a Runnable has already passed
6399
6909
  // then fails asynchronously
6400
6910
  if (runnable.isPassed()) {
6911
+ debug('uncaught(): Runnable has already passed; bailing gracefully');
6401
6912
  this.fail(runnable, err);
6402
6913
  this.abort();
6403
6914
  } else {
6404
- debug(runnable);
6915
+ debug('uncaught(): forcing Runnable to complete with Error');
6405
6916
  return runnable.callback(err);
6406
6917
  }
6407
6918
  };
6408
6919
 
6409
- /**
6410
- * Handle uncaught exceptions after runner's end event.
6411
- *
6412
- * @param {Error} err
6413
- * @private
6414
- */
6415
- Runner.prototype.uncaughtEnd = function uncaughtEnd(err) {
6416
- if (err instanceof Pending) return;
6417
- throw err;
6418
- };
6419
-
6420
6920
  /**
6421
6921
  * Run the root suite and invoke `fn(failures)`
6422
6922
  * on completion.
@@ -6432,53 +6932,60 @@ Runner.prototype.run = function(fn) {
6432
6932
 
6433
6933
  fn = fn || function() {};
6434
6934
 
6435
- function uncaught(err) {
6436
- self.uncaught(err);
6437
- }
6438
-
6439
6935
  function start() {
6936
+ debug('run(): starting');
6440
6937
  // If there is an `only` filter
6441
6938
  if (rootSuite.hasOnly()) {
6442
6939
  rootSuite.filterOnly();
6940
+ debug('run(): filtered exclusive Runnables');
6443
6941
  }
6444
- self.started = true;
6942
+ self.state = constants.STATE_RUNNING;
6445
6943
  if (self._delay) {
6446
6944
  self.emit(constants.EVENT_DELAY_END);
6945
+ debug('run(): "delay" ended');
6447
6946
  }
6947
+ debug('run(): emitting %s', constants.EVENT_RUN_BEGIN);
6448
6948
  self.emit(constants.EVENT_RUN_BEGIN);
6949
+ debug('run(): emitted %s', constants.EVENT_RUN_BEGIN);
6449
6950
 
6450
6951
  self.runSuite(rootSuite, function() {
6451
- debug('finished running');
6952
+ debug(
6953
+ 'run(): root suite completed; emitting %s',
6954
+ constants.EVENT_RUN_END
6955
+ );
6452
6956
  self.emit(constants.EVENT_RUN_END);
6957
+ debug('run(): emitted %s', constants.EVENT_RUN_END);
6453
6958
  });
6454
6959
  }
6455
6960
 
6456
- debug(constants.EVENT_RUN_BEGIN);
6457
-
6458
6961
  // references cleanup to avoid memory leaks
6459
- this.on(constants.EVENT_SUITE_END, function(suite) {
6460
- suite.cleanReferences();
6461
- });
6962
+ if (this._opts.cleanReferencesAfterRun) {
6963
+ this.on(constants.EVENT_SUITE_END, function(suite) {
6964
+ suite.cleanReferences();
6965
+ });
6966
+ }
6462
6967
 
6463
6968
  // callback
6464
6969
  this.on(constants.EVENT_RUN_END, function() {
6970
+ self.state = constants.STATE_STOPPED;
6465
6971
  debug(constants.EVENT_RUN_END);
6466
- process.removeListener('uncaughtException', uncaught);
6467
- process.on('uncaughtException', self.uncaughtEnd);
6972
+ debug('run(): emitted %s', constants.EVENT_RUN_END);
6468
6973
  fn(self.failures);
6469
6974
  });
6470
6975
 
6471
- // uncaught exception
6472
- process.removeListener('uncaughtException', self.uncaughtEnd);
6473
- process.on('uncaughtException', uncaught);
6976
+ self._removeEventListener(process, 'uncaughtException', self.uncaught);
6977
+ self._addEventListener(process, 'uncaughtException', self.uncaught);
6474
6978
 
6475
6979
  if (this._delay) {
6476
6980
  // for reporters, I guess.
6477
6981
  // might be nice to debounce some dots while we wait.
6478
6982
  this.emit(constants.EVENT_DELAY_BEGIN, rootSuite);
6479
6983
  rootSuite.once(EVENT_ROOT_SUITE_RUN, start);
6984
+ debug('run(): waiting for green light due to --delay');
6480
6985
  } else {
6481
- start();
6986
+ Runner.immediately(function() {
6987
+ start();
6988
+ });
6482
6989
  }
6483
6990
 
6484
6991
  return this;
@@ -6492,7 +6999,7 @@ Runner.prototype.run = function(fn) {
6492
6999
  * @return {Runner} Runner instance.
6493
7000
  */
6494
7001
  Runner.prototype.abort = function() {
6495
- debug('aborting');
7002
+ debug('abort(): aborting');
6496
7003
  this._abort = true;
6497
7004
 
6498
7005
  return this;
@@ -6727,20 +7234,20 @@ function Suite(title, parentContext, isRoot) {
6727
7234
  this.ctx = new Context();
6728
7235
  this.suites = [];
6729
7236
  this.tests = [];
7237
+ this.root = isRoot === true;
6730
7238
  this.pending = false;
7239
+ this._retries = -1;
6731
7240
  this._beforeEach = [];
6732
7241
  this._beforeAll = [];
6733
7242
  this._afterEach = [];
6734
7243
  this._afterAll = [];
6735
- this.root = isRoot === true;
6736
7244
  this._timeout = 2000;
6737
7245
  this._enableTimeouts = true;
6738
7246
  this._slow = 75;
6739
7247
  this._bail = false;
6740
- this._retries = -1;
6741
7248
  this._onlyTests = [];
6742
7249
  this._onlySuites = [];
6743
- this.delayed = false;
7250
+ this.reset();
6744
7251
 
6745
7252
  this.on('newListener', function(event) {
6746
7253
  if (deprecatedEvents[event]) {
@@ -6758,6 +7265,22 @@ function Suite(title, parentContext, isRoot) {
6758
7265
  */
6759
7266
  inherits(Suite, EventEmitter);
6760
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
+
6761
7284
  /**
6762
7285
  * Return a clone of this `Suite`.
6763
7286
  *
@@ -7177,6 +7700,16 @@ Suite.prototype.getHooks = function getHooks(name) {
7177
7700
  return this['_' + name];
7178
7701
  };
7179
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
+
7180
7713
  /**
7181
7714
  * Cleans up the references to all the deferred functions
7182
7715
  * (before/after/beforeEach/afterEach) and tests of a Suite.
@@ -7336,9 +7869,9 @@ function Test(title, fn) {
7336
7869
  'string'
7337
7870
  );
7338
7871
  }
7339
- Runnable.call(this, title, fn);
7340
- this.pending = !fn;
7341
7872
  this.type = 'test';
7873
+ Runnable.call(this, title, fn);
7874
+ this.reset();
7342
7875
  }
7343
7876
 
7344
7877
  /**
@@ -7346,6 +7879,36 @@ function Test(title, fn) {
7346
7879
  */
7347
7880
  utils.inherits(Test, Runnable);
7348
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
+
7891
+ /**
7892
+ * Set or get retried test
7893
+ *
7894
+ * @private
7895
+ */
7896
+ Test.prototype.retriedTest = function(n) {
7897
+ if (!arguments.length) {
7898
+ return this._retriedTest;
7899
+ }
7900
+ this._retriedTest = n;
7901
+ };
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
+
7349
7912
  Test.prototype.clone = function() {
7350
7913
  var test = new Test(this.title, this.fn);
7351
7914
  test.timeout(this.timeout());
@@ -7353,6 +7916,7 @@ Test.prototype.clone = function() {
7353
7916
  test.enableTimeouts(this.enableTimeouts());
7354
7917
  test.retries(this.retries());
7355
7918
  test.currentRetry(this.currentRetry());
7919
+ test.retriedTest(this.retriedTest() || this);
7356
7920
  test.globals(this.globals());
7357
7921
  test.parent = this.parent;
7358
7922
  test.file = this.file;
@@ -7427,8 +7991,9 @@ exports.isString = function(obj) {
7427
7991
  exports.slug = function(str) {
7428
7992
  return str
7429
7993
  .toLowerCase()
7430
- .replace(/ +/g, '-')
7431
- .replace(/[^-\w]/g, '');
7994
+ .replace(/\s+/g, '-')
7995
+ .replace(/[^-\w]/g, '')
7996
+ .replace(/-{2,}/g, '-');
7432
7997
  };
7433
7998
 
7434
7999
  /**
@@ -8001,7 +8566,7 @@ exports.stackTraceFilter = function() {
8001
8566
  var slash = path.sep;
8002
8567
  var cwd;
8003
8568
  if (is.node) {
8004
- cwd = process.cwd() + slash;
8569
+ cwd = exports.cwd() + slash;
8005
8570
  } else {
8006
8571
  cwd = (typeof location === 'undefined'
8007
8572
  ? window.location
@@ -8117,38 +8682,6 @@ exports.dQuote = function(str) {
8117
8682
  return '"' + str + '"';
8118
8683
  };
8119
8684
 
8120
- /**
8121
- * Provides simplistic message translation for dealing with plurality.
8122
- *
8123
- * @description
8124
- * Use this to create messages which need to be singular or plural.
8125
- * Some languages have several plural forms, so _complete_ message clauses
8126
- * are preferable to generating the message on the fly.
8127
- *
8128
- * @private
8129
- * @param {number} n - Non-negative integer
8130
- * @param {string} msg1 - Message to be used in English for `n = 1`
8131
- * @param {string} msg2 - Message to be used in English for `n = 0, 2, 3, ...`
8132
- * @returns {string} message corresponding to value of `n`
8133
- * @example
8134
- * var sprintf = require('util').format;
8135
- * var pkgs = ['one', 'two'];
8136
- * var msg = sprintf(
8137
- * ngettext(
8138
- * pkgs.length,
8139
- * 'cannot load package: %s',
8140
- * 'cannot load packages: %s'
8141
- * ),
8142
- * pkgs.map(sQuote).join(', ')
8143
- * );
8144
- * console.log(msg); // => cannot load packages: 'one', 'two'
8145
- */
8146
- exports.ngettext = function(n, msg1, msg2) {
8147
- if (typeof n === 'number' && n >= 0) {
8148
- return n === 1 ? msg1 : msg2;
8149
- }
8150
- };
8151
-
8152
8685
  /**
8153
8686
  * It's a noop.
8154
8687
  * @public
@@ -8196,6 +8729,38 @@ exports.defineConstants = function(obj) {
8196
8729
  return Object.freeze(exports.createMap(obj));
8197
8730
  };
8198
8731
 
8732
+ /**
8733
+ * Whether current version of Node support ES modules
8734
+ *
8735
+ * @description
8736
+ * Versions prior to 10 did not support ES Modules, and version 10 has an old incompatibile version of ESM.
8737
+ * This function returns whether Node.JS has ES Module supports that is compatible with Mocha's needs,
8738
+ * which is version >=12.11.
8739
+ *
8740
+ * @returns {Boolean} whether the current version of Node.JS supports ES Modules in a way that is compatible with Mocha
8741
+ */
8742
+ exports.supportsEsModules = function() {
8743
+ if (!process.browser && process.versions && process.versions.node) {
8744
+ var versionFields = process.versions.node.split('.');
8745
+ var major = +versionFields[0];
8746
+ var minor = +versionFields[1];
8747
+
8748
+ if (major >= 13 || (major === 12 && minor >= 11)) {
8749
+ return true;
8750
+ }
8751
+ }
8752
+ };
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
+
8199
8764
  }).call(this,require('_process'),require("buffer").Buffer)
8200
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){
8201
8766
  'use strict'
@@ -13746,7 +14311,6 @@ module.exports = Array.isArray || function (arr) {
13746
14311
  };
13747
14312
 
13748
14313
  },{}],59:[function(require,module,exports){
13749
- (function (process){
13750
14314
  var path = require('path');
13751
14315
  var fs = require('fs');
13752
14316
  var _0777 = parseInt('0777', 8);
@@ -13766,7 +14330,7 @@ function mkdirP (p, opts, f, made) {
13766
14330
  var xfs = opts.fs || fs;
13767
14331
 
13768
14332
  if (mode === undefined) {
13769
- mode = _0777 & (~process.umask());
14333
+ mode = _0777
13770
14334
  }
13771
14335
  if (!made) made = null;
13772
14336
 
@@ -13780,6 +14344,7 @@ function mkdirP (p, opts, f, made) {
13780
14344
  }
13781
14345
  switch (er.code) {
13782
14346
  case 'ENOENT':
14347
+ if (path.dirname(p) === p) return cb(er);
13783
14348
  mkdirP(path.dirname(p), opts, function (er, made) {
13784
14349
  if (er) cb(er, made);
13785
14350
  else mkdirP(p, opts, cb, made);
@@ -13810,7 +14375,7 @@ mkdirP.sync = function sync (p, opts, made) {
13810
14375
  var xfs = opts.fs || fs;
13811
14376
 
13812
14377
  if (mode === undefined) {
13813
- mode = _0777 & (~process.umask());
14378
+ mode = _0777
13814
14379
  }
13815
14380
  if (!made) made = null;
13816
14381
 
@@ -13846,8 +14411,7 @@ mkdirP.sync = function sync (p, opts, made) {
13846
14411
  return made;
13847
14412
  };
13848
14413
 
13849
- }).call(this,require('_process'))
13850
- },{"_process":69,"fs":42,"path":42}],60:[function(require,module,exports){
14414
+ },{"fs":42,"path":42}],60:[function(require,module,exports){
13851
14415
  /**
13852
14416
  * Helpers.
13853
14417
  */
@@ -18077,7 +18641,7 @@ function hasOwnProperty(obj, prop) {
18077
18641
  },{"./support/isBuffer":88,"_process":69,"inherits":56}],90:[function(require,module,exports){
18078
18642
  module.exports={
18079
18643
  "name": "mocha",
18080
- "version": "7.0.1",
18644
+ "version": "7.2.0",
18081
18645
  "homepage": "https://mochajs.org/",
18082
18646
  "notifyLogo": "https://ibin.co/4QuRuGjXvl36.png"
18083
18647
  }