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/CHANGELOG.md +86 -2
- package/bin/mocha +7 -2
- package/browser-entry.js +13 -2
- package/lib/cli/cli.js +4 -1
- package/lib/cli/collect-files.js +2 -1
- package/lib/cli/config.js +8 -6
- package/lib/cli/options.js +4 -4
- package/lib/cli/run-helpers.js +93 -33
- package/lib/cli/run.js +23 -5
- package/lib/errors.js +179 -9
- package/lib/esm-utils.js +31 -0
- package/lib/hook.js +8 -0
- package/lib/interfaces/common.js +6 -3
- package/lib/mocha.js +226 -16
- package/lib/mocharc.json +1 -1
- package/lib/reporters/doc.js +6 -0
- package/lib/reporters/json-stream.js +1 -0
- package/lib/reporters/json.js +1 -0
- package/lib/reporters/landing.js +8 -0
- package/lib/runnable.js +21 -42
- package/lib/runner.js +173 -63
- package/lib/suite.js +29 -3
- package/lib/test.js +33 -2
- package/lib/utils.js +36 -35
- package/mocha.js +749 -185
- package/package.json +56 -549
package/lib/mocha.js
CHANGED
|
@@ -14,9 +14,14 @@ var utils = require('./utils');
|
|
|
14
14
|
var mocharc = require('./mocharc.json');
|
|
15
15
|
var errors = require('./errors');
|
|
16
16
|
var Suite = require('./suite');
|
|
17
|
+
var esmUtils = utils.supportsEsModules() ? require('./esm-utils') : undefined;
|
|
17
18
|
var createStatsCollector = require('./stats-collector');
|
|
18
19
|
var createInvalidReporterError = errors.createInvalidReporterError;
|
|
19
20
|
var createInvalidInterfaceError = errors.createInvalidInterfaceError;
|
|
21
|
+
var createMochaInstanceAlreadyDisposedError =
|
|
22
|
+
errors.createMochaInstanceAlreadyDisposedError;
|
|
23
|
+
var createMochaInstanceAlreadyRunningError =
|
|
24
|
+
errors.createMochaInstanceAlreadyRunningError;
|
|
20
25
|
var EVENT_FILE_PRE_REQUIRE = Suite.constants.EVENT_FILE_PRE_REQUIRE;
|
|
21
26
|
var EVENT_FILE_POST_REQUIRE = Suite.constants.EVENT_FILE_POST_REQUIRE;
|
|
22
27
|
var EVENT_FILE_REQUIRE = Suite.constants.EVENT_FILE_REQUIRE;
|
|
@@ -24,12 +29,36 @@ var sQuote = utils.sQuote;
|
|
|
24
29
|
|
|
25
30
|
exports = module.exports = Mocha;
|
|
26
31
|
|
|
32
|
+
/**
|
|
33
|
+
* A Mocha instance is a finite state machine.
|
|
34
|
+
* These are the states it can be in.
|
|
35
|
+
*/
|
|
36
|
+
var mochaStates = utils.defineConstants({
|
|
37
|
+
/**
|
|
38
|
+
* Initial state of the mocha instance
|
|
39
|
+
*/
|
|
40
|
+
INIT: 'init',
|
|
41
|
+
/**
|
|
42
|
+
* Mocha instance is running tests
|
|
43
|
+
*/
|
|
44
|
+
RUNNING: 'running',
|
|
45
|
+
/**
|
|
46
|
+
* Mocha instance is done running tests and references to test functions and hooks are cleaned.
|
|
47
|
+
* You can reset this state by unloading the test files.
|
|
48
|
+
*/
|
|
49
|
+
REFERENCES_CLEANED: 'referencesCleaned',
|
|
50
|
+
/**
|
|
51
|
+
* Mocha instance is disposed and can no longer be used.
|
|
52
|
+
*/
|
|
53
|
+
DISPOSED: 'disposed'
|
|
54
|
+
});
|
|
55
|
+
|
|
27
56
|
/**
|
|
28
57
|
* To require local UIs and reporters when running in node.
|
|
29
58
|
*/
|
|
30
59
|
|
|
31
|
-
if (!process.browser) {
|
|
32
|
-
var cwd =
|
|
60
|
+
if (!process.browser && typeof module.paths !== 'undefined') {
|
|
61
|
+
var cwd = utils.cwd();
|
|
33
62
|
module.paths.push(cwd, path.join(cwd, 'node_modules'));
|
|
34
63
|
}
|
|
35
64
|
|
|
@@ -89,6 +118,8 @@ exports.Test = require('./test');
|
|
|
89
118
|
* @param {number} [options.slow] - Slow threshold value.
|
|
90
119
|
* @param {number|string} [options.timeout] - Timeout threshold value.
|
|
91
120
|
* @param {string} [options.ui] - Interface name.
|
|
121
|
+
* @param {MochaRootHookObject} [options.rootHooks] - Hooks to bootstrap the root
|
|
122
|
+
* suite with
|
|
92
123
|
*/
|
|
93
124
|
function Mocha(options) {
|
|
94
125
|
options = utils.assign({}, mocharc, options || {});
|
|
@@ -96,6 +127,7 @@ function Mocha(options) {
|
|
|
96
127
|
this.options = options;
|
|
97
128
|
// root suite
|
|
98
129
|
this.suite = new exports.Suite('', new exports.Context(), true);
|
|
130
|
+
this._cleanReferencesAfterRun = true;
|
|
99
131
|
|
|
100
132
|
this.grep(options.grep)
|
|
101
133
|
.fgrep(options.fgrep)
|
|
@@ -135,6 +167,10 @@ function Mocha(options) {
|
|
|
135
167
|
this[opt]();
|
|
136
168
|
}
|
|
137
169
|
}, this);
|
|
170
|
+
|
|
171
|
+
if (options.rootHooks) {
|
|
172
|
+
this.rootHooks(options.rootHooks);
|
|
173
|
+
}
|
|
138
174
|
}
|
|
139
175
|
|
|
140
176
|
/**
|
|
@@ -201,24 +237,24 @@ Mocha.prototype.reporter = function(reporter, reporterOptions) {
|
|
|
201
237
|
_reporter = require(reporter);
|
|
202
238
|
} catch (err) {
|
|
203
239
|
if (
|
|
204
|
-
err.code
|
|
205
|
-
err.message.indexOf('Cannot find module')
|
|
240
|
+
err.code === 'MODULE_NOT_FOUND' ||
|
|
241
|
+
err.message.indexOf('Cannot find module') >= 0
|
|
206
242
|
) {
|
|
207
243
|
// Try to load reporters from a path (absolute or relative)
|
|
208
244
|
try {
|
|
209
|
-
_reporter = require(path.resolve(
|
|
245
|
+
_reporter = require(path.resolve(utils.cwd(), reporter));
|
|
210
246
|
} catch (_err) {
|
|
211
|
-
_err.code
|
|
212
|
-
_err.message.indexOf('Cannot find module')
|
|
213
|
-
?
|
|
214
|
-
:
|
|
247
|
+
_err.code === 'MODULE_NOT_FOUND' ||
|
|
248
|
+
_err.message.indexOf('Cannot find module') >= 0
|
|
249
|
+
? utils.warn(sQuote(reporter) + ' reporter not found')
|
|
250
|
+
: utils.warn(
|
|
215
251
|
sQuote(reporter) +
|
|
216
252
|
' reporter blew up with error:\n' +
|
|
217
253
|
err.stack
|
|
218
254
|
);
|
|
219
255
|
}
|
|
220
256
|
} else {
|
|
221
|
-
|
|
257
|
+
utils.warn(
|
|
222
258
|
sQuote(reporter) + ' reporter blew up with error:\n' + err.stack
|
|
223
259
|
);
|
|
224
260
|
}
|
|
@@ -290,16 +326,18 @@ Mocha.prototype.ui = function(ui) {
|
|
|
290
326
|
};
|
|
291
327
|
|
|
292
328
|
/**
|
|
293
|
-
* Loads `files` prior to execution.
|
|
329
|
+
* Loads `files` prior to execution. Does not support ES Modules.
|
|
294
330
|
*
|
|
295
331
|
* @description
|
|
296
332
|
* The implementation relies on Node's `require` to execute
|
|
297
333
|
* the test interface functions and will be subject to its cache.
|
|
334
|
+
* Supports only CommonJS modules. To load ES modules, use Mocha#loadFilesAsync.
|
|
298
335
|
*
|
|
299
336
|
* @private
|
|
300
337
|
* @see {@link Mocha#addFile}
|
|
301
338
|
* @see {@link Mocha#run}
|
|
302
339
|
* @see {@link Mocha#unloadFiles}
|
|
340
|
+
* @see {@link Mocha#loadFilesAsync}
|
|
303
341
|
* @param {Function} [fn] - Callback invoked upon completion.
|
|
304
342
|
*/
|
|
305
343
|
Mocha.prototype.loadFiles = function(fn) {
|
|
@@ -314,6 +352,49 @@ Mocha.prototype.loadFiles = function(fn) {
|
|
|
314
352
|
fn && fn();
|
|
315
353
|
};
|
|
316
354
|
|
|
355
|
+
/**
|
|
356
|
+
* Loads `files` prior to execution. Supports Node ES Modules.
|
|
357
|
+
*
|
|
358
|
+
* @description
|
|
359
|
+
* The implementation relies on Node's `require` and `import` to execute
|
|
360
|
+
* the test interface functions and will be subject to its cache.
|
|
361
|
+
* Supports both CJS and ESM modules.
|
|
362
|
+
*
|
|
363
|
+
* @public
|
|
364
|
+
* @see {@link Mocha#addFile}
|
|
365
|
+
* @see {@link Mocha#run}
|
|
366
|
+
* @see {@link Mocha#unloadFiles}
|
|
367
|
+
* @returns {Promise}
|
|
368
|
+
* @example
|
|
369
|
+
*
|
|
370
|
+
* // loads ESM (and CJS) test files asynchronously, then runs root suite
|
|
371
|
+
* mocha.loadFilesAsync()
|
|
372
|
+
* .then(() => mocha.run(failures => process.exitCode = failures ? 1 : 0))
|
|
373
|
+
* .catch(() => process.exitCode = 1);
|
|
374
|
+
*/
|
|
375
|
+
Mocha.prototype.loadFilesAsync = function() {
|
|
376
|
+
var self = this;
|
|
377
|
+
var suite = this.suite;
|
|
378
|
+
this.loadAsync = true;
|
|
379
|
+
|
|
380
|
+
if (!esmUtils) {
|
|
381
|
+
return new Promise(function(resolve) {
|
|
382
|
+
self.loadFiles(resolve);
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return esmUtils.loadFilesAsync(
|
|
387
|
+
this.files,
|
|
388
|
+
function(file) {
|
|
389
|
+
suite.emit(EVENT_FILE_PRE_REQUIRE, global, file, self);
|
|
390
|
+
},
|
|
391
|
+
function(file, resultModule) {
|
|
392
|
+
suite.emit(EVENT_FILE_REQUIRE, resultModule, file, self);
|
|
393
|
+
suite.emit(EVENT_FILE_POST_REQUIRE, global, file, self);
|
|
394
|
+
}
|
|
395
|
+
);
|
|
396
|
+
};
|
|
397
|
+
|
|
317
398
|
/**
|
|
318
399
|
* Removes a previously loaded file from Node's `require` cache.
|
|
319
400
|
*
|
|
@@ -330,8 +411,9 @@ Mocha.unloadFile = function(file) {
|
|
|
330
411
|
* Unloads `files` from Node's `require` cache.
|
|
331
412
|
*
|
|
332
413
|
* @description
|
|
333
|
-
* This allows files to be "freshly" reloaded, providing the ability
|
|
414
|
+
* This allows required files to be "freshly" reloaded, providing the ability
|
|
334
415
|
* to reuse a Mocha instance programmatically.
|
|
416
|
+
* Note: does not clear ESM module files from the cache
|
|
335
417
|
*
|
|
336
418
|
* <strong>Intended for consumers — not used internally</strong>
|
|
337
419
|
*
|
|
@@ -341,7 +423,18 @@ Mocha.unloadFile = function(file) {
|
|
|
341
423
|
* @chainable
|
|
342
424
|
*/
|
|
343
425
|
Mocha.prototype.unloadFiles = function() {
|
|
344
|
-
this.
|
|
426
|
+
if (this._state === mochaStates.DISPOSED) {
|
|
427
|
+
throw createMochaInstanceAlreadyDisposedError(
|
|
428
|
+
'Mocha instance is already disposed, it cannot be used again.',
|
|
429
|
+
this._cleanReferencesAfterRun,
|
|
430
|
+
this
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
this.files.forEach(function(file) {
|
|
435
|
+
Mocha.unloadFile(file);
|
|
436
|
+
});
|
|
437
|
+
this._state = mochaStates.INIT;
|
|
345
438
|
return this;
|
|
346
439
|
};
|
|
347
440
|
|
|
@@ -459,6 +552,38 @@ Mocha.prototype.checkLeaks = function(checkLeaks) {
|
|
|
459
552
|
return this;
|
|
460
553
|
};
|
|
461
554
|
|
|
555
|
+
/**
|
|
556
|
+
* Enables or disables whether or not to dispose after each test run.
|
|
557
|
+
* Disable this to ensure you can run the test suite multiple times.
|
|
558
|
+
* If disabled, be sure to dispose mocha when you're done to prevent memory leaks.
|
|
559
|
+
* @public
|
|
560
|
+
* @see {@link Mocha#dispose}
|
|
561
|
+
* @param {boolean} cleanReferencesAfterRun
|
|
562
|
+
* @return {Mocha} this
|
|
563
|
+
* @chainable
|
|
564
|
+
*/
|
|
565
|
+
Mocha.prototype.cleanReferencesAfterRun = function(cleanReferencesAfterRun) {
|
|
566
|
+
this._cleanReferencesAfterRun = cleanReferencesAfterRun !== false;
|
|
567
|
+
return this;
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Manually dispose this mocha instance. Mark this instance as `disposed` and unable to run more tests.
|
|
572
|
+
* It also removes function references to tests functions and hooks, so variables trapped in closures can be cleaned by the garbage collector.
|
|
573
|
+
* @public
|
|
574
|
+
*/
|
|
575
|
+
Mocha.prototype.dispose = function() {
|
|
576
|
+
if (this._state === mochaStates.RUNNING) {
|
|
577
|
+
throw createMochaInstanceAlreadyRunningError(
|
|
578
|
+
'Cannot dispose while the mocha instance is still running tests.'
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
this.unloadFiles();
|
|
582
|
+
this._previousRunner && this._previousRunner.dispose();
|
|
583
|
+
this.suite.dispose();
|
|
584
|
+
this._state = mochaStates.DISPOSED;
|
|
585
|
+
};
|
|
586
|
+
|
|
462
587
|
/**
|
|
463
588
|
* Displays full stack trace upon test failure.
|
|
464
589
|
*
|
|
@@ -809,6 +934,28 @@ Mocha.prototype.forbidPending = function(forbidPending) {
|
|
|
809
934
|
return this;
|
|
810
935
|
};
|
|
811
936
|
|
|
937
|
+
/**
|
|
938
|
+
* Throws an error if mocha is in the wrong state to be able to transition to a "running" state.
|
|
939
|
+
*/
|
|
940
|
+
Mocha.prototype._guardRunningStateTransition = function() {
|
|
941
|
+
if (this._state === mochaStates.RUNNING) {
|
|
942
|
+
throw createMochaInstanceAlreadyRunningError(
|
|
943
|
+
'Mocha instance is currently running tests, cannot start a next test run until this one is done',
|
|
944
|
+
this
|
|
945
|
+
);
|
|
946
|
+
}
|
|
947
|
+
if (
|
|
948
|
+
this._state === mochaStates.DISPOSED ||
|
|
949
|
+
this._state === mochaStates.REFERENCES_CLEANED
|
|
950
|
+
) {
|
|
951
|
+
throw createMochaInstanceAlreadyDisposedError(
|
|
952
|
+
'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.',
|
|
953
|
+
this._cleanReferencesAfterRun,
|
|
954
|
+
this
|
|
955
|
+
);
|
|
956
|
+
}
|
|
957
|
+
};
|
|
958
|
+
|
|
812
959
|
/**
|
|
813
960
|
* Mocha version as specified by "package.json".
|
|
814
961
|
*
|
|
@@ -842,16 +989,30 @@ Object.defineProperty(Mocha.prototype, 'version', {
|
|
|
842
989
|
* @see {@link Mocha#unloadFiles}
|
|
843
990
|
* @see {@link Runner#run}
|
|
844
991
|
* @param {DoneCB} [fn] - Callback invoked when test execution completed.
|
|
845
|
-
* @
|
|
992
|
+
* @returns {Runner} runner instance
|
|
993
|
+
* @example
|
|
994
|
+
*
|
|
995
|
+
* // exit with non-zero status if there were test failures
|
|
996
|
+
* mocha.run(failures => process.exitCode = failures ? 1 : 0);
|
|
846
997
|
*/
|
|
847
998
|
Mocha.prototype.run = function(fn) {
|
|
848
|
-
|
|
999
|
+
this._guardRunningStateTransition();
|
|
1000
|
+
this._state = mochaStates.RUNNING;
|
|
1001
|
+
if (this._previousRunner) {
|
|
1002
|
+
this._previousRunner.dispose();
|
|
1003
|
+
this.suite.reset();
|
|
1004
|
+
}
|
|
1005
|
+
if (this.files.length && !this.loadAsync) {
|
|
849
1006
|
this.loadFiles();
|
|
850
1007
|
}
|
|
1008
|
+
var self = this;
|
|
851
1009
|
var suite = this.suite;
|
|
852
1010
|
var options = this.options;
|
|
853
1011
|
options.files = this.files;
|
|
854
|
-
var runner = new exports.Runner(suite,
|
|
1012
|
+
var runner = new exports.Runner(suite, {
|
|
1013
|
+
delay: options.delay,
|
|
1014
|
+
cleanReferencesAfterRun: this._cleanReferencesAfterRun
|
|
1015
|
+
});
|
|
855
1016
|
createStatsCollector(runner);
|
|
856
1017
|
var reporter = new this._reporter(runner, options);
|
|
857
1018
|
runner.checkLeaks = options.checkLeaks === true;
|
|
@@ -876,6 +1037,12 @@ Mocha.prototype.run = function(fn) {
|
|
|
876
1037
|
exports.reporters.Base.hideDiff = !options.diff;
|
|
877
1038
|
|
|
878
1039
|
function done(failures) {
|
|
1040
|
+
self._previousRunner = runner;
|
|
1041
|
+
if (self._cleanReferencesAfterRun) {
|
|
1042
|
+
self._state = mochaStates.REFERENCES_CLEANED;
|
|
1043
|
+
} else {
|
|
1044
|
+
self._state = mochaStates.INIT;
|
|
1045
|
+
}
|
|
879
1046
|
fn = fn || utils.noop;
|
|
880
1047
|
if (reporter.done) {
|
|
881
1048
|
reporter.done(failures, fn);
|
|
@@ -886,3 +1053,46 @@ Mocha.prototype.run = function(fn) {
|
|
|
886
1053
|
|
|
887
1054
|
return runner.run(done);
|
|
888
1055
|
};
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* Assigns hooks to the root suite
|
|
1059
|
+
* @param {MochaRootHookObject} [hooks] - Hooks to assign to root suite
|
|
1060
|
+
* @chainable
|
|
1061
|
+
*/
|
|
1062
|
+
Mocha.prototype.rootHooks = function rootHooks(hooks) {
|
|
1063
|
+
if (utils.type(hooks) === 'object') {
|
|
1064
|
+
var beforeAll = [].concat(hooks.beforeAll || []);
|
|
1065
|
+
var beforeEach = [].concat(hooks.beforeEach || []);
|
|
1066
|
+
var afterAll = [].concat(hooks.afterAll || []);
|
|
1067
|
+
var afterEach = [].concat(hooks.afterEach || []);
|
|
1068
|
+
var rootSuite = this.suite;
|
|
1069
|
+
beforeAll.forEach(function(hook) {
|
|
1070
|
+
rootSuite.beforeAll(hook);
|
|
1071
|
+
});
|
|
1072
|
+
beforeEach.forEach(function(hook) {
|
|
1073
|
+
rootSuite.beforeEach(hook);
|
|
1074
|
+
});
|
|
1075
|
+
afterAll.forEach(function(hook) {
|
|
1076
|
+
rootSuite.afterAll(hook);
|
|
1077
|
+
});
|
|
1078
|
+
afterEach.forEach(function(hook) {
|
|
1079
|
+
rootSuite.afterEach(hook);
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
return this;
|
|
1083
|
+
};
|
|
1084
|
+
|
|
1085
|
+
/**
|
|
1086
|
+
* An alternative way to define root hooks that works with parallel runs.
|
|
1087
|
+
* @typedef {Object} MochaRootHookObject
|
|
1088
|
+
* @property {Function|Function[]} [beforeAll] - "Before all" hook(s)
|
|
1089
|
+
* @property {Function|Function[]} [beforeEach] - "Before each" hook(s)
|
|
1090
|
+
* @property {Function|Function[]} [afterAll] - "After all" hook(s)
|
|
1091
|
+
* @property {Function|Function[]} [afterEach] - "After each" hook(s)
|
|
1092
|
+
*/
|
|
1093
|
+
|
|
1094
|
+
/**
|
|
1095
|
+
* An function that returns a {@link MochaRootHookObject}, either sync or async.
|
|
1096
|
+
* @callback MochaRootHookFunction
|
|
1097
|
+
* @returns {MochaRootHookObject|Promise<MochaRootHookObject>}
|
|
1098
|
+
*/
|
package/lib/mocharc.json
CHANGED
package/lib/reporters/doc.js
CHANGED
|
@@ -62,6 +62,7 @@ function Doc(runner, options) {
|
|
|
62
62
|
|
|
63
63
|
runner.on(EVENT_TEST_PASS, function(test) {
|
|
64
64
|
Base.consoleLog('%s <dt>%s</dt>', indent(), utils.escape(test.title));
|
|
65
|
+
Base.consoleLog('%s <dt>%s</dt>', indent(), utils.escape(test.file));
|
|
65
66
|
var code = utils.escape(utils.clean(test.body));
|
|
66
67
|
Base.consoleLog('%s <dd><pre><code>%s</code></pre></dd>', indent(), code);
|
|
67
68
|
});
|
|
@@ -72,6 +73,11 @@ function Doc(runner, options) {
|
|
|
72
73
|
indent(),
|
|
73
74
|
utils.escape(test.title)
|
|
74
75
|
);
|
|
76
|
+
Base.consoleLog(
|
|
77
|
+
'%s <dt class="error">%s</dt>',
|
|
78
|
+
indent(),
|
|
79
|
+
utils.escape(test.file)
|
|
80
|
+
);
|
|
75
81
|
var code = utils.escape(utils.clean(test.body));
|
|
76
82
|
Base.consoleLog(
|
|
77
83
|
'%s <dd class="error"><pre><code>%s</code></pre></dd>',
|
package/lib/reporters/json.js
CHANGED
package/lib/reporters/landing.js
CHANGED
|
@@ -98,6 +98,14 @@ function Landing(runner, options) {
|
|
|
98
98
|
process.stdout.write('\n');
|
|
99
99
|
self.epilogue();
|
|
100
100
|
});
|
|
101
|
+
|
|
102
|
+
// if cursor is hidden when we ctrl-C, then it will remain hidden unless...
|
|
103
|
+
process.once('SIGINT', function() {
|
|
104
|
+
cursor.show();
|
|
105
|
+
process.nextTick(function() {
|
|
106
|
+
process.kill(process.pid, 'SIGINT');
|
|
107
|
+
});
|
|
108
|
+
});
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
/**
|
package/lib/runnable.js
CHANGED
|
@@ -5,8 +5,9 @@ var Pending = require('./pending');
|
|
|
5
5
|
var debug = require('debug')('mocha:runnable');
|
|
6
6
|
var milliseconds = require('ms');
|
|
7
7
|
var utils = require('./utils');
|
|
8
|
-
var
|
|
9
|
-
|
|
8
|
+
var errors = require('./errors');
|
|
9
|
+
var createInvalidExceptionError = errors.createInvalidExceptionError;
|
|
10
|
+
var createMultipleDoneError = errors.createMultipleDoneError;
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Save timer references to avoid Sinon interfering (see GH-237).
|
|
@@ -36,10 +37,8 @@ function Runnable(title, fn) {
|
|
|
36
37
|
this._timeout = 2000;
|
|
37
38
|
this._slow = 75;
|
|
38
39
|
this._enableTimeouts = true;
|
|
39
|
-
this.timedOut = false;
|
|
40
40
|
this._retries = -1;
|
|
41
|
-
this.
|
|
42
|
-
this.pending = false;
|
|
41
|
+
this.reset();
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
/**
|
|
@@ -47,6 +46,17 @@ function Runnable(title, fn) {
|
|
|
47
46
|
*/
|
|
48
47
|
utils.inherits(Runnable, EventEmitter);
|
|
49
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Resets the state initially or for a next run.
|
|
51
|
+
*/
|
|
52
|
+
Runnable.prototype.reset = function() {
|
|
53
|
+
this.timedOut = false;
|
|
54
|
+
this._currentRetry = 0;
|
|
55
|
+
this.pending = false;
|
|
56
|
+
delete this.state;
|
|
57
|
+
delete this.err;
|
|
58
|
+
};
|
|
59
|
+
|
|
50
60
|
/**
|
|
51
61
|
* Get current timeout value in msecs.
|
|
52
62
|
*
|
|
@@ -222,31 +232,6 @@ Runnable.prototype.clearTimeout = function() {
|
|
|
222
232
|
clearTimeout(this.timer);
|
|
223
233
|
};
|
|
224
234
|
|
|
225
|
-
/**
|
|
226
|
-
* Inspect the runnable void of private properties.
|
|
227
|
-
*
|
|
228
|
-
* @private
|
|
229
|
-
* @return {string}
|
|
230
|
-
*/
|
|
231
|
-
Runnable.prototype.inspect = function() {
|
|
232
|
-
return JSON.stringify(
|
|
233
|
-
this,
|
|
234
|
-
function(key, val) {
|
|
235
|
-
if (key[0] === '_') {
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
if (key === 'parent') {
|
|
239
|
-
return '#<Suite>';
|
|
240
|
-
}
|
|
241
|
-
if (key === 'ctx') {
|
|
242
|
-
return '#<Context>';
|
|
243
|
-
}
|
|
244
|
-
return val;
|
|
245
|
-
},
|
|
246
|
-
2
|
|
247
|
-
);
|
|
248
|
-
};
|
|
249
|
-
|
|
250
235
|
/**
|
|
251
236
|
* Reset the timeout.
|
|
252
237
|
*
|
|
@@ -293,7 +278,7 @@ Runnable.prototype.run = function(fn) {
|
|
|
293
278
|
var start = new Date();
|
|
294
279
|
var ctx = this.ctx;
|
|
295
280
|
var finished;
|
|
296
|
-
var
|
|
281
|
+
var errorWasHandled = false;
|
|
297
282
|
|
|
298
283
|
// Sometimes the ctx exists, but it is not runnable
|
|
299
284
|
if (ctx && ctx.runnable) {
|
|
@@ -302,17 +287,11 @@ Runnable.prototype.run = function(fn) {
|
|
|
302
287
|
|
|
303
288
|
// called multiple times
|
|
304
289
|
function multiple(err) {
|
|
305
|
-
if (
|
|
290
|
+
if (errorWasHandled) {
|
|
306
291
|
return;
|
|
307
292
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if (err && err.message) {
|
|
311
|
-
err.message += " (and Mocha's " + msg + ')';
|
|
312
|
-
self.emit('error', err);
|
|
313
|
-
} else {
|
|
314
|
-
self.emit('error', new Error(msg));
|
|
315
|
-
}
|
|
293
|
+
errorWasHandled = true;
|
|
294
|
+
self.emit('error', createMultipleDoneError(self, err));
|
|
316
295
|
}
|
|
317
296
|
|
|
318
297
|
// finished
|
|
@@ -363,7 +342,7 @@ Runnable.prototype.run = function(fn) {
|
|
|
363
342
|
callFnAsync(this.fn);
|
|
364
343
|
} catch (err) {
|
|
365
344
|
// handles async runnables which actually run synchronously
|
|
366
|
-
|
|
345
|
+
errorWasHandled = true;
|
|
367
346
|
if (err instanceof Pending) {
|
|
368
347
|
return; // done() is already called in this.skip()
|
|
369
348
|
} else if (this.allowUncaught) {
|
|
@@ -382,7 +361,7 @@ Runnable.prototype.run = function(fn) {
|
|
|
382
361
|
callFn(this.fn);
|
|
383
362
|
}
|
|
384
363
|
} catch (err) {
|
|
385
|
-
|
|
364
|
+
errorWasHandled = true;
|
|
386
365
|
if (err instanceof Pending) {
|
|
387
366
|
return done();
|
|
388
367
|
} else if (this.allowUncaught) {
|