mocha 5.1.1 → 6.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +686 -984
  2. package/README.md +2 -1
  3. package/{images → assets/growl}/error.png +0 -0
  4. package/{images → assets/growl}/ok.png +0 -0
  5. package/bin/_mocha +4 -595
  6. package/bin/mocha +121 -61
  7. package/bin/options.js +6 -39
  8. package/browser-entry.js +21 -17
  9. package/lib/browser/growl.js +165 -2
  10. package/lib/browser/progress.js +11 -11
  11. package/lib/{template.html → browser/template.html} +0 -0
  12. package/lib/browser/tty.js +2 -2
  13. package/lib/cli/cli.js +68 -0
  14. package/lib/cli/commands.js +13 -0
  15. package/lib/cli/config.js +79 -0
  16. package/lib/cli/index.js +9 -0
  17. package/lib/cli/init.js +37 -0
  18. package/lib/cli/node-flags.js +69 -0
  19. package/lib/cli/one-and-dones.js +70 -0
  20. package/lib/cli/options.js +330 -0
  21. package/lib/cli/run-helpers.js +337 -0
  22. package/lib/cli/run-option-metadata.js +76 -0
  23. package/lib/cli/run.js +297 -0
  24. package/lib/context.js +14 -14
  25. package/lib/errors.js +141 -0
  26. package/lib/growl.js +136 -0
  27. package/lib/hook.js +5 -16
  28. package/lib/interfaces/bdd.js +16 -13
  29. package/lib/interfaces/common.js +62 -18
  30. package/lib/interfaces/exports.js +5 -8
  31. package/lib/interfaces/qunit.js +10 -10
  32. package/lib/interfaces/tdd.js +12 -11
  33. package/lib/mocha.js +477 -256
  34. package/lib/mocharc.json +10 -0
  35. package/lib/pending.js +1 -5
  36. package/lib/reporters/base.js +95 -117
  37. package/lib/reporters/doc.js +23 -9
  38. package/lib/reporters/dot.js +19 -13
  39. package/lib/reporters/html.js +82 -47
  40. package/lib/reporters/json-stream.js +43 -23
  41. package/lib/reporters/json.js +32 -23
  42. package/lib/reporters/landing.js +16 -9
  43. package/lib/reporters/list.js +19 -11
  44. package/lib/reporters/markdown.js +18 -12
  45. package/lib/reporters/min.js +8 -4
  46. package/lib/reporters/nyan.js +42 -35
  47. package/lib/reporters/progress.js +12 -7
  48. package/lib/reporters/spec.js +23 -12
  49. package/lib/reporters/tap.js +250 -32
  50. package/lib/reporters/xunit.js +61 -35
  51. package/lib/runnable.js +152 -95
  52. package/lib/runner.js +296 -248
  53. package/lib/stats-collector.js +83 -0
  54. package/lib/suite.js +294 -75
  55. package/lib/test.js +16 -15
  56. package/lib/utils.js +419 -146
  57. package/mocha.js +4589 -2228
  58. package/package.json +137 -38
  59. package/lib/ms.js +0 -94
  60. package/lib/reporters/base.js.orig +0 -498
  61. package/lib/reporters/json.js.orig +0 -128
package/lib/runner.js CHANGED
@@ -1,26 +1,36 @@
1
1
  'use strict';
2
2
 
3
- /**
4
- * @module Runner
5
- */
6
3
  /**
7
4
  * Module dependencies.
8
5
  */
6
+ var util = require('util');
9
7
  var EventEmitter = require('events').EventEmitter;
10
8
  var Pending = require('./pending');
11
9
  var utils = require('./utils');
12
10
  var inherits = utils.inherits;
13
11
  var debug = require('debug')('mocha:runner');
14
12
  var Runnable = require('./runnable');
13
+ var Suite = require('./suite');
14
+ var HOOK_TYPE_BEFORE_EACH = Suite.constants.HOOK_TYPE_BEFORE_EACH;
15
+ var HOOK_TYPE_AFTER_EACH = Suite.constants.HOOK_TYPE_AFTER_EACH;
16
+ var HOOK_TYPE_AFTER_ALL = Suite.constants.HOOK_TYPE_AFTER_ALL;
17
+ var HOOK_TYPE_BEFORE_ALL = Suite.constants.HOOK_TYPE_BEFORE_ALL;
18
+ var EVENT_ROOT_SUITE_RUN = Suite.constants.EVENT_ROOT_SUITE_RUN;
19
+ var STATE_FAILED = Runnable.constants.STATE_FAILED;
20
+ var STATE_PASSED = Runnable.constants.STATE_PASSED;
21
+ var dQuote = utils.dQuote;
22
+ var ngettext = utils.ngettext;
23
+ var sQuote = utils.sQuote;
15
24
  var stackFilter = utils.stackTraceFilter();
16
25
  var stringify = utils.stringify;
17
26
  var type = utils.type;
18
- var undefinedError = utils.undefinedError;
27
+ var createInvalidExceptionError = require('./errors')
28
+ .createInvalidExceptionError;
19
29
 
20
30
  /**
21
31
  * Non-enumerable globals.
32
+ * @readonly
22
33
  */
