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/CHANGELOG.md +77 -1344
- package/LICENSE +1 -1
- package/README.md +6 -6
- package/bin/mocha +12 -43
- package/lib/cli/node-flags.js +1 -1
- package/lib/cli/one-and-dones.js +2 -2
- package/lib/cli/options.js +3 -34
- package/lib/cli/run-helpers.js +4 -3
- package/lib/cli/run-option-metadata.js +6 -5
- package/lib/cli/run.js +24 -11
- package/lib/cli/watch-run.js +116 -31
- package/lib/mocha.js +139 -99
- package/lib/mocharc.json +2 -1
- package/lib/reporters/base.js +15 -5
- package/lib/reporters/xunit.js +3 -3
- package/lib/runnable.js +26 -18
- package/lib/runner.js +93 -87
- package/lib/utils.js +0 -74
- package/mocha.js +280 -289
- package/package.json +27 -4
- package/bin/options.js +0 -10
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
|
|
28
|
-
|
|
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.
|
|
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
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
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
|
-
|
|
398
|
-
|
|
399
|
-
|
|
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
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
return fn(
|
|
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
|
-
|
|
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
|
-
|
|
656
|
-
|
|
657
|
-
if (
|
|
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
|
-
|
|
660
|
-
|
|
674
|
+
delete test.isPending;
|
|
675
|
+
} else {
|
|
661
676
|
self.emit(constants.EVENT_TEST_PENDING, test);
|
|
662
|
-
}
|
|
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
|
-
|
|
761
|
-
|
|
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
|
-
|
|
771
|
-
|
|
772
|
-
|
|
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
|
-
|
|
833
|
-
|
|
834
|
-
|
|
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
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
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
|
-
|
|
868
|
-
|
|
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
|
*
|