mocha 6.2.2 → 7.0.1

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/lib/runner.js CHANGED
@@ -24,8 +24,9 @@ var sQuote = utils.sQuote;
24
24
  var stackFilter = utils.stackTraceFilter();
25
25
  var stringify = utils.stringify;
26
26
  var type = utils.type;
27
- var createInvalidExceptionError = require('./errors')
28
- .createInvalidExceptionError;
27
+ var errors = require('./errors');
28
+ var createInvalidExceptionError = errors.createInvalidExceptionError;
29
+ var createUnsupportedError = errors.createUnsupportedError;
29
30
 
30
31
  /**
31
32
  * Non-enumerable globals.
@@ -244,7 +245,7 @@ Runner.prototype.globals = function(arr) {
244
245
  * @private
245
246
  */
246
247
  Runner.prototype.checkGlobals = function(test) {
247
- if (this.ignoreLeaks) {
248
+ if (!this.checkLeaks) {
248
249
  return;
249
250
  }
250
251
  var ok = this._globals;
@@ -315,8 +316,7 @@ Runner.prototype.fail = function(test, err) {
315
316
  * - Failed `before each` hook skips remaining tests in a
316
317
  * suite and jumps to corresponding `after each` hook,
317
318
  * which is run only once
318
- * - Failed `after` hook does not alter
319
- * execution order
319
+ * - Failed `after` hook does not alter execution order
320
320
  * - Failed `after each` hook skips remaining tests in a
321
321
  * suite and subsuites, but executes other `after each`
322
322
  * hooks
@@ -386,34 +386,37 @@ Runner.prototype.hook = function(name, fn) {
386
386
  if (testError) {
387
387
  self.fail(self.test, testError);
388
388
  }
389
- if (err) {
390
- if (err instanceof Pending) {
391
- if (name === HOOK_TYPE_AFTER_ALL) {
392
- utils.deprecate(
393
- 'Skipping a test within an "after all" hook is DEPRECATED and will throw an exception in a future version of Mocha. ' +
394
- 'Use a return statement or other means to abort hook execution.'
395
- );
389
+ // conditional skip
390
+ if (hook.pending) {
391
+ if (name === HOOK_TYPE_AFTER_EACH) {
392
+ // TODO define and implement use case
393
+ if (self.test) {
394
+ self.test.pending = true;
396
395
  }
397
- if (name === HOOK_TYPE_BEFORE_EACH || name === HOOK_TYPE_AFTER_EACH) {
398
- if (self.test) {
399
- self.test.pending = true;
400
- }
401
- } else {
402
- suite.tests.forEach(function(test) {
403
- test.pending = true;
404
- });
405
- suite.suites.forEach(function(suite) {
406
- suite.pending = true;
407
- });
408
- // a pending hook won't be executed twice.
409
- hook.pending = true;
396
+ } else if (name === HOOK_TYPE_BEFORE_EACH) {
397
+ if (self.test) {
398
+ self.test.pending = true;
410
399
  }
400
+ self.emit(constants.EVENT_HOOK_END, hook);
401
+ hook.pending = false; // activates hook for next test
402
+ return fn(new Error('abort hookDown'));
403
+ } else if (name === HOOK_TYPE_BEFORE_ALL) {
404
+ suite.tests.forEach(function(test) {
405
+ test.pending = true;
406
+ });
407
+ suite.suites.forEach(function(suite) {
408
+ suite.pending = true;
409
+ });
411
410
  } else {
412
- self.failHook(hook, err);
413
-
414
- // stop executing hooks, notify callee of hook err
415
- return fn(err);
411
+ hook.pending = false;
412
+ var errForbid = createUnsupportedError('`this.skip` forbidden');
413
+ self.failHook(hook, errForbid);
414
+ return fn(errForbid);
416
415
  }
416
+ } else if (err) {
417
+ self.failHook(hook, err);
418
+ // stop executing hooks, notify callee of hook err
419
+ return fn(err);
417
420
  }
418
421
  self.emit(constants.EVENT_HOOK_END, hook);
419
422
  delete hook.ctx.currentTest;
@@ -525,6 +528,9 @@ Runner.prototype.runTest = function(fn) {
525
528
  test.asyncOnly = true;
526
529
  }
527
530
  test.on('error', function(err) {
531
+ if (err instanceof Pending) {
532
+ return;
533
+ }
528
534
  self.fail(test, err);
529
535
  });
530
536
  if (this.allowUncaught) {
@@ -620,6 +626,7 @@ Runner.prototype.runTests = function(suite, fn) {
620
626
  return;
621
627
  }
622
628
 
629
+ // static skip, no hooks are executed
623
630
  if (test.isPending()) {
624
631
  if (self.forbidPending) {
625
632
  test.isPending = alwaysFalse;
@@ -635,6 +642,7 @@ Runner.prototype.runTests = function(suite, fn) {
635
642
  // execute test and hook(s)
636
643
  self.emit(constants.EVENT_TEST_BEGIN, (self.test = test));
637
644
  self.hookDown(HOOK_TYPE_BEFORE_EACH, function(err, errSuite) {
645
+ // conditional skip within beforeEach
638
646
  if (test.isPending()) {
639
647
  if (self.forbidPending) {
640
648
  test.isPending = alwaysFalse;
@@ -644,7 +652,13 @@ Runner.prototype.runTests = function(suite, fn) {
644
652
  self.emit(constants.EVENT_TEST_PENDING, test);
645
653
  }
646
654
  self.emit(constants.EVENT_TEST_END, test);
647
- return next();
655
+ // skip inner afterEach hooks below errSuite level
656
+ var origSuite = self.suite;
657
+ self.suite = errSuite || self.suite;
658
+ return self.hookUp(HOOK_TYPE_AFTER_EACH, function(e, eSuite) {
659
+ self.suite = origSuite;
660
+ next(e, eSuite);
661
+ });
648
662
  }
649
663
  if (err) {
650
664
  return hookErr(err, errSuite, false);
@@ -652,14 +666,20 @@ Runner.prototype.runTests = function(suite, fn) {
652
666
  self.currentRunnable = self.test;
653
667
  self.runTest(function(err) {
654
668
  test = self.test;
655
- if (err) {
656
- var retry = test.currentRetry();
657
- if (err instanceof Pending && self.forbidPending) {
669
+ // conditional skip within it
670
+ if (test.pending) {
671
+ if (self.forbidPending) {
672
+ test.isPending = alwaysFalse;
658
673
  self.fail(test, new Error('Pending test forbidden'));
659
- } else if (err instanceof Pending) {
660
- test.pending = true;
674
+ delete test.isPending;
675
+ } else {
661
676
  self.emit(constants.EVENT_TEST_PENDING, test);
662
- } else if (retry < test.retries()) {
677
+ }
678
+ self.emit(constants.EVENT_TEST_END, test);
679
+ return self.hookUp(HOOK_TYPE_AFTER_EACH, next);
680
+ } else if (err) {
681
+ var retry = test.currentRetry();
682
+ if (retry < test.retries()) {
663
683
  var clonedTest = test.clone();
664
684
  clonedTest.currentRetry(retry + 1);
665
685
  tests.unshift(clonedTest);
@@ -673,11 +693,6 @@ Runner.prototype.runTests = function(suite, fn) {
673
693
  self.fail(test, err);
674
694
  }
675
695
  self.emit(constants.EVENT_TEST_END, test);
676
-
677
- if (err instanceof Pending) {
678
- return next();
679
- }
680
-
681
696
  return self.hookUp(HOOK_TYPE_AFTER_EACH, next);
682
697
  }
683
698
 
@@ -709,7 +724,6 @@ Runner.prototype.runSuite = function(suite, fn) {
709
724
  var i = 0;
710
725
  var self = this;
711
726
  var total = this.grepTotal(suite);
712
- var afterAllHookCalled = false;
713
727
 
714
728
  debug('run suite %s', suite.fullTitle());
715
729
 
@@ -757,21 +771,13 @@ Runner.prototype.runSuite = function(suite, fn) {
757
771
  self.suite = suite;
758
772
  self.nextSuite = next;
759
773
 
760
- if (afterAllHookCalled) {
761
- fn(errSuite);
762
- } else {
763
- // mark that the afterAll block has been called once
764
- // and so can be skipped if there is an error in it.
765
- afterAllHookCalled = true;
766
-
767
- // remove reference to test
768
- delete self.test;
774
+ // remove reference to test
775
+ delete self.test;
769
776
 
770
- self.hook(HOOK_TYPE_AFTER_ALL, function() {
771
- self.emit(constants.EVENT_SUITE_END, suite);
772
- fn(errSuite);
773
- });
774
- }
777
+ self.hook(HOOK_TYPE_AFTER_ALL, function() {
778
+ self.emit(constants.EVENT_SUITE_END, suite);
779
+ fn(errSuite);
780
+ });
775
781
  }
776
782
 
777
783
  this.nextSuite = next;
@@ -785,7 +791,7 @@ Runner.prototype.runSuite = function(suite, fn) {
785
791
  };
786
792
 
787
793
  /**
788
- * Handle uncaught exceptions.
794
+ * Handle uncaught exceptions within runner.
789
795
  *
790
796
  * @param {Error} err
791
797
  * @private
@@ -794,6 +800,10 @@ Runner.prototype.uncaught = function(err) {
794
800
  if (err instanceof Pending) {
795
801
  return;
796
802
  }
803
+ if (this.allowUncaught) {
804
+ throw err;
805
+ }
806
+
797
807
  if (err) {
798
808
  debug('uncaught exception %O', err);
799
809
  } else {
@@ -829,43 +839,37 @@ Runner.prototype.uncaught = function(err) {
829
839
 
830
840
  runnable.clearTimeout();
831
841
 
832
- // Ignore errors if already failed or pending
833
- // See #3226
834
- if (runnable.isFailed() || runnable.isPending()) {
842
+ if (runnable.isFailed()) {
843
+ // Ignore error if already failed
844
+ return;
845
+ } else if (runnable.isPending()) {
846
+ // report 'pending test' retrospectively as failed
847
+ runnable.isPending = alwaysFalse;
848
+ this.fail(runnable, err);
849
+ delete runnable.isPending;
835
850
  return;
836
851
  }
852
+
837
853
  // we cannot recover gracefully if a Runnable has already passed
838
854
  // then fails asynchronously
839
- var alreadyPassed = runnable.isPassed();
840
- // this will change the state to "failed" regardless of the current value
841
- this.fail(runnable, err);
842
- if (!alreadyPassed) {
843
- // recover from test
844
- if (runnable.type === constants.EVENT_TEST_BEGIN) {
845
- this.emit(constants.EVENT_TEST_END, runnable);
846
- this.hookUp(HOOK_TYPE_AFTER_EACH, this.next);
847
- return;
848
- }
855
+ if (runnable.isPassed()) {
856
+ this.fail(runnable, err);
857
+ this.abort();
858
+ } else {
849
859
  debug(runnable);
850
-
851
- // recover from hooks
852
- var errSuite = this.suite;
853
-
854
- // XXX how about a less awful way to determine this?
855
- // if hook failure is in afterEach block
856
- if (runnable.fullTitle().indexOf('after each') > -1) {
857
- return this.hookErr(err, errSuite, true);
858
- }
859
- // if hook failure is in beforeEach block
860
- if (runnable.fullTitle().indexOf('before each') > -1) {
861
- return this.hookErr(err, errSuite, false);
862
- }
863
- // if hook failure is in after or before blocks
864
- return this.nextSuite(errSuite);
860
+ return runnable.callback(err);
865
861
  }
862
+ };
866
863
 
867
- // bail
868
- this.abort();
864
+ /**
865
+ * Handle uncaught exceptions after runner's end event.
866
+ *
867
+ * @param {Error} err
868
+ * @private
869
+ */
870
+ Runner.prototype.uncaughtEnd = function uncaughtEnd(err) {
871
+ if (err instanceof Pending) return;
872
+ throw err;
869
873
  };
870
874
 
871
875
  /**
@@ -915,10 +919,12 @@ Runner.prototype.run = function(fn) {
915
919
  this.on(constants.EVENT_RUN_END, function() {
916
920
  debug(constants.EVENT_RUN_END);
917
921
  process.removeListener('uncaughtException', uncaught);
922
+ process.on('uncaughtException', self.uncaughtEnd);
918
923
  fn(self.failures);
919
924
  });
920
925
 
921
926
  // uncaught exception
927
+ process.removeListener('uncaughtException', self.uncaughtEnd);
922
928
  process.on('uncaughtException', uncaught);
923
929
 
924
930
  if (this._delay) {
package/lib/utils.js CHANGED
@@ -53,80 +53,6 @@ exports.isString = function(obj) {
53
53
  return typeof obj === 'string';
54
54
  };
55
55
 
56
- /**
57
- * Watch the given `files` for changes
58
- * and invoke `fn(file)` on modification.
59
- *
60
- * @private
61
- * @param {Array} files
62
- * @param {Function} fn
63
- */
64
- exports.watch = function(files, fn) {
65
- var options = {interval: 100};
66
- var debug = require('debug')('mocha:watch');
67
- files.forEach(function(file) {
68
- debug('file %s', file);
69
- fs.watchFile(file, options, function(curr, prev) {
70
- if (prev.mtime < curr.mtime) {
71
- fn(file);
72
- }
73
- });
74
- });
75
- };
76
-
77
- /**
78
- * Predicate to screen `pathname` for further consideration.
79
- *
80
- * @description
81
- * Returns <code>false</code> for pathname referencing:
82
- * <ul>
83
- * <li>'npm' package installation directory
84
- * <li>'git' version control directory
85
- * </ul>
86
- *
87
- * @private
88
- * @param {string} pathname - File or directory name to screen
89
- * @return {boolean} whether pathname should be further considered
90
- * @example
91
- * ['node_modules', 'test.js'].filter(considerFurther); // => ['test.js']
92
- */
93
- function considerFurther(pathname) {
94
- var ignore = ['node_modules', '.git'];
95
-
96
- return !~ignore.indexOf(pathname);
97
- }
98
-
99
- /**
100
- * Lookup files in the given `dir`.
101
- *
102
- * @description
103
- * Filenames are returned in _traversal_ order by the OS/filesystem.
104
- * **Make no assumption that the names will be sorted in any fashion.**
105
- *
106
- * @private
107
- * @param {string} dir
108
- * @param {string[]} [exts=['js']]
109
- * @param {Array} [ret=[]]
110
- * @return {Array}
111
- */
112
- exports.files = function(dir, exts, ret) {
113
- ret = ret || [];
114
- exts = exts || ['js'];
115
-
116
- fs.readdirSync(dir)
117
- .filter(considerFurther)
118
- .forEach(function(dirent) {
119
- var pathname = path.join(dir, dirent);
120
- if (fs.lstatSync(pathname).isDirectory()) {
121
- exports.files(pathname, exts, ret);
122
- } else if (hasMatchingExtname(pathname, exts)) {
123
- ret.push(pathname);
124
- }
125
- });
126
-
127
- return ret;
128
- };
129
-
130
56
  /**
131
57
  * Compute a slug from the given `str`.
132
58
  *