mocha 6.2.1 → 7.0.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/lib/runnable.js CHANGED
@@ -135,7 +135,8 @@ Runnable.prototype.enableTimeouts = function(enabled) {
135
135
  * @public
136
136
  */
137
137
  Runnable.prototype.skip = function() {
138
- throw new Pending('sync skip');
138
+ this.pending = true;
139
+ throw new Pending('sync skip; aborting execution');
139
140
  };
140
141
 
141
142
  /**
@@ -343,34 +344,27 @@ Runnable.prototype.run = function(fn) {
343
344
 
344
345
  // allows skip() to be used in an explicit async context
345
346
  this.skip = function asyncSkip() {
346
- done(new Pending('async skip call'));
347
- // halt execution. the Runnable will be marked pending
348
- // by the previous call, and the uncaught handler will ignore
349
- // the failure.
347
+ this.pending = true;
348
+ done();
349
+ // halt execution, the uncaught handler will ignore the failure.
350
350
  throw new Pending('async skip; aborting execution');
351
351
  };
352
352
 
353
- if (this.allowUncaught) {
354
- return callFnAsync(this.fn);
355
- }
356
353
  try {
357
354
  callFnAsync(this.fn);
358
355
  } catch (err) {
356
+ // handles async runnables which actually run synchronously
359
357
  emitted = true;
358
+ if (err instanceof Pending) {
359
+ return; // done() is already called in this.skip()
360
+ } else if (this.allowUncaught) {
361
+ throw err;
362
+ }
360
363
  done(Runnable.toValueOrError(err));
361
364
  }
362
365
  return;
363
366
  }
364
367
 
365
- if (this.allowUncaught) {
366
- if (this.isPending()) {
367
- done();
368
- } else {
369
- callFn(this.fn);
370
- }
371
- return;
372
- }
373
-
374
368
  // sync or promise-returning
375
369
  try {
376
370
  if (this.isPending()) {
@@ -380,6 +374,11 @@ Runnable.prototype.run = function(fn) {
380
374
  }
381
375
  } catch (err) {
382
376
  emitted = true;
377
+ if (err instanceof Pending) {
378
+ return done();
379
+ } else if (this.allowUncaught) {
380
+ throw err;
381
+ }
383
382
  done(Runnable.toValueOrError(err));
384
383
  }
385
384
 
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;
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
 
@@ -794,6 +809,10 @@ Runner.prototype.uncaught = function(err) {
794
809
  if (err instanceof Pending) {
795
810
  return;
796
811
  }
812
+ if (this.allowUncaught) {
813
+ throw err;
814
+ }
815
+
797
816
  if (err) {
798
817
  debug('uncaught exception %O', err);
799
818
  } else {
@@ -829,11 +848,17 @@ Runner.prototype.uncaught = function(err) {
829
848
 
830
849
  runnable.clearTimeout();
831
850
 
832
- // Ignore errors if already failed or pending
833
- // See #3226
834
- if (runnable.isFailed() || runnable.isPending()) {
851
+ if (runnable.isFailed()) {
852
+ // Ignore error if already failed
853
+ return;
854
+ } else if (runnable.isPending()) {
855
+ // report 'pending test' retrospectively as failed
856
+ runnable.isPending = alwaysFalse;
857
+ this.fail(runnable, err);
858
+ delete runnable.isPending;
835
859
  return;
836
860
  }
861
+
837
862
  // we cannot recover gracefully if a Runnable has already passed
838
863
  // then fails asynchronously
839
864
  var alreadyPassed = runnable.isPassed();
@@ -865,7 +890,7 @@ Runner.prototype.uncaught = function(err) {
865
890
  }
866
891
 
867
892
  // bail
868
- this.emit(constants.EVENT_RUN_END);
893
+ this.abort();
869
894
  };
870
895
 
871
896
  /**
@@ -915,6 +940,12 @@ Runner.prototype.run = function(fn) {
915
940
  this.on(constants.EVENT_RUN_END, function() {
916
941
  debug(constants.EVENT_RUN_END);
917
942
  process.removeListener('uncaughtException', uncaught);
943
+ process.on('uncaughtException', function(err) {
944
+ if (err instanceof Pending) {
945
+ return;
946
+ }
947
+ throw err;
948
+ });
918
949
  fn(self.failures);
919
950
  });
920
951
 
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
  *