23
-
24
34
  var globals = [
25
35
  'setTimeout',
26
36
  'clearTimeout',
@@ -32,38 +42,89 @@ var globals = [
32
42
  'clearImmediate'
33
43
  ];
34
44
 
35
- /**
36
- * Expose `Runner`.
37
- */
45
+ var constants = utils.defineConstants(
46
+ /**
47
+ * {@link Runner}-related constants.
48
+ * @public
49
+ * @memberof Runner
50
+ * @readonly
51
+ * @alias constants
52
+ * @static
53
+ * @enum {string}
54
+ */
55
+ {
56
+ /**
57
+ * Emitted when {@link Hook} execution begins
58
+ */
59
+ EVENT_HOOK_BEGIN: 'hook',
60
+ /**
61
+ * Emitted when {@link Hook} execution ends
62
+ */
63
+ EVENT_HOOK_END: 'hook end',
64
+ /**
65
+ * Emitted when Root {@link Suite} execution begins (all files have been parsed and hooks/tests are ready for execution)
66
+ */
67
+ EVENT_RUN_BEGIN: 'start',
68
+ /**
69
+ * Emitted when Root {@link Suite} execution has been delayed via `delay` option
70
+ */
71
+ EVENT_DELAY_BEGIN: 'waiting',
72
+ /**
73
+ * Emitted when delayed Root {@link Suite} execution is triggered by user via `global.run()`
74
+ */
75
+ EVENT_DELAY_END: 'ready',
76
+ /**
77
+ * Emitted when Root {@link Suite} execution ends
78
+ */
79
+ EVENT_RUN_END: 'end',
80
+ /**
81
+ * Emitted when {@link Suite} execution begins
82
+ */
83
+ EVENT_SUITE_BEGIN: 'suite',
84
+ /**
85
+ * Emitted when {@link Suite} execution ends
86
+ */
87
+ EVENT_SUITE_END: 'suite end',
88
+ /**
89
+ * Emitted when {@link Test} execution begins
90
+ */
91
+ EVENT_TEST_BEGIN: 'test',
92
+ /**
93
+ * Emitted when {@link Test} execution ends
94
+ */
95
+ EVENT_TEST_END: 'test end',
96
+ /**
97
+ * Emitted when {@link Test} execution fails
98
+ */
99
+ EVENT_TEST_FAIL: 'fail',
100
+ /**
101
+ * Emitted when {@link Test} execution succeeds
102
+ */
103
+ EVENT_TEST_PASS: 'pass',
104
+ /**
105
+ * Emitted when {@link Test} becomes pending
106
+ */
107
+ EVENT_TEST_PENDING: 'pending',
108
+ /**
109
+ * Emitted when {@link Test} execution has failed, but will retry
110
+ */
111
+ EVENT_TEST_RETRY: 'retry'
112
+ }
113
+ );
38
114
 
39
115
  module.exports = Runner;
40
116
 
41
117
  /**
42
- * Initialize a `Runner` for the given `suite`. Derived from [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
43
- *
44
- * Events:
45
- *
46
- * - `start` execution started
47
- * - `end` execution complete
48
- * - `suite` (suite) test suite execution started
49
- * - `suite end` (suite) all tests (and sub-suites) have finished
50
- * - `test` (test) test execution started
51
- * - `test end` (test) test completed
52
- * - `hook` (hook) hook execution started
53
- * - `hook end` (hook) hook complete
54
- * - `pass` (test) test passed
55
- * - `fail` (test, err) test failed
56
- * - `pending` (test) test pending
118
+ * Initialize a `Runner` at the Root {@link Suite}, which represents a hierarchy of {@link Suite|Suites} and {@link Test|Tests}.
57
119
  *
58
- * @memberof Mocha
120
+ * @extends external:EventEmitter
59
121
  * @public
60
122
  * @class
61
- * @api public
62
- * @param {Suite} [suite] Root suite
123
+ * @param {Suite} suite Root suite
63
124
  * @param {boolean} [delay] Whether or not to delay execution of root suite
64
125
  * until ready.
65
126
  */
66
- function Runner (suite, delay) {
127
+ function Runner(suite, delay) {
67
128
  var self = this;
68
129
  this._globals = [];
69
130
  this._abort = false;
@@ -72,10 +133,10 @@ function Runner (suite, delay) {
72
133
  this.started = false;
73
134
  this.total = suite.total();
74
135
  this.failures = 0;
75
- this.on('test end', function (test) {
136
+ this.on(constants.EVENT_TEST_END, function(test) {
76
137
  self.checkGlobals(test);
77
138
  });
78
- this.on('hook end', function (hook) {
139
+ this.on(constants.EVENT_HOOK_END, function(hook) {
79
140
  self.checkGlobals(hook);
80
141
  });
81
142
  this._defaultGrep = /.*/;
@@ -87,7 +148,7 @@ function Runner (suite, delay) {
87
148
  * Wrapper for setImmediate, process.nextTick, or browser polyfill.
88
149
  *
89
150
  * @param {Function} fn
90
- * @api private
151
+ * @private
91
152
  */
92
153
  Runner.immediately = global.setImmediate || process.nextTick;
93
154
 
@@ -100,14 +161,13 @@ inherits(Runner, EventEmitter);
100
161
  * Run tests with full titles matching `re`. Updates runner.total
101
162
  * with number of tests matched.
102
163
  *
103
- * @api public
104
164
  * @public
105
- * @memberof Mocha.Runner
165
+ * @memberof Runner
106
166
  * @param {RegExp} re
107
167
  * @param {boolean} invert
108
168
  * @return {Runner} Runner instance.
109
169
  */
110
- Runner.prototype.grep = function (re, invert) {
170
+ Runner.prototype.grep = function(re, invert) {
111
171
  debug('grep %s', re);
112
172
  this._grep = re;
113
173
  this._invert = invert;
@@ -119,17 +179,16 @@ Runner.prototype.grep = function (re, invert) {
119
179
  * Returns the number of tests matching the grep search for the
120
180
  * given suite.
121
181
  *
122
- * @memberof Mocha.Runner
123
- * @api public
182
+ * @memberof Runner
124
183
  * @public
125
184
  * @param {Suite} suite
126
185
  * @return {number}
127
186
  */
128
- Runner.prototype.grepTotal = function (suite) {
187
+ Runner.prototype.grepTotal = function(suite) {
129
188
  var self = this;
130
189
  var total = 0;
131
190
 
132
- suite.eachTest(function (test) {
191
+ suite.eachTest(function(test) {
133
192
  var match = self._grep.test(test.fullTitle());
134
193
  if (self._invert) {
135
194
  match = !match;
@@ -146,9 +205,9 @@ Runner.prototype.grepTotal = function (suite) {
146
205
  * Return a list of global properties.
147
206
  *
148
207
  * @return {Array}
149
- * @api private
208
+ * @private
150
209
  */
151
- Runner.prototype.globalProps = function () {
210
+ Runner.prototype.globalProps = function() {
152
211
  var props = Object.keys(global);
153
212
 
154
213
  // non-enumerables
@@ -165,13 +224,12 @@ Runner.prototype.globalProps = function () {
165
224
  /**
166
225
  * Allow the given `arr` of globals.
167
226
  *
168
- * @api public
169
227
  * @public
170
- * @memberof Mocha.Runner
228
+ * @memberof Runner
171
229
  * @param {Array} arr
172
230
  * @return {Runner} Runner instance.
173
231
  */
174
- Runner.prototype.globals = function (arr) {
232
+ Runner.prototype.globals = function(arr) {
175
233
  if (!arguments.length) {
176
234
  return this._globals;
177
235
  }
@@ -183,9 +241,9 @@ Runner.prototype.globals = function (arr) {
183
241
  /**
184
242
  * Check for global variable leaks.
185
243
  *
186
- * @api private
244
+ * @private
187
245
  */
188
- Runner.prototype.checkGlobals = function (test) {
246
+ Runner.prototype.checkGlobals = function(test) {
189
247
  if (this.ignoreLeaks) {
190
248
  return;
191
249
  }
@@ -206,48 +264,52 @@ Runner.prototype.checkGlobals = function (test) {
206
264
  leaks = filterLeaks(ok, globals);
207
265
  this._globals = this._globals.concat(leaks);
208
266
 
209
- if (leaks.length > 1) {
210
- this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + ''));
211
- } else if (leaks.length) {
212
- this.fail(test, new Error('global leak detected: ' + leaks[0]));
267
+ if (leaks.length) {
268
+ var format = ngettext(
269
+ leaks.length,
270
+ 'global leak detected: %s',
271
+ 'global leaks detected: %s'
272
+ );
273
+ var error = new Error(util.format(format, leaks.map(sQuote).join(', ')));
274
+ this.fail(test, error);
213
275
  }
214
276
  };
215
277
 
216
278
  /**
217
279
  * Fail the given `test`.
218
280
  *
219
- * @api private
281
+ * @private
220
282
  * @param {Test} test
221
283
  * @param {Error} err
222
284
  */
223
- Runner.prototype.fail = function (test, err) {
285
+ Runner.prototype.fail = function(test, err) {
224
286
  if (test.isPending()) {
225
287
  return;
226
288
  }
227
289
 
228
290
  ++this.failures;
229
- test.state = 'failed';
291
+ test.state = STATE_FAILED;
230
292
 
231
- if (!(err instanceof Error || (err && typeof err.message === 'string'))) {
232
- err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)');
293
+ if (!isError(err)) {
294
+ err = thrown2Error(err);
233
295
  }
234
296
 
235
297
  try {
236
- err.stack = (this.fullStackTrace || !err.stack)
237
- ? err.stack
238
- : stackFilter(err.stack);
239
- } catch (ignored) {
298
+ err.stack =
299
+ this.fullStackTrace || !err.stack ? err.stack : stackFilter(err.stack);
300
+ } catch (ignore) {
240
301
  // some environments do not take kindly to monkeying with the stack
241
302
  }
242
303
 
243
- this.emit('fail', test, err);
304
+ this.emit(constants.EVENT_TEST_FAIL, test, err);
244
305
  };
245
306
 
246
307
  /**
247
308
  * Fail the given `hook` with `err`.
248
309
  *
249
310
  * Hook failures work in the following pattern:
250
- * - If bail, then exit
311
+ * - If bail, run corresponding `after each` and `after` hooks,
312
+ * then exit
251
313
  * - Failed `before` hook skips all tests in a suite and subsuites,
252
314
  * but jumps to corresponding `after` hook
253
315
  * - Failed `before each` hook skips remaining tests in a
@@ -259,65 +321,80 @@ Runner.prototype.fail = function (test, err) {
259
321
  * suite and subsuites, but executes other `after each`
260
322
  * hooks
261
323
  *
262
- * @api private
324
+ * @private
263
325
  * @param {Hook} hook
264
326
  * @param {Error} err
265
327
  */
266
- Runner.prototype.failHook = function (hook, err) {
328
+ Runner.prototype.failHook = function(hook, err) {
329
+ hook.originalTitle = hook.originalTitle || hook.title;
267
330
  if (hook.ctx && hook.ctx.currentTest) {
268
- hook.originalTitle = hook.originalTitle || hook.title;
269
- hook.title = hook.originalTitle + ' for "' + hook.ctx.currentTest.title + '"';
331
+ hook.title =
332
+ hook.originalTitle + ' for ' + dQuote(hook.ctx.currentTest.title);
333
+ } else {
334
+ var parentTitle;
335
+ if (hook.parent.title) {
336
+ parentTitle = hook.parent.title;
337
+ } else {
338
+ parentTitle = hook.parent.root ? '{root}' : '';
339
+ }
340
+ hook.title = hook.originalTitle + ' in ' + dQuote(parentTitle);
270
341
  }
271
342
 
272
- if (this.suite.bail()) {
273
- this.emit('end');
274
- }
275
343
  this.fail(hook, err);
276
344
  };
277
345
 
278
346
  /**
279
347
  * Run hook `name` callbacks and then invoke `fn()`.
280
348
  *
281
- * @api private
349
+ * @private
282
350
  * @param {string} name
283
351
  * @param {Function} fn
284
352
  */
285
353
 
286
- Runner.prototype.hook = function (name, fn) {
354
+ Runner.prototype.hook = function(name, fn) {
287
355
  var suite = this.suite;
288
- var hooks = suite['_' + name];
356
+ var hooks = suite.getHooks(name);
289
357
  var self = this;
290
358
 
291
- function next (i) {
359
+ function next(i) {
292
360
  var hook = hooks[i];
293
361
  if (!hook) {
294
362
  return fn();
295
363
  }
296
364
  self.currentRunnable = hook;
297
365
 
298
- hook.ctx.currentTest = self.test;
366
+ if (name === 'beforeAll') {
367
+ hook.ctx.currentTest = hook.parent.tests[0];
368
+ } else if (name === 'afterAll') {
369
+ hook.ctx.currentTest = hook.parent.tests[hook.parent.tests.length - 1];
370
+ } else {
371
+ hook.ctx.currentTest = self.test;
372
+ }
299
373
 
300
- self.emit('hook', hook);
374
+ self.emit(constants.EVENT_HOOK_BEGIN, hook);
301
375
 
302
376
  if (!hook.listeners('error').length) {
303
- hook.on('error', function (err) {
377
+ hook.on('error', function(err) {
304
378
  self.failHook(hook, err);
305
379
  });
306
380
  }
307
381
 
308
- hook.run(function (err) {
382
+ hook.run(function(err) {
309
383
  var testError = hook.error();
310
384
  if (testError) {
311
385
  self.fail(self.test, testError);
312
386
  }
313
387
  if (err) {
314
388
  if (err instanceof Pending) {
315
- if (name === 'beforeEach' || name === 'afterEach') {
389
+ if (name === HOOK_TYPE_BEFORE_EACH || name === HOOK_TYPE_AFTER_EACH) {
316
390
  self.test.pending = true;
317
391
  } else {
318
- suite.tests.forEach(function (test) {
392
+ suite.tests.forEach(function(test) {
319
393
  test.pending = true;
320
394
  });
395
+ suite.suites.forEach(function(suite) {
396
+ suite.pending = true;
397
+ });
321
398
  // a pending hook won't be executed twice.
322
399
  hook.pending = true;
323
400
  }
@@ -328,13 +405,13 @@ Runner.prototype.hook = function (name, fn) {
328
405
  return fn(err);
329
406
  }
330
407
  }
331
- self.emit('hook end', hook);
408
+ self.emit(constants.EVENT_HOOK_END, hook);
332
409
  delete hook.ctx.currentTest;
333
410
  next(++i);
334
411
  });
335
412
  }
336
413
 
337
- Runner.immediately(function () {
414
+ Runner.immediately(function() {
338
415
  next(0);
339
416
  });
340
417
  };
@@ -343,16 +420,16 @@ Runner.prototype.hook = function (name, fn) {
343
420
  * Run hook `name` for the given array of `suites`
344
421
  * in order, and callback `fn(err, errSuite)`.
345
422
  *
346
- * @api private
423
+ * @private
347
424
  * @param {string} name
348
425
  * @param {Array} suites
349
426
  * @param {Function} fn
350
427
  */
351
- Runner.prototype.hooks = function (name, suites, fn) {
428
+ Runner.prototype.hooks = function(name, suites, fn) {
352
429
  var self = this;
353
430
  var orig = this.suite;
354
431
 
355
- function next (suite) {
432
+ function next(suite) {
356
433
  self.suite = suite;
357
434
 
358
435
  if (!suite) {
@@ -360,7 +437,7 @@ Runner.prototype.hooks = function (name, suites, fn) {
360
437
  return fn();
361
438
  }
362
439
 
363
- self.hook(name, function (err) {
440
+ self.hook(name, function(err) {
364
441
  if (err) {
365
442
  var errSuite = self.suite;
366
443
  self.suite = orig;
@@ -379,9 +456,9 @@ Runner.prototype.hooks = function (name, suites, fn) {
379
456
  *
380
457
  * @param {String} name
381
458
  * @param {Function} fn
382
- * @api private
459
+ * @private
383
460
  */
384
- Runner.prototype.hookUp = function (name, fn) {
461
+ Runner.prototype.hookUp = function(name, fn) {
385
462
  var suites = [this.suite].concat(this.parents()).reverse();
386
463
  this.hooks(name, suites, fn);
387
464
  };
@@ -391,9 +468,9 @@ Runner.prototype.hookUp = function (name, fn) {
391
468
  *
392
469
  * @param {String} name
393
470
  * @param {Function} fn
394
- * @api private
471
+ * @private
395
472
  */
396
- Runner.prototype.hookDown = function (name, fn) {
473
+ Runner.prototype.hookDown = function(name, fn) {
397
474
  var suites = [this.suite].concat(this.parents());
398
475
  this.hooks(name, suites, fn);
399
476
  };
@@ -403,9 +480,9 @@ Runner.prototype.hookDown = function (name, fn) {
403
480
  * closest to furthest.
404
481
  *
405
482
  * @return {Array}
406
- * @api private
483
+ * @private
407
484
  */
408
- Runner.prototype.parents = function () {
485
+ Runner.prototype.parents = function() {
409
486
  var suite = this.suite;
410
487
  var suites = [];
411
488
  while (suite.parent) {
@@ -419,23 +496,25 @@ Runner.prototype.parents = function () {
419
496
  * Run the current test and callback `fn(err)`.
420
497
  *
421
498
  * @param {Function} fn
422
- * @api private
499
+ * @private
423
500
  */
424
- Runner.prototype.runTest = function (fn) {
501
+ Runner.prototype.runTest = function(fn) {
425
502
  var self = this;
426
503
  var test = this.test;
427
504
 
428
505
  if (!test) {
429
506
  return;
430
507
  }
431
- if (this.forbidOnly && hasOnly(this.parents().reverse()[0] || this.suite)) {
508
+
509
+ var suite = this.parents().reverse()[0] || this.suite;
510
+ if (this.forbidOnly && suite.hasOnly()) {
432
511
  fn(new Error('`.only` forbidden'));
433
512
  return;
434
513
  }
435
514
  if (this.asyncOnly) {
436
515
  test.asyncOnly = true;
437
516
  }
438
- test.on('error', function (err) {
517
+ test.on('error', function(err) {
439
518
  self.fail(test, err);
440
519
  });
441
520
  if (this.allowUncaught) {
@@ -452,16 +531,16 @@ Runner.prototype.runTest = function (fn) {
452
531
  /**
453
532
  * Run tests in the given `suite` and invoke the callback `fn()` when complete.
454
533
  *
455
- * @api private
534
+ * @private
456
535
  * @param {Suite} suite
457
536
  * @param {Function} fn
458
537
  */
459
- Runner.prototype.runTests = function (suite, fn) {
538
+ Runner.prototype.runTests = function(suite, fn) {
460
539
  var self = this;
461
540
  var tests = suite.tests.slice();
462
541
  var test;
463
542
 
464
- function hookErr (_, errSuite, after) {
543
+ function hookErr(_, errSuite, after) {
465
544
  // before/after Each hook for errSuite failed:
466
545
  var orig = self.suite;
467
546
 
@@ -471,7 +550,7 @@ Runner.prototype.runTests = function (suite, fn) {
471
550
 
472
551
  if (self.suite) {
473
552
  // call hookUp afterEach
474
- self.hookUp('afterEach', function (err2, errSuite2) {
553
+ self.hookUp(HOOK_TYPE_AFTER_EACH, function(err2, errSuite2) {
475
554
  self.suite = orig;
476
555
  // some hooks may fail even now
477
556
  if (err2) {
@@ -487,10 +566,10 @@ Runner.prototype.runTests = function (suite, fn) {
487
566
  }
488
567
  }
489
568
 
490
- function next (err, errSuite) {
569
+ function next(err, errSuite) {
491
570
  // if we bail after first err
492
571
  if (self.failures && suite._bail) {
493
- return fn();
572
+ tests = [];
494
573
  }
495
574
 
496
575
  if (self._abort) {
@@ -537,31 +616,31 @@ Runner.prototype.runTests = function (suite, fn) {
537
616
  self.fail(test, new Error('Pending test forbidden'));
538
617
  delete test.isPending;
539
618
  } else {
540
- self.emit('pending', test);
619
+ self.emit(constants.EVENT_TEST_PENDING, test);
541
620
  }
542
- self.emit('test end', test);
621
+ self.emit(constants.EVENT_TEST_END, test);
543
622
  return next();
544
623
  }
545
624
 
546
625
  // execute test and hook(s)
547
- self.emit('test', self.test = test);
548
- self.hookDown('beforeEach', function (err, errSuite) {
626
+ self.emit(constants.EVENT_TEST_BEGIN, (self.test = test));
627
+ self.hookDown(HOOK_TYPE_BEFORE_EACH, function(err, errSuite) {
549
628
  if (test.isPending()) {
550
629
  if (self.forbidPending) {
551
630
  test.isPending = alwaysFalse;
552
631
  self.fail(test, new Error('Pending test forbidden'));
553
632
  delete test.isPending;
554
633
  } else {
555
- self.emit('pending', test);
634
+ self.emit(constants.EVENT_TEST_PENDING, test);
556
635
  }
557
- self.emit('test end', test);
636
+ self.emit(constants.EVENT_TEST_END, test);
558
637
  return next();
559
638
  }
560
639
  if (err) {
561
640
  return hookErr(err, errSuite, false);
562
641
  }
563
642
  self.currentRunnable = self.test;
564
- self.runTest(function (err) {
643
+ self.runTest(function(err) {
565
644
  test = self.test;
566
645
  if (err) {
567
646
  var retry = test.currentRetry();
@@ -569,31 +648,33 @@ Runner.prototype.runTests = function (suite, fn) {
569
648
  self.fail(test, new Error('Pending test forbidden'));
570
649
  } else if (err instanceof Pending) {
571
650
  test.pending = true;
572
- self.emit('pending', test);
651
+ self.emit(constants.EVENT_TEST_PENDING, test);
573
652
  } else if (retry < test.retries()) {
574
653
  var clonedTest = test.clone();
575
654
  clonedTest.currentRetry(retry + 1);
576
655
  tests.unshift(clonedTest);
577
656
 
657
+ self.emit(constants.EVENT_TEST_RETRY, test, err);
658
+
578
659
  // Early return + hook trigger so that it doesn't
579
660
  // increment the count wrong
580
- return self.hookUp('afterEach', next);
661
+ return self.hookUp(HOOK_TYPE_AFTER_EACH, next);
581
662
  } else {
582
663
  self.fail(test, err);
583
664
  }
584
- self.emit('test end', test);
665
+ self.emit(constants.EVENT_TEST_END, test);
585
666
 
586
667
  if (err instanceof Pending) {
587
668
  return next();
588
669
  }
589
670
 
590
- return self.hookUp('afterEach', next);
671
+ return self.hookUp(HOOK_TYPE_AFTER_EACH, next);
591
672
  }
592
673
 
593
- test.state = 'passed';
594
- self.emit('pass', test);
595
- self.emit('test end', test);
596
- self.hookUp('afterEach', next);
674
+ test.state = STATE_PASSED;
675
+ self.emit(constants.EVENT_TEST_PASS, test);
676
+ self.emit(constants.EVENT_TEST_END, test);
677
+ self.hookUp(HOOK_TYPE_AFTER_EACH, next);
597
678
  });
598
679
  });
599
680
  }
@@ -603,18 +684,18 @@ Runner.prototype.runTests = function (suite, fn) {
603
684
  next();
604
685
  };
605
686
 
606
- function alwaysFalse () {
687
+ function alwaysFalse() {
607
688
  return false;
608
689
  }
609
690
 
610
691
  /**
611
692
  * Run the given `suite` and invoke the callback `fn()` when complete.
612
693
  *
613
- * @api private
694
+ * @private
614
695
  * @param {Suite} suite
615
696
  * @param {Function} fn
616
697
  */
617
- Runner.prototype.runSuite = function (suite, fn) {
698
+ Runner.prototype.runSuite = function(suite, fn) {
618
699
  var i = 0;
619
700
  var self = this;
620
701
  var total = this.grepTotal(suite);
@@ -626,9 +707,9 @@ Runner.prototype.runSuite = function (suite, fn) {
626
707
  return fn();
627
708
  }
628
709
 
629
- this.emit('suite', this.suite = suite);
710
+ this.emit(constants.EVENT_SUITE_BEGIN, (this.suite = suite));
630
711
 
631
- function next (errSuite) {
712
+ function next(errSuite) {
632
713
  if (errSuite) {
633
714
  // current suite failed on a hook from errSuite
634
715
  if (errSuite === suite) {
@@ -654,7 +735,7 @@ Runner.prototype.runSuite = function (suite, fn) {
654
735
  // huge recursive loop and thus a maximum call stack error.
655
736
  // See comment in `this.runTests()` for more information.
656
737
  if (self._grep !== self._defaultGrep) {
657
- Runner.immediately(function () {
738
+ Runner.immediately(function() {
658
739
  self.runSuite(curr, next);
659
740
  });
660
741
  } else {
@@ -662,7 +743,7 @@ Runner.prototype.runSuite = function (suite, fn) {
662
743
  }
663
744
  }
664
745
 
665
- function done (errSuite) {
746
+ function done(errSuite) {
666
747
  self.suite = suite;
667
748
  self.nextSuite = next;
668
749
 
@@ -676,8 +757,8 @@ Runner.prototype.runSuite = function (suite, fn) {
676
757
  // remove reference to test
677
758
  delete self.test;
678
759
 
679
- self.hook('afterAll', function () {
680
- self.emit('suite end', suite);
760
+ self.hook(HOOK_TYPE_AFTER_ALL, function() {
761
+ self.emit(constants.EVENT_SUITE_END, suite);
681
762
  fn(errSuite);
682
763
  });
683
764
  }
@@ -685,7 +766,7 @@ Runner.prototype.runSuite = function (suite, fn) {
685
766
 
686
767
  this.nextSuite = next;
687
768
 
688
- this.hook('beforeAll', function (err) {
769
+ this.hook(HOOK_TYPE_BEFORE_ALL, function(err) {
689
770
  if (err) {
690
771
  return done();
691
772
  }
@@ -697,16 +778,21 @@ Runner.prototype.runSuite = function (suite, fn) {
697
778
  * Handle uncaught exceptions.
698
779
  *
699
780
  * @param {Error} err
700
- * @api private
781
+ * @private
701
782
  */
702
- Runner.prototype.uncaught = function (err) {
783
+ Runner.prototype.uncaught = function(err) {
703
784
  if (err) {
704
- debug('uncaught exception %s', err === (function () {
705
- return this;
706
- }.call(err)) ? (err.message || err) : err);
785
+ debug('uncaught exception %O', err);
707
786
  } else {
708
- debug('uncaught undefined exception');
709
- err = undefinedError();
787
+ debug('uncaught undefined/falsy exception');
788
+ err = createInvalidExceptionError(
789
+ 'Caught falsy/undefined exception which would otherwise be uncaught. No stack trace found; try a debugger',
790
+ err
791
+ );
792
+ }
793
+
794
+ if (!isError(err)) {
795
+ err = thrown2Error(err);
710
796
  }
711
797
  err.uncaught = true;
712
798
 
@@ -720,9 +806,9 @@ Runner.prototype.uncaught = function (err) {
720
806
  this.fail(runnable, err);
721
807
  } else {
722
808
  // Can't recover from this failure
723
- this.emit('start');
809
+ this.emit(constants.EVENT_RUN_BEGIN);
724
810
  this.fail(runnable, err);
725
- this.emit('end');
811
+ this.emit(constants.EVENT_RUN_END);
726
812
  }
727
813
 
728
814
  return;
@@ -742,14 +828,17 @@ Runner.prototype.uncaught = function (err) {
742
828
  this.fail(runnable, err);
743
829
  if (!alreadyPassed) {
744
830
  // recover from test
745
- if (runnable.type === 'test') {
746
- this.emit('test end', runnable);
747
- this.hookUp('afterEach', this.next);
831
+ if (runnable.type === constants.EVENT_TEST_BEGIN) {
832
+ this.emit(constants.EVENT_TEST_END, runnable);
833
+ this.hookUp(HOOK_TYPE_AFTER_EACH, this.next);
748
834
  return;
749
835
  }
836
+ debug(runnable);
750
837
 
751
838
  // recover from hooks
752
839
  var errSuite = this.suite;
840
+
841
+ // XXX how about a less awful way to determine this?
753
842
  // if hook failure is in afterEach block
754
843
  if (runnable.fullTitle().indexOf('after each') > -1) {
755
844
  return this.hookErr(err, errSuite, true);
@@ -763,88 +852,55 @@ Runner.prototype.uncaught = function (err) {
763
852
  }
764
853
 
765
854
  // bail
766
- this.emit('end');
855
+ this.emit(constants.EVENT_RUN_END);
767
856
  };
768
857
 
769
- /**
770
- * Cleans up the references to all the deferred functions
771
- * (before/after/beforeEach/afterEach) and tests of a Suite.
772
- * These must be deleted otherwise a memory leak can happen,
773
- * as those functions may reference variables from closures,
774
- * thus those variables can never be garbage collected as long
775
- * as the deferred functions exist.
776
- *
777
- * @param {Suite} suite
778
- */
779
- function cleanSuiteReferences (suite) {
780
- function cleanArrReferences (arr) {
781
- for (var i = 0; i < arr.length; i++) {
782
- delete arr[i].fn;
783
- }
784
- }
785
-
786
- if (Array.isArray(suite._beforeAll)) {
787
- cleanArrReferences(suite._beforeAll);
788
- }
789
-
790
- if (Array.isArray(suite._beforeEach)) {
791
- cleanArrReferences(suite._beforeEach);
792
- }
793
-
794
- if (Array.isArray(suite._afterAll)) {
795
- cleanArrReferences(suite._afterAll);
796
- }
797
-
798
- if (Array.isArray(suite._afterEach)) {
799
- cleanArrReferences(suite._afterEach);
800
- }
801
-
802
- for (var i = 0; i < suite.tests.length; i++) {
803
- delete suite.tests[i].fn;
804
- }
805
- }
806
-
807
858
  /**
808
859
  * Run the root suite and invoke `fn(failures)`
809
860
  * on completion.
810
861
  *
811
- * @api public
812
862
  * @public
813
- * @memberof Mocha.Runner
863
+ * @memberof Runner
814
864
  * @param {Function} fn
815
865
  * @return {Runner} Runner instance.
816
866
  */
817
- Runner.prototype.run = function (fn) {
867
+ Runner.prototype.run = function(fn) {
818
868
  var self = this;
819
869
  var rootSuite = this.suite;
820
870
 
821
- fn = fn || function () {};
871
+ fn = fn || function() {};
822
872
 
823
- function uncaught (err) {
873
+ function uncaught(err) {
824
874
  self.uncaught(err);
825
875
  }
826
876
 
827
- function start () {
877
+ function start() {
828
878
  // If there is an `only` filter
829
- if (hasOnly(rootSuite)) {
830
- filterOnly(rootSuite);
879
+ if (rootSuite.hasOnly()) {
880
+ rootSuite.filterOnly();
831
881
  }
832
882
  self.started = true;
833
- self.emit('start');
834
- self.runSuite(rootSuite, function () {
883
+ if (self._delay) {
884
+ self.emit(constants.EVENT_DELAY_END);
885
+ }
886
+ self.emit(constants.EVENT_RUN_BEGIN);
887
+
888
+ self.runSuite(rootSuite, function() {
835
889
  debug('finished running');
836
- self.emit('end');
890
+ self.emit(constants.EVENT_RUN_END);
837
891
  });
838
892
  }
839
893
 
840
- debug('start');
894
+ debug(constants.EVENT_RUN_BEGIN);
841
895
 
842
896
  // references cleanup to avoid memory leaks
843
- this.on('suite end', cleanSuiteReferences);
897
+ this.on(constants.EVENT_SUITE_END, function(suite) {
898
+ suite.cleanReferences();
899
+ });
844
900
 
845
901
  // callback
846
- this.on('end', function () {
847
- debug('end');
902
+ this.on(constants.EVENT_RUN_END, function() {
903
+ debug(constants.EVENT_RUN_END);
848
904
  process.removeListener('uncaughtException', uncaught);
849
905
  fn(self.failures);
850
906
  });
@@ -855,8 +911,8 @@ Runner.prototype.run = function (fn) {
855
911
  if (this._delay) {
856
912
  // for reporters, I guess.
857
913
  // might be nice to debounce some dots while we wait.
858
- this.emit('waiting', rootSuite);
859
- rootSuite.once('run', start);
914
+ this.emit(constants.EVENT_DELAY_BEGIN, rootSuite);
915
+ rootSuite.once(EVENT_ROOT_SUITE_RUN, start);
860
916
  } else {
861
917
  start();
862
918
  }
@@ -867,70 +923,27 @@ Runner.prototype.run = function (fn) {
867
923
  /**
868
924
  * Cleanly abort execution.
869
925
  *
870
- * @memberof Mocha.Runner
926
+ * @memberof Runner
871
927
  * @public
872
- * @api public
873
928
  * @return {Runner} Runner instance.
874
929
  */
875
- Runner.prototype.abort = function () {
930
+ Runner.prototype.abort = function() {
876
931
  debug('aborting');
877
932
  this._abort = true;
878
933
 
879
934
  return this;
880
935
  };
881
936
 
882
- /**
883
- * Filter suites based on `isOnly` logic.
884
- *
885
- * @param {Array} suite
886
- * @returns {Boolean}
887
- * @api private
888
- */
889
- function filterOnly (suite) {
890
- if (suite._onlyTests.length) {
891
- // If the suite contains `only` tests, run those and ignore any nested suites.
892
- suite.tests = suite._onlyTests;
893
- suite.suites = [];
894
- } else {
895
- // Otherwise, do not run any of the tests in this suite.
896
- suite.tests = [];
897
- suite._onlySuites.forEach(function (onlySuite) {
898
- // If there are other `only` tests/suites nested in the current `only` suite, then filter that `only` suite.
899
- // Otherwise, all of the tests on this `only` suite should be run, so don't filter it.
900
- if (hasOnly(onlySuite)) {
901
- filterOnly(onlySuite);
902
- }
903
- });
904
- // Run the `only` suites, as well as any other suites that have `only` tests/suites as descendants.
905
- suite.suites = suite.suites.filter(function (childSuite) {
906
- return suite._onlySuites.indexOf(childSuite) !== -1 || filterOnly(childSuite);
907
- });
908
- }
909
- // Keep the suite only if there is something to run
910
- return suite.tests.length || suite.suites.length;
911
- }
912
-
913
- /**
914
- * Determines whether a suite has an `only` test or suite as a descendant.
915
- *
916
- * @param {Array} suite
917
- * @returns {Boolean}
918
- * @api private
919
- */
920
- function hasOnly (suite) {
921
- return suite._onlyTests.length || suite._onlySuites.length || suite.suites.some(hasOnly);
922
- }
923
-
924
937
  /**
925
938
  * Filter leaks with the given globals flagged as `ok`.
926
939
  *
927
- * @api private
940
+ * @private
928
941
  * @param {Array} ok
929
942
  * @param {Array} globals
930
943
  * @return {Array}
931
944
  */
932
- function filterLeaks (ok, globals) {
933
- return globals.filter(function (key) {
945
+ function filterLeaks(ok, globals) {
946
+ return globals.filter(function(key) {
934
947
  // Firefox and Chrome exposes iframes as index inside the window object
935
948
  if (/^\d+/.test(key)) {
936
949
  return false;
@@ -939,13 +952,13 @@ function filterLeaks (ok, globals) {
939
952
  // in firefox
940
953
  // if runner runs in an iframe, this iframe's window.getInterface method
941
954
  // not init at first it is assigned in some seconds
942
- if (global.navigator && (/^getInterface/).test(key)) {
955
+ if (global.navigator && /^getInterface/.test(key)) {
943
956
  return false;
944
957
  }
945
958
 
946
959
  // an iframe could be approached by window[iframeIndex]
947
960
  // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak
948
- if (global.navigator && (/^\d+/).test(key)) {
961
+ if (global.navigator && /^\d+/.test(key)) {
949
962
  return false;
950
963
  }
951
964
 
@@ -954,7 +967,7 @@ function filterLeaks (ok, globals) {
954
967
  return false;
955
968
  }
956
969
 
957
- var matched = ok.filter(function (ok) {
970
+ var matched = ok.filter(function(ok) {
958
971
  if (~ok.indexOf('*')) {
959
972
  return key.indexOf(ok.split('*')[0]) === 0;
960
973
  }
@@ -964,25 +977,60 @@ function filterLeaks (ok, globals) {
964
977
  });
965
978
  }
966
979
 
980
+ /**
981
+ * Check if argument is an instance of Error object or a duck-typed equivalent.
982
+ *
983
+ * @private
984
+ * @param {Object} err - object to check
985
+ * @param {string} err.message - error message
986
+ * @returns {boolean}
987
+ */
988
+ function isError(err) {
989
+ return err instanceof Error || (err && typeof err.message === 'string');
990
+ }
991
+
992
+ /**
993
+ *
994
+ * Converts thrown non-extensible type into proper Error.
995
+ *
996
+ * @private
997
+ * @param {*} thrown - Non-extensible type thrown by code
998
+ * @return {Error}
999
+ */
1000
+ function thrown2Error(err) {
1001
+ return new Error(
1002
+ 'the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)'
1003
+ );
1004
+ }
1005
+
967
1006
  /**
968
1007
  * Array of globals dependent on the environment.
969
1008
  *
970
1009
  * @return {Array}
971
- * @api private
1010
+ * @deprecated
1011
+ * @todo remove; long since unsupported
1012
+ * @private
972
1013
  */
973
- function extraGlobals () {
1014
+ function extraGlobals() {
974
1015
  if (typeof process === 'object' && typeof process.version === 'string') {
975
1016
  var parts = process.version.split('.');
976
- var nodeVersion = parts.reduce(function (a, v) {
977
- return a << 8 | v;
1017
+ var nodeVersion = parts.reduce(function(a, v) {
1018
+ return (a << 8) | v;
978
1019
  });
979
1020
 
980
1021
  // 'errno' was renamed to process._errno in v0.9.11.
981
-
982
- if (nodeVersion < 0x00090B) {
1022
+ if (nodeVersion < 0x00090b) {
983
1023
  return ['errno'];
984
1024
  }
985
1025
  }
986
1026
 
987
1027
  return [];
988
1028
  }
1029
+
1030
+ Runner.constants = constants;
1031
+
1032
+ /**
1033
+ * Node.js' `EventEmitter`
1034
+ * @external EventEmitter
1035
+ * @see {@link https://nodejs.org/api/events.html#events_class_eventemitter}
1036
+ */