mocha 6.1.0 → 6.1.4

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.
Files changed (61) hide show
  1. package/CHANGELOG.md +1776 -1751
  2. package/LICENSE +22 -22
  3. package/README.md +105 -105
  4. package/bin/_mocha +10 -10
  5. package/bin/mocha +149 -149
  6. package/bin/options.js +10 -10
  7. package/browser-entry.js +191 -191
  8. package/index.js +3 -3
  9. package/lib/browser/growl.js +168 -168
  10. package/lib/browser/progress.js +119 -119
  11. package/lib/browser/template.html +18 -18
  12. package/lib/browser/tty.js +13 -13
  13. package/lib/cli/cli.js +69 -69
  14. package/lib/cli/commands.js +13 -13
  15. package/lib/cli/config.js +101 -101
  16. package/lib/cli/index.js +9 -9
  17. package/lib/cli/init.js +37 -37
  18. package/lib/cli/node-flags.js +86 -86
  19. package/lib/cli/one-and-dones.js +70 -70
  20. package/lib/cli/options.js +347 -347
  21. package/lib/cli/run-helpers.js +337 -337
  22. package/lib/cli/run-option-metadata.js +76 -76
  23. package/lib/cli/run.js +297 -297
  24. package/lib/context.js +101 -101
  25. package/lib/errors.js +141 -141
  26. package/lib/growl.js +136 -136
  27. package/lib/hook.js +46 -46
  28. package/lib/interfaces/bdd.js +118 -118
  29. package/lib/interfaces/common.js +191 -191
  30. package/lib/interfaces/exports.js +60 -60
  31. package/lib/interfaces/index.js +6 -6
  32. package/lib/interfaces/qunit.js +99 -99
  33. package/lib/interfaces/tdd.js +107 -107
  34. package/lib/mocha.js +843 -843
  35. package/lib/mocharc.json +10 -10
  36. package/lib/pending.js +12 -12
  37. package/lib/reporters/base.js +491 -491
  38. package/lib/reporters/doc.js +85 -85
  39. package/lib/reporters/dot.js +81 -81
  40. package/lib/reporters/html.js +390 -390
  41. package/lib/reporters/index.js +19 -19
  42. package/lib/reporters/json-stream.js +90 -90
  43. package/lib/reporters/json.js +135 -135
  44. package/lib/reporters/landing.js +108 -108
  45. package/lib/reporters/list.js +78 -78
  46. package/lib/reporters/markdown.js +112 -112
  47. package/lib/reporters/min.js +52 -52
  48. package/lib/reporters/nyan.js +276 -276
  49. package/lib/reporters/progress.js +104 -104
  50. package/lib/reporters/spec.js +99 -99
  51. package/lib/reporters/tap.js +294 -294
  52. package/lib/reporters/xunit.js +216 -216
  53. package/lib/runnable.js +496 -496
  54. package/lib/runner.js +1049 -1049
  55. package/lib/stats-collector.js +83 -83
  56. package/lib/suite.js +642 -642
  57. package/lib/test.js +51 -51
  58. package/lib/utils.js +897 -897
  59. package/mocha.css +326 -326
  60. package/mocha.js +8170 -8476
  61. package/package.json +630 -628
package/lib/runnable.js CHANGED
@@ -1,496 +1,496 @@
1
- 'use strict';
2
-
3
- var EventEmitter = require('events').EventEmitter;
4
- var Pending = require('./pending');
5
- var debug = require('debug')('mocha:runnable');
6
- var milliseconds = require('ms');
7
- var utils = require('./utils');
8
- var createInvalidExceptionError = require('./errors')
9
- .createInvalidExceptionError;
10
-
11
- /**
12
- * Save timer references to avoid Sinon interfering (see GH-237).
13
- */
14
- var Date = global.Date;
15
- var setTimeout = global.setTimeout;
16
- var clearTimeout = global.clearTimeout;
17
- var toString = Object.prototype.toString;
18
-
19
- module.exports = Runnable;
20
-
21
- /**
22
- * Initialize a new `Runnable` with the given `title` and callback `fn`.
23
- *
24
- * @class
25
- * @extends external:EventEmitter
26
- * @public
27
- * @param {String} title
28
- * @param {Function} fn
29
- */
30
- function Runnable(title, fn) {
31
- this.title = title;
32
- this.fn = fn;
33
- this.body = (fn || '').toString();
34
- this.async = fn && fn.length;
35
- this.sync = !this.async;
36
- this._timeout = 2000;
37
- this._slow = 75;
38
- this._enableTimeouts = true;
39
- this.timedOut = false;
40
- this._retries = -1;
41
- this._currentRetry = 0;
42
- this.pending = false;
43
- }
44
-
45
- /**
46
- * Inherit from `EventEmitter.prototype`.
47
- */
48
- utils.inherits(Runnable, EventEmitter);
49
-
50
- /**
51
- * Get current timeout value in msecs.
52
- *
53
- * @private
54
- * @returns {number} current timeout threshold value
55
- */
56
- /**
57
- * @summary
58
- * Set timeout threshold value (msecs).
59
- *
60
- * @description
61
- * A string argument can use shorthand (e.g., "2s") and will be converted.
62
- * The value will be clamped to range [<code>0</code>, <code>2^<sup>31</sup>-1</code>].
63
- * If clamped value matches either range endpoint, timeouts will be disabled.
64
- *
65
- * @private
66
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#Maximum_delay_value}
67
- * @param {number|string} ms - Timeout threshold value.
68
- * @returns {Runnable} this
69
- * @chainable
70
- */
71
- Runnable.prototype.timeout = function(ms) {
72
- if (!arguments.length) {
73
- return this._timeout;
74
- }
75
- if (typeof ms === 'string') {
76
- ms = milliseconds(ms);
77
- }
78
-
79
- // Clamp to range
80
- var INT_MAX = Math.pow(2, 31) - 1;
81
- var range = [0, INT_MAX];
82
- ms = utils.clamp(ms, range);
83
-
84
- // see #1652 for reasoning
85
- if (ms === range[0] || ms === range[1]) {
86
- this._enableTimeouts = false;
87
- }
88
- debug('timeout %d', ms);
89
- this._timeout = ms;
90
- if (this.timer) {
91
- this.resetTimeout();
92
- }
93
- return this;
94
- };
95
-
96
- /**
97
- * Set or get slow `ms`.
98
- *
99
- * @private
100
- * @param {number|string} ms
101
- * @return {Runnable|number} ms or Runnable instance.
102
- */
103
- Runnable.prototype.slow = function(ms) {
104
- if (!arguments.length || typeof ms === 'undefined') {
105
- return this._slow;
106
- }
107
- if (typeof ms === 'string') {
108
- ms = milliseconds(ms);
109
- }
110
- debug('slow %d', ms);
111
- this._slow = ms;
112
- return this;
113
- };
114
-
115
- /**
116
- * Set and get whether timeout is `enabled`.
117
- *
118
- * @private
119
- * @param {boolean} enabled
120
- * @return {Runnable|boolean} enabled or Runnable instance.
121
- */
122
- Runnable.prototype.enableTimeouts = function(enabled) {
123
- if (!arguments.length) {
124
- return this._enableTimeouts;
125
- }
126
- debug('enableTimeouts %s', enabled);
127
- this._enableTimeouts = enabled;
128
- return this;
129
- };
130
-
131
- /**
132
- * Halt and mark as pending.
133
- *
134
- * @memberof Mocha.Runnable
135
- * @public
136
- */
137
- Runnable.prototype.skip = function() {
138
- throw new Pending('sync skip');
139
- };
140
-
141
- /**
142
- * Check if this runnable or its parent suite is marked as pending.
143
- *
144
- * @private
145
- */
146
- Runnable.prototype.isPending = function() {
147
- return this.pending || (this.parent && this.parent.isPending());
148
- };
149
-
150
- /**
151
- * Return `true` if this Runnable has failed.
152
- * @return {boolean}
153
- * @private
154
- */
155
- Runnable.prototype.isFailed = function() {
156
- return !this.isPending() && this.state === constants.STATE_FAILED;
157
- };
158
-
159
- /**
160
- * Return `true` if this Runnable has passed.
161
- * @return {boolean}
162
- * @private
163
- */
164
- Runnable.prototype.isPassed = function() {
165
- return !this.isPending() && this.state === constants.STATE_PASSED;
166
- };
167
-
168
- /**
169
- * Set or get number of retries.
170
- *
171
- * @private
172
- */
173
- Runnable.prototype.retries = function(n) {
174
- if (!arguments.length) {
175
- return this._retries;
176
- }
177
- this._retries = n;
178
- };
179
-
180
- /**
181
- * Set or get current retry
182
- *
183
- * @private
184
- */
185
- Runnable.prototype.currentRetry = function(n) {
186
- if (!arguments.length) {
187
- return this._currentRetry;
188
- }
189
- this._currentRetry = n;
190
- };
191
-
192
- /**
193
- * Return the full title generated by recursively concatenating the parent's
194
- * full title.
195
- *
196
- * @memberof Mocha.Runnable
197
- * @public
198
- * @return {string}
199
- */
200
- Runnable.prototype.fullTitle = function() {
201
- return this.titlePath().join(' ');
202
- };
203
-
204
- /**
205
- * Return the title path generated by concatenating the parent's title path with the title.
206
- *
207
- * @memberof Mocha.Runnable
208
- * @public
209
- * @return {string}
210
- */
211
- Runnable.prototype.titlePath = function() {
212
- return this.parent.titlePath().concat([this.title]);
213
- };
214
-
215
- /**
216
- * Clear the timeout.
217
- *
218
- * @private
219
- */
220
- Runnable.prototype.clearTimeout = function() {
221
- clearTimeout(this.timer);
222
- };
223
-
224
- /**
225
- * Inspect the runnable void of private properties.
226
- *
227
- * @private
228
- * @return {string}
229
- */
230
- Runnable.prototype.inspect = function() {
231
- return JSON.stringify(
232
- this,
233
- function(key, val) {
234
- if (key[0] === '_') {
235
- return;
236
- }
237
- if (key === 'parent') {
238
- return '#<Suite>';
239
- }
240
- if (key === 'ctx') {
241
- return '#<Context>';
242
- }
243
- return val;
244
- },
245
- 2
246
- );
247
- };
248
-
249
- /**
250
- * Reset the timeout.
251
- *
252
- * @private
253
- */
254
- Runnable.prototype.resetTimeout = function() {
255
- var self = this;
256
- var ms = this.timeout() || 1e9;
257
-
258
- if (!this._enableTimeouts) {
259
- return;
260
- }
261
- this.clearTimeout();
262
- this.timer = setTimeout(function() {
263
- if (!self._enableTimeouts) {
264
- return;
265
- }
266
- self.callback(self._timeoutError(ms));
267
- self.timedOut = true;
268
- }, ms);
269
- };
270
-
271
- /**
272
- * Set or get a list of whitelisted globals for this test run.
273
- *
274
- * @private
275
- * @param {string[]} globals
276
- */
277
- Runnable.prototype.globals = function(globals) {
278
- if (!arguments.length) {
279
- return this._allowedGlobals;
280
- }
281
- this._allowedGlobals = globals;
282
- };
283
-
284
- /**
285
- * Run the test and invoke `fn(err)`.
286
- *
287
- * @param {Function} fn
288
- * @private
289
- */
290
- Runnable.prototype.run = function(fn) {
291
- var self = this;
292
- var start = new Date();
293
- var ctx = this.ctx;
294
- var finished;
295
- var emitted;
296
-
297
- // Sometimes the ctx exists, but it is not runnable
298
- if (ctx && ctx.runnable) {
299
- ctx.runnable(this);
300
- }
301
-
302
- // called multiple times
303
- function multiple(err) {
304
- if (emitted) {
305
- return;
306
- }
307
- emitted = true;
308
- var msg = 'done() called multiple times';
309
- if (err && err.message) {
310
- err.message += " (and Mocha's " + msg + ')';
311
- self.emit('error', err);
312
- } else {
313
- self.emit('error', new Error(msg));
314
- }
315
- }
316
-
317
- // finished
318
- function done(err) {
319
- var ms = self.timeout();
320
- if (self.timedOut) {
321
- return;
322
- }
323
-
324
- if (finished) {
325
- return multiple(err);
326
- }
327
-
328
- self.clearTimeout();
329
- self.duration = new Date() - start;
330
- finished = true;
331
- if (!err && self.duration > ms && self._enableTimeouts) {
332
- err = self._timeoutError(ms);
333
- }
334
- fn(err);
335
- }
336
-
337
- // for .resetTimeout()
338
- this.callback = done;
339
-
340
- // explicit async with `done` argument
341
- if (this.async) {
342
- this.resetTimeout();
343
-
344
- // allows skip() to be used in an explicit async context
345
- 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.
350
- throw new Pending('async skip; aborting execution');
351
- };
352
-
353
- if (this.allowUncaught) {
354
- return callFnAsync(this.fn);
355
- }
356
- try {
357
- callFnAsync(this.fn);
358
- } catch (err) {
359
- emitted = true;
360
- done(Runnable.toValueOrError(err));
361
- }
362
- return;
363
- }
364
-
365
- if (this.allowUncaught) {
366
- if (this.isPending()) {
367
- done();
368
- } else {
369
- callFn(this.fn);
370
- }
371
- return;
372
- }
373
-
374
- // sync or promise-returning
375
- try {
376
- if (this.isPending()) {
377
- done();
378
- } else {
379
- callFn(this.fn);
380
- }
381
- } catch (err) {
382
- emitted = true;
383
- done(Runnable.toValueOrError(err));
384
- }
385
-
386
- function callFn(fn) {
387
- var result = fn.call(ctx);
388
- if (result && typeof result.then === 'function') {
389
- self.resetTimeout();
390
- result.then(
391
- function() {
392
- done();
393
- // Return null so libraries like bluebird do not warn about
394
- // subsequently constructed Promises.
395
- return null;
396
- },
397
- function(reason) {
398
- done(reason || new Error('Promise rejected with no or falsy reason'));
399
- }
400
- );
401
- } else {
402
- if (self.asyncOnly) {
403
- return done(
404
- new Error(
405
- '--async-only option in use without declaring `done()` or returning a promise'
406
- )
407
- );
408
- }
409
-
410
- done();
411
- }
412
- }
413
-
414
- function callFnAsync(fn) {
415
- var result = fn.call(ctx, function(err) {
416
- if (err instanceof Error || toString.call(err) === '[object Error]') {
417
- return done(err);
418
- }
419
- if (err) {
420
- if (Object.prototype.toString.call(err) === '[object Object]') {
421
- return done(
422
- new Error('done() invoked with non-Error: ' + JSON.stringify(err))
423
- );
424
- }
425
- return done(new Error('done() invoked with non-Error: ' + err));
426
- }
427
- if (result && utils.isPromise(result)) {
428
- return done(
429
- new Error(
430
- 'Resolution method is overspecified. Specify a callback *or* return a Promise; not both.'
431
- )
432
- );
433
- }
434
-
435
- done();
436
- });
437
- }
438
- };
439
-
440
- /**
441
- * Instantiates a "timeout" error
442
- *
443
- * @param {number} ms - Timeout (in milliseconds)
444
- * @returns {Error} a "timeout" error
445
- * @private
446
- */
447
- Runnable.prototype._timeoutError = function(ms) {
448
- var msg =
449
- 'Timeout of ' +
450
- ms +
451
- 'ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.';
452
- if (this.file) {
453
- msg += ' (' + this.file + ')';
454
- }
455
- return new Error(msg);
456
- };
457
-
458
- var constants = utils.defineConstants(
459
- /**
460
- * {@link Runnable}-related constants.
461
- * @public
462
- * @memberof Runnable
463
- * @readonly
464
- * @static
465
- * @alias constants
466
- * @enum {string}
467
- */
468
- {
469
- /**
470
- * Value of `state` prop when a `Runnable` has failed
471
- */
472
- STATE_FAILED: 'failed',
473
- /**
474
- * Value of `state` prop when a `Runnable` has passed
475
- */
476
- STATE_PASSED: 'passed'
477
- }
478
- );
479
-
480
- /**
481
- * Given `value`, return identity if truthy, otherwise create an "invalid exception" error and return that.
482
- * @param {*} [value] - Value to return, if present
483
- * @returns {*|Error} `value`, otherwise an `Error`
484
- * @private
485
- */
486
- Runnable.toValueOrError = function(value) {
487
- return (
488
- value ||
489
- createInvalidExceptionError(
490
- 'Runnable failed with falsy or undefined exception. Please throw an Error instead.',
491
- value
492
- )
493
- );
494
- };
495
-
496
- Runnable.constants = constants;
1
+ 'use strict';
2
+
3
+ var EventEmitter = require('events').EventEmitter;
4
+ var Pending = require('./pending');
5
+ var debug = require('debug')('mocha:runnable');
6
+ var milliseconds = require('ms');
7
+ var utils = require('./utils');
8
+ var createInvalidExceptionError = require('./errors')
9
+ .createInvalidExceptionError;
10
+
11
+ /**
12
+ * Save timer references to avoid Sinon interfering (see GH-237).
13
+ */
14
+ var Date = global.Date;
15
+ var setTimeout = global.setTimeout;
16
+ var clearTimeout = global.clearTimeout;
17
+ var toString = Object.prototype.toString;
18
+
19
+ module.exports = Runnable;
20
+
21
+ /**
22
+ * Initialize a new `Runnable` with the given `title` and callback `fn`.
23
+ *
24
+ * @class
25
+ * @extends external:EventEmitter
26
+ * @public
27
+ * @param {String} title
28
+ * @param {Function} fn
29
+ */
30
+ function Runnable(title, fn) {
31
+ this.title = title;
32
+ this.fn = fn;
33
+ this.body = (fn || '').toString();
34
+ this.async = fn && fn.length;
35
+ this.sync = !this.async;
36
+ this._timeout = 2000;
37
+ this._slow = 75;
38
+ this._enableTimeouts = true;
39
+ this.timedOut = false;
40
+ this._retries = -1;
41
+ this._currentRetry = 0;
42
+ this.pending = false;
43
+ }
44
+
45
+ /**
46
+ * Inherit from `EventEmitter.prototype`.
47
+ */
48
+ utils.inherits(Runnable, EventEmitter);
49
+
50
+ /**
51
+ * Get current timeout value in msecs.
52
+ *
53
+ * @private
54
+ * @returns {number} current timeout threshold value
55
+ */
56
+ /**
57
+ * @summary
58
+ * Set timeout threshold value (msecs).
59
+ *
60
+ * @description
61
+ * A string argument can use shorthand (e.g., "2s") and will be converted.
62
+ * The value will be clamped to range [<code>0</code>, <code>2^<sup>31</sup>-1</code>].
63
+ * If clamped value matches either range endpoint, timeouts will be disabled.
64
+ *
65
+ * @private
66
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#Maximum_delay_value}
67
+ * @param {number|string} ms - Timeout threshold value.
68
+ * @returns {Runnable} this
69
+ * @chainable
70
+ */
71
+ Runnable.prototype.timeout = function(ms) {
72
+ if (!arguments.length) {
73
+ return this._timeout;
74
+ }
75
+ if (typeof ms === 'string') {
76
+ ms = milliseconds(ms);
77
+ }
78
+
79
+ // Clamp to range
80
+ var INT_MAX = Math.pow(2, 31) - 1;
81
+ var range = [0, INT_MAX];
82
+ ms = utils.clamp(ms, range);
83
+
84
+ // see #1652 for reasoning
85
+ if (ms === range[0] || ms === range[1]) {
86
+ this._enableTimeouts = false;
87
+ }
88
+ debug('timeout %d', ms);
89
+ this._timeout = ms;
90
+ if (this.timer) {
91
+ this.resetTimeout();
92
+ }
93
+ return this;
94
+ };
95
+
96
+ /**
97
+ * Set or get slow `ms`.
98
+ *
99
+ * @private
100
+ * @param {number|string} ms
101
+ * @return {Runnable|number} ms or Runnable instance.
102
+ */
103
+ Runnable.prototype.slow = function(ms) {
104
+ if (!arguments.length || typeof ms === 'undefined') {
105
+ return this._slow;
106
+ }
107
+ if (typeof ms === 'string') {
108
+ ms = milliseconds(ms);
109
+ }
110
+ debug('slow %d', ms);
111
+ this._slow = ms;
112
+ return this;
113
+ };
114
+
115
+ /**
116
+ * Set and get whether timeout is `enabled`.
117
+ *
118
+ * @private
119
+ * @param {boolean} enabled
120
+ * @return {Runnable|boolean} enabled or Runnable instance.
121
+ */
122
+ Runnable.prototype.enableTimeouts = function(enabled) {
123
+ if (!arguments.length) {
124
+ return this._enableTimeouts;
125
+ }
126
+ debug('enableTimeouts %s', enabled);
127
+ this._enableTimeouts = enabled;
128
+ return this;
129
+ };
130
+
131
+ /**
132
+ * Halt and mark as pending.
133
+ *
134
+ * @memberof Mocha.Runnable
135
+ * @public
136
+ */
137
+ Runnable.prototype.skip = function() {
138
+ throw new Pending('sync skip');
139
+ };
140
+
141
+ /**
142
+ * Check if this runnable or its parent suite is marked as pending.
143
+ *
144
+ * @private
145
+ */
146
+ Runnable.prototype.isPending = function() {
147
+ return this.pending || (this.parent && this.parent.isPending());
148
+ };
149
+
150
+ /**
151
+ * Return `true` if this Runnable has failed.
152
+ * @return {boolean}
153
+ * @private
154
+ */
155
+ Runnable.prototype.isFailed = function() {
156
+ return !this.isPending() && this.state === constants.STATE_FAILED;
157
+ };
158
+
159
+ /**
160
+ * Return `true` if this Runnable has passed.
161
+ * @return {boolean}
162
+ * @private
163
+ */
164
+ Runnable.prototype.isPassed = function() {
165
+ return !this.isPending() && this.state === constants.STATE_PASSED;
166
+ };
167
+
168
+ /**
169
+ * Set or get number of retries.
170
+ *
171
+ * @private
172
+ */
173
+ Runnable.prototype.retries = function(n) {
174
+ if (!arguments.length) {
175
+ return this._retries;
176
+ }
177
+ this._retries = n;
178
+ };
179
+
180
+ /**
181
+ * Set or get current retry
182
+ *
183
+ * @private
184
+ */
185
+ Runnable.prototype.currentRetry = function(n) {
186
+ if (!arguments.length) {
187
+ return this._currentRetry;
188
+ }
189
+ this._currentRetry = n;
190
+ };
191
+
192
+ /**
193
+ * Return the full title generated by recursively concatenating the parent's
194
+ * full title.
195
+ *
196
+ * @memberof Mocha.Runnable
197
+ * @public
198
+ * @return {string}
199
+ */
200
+ Runnable.prototype.fullTitle = function() {
201
+ return this.titlePath().join(' ');
202
+ };
203
+
204
+ /**
205
+ * Return the title path generated by concatenating the parent's title path with the title.
206
+ *
207
+ * @memberof Mocha.Runnable
208
+ * @public
209
+ * @return {string}
210
+ */
211
+ Runnable.prototype.titlePath = function() {
212
+ return this.parent.titlePath().concat([this.title]);
213
+ };
214
+
215
+ /**
216
+ * Clear the timeout.
217
+ *
218
+ * @private
219
+ */
220
+ Runnable.prototype.clearTimeout = function() {
221
+ clearTimeout(this.timer);
222
+ };
223
+
224
+ /**
225
+ * Inspect the runnable void of private properties.
226
+ *
227
+ * @private
228
+ * @return {string}
229
+ */
230
+ Runnable.prototype.inspect = function() {
231
+ return JSON.stringify(
232
+ this,
233
+ function(key, val) {
234
+ if (key[0] === '_') {
235
+ return;
236
+ }
237
+ if (key === 'parent') {
238
+ return '#<Suite>';
239
+ }
240
+ if (key === 'ctx') {
241
+ return '#<Context>';
242
+ }
243
+ return val;
244
+ },
245
+ 2
246
+ );
247
+ };
248
+
249
+ /**
250
+ * Reset the timeout.
251
+ *
252
+ * @private
253
+ */
254
+ Runnable.prototype.resetTimeout = function() {
255
+ var self = this;
256
+ var ms = this.timeout() || 1e9;
257
+
258
+ if (!this._enableTimeouts) {
259
+ return;
260
+ }
261
+ this.clearTimeout();
262
+ this.timer = setTimeout(function() {
263
+ if (!self._enableTimeouts) {
264
+ return;
265
+ }
266
+ self.callback(self._timeoutError(ms));
267
+ self.timedOut = true;
268
+ }, ms);
269
+ };
270
+
271
+ /**
272
+ * Set or get a list of whitelisted globals for this test run.
273
+ *
274
+ * @private
275
+ * @param {string[]} globals
276
+ */
277
+ Runnable.prototype.globals = function(globals) {
278
+ if (!arguments.length) {
279
+ return this._allowedGlobals;
280
+ }
281
+ this._allowedGlobals = globals;
282
+ };
283
+
284
+ /**
285
+ * Run the test and invoke `fn(err)`.
286
+ *
287
+ * @param {Function} fn
288
+ * @private
289
+ */
290
+ Runnable.prototype.run = function(fn) {
291
+ var self = this;
292
+ var start = new Date();
293
+ var ctx = this.ctx;
294
+ var finished;
295
+ var emitted;
296
+
297
+ // Sometimes the ctx exists, but it is not runnable
298
+ if (ctx && ctx.runnable) {
299
+ ctx.runnable(this);
300
+ }
301
+
302
+ // called multiple times
303
+ function multiple(err) {
304
+ if (emitted) {
305
+ return;
306
+ }
307
+ emitted = true;
308
+ var msg = 'done() called multiple times';
309
+ if (err && err.message) {
310
+ err.message += " (and Mocha's " + msg + ')';
311
+ self.emit('error', err);
312
+ } else {
313
+ self.emit('error', new Error(msg));
314
+ }
315
+ }
316
+
317
+ // finished
318
+ function done(err) {
319
+ var ms = self.timeout();
320
+ if (self.timedOut) {
321
+ return;
322
+ }
323
+
324
+ if (finished) {
325
+ return multiple(err);
326
+ }
327
+
328
+ self.clearTimeout();
329
+ self.duration = new Date() - start;
330
+ finished = true;
331
+ if (!err && self.duration > ms && self._enableTimeouts) {
332
+ err = self._timeoutError(ms);
333
+ }
334
+ fn(err);
335
+ }
336
+
337
+ // for .resetTimeout()
338
+ this.callback = done;
339
+
340
+ // explicit async with `done` argument
341
+ if (this.async) {
342
+ this.resetTimeout();
343
+
344
+ // allows skip() to be used in an explicit async context
345
+ 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.
350
+ throw new Pending('async skip; aborting execution');
351
+ };
352
+
353
+ if (this.allowUncaught) {
354
+ return callFnAsync(this.fn);
355
+ }
356
+ try {
357
+ callFnAsync(this.fn);
358
+ } catch (err) {
359
+ emitted = true;
360
+ done(Runnable.toValueOrError(err));
361
+ }
362
+ return;
363
+ }
364
+
365
+ if (this.allowUncaught) {
366
+ if (this.isPending()) {
367
+ done();
368
+ } else {
369
+ callFn(this.fn);
370
+ }
371
+ return;
372
+ }
373
+
374
+ // sync or promise-returning
375
+ try {
376
+ if (this.isPending()) {
377
+ done();
378
+ } else {
379
+ callFn(this.fn);
380
+ }
381
+ } catch (err) {
382
+ emitted = true;
383
+ done(Runnable.toValueOrError(err));
384
+ }
385
+
386
+ function callFn(fn) {
387
+ var result = fn.call(ctx);
388
+ if (result && typeof result.then === 'function') {
389
+ self.resetTimeout();
390
+ result.then(
391
+ function() {
392
+ done();
393
+ // Return null so libraries like bluebird do not warn about
394
+ // subsequently constructed Promises.
395
+ return null;
396
+ },
397
+ function(reason) {
398
+ done(reason || new Error('Promise rejected with no or falsy reason'));
399
+ }
400
+ );
401
+ } else {
402
+ if (self.asyncOnly) {
403
+ return done(
404
+ new Error(
405
+ '--async-only option in use without declaring `done()` or returning a promise'
406
+ )
407
+ );
408
+ }
409
+
410
+ done();
411
+ }
412
+ }
413
+
414
+ function callFnAsync(fn) {
415
+ var result = fn.call(ctx, function(err) {
416
+ if (err instanceof Error || toString.call(err) === '[object Error]') {
417
+ return done(err);
418
+ }
419
+ if (err) {
420
+ if (Object.prototype.toString.call(err) === '[object Object]') {
421
+ return done(
422
+ new Error('done() invoked with non-Error: ' + JSON.stringify(err))
423
+ );
424
+ }
425
+ return done(new Error('done() invoked with non-Error: ' + err));
426
+ }
427
+ if (result && utils.isPromise(result)) {
428
+ return done(
429
+ new Error(
430
+ 'Resolution method is overspecified. Specify a callback *or* return a Promise; not both.'
431
+ )
432
+ );
433
+ }
434
+
435
+ done();
436
+ });
437
+ }
438
+ };
439
+
440
+ /**
441
+ * Instantiates a "timeout" error
442
+ *
443
+ * @param {number} ms - Timeout (in milliseconds)
444
+ * @returns {Error} a "timeout" error
445
+ * @private
446
+ */
447
+ Runnable.prototype._timeoutError = function(ms) {
448
+ var msg =
449
+ 'Timeout of ' +
450
+ ms +
451
+ 'ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.';
452
+ if (this.file) {
453
+ msg += ' (' + this.file + ')';
454
+ }
455
+ return new Error(msg);
456
+ };
457
+
458
+ var constants = utils.defineConstants(
459
+ /**
460
+ * {@link Runnable}-related constants.
461
+ * @public
462
+ * @memberof Runnable
463
+ * @readonly
464
+ * @static
465
+ * @alias constants
466
+ * @enum {string}
467
+ */
468
+ {
469
+ /**
470
+ * Value of `state` prop when a `Runnable` has failed
471
+ */
472
+ STATE_FAILED: 'failed',
473
+ /**
474
+ * Value of `state` prop when a `Runnable` has passed
475
+ */
476
+ STATE_PASSED: 'passed'
477
+ }
478
+ );
479
+
480
+ /**
481
+ * Given `value`, return identity if truthy, otherwise create an "invalid exception" error and return that.
482
+ * @param {*} [value] - Value to return, if present
483
+ * @returns {*|Error} `value`, otherwise an `Error`
484
+ * @private
485
+ */
486
+ Runnable.toValueOrError = function(value) {
487
+ return (
488
+ value ||
489
+ createInvalidExceptionError(
490
+ 'Runnable failed with falsy or undefined exception. Please throw an Error instead.',
491
+ value
492
+ )
493
+ );
494
+ };
495
+
496
+ Runnable.constants = constants;