mocha 12.0.0-beta-4 → 12.0.0-beta-6

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/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  <p align="center">
2
- <img src="assets/mocha-logo.svg" alt="Mocha test framework logo"/>
2
+ <img src="docs-next/src/components/mocha-logo.svg" alt="Mocha test framework logo"/>
3
3
  </p>
4
4
 
5
- <p align="center">☕️ Simple, flexible, fun JavaScript test framework for Node.js & The Browser ☕️</p>
5
+ <p align="center">☕️ Classic, reliable, trusted test framework for Node.js and the browser ☕️</p>
6
6
 
7
7
  <div align="center">
8
8
 
@@ -35,6 +35,7 @@ const TYPES = (exports.types = {
35
35
  "diff",
36
36
  "dry-run",
37
37
  "exit",
38
+ "fail-hook-affected-tests",
38
39
  "pass-on-failing-test-suite",
39
40
  "fail-zero",
40
41
  "forbid-only",
package/lib/cli/run.js CHANGED
@@ -104,6 +104,11 @@ exports.builder = (yargs) =>
104
104
  description: "Not fail test run if tests were failed",
105
105
  group: GROUPS.RULES,
106
106
  },
107
+ "fail-hook-affected-tests": {
108
+ description:
109
+ "Report tests as failed when affected by hook failures (before/beforeEach)",
110
+ group: GROUPS.RULES,
111
+ },
107
112
  "fail-zero": {
108
113
  description: "Fail test run if no test(s) encountered",
109
114
  group: GROUPS.RULES,
package/lib/mocha.js CHANGED
@@ -846,6 +846,20 @@ Mocha.prototype.dryRun = function (dryRun) {
846
846
  return this;
847
847
  };
848
848
 
849
+ /**
850
+ * Reports tests as failed when they are skipped due to a hook failure.
851
+ *
852
+ * @public
853
+ * @see [CLI option](../#-fail-hook-affected-tests)
854
+ * @param {boolean} [failHookAffectedTests=true] - Whether to fail tests affected by hook failures.
855
+ * @return {Mocha} this
856
+ * @chainable
857
+ */
858
+ Mocha.prototype.failHookAffectedTests = function (failHookAffectedTests) {
859
+ this.options.failHookAffectedTests = failHookAffectedTests !== false;
860
+ return this;
861
+ };
862
+
849
863
  /**
850
864
  * Fails test run if no tests encountered with exit-code 1.
851
865
  *
@@ -974,6 +988,7 @@ Mocha.prototype.run = function (fn) {
974
988
  cleanReferencesAfterRun: this._cleanReferencesAfterRun,
975
989
  delay: options.delay,
976
990
  dryRun: options.dryRun,
991
+ failHookAffectedTests: options.failHookAffectedTests,
977
992
  failZero: options.failZero,
978
993
  });
979
994
  createStatsCollector(runner);
@@ -1,6 +1,7 @@
1
1
  const path = require("node:path");
2
2
  const url = require("node:url");
3
3
  const debug = require("debug")("mocha:esm-utils");
4
+ const { isMochaError } = require("../errors");
4
5
 
5
6
  const forward = (x) => x;
6
7
 
@@ -98,7 +99,7 @@ const requireModule = async (file, esmDecorator) => {
98
99
  return require(file);
99
100
  } catch (requireErr) {
100
101
  debug("requireModule caught err: %O", requireErr.message);
101
- if (requireErr.name === "TSError") {
102
+ if (requireErr.name === "TSError" || isMochaError(requireErr)) {
102
103
  throw requireErr;
103
104
  }
104
105
  try {
package/lib/runner.js CHANGED
@@ -182,6 +182,7 @@ class Runner extends EventEmitter {
182
182
  * @param {boolean} [opts.delay] - Whether to delay execution of root suite until ready.
183
183
  * @param {boolean} [opts.dryRun] - Whether to report tests without running them.
184
184
  * @param {boolean} [opts.failZero] - Whether to fail test run if zero tests encountered.
185
+ * @param {boolean} [opts.failHookAffectedTests] - Whether to fail all tests affected by hook failures.
185
186
  */
186
187
  constructor(suite, opts = {}) {
187
188
  super();
@@ -441,6 +442,73 @@ Runner.prototype.checkGlobals = function (test) {
441
442
  }
442
443
  };
443
444
 
445
+ /**
446
+ * Create an error object for a test that was skipped due to a hook failure.
447
+ *
448
+ * @private
449
+ * @param {string} hookTitle - The title of the failed hook
450
+ * @param {*} hookError - The error from the failed hook (may not be an Error object)
451
+ * @returns {Error} The error object for the skipped test
452
+ */
453
+ function createHookSkipError(hookTitle, hookError) {
454
+ // Handle falsy or undefined exceptions
455
+ if (!hookError) {
456
+ hookError = createInvalidExceptionError(
457
+ 'Hook "' + hookTitle + '" failed with exception: ' + hookError,
458
+ hookError,
459
+ );
460
+ }
461
+ // Convert non-Error objects to Error
462
+ else if (!isError(hookError)) {
463
+ hookError = thrown2Error(hookError);
464
+ }
465
+
466
+ var errorMessage =
467
+ 'Test skipped due to failure in hook "' +
468
+ hookTitle +
469
+ '": ' +
470
+ hookError.message;
471
+ var testError = new Error(errorMessage);
472
+ testError.stack = hookError.stack;
473
+ return testError;
474
+ }
475
+
476
+ /**
477
+ * Fail all tests that are affected by a hook failure.
478
+ * This is used when the `failHookAffectedTests` option is enabled.
479
+ *
480
+ * @private
481
+ * @param {Suite} suite - The suite containing the affected tests
482
+ * @param {Error} hookError - The error from the failed hook
483
+ * @param {string} hookTitle - The title of the failed hook
484
+ */
485
+ Runner.prototype.failAffectedTests = function (suite, hookError, hookTitle) {
486
+ if (!this._opts.failHookAffectedTests) {
487
+ return;
488
+ }
489
+
490
+ var self = this;
491
+ var testError = createHookSkipError(hookTitle, hookError);
492
+
493
+ // Recursively fail all tests in this suite and its child suites
494
+ function failTestsInSuite(s) {
495
+ s.tests.forEach(function (test) {
496
+ // Only fail tests that haven't been executed yet
497
+ if (!test.state) {
498
+ test.state = STATE_FAILED;
499
+ self.failures++;
500
+ self.emit(constants.EVENT_TEST_BEGIN, test);
501
+ self.emit(constants.EVENT_TEST_FAIL, test, testError);
502
+ self.emit(constants.EVENT_TEST_END, test);
503
+ }
504
+ });
505
+
506
+ s.suites.forEach(failTestsInSuite);
507
+ }
508
+
509
+ failTestsInSuite(suite);
510
+ };
511
+
444
512
  /**
445
513
  * Fail the given `test`.
446
514
  *
@@ -583,6 +651,28 @@ Runner.prototype.hook = function (name, fn) {
583
651
  }
584
652
  } else if (err) {
585
653
  self.fail(hook, err);
654
+ // If failHookAffectedTests is enabled, mark affected tests as failed
655
+ if (self._opts.failHookAffectedTests) {
656
+ if (name === HOOK_TYPE_BEFORE_ALL) {
657
+ self.failAffectedTests(self.suite, err, hook.title);
658
+ } else if (name === HOOK_TYPE_BEFORE_EACH) {
659
+ // Fail the current test
660
+ if (self.test && !self.test.state) {
661
+ var testError = createHookSkipError(hook.title, err);
662
+
663
+ self.test.state = STATE_FAILED;
664
+ self.failures++;
665
+ self.emit(constants.EVENT_TEST_BEGIN, self.test);
666
+ self.emit(constants.EVENT_TEST_FAIL, self.test, testError);
667
+ self.emit(constants.EVENT_TEST_END, self.test);
668
+ }
669
+ // Store the hook error info for remaining tests
670
+ self._failedBeforeEachHook = {
671
+ error: err,
672
+ title: hook.title,
673
+ };
674
+ }
675
+ }
586
676
  // stop executing hooks, notify callee of hook err
587
677
  return fn(err);
588
678
  }
@@ -734,10 +824,37 @@ Runner.prototype.runTests = function (suite, fn) {
734
824
  var tests = suite.tests.slice();
735
825
  var test;
736
826
 
737
- function hookErr(_, errSuite, after) {
827
+ function hookErr(err, errSuite, after) {
738
828
  // before/after Each hook for errSuite failed:
739
829
  var orig = self.suite;
740
830
 
831
+ // If failHookAffectedTests is enabled and this is a beforeEach failure,
832
+ // mark remaining tests as failed
833
+ if (
834
+ self._opts.failHookAffectedTests &&
835
+ !after &&
836
+ self._failedBeforeEachHook
837
+ ) {
838
+ // Fail all remaining tests in the suite
839
+ var remainingTests = tests.slice();
840
+ remainingTests.forEach(function (t) {
841
+ if (!t.state) {
842
+ var testError = createHookSkipError(
843
+ self._failedBeforeEachHook.title,
844
+ self._failedBeforeEachHook.error,
845
+ );
846
+
847
+ t.state = STATE_FAILED;
848
+ self.failures++;
849
+ self.emit(constants.EVENT_TEST_BEGIN, t);
850
+ self.emit(constants.EVENT_TEST_FAIL, t, testError);
851
+ self.emit(constants.EVENT_TEST_END, t);
852
+ }
853
+ });
854
+ // Clear the stored hook info
855
+ delete self._failedBeforeEachHook;
856
+ }
857
+
741
858
  // for failed 'after each' hook start from errSuite parent,
742
859
  // otherwise start from errSuite itself
743
860
  self.suite = after ? errSuite.parent : errSuite;
package/lib/suite.js CHANGED
@@ -159,6 +159,16 @@ Suite.prototype.timeout = function (ms) {
159
159
 
160
160
  debug("timeout %d", ms);
161
161
  this._timeout = parseInt(ms, 10);
162
+
163
+ // Allow overriding inner/nested suites
164
+ // See and test-cases with chain-called timeout argument.
165
+ // https://github.com/mochajs/mocha/issues/5422
166
+ for (const t of this.tests) {
167
+ t.timeout(this._timeout);
168
+ }
169
+ for (const s of this.suites) {
170
+ s.timeout(this._timeout);
171
+ }
162
172
  return this;
163
173
  };
164
174
 
package/mocha.js CHANGED
@@ -1,4 +1,4 @@
1
- // mocha@12.0.0-beta-4 in javascript ES2018
1
+ // mocha@12.0.0-beta-6 in javascript ES2018
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
4
4
  typeof define === 'function' && define.amd ? define(factory) :
@@ -11340,6 +11340,16 @@
11340
11340
 
11341
11341
  debug("timeout %d", ms);
11342
11342
  this._timeout = parseInt(ms, 10);
11343
+
11344
+ // Allow overriding inner/nested suites
11345
+ // See and test-cases with chain-called timeout argument.
11346
+ // https://github.com/mochajs/mocha/issues/5422
11347
+ for (const t of this.tests) {
11348
+ t.timeout(this._timeout);
11349
+ }
11350
+ for (const s of this.suites) {
11351
+ s.timeout(this._timeout);
11352
+ }
11343
11353
  return this;
11344
11354
  };
11345
11355
 
@@ -12042,6 +12052,7 @@
12042
12052
  * @param {boolean} [opts.delay] - Whether to delay execution of root suite until ready.
12043
12053
  * @param {boolean} [opts.dryRun] - Whether to report tests without running them.
12044
12054
  * @param {boolean} [opts.failZero] - Whether to fail test run if zero tests encountered.
12055
+ * @param {boolean} [opts.failHookAffectedTests] - Whether to fail all tests affected by hook failures.
12045
12056
  */
12046
12057
  constructor(suite, opts = {}) {
12047
12058
  super();
@@ -12301,6 +12312,73 @@
12301
12312
  }
12302
12313
  };
12303
12314
 
12315
+ /**
12316
+ * Create an error object for a test that was skipped due to a hook failure.
12317
+ *
12318
+ * @private
12319
+ * @param {string} hookTitle - The title of the failed hook
12320
+ * @param {*} hookError - The error from the failed hook (may not be an Error object)
12321
+ * @returns {Error} The error object for the skipped test
12322
+ */
12323
+ function createHookSkipError(hookTitle, hookError) {
12324
+ // Handle falsy or undefined exceptions
12325
+ if (!hookError) {
12326
+ hookError = createInvalidExceptionError(
12327
+ 'Hook "' + hookTitle + '" failed with exception: ' + hookError,
12328
+ hookError,
12329
+ );
12330
+ }
12331
+ // Convert non-Error objects to Error
12332
+ else if (!isError(hookError)) {
12333
+ hookError = thrown2Error(hookError);
12334
+ }
12335
+
12336
+ var errorMessage =
12337
+ 'Test skipped due to failure in hook "' +
12338
+ hookTitle +
12339
+ '": ' +
12340
+ hookError.message;
12341
+ var testError = new Error(errorMessage);
12342
+ testError.stack = hookError.stack;
12343
+ return testError;
12344
+ }
12345
+
12346
+ /**
12347
+ * Fail all tests that are affected by a hook failure.
12348
+ * This is used when the `failHookAffectedTests` option is enabled.
12349
+ *
12350
+ * @private
12351
+ * @param {Suite} suite - The suite containing the affected tests
12352
+ * @param {Error} hookError - The error from the failed hook
12353
+ * @param {string} hookTitle - The title of the failed hook
12354
+ */
12355
+ Runner.prototype.failAffectedTests = function (suite, hookError, hookTitle) {
12356
+ if (!this._opts.failHookAffectedTests) {
12357
+ return;
12358
+ }
12359
+
12360
+ var self = this;
12361
+ var testError = createHookSkipError(hookTitle, hookError);
12362
+
12363
+ // Recursively fail all tests in this suite and its child suites
12364
+ function failTestsInSuite(s) {
12365
+ s.tests.forEach(function (test) {
12366
+ // Only fail tests that haven't been executed yet
12367
+ if (!test.state) {
12368
+ test.state = STATE_FAILED;
12369
+ self.failures++;
12370
+ self.emit(constants.EVENT_TEST_BEGIN, test);
12371
+ self.emit(constants.EVENT_TEST_FAIL, test, testError);
12372
+ self.emit(constants.EVENT_TEST_END, test);
12373
+ }
12374
+ });
12375
+
12376
+ s.suites.forEach(failTestsInSuite);
12377
+ }
12378
+
12379
+ failTestsInSuite(suite);
12380
+ };
12381
+
12304
12382
  /**
12305
12383
  * Fail the given `test`.
12306
12384
  *
@@ -12443,6 +12521,28 @@
12443
12521
  }
12444
12522
  } else if (err) {
12445
12523
  self.fail(hook, err);
12524
+ // If failHookAffectedTests is enabled, mark affected tests as failed
12525
+ if (self._opts.failHookAffectedTests) {
12526
+ if (name === HOOK_TYPE_BEFORE_ALL) {
12527
+ self.failAffectedTests(self.suite, err, hook.title);
12528
+ } else if (name === HOOK_TYPE_BEFORE_EACH) {
12529
+ // Fail the current test
12530
+ if (self.test && !self.test.state) {
12531
+ var testError = createHookSkipError(hook.title, err);
12532
+
12533
+ self.test.state = STATE_FAILED;
12534
+ self.failures++;
12535
+ self.emit(constants.EVENT_TEST_BEGIN, self.test);
12536
+ self.emit(constants.EVENT_TEST_FAIL, self.test, testError);
12537
+ self.emit(constants.EVENT_TEST_END, self.test);
12538
+ }
12539
+ // Store the hook error info for remaining tests
12540
+ self._failedBeforeEachHook = {
12541
+ error: err,
12542
+ title: hook.title,
12543
+ };
12544
+ }
12545
+ }
12446
12546
  // stop executing hooks, notify callee of hook err
12447
12547
  return fn(err);
12448
12548
  }
@@ -12594,10 +12694,37 @@
12594
12694
  var tests = suite.tests.slice();
12595
12695
  var test;
12596
12696
 
12597
- function hookErr(_, errSuite, after) {
12697
+ function hookErr(err, errSuite, after) {
12598
12698
  // before/after Each hook for errSuite failed:
12599
12699
  var orig = self.suite;
12600
12700
 
12701
+ // If failHookAffectedTests is enabled and this is a beforeEach failure,
12702
+ // mark remaining tests as failed
12703
+ if (
12704
+ self._opts.failHookAffectedTests &&
12705
+ !after &&
12706
+ self._failedBeforeEachHook
12707
+ ) {
12708
+ // Fail all remaining tests in the suite
12709
+ var remainingTests = tests.slice();
12710
+ remainingTests.forEach(function (t) {
12711
+ if (!t.state) {
12712
+ var testError = createHookSkipError(
12713
+ self._failedBeforeEachHook.title,
12714
+ self._failedBeforeEachHook.error,
12715
+ );
12716
+
12717
+ t.state = STATE_FAILED;
12718
+ self.failures++;
12719
+ self.emit(constants.EVENT_TEST_BEGIN, t);
12720
+ self.emit(constants.EVENT_TEST_FAIL, t, testError);
12721
+ self.emit(constants.EVENT_TEST_END, t);
12722
+ }
12723
+ });
12724
+ // Clear the stored hook info
12725
+ delete self._failedBeforeEachHook;
12726
+ }
12727
+
12601
12728
  // for failed 'after each' hook start from errSuite parent,
12602
12729
  // otherwise start from errSuite itself
12603
12730
  self.suite = after ? errSuite.parent : errSuite;
@@ -18060,6 +18187,20 @@
18060
18187
  return this;
18061
18188
  };
18062
18189
 
18190
+ /**
18191
+ * Reports tests as failed when they are skipped due to a hook failure.
18192
+ *
18193
+ * @public
18194
+ * @see [CLI option](../#-fail-hook-affected-tests)
18195
+ * @param {boolean} [failHookAffectedTests=true] - Whether to fail tests affected by hook failures.
18196
+ * @return {Mocha} this
18197
+ * @chainable
18198
+ */
18199
+ Mocha.prototype.failHookAffectedTests = function (failHookAffectedTests) {
18200
+ this.options.failHookAffectedTests = failHookAffectedTests !== false;
18201
+ return this;
18202
+ };
18203
+
18063
18204
  /**
18064
18205
  * Fails test run if no tests encountered with exit-code 1.
18065
18206
  *
@@ -18188,6 +18329,7 @@
18188
18329
  cleanReferencesAfterRun: this._cleanReferencesAfterRun,
18189
18330
  delay: options.delay,
18190
18331
  dryRun: options.dryRun,
18332
+ failHookAffectedTests: options.failHookAffectedTests,
18191
18333
  failZero: options.failZero,
18192
18334
  });
18193
18335
  createStatsCollector(runner);