mocha 5.0.1 → 5.0.5

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 CHANGED
@@ -1,18 +1,115 @@
1
+ # 5.0.5 / 2018-03-22
2
+
3
+ Welcome [@outsideris] to the team!
4
+
5
+ ## :bug: Fixes
6
+
7
+ - [#3096]: Fix `--bail` failing to bail within hooks ([@outsideris])
8
+ - [#3184]: Don't skip too many suites (using `describe.skip()`) ([@outsideris])
9
+
10
+ ## :book: Documentation
11
+
12
+ - [#3133]: Improve docs regarding "pending" behavior ([@ematicipo])
13
+ - [#3276], [#3274]: Fix broken stuff in `CHANGELOG.md` ([@tagoro9], [@honzajavorek])
14
+
15
+ ## :nut_and_bolt: Other
16
+
17
+ - [#3208]: Improve test coverage for AMD users ([@outsideris])
18
+ - [#3267]: Remove vestiges of PhantomJS from CI ([@anishkny])
19
+ - [#2952]: Fix a debug message ([@boneskull])
20
+
21
+ [#3096]: https://github.com/mochajs/mocha/issues/3096
22
+ [#3184]: https://github.com/mochajs/mocha/issues/3184
23
+ [#3133]: https://github.com/mochajs/mocha/issues/3133
24
+ [#3276]: https://github.com/mochajs/mocha/pull/3276
25
+ [#3274]: https://github.com/mochajs/mocha/pull/3274
26
+ [#3208]: https://github.com/mochajs/mocha/issues/3208
27
+ [#2952]: https://github.com/mochajs/mocha/issues/2952
28
+ [#3267]: https://github.com/mochajs/mocha/pull/3267
29
+
30
+ [@ematicipo]: https://github.com/ematicipo
31
+ [@tagoro9]: https://github.com/tagoro9
32
+ [@honzajavorek]: https://github.com/honajavorek
33
+ [@anishkny]: https://github.com/anishkny
34
+
35
+ # 5.0.4 / 2018-03-07
36
+
37
+ ## :bug: Fixes
38
+
39
+ - [#3265]: Fixes regression in "watch" functionality introduced in v5.0.2 ([@outsideris])
40
+
41
+ [#3265]: https://github.com/mochajs/mocha/issues/3265
42
+
43
+ # 5.0.3 / 2018-03-06
44
+
45
+ This patch features a fix to address a potential "low severity" [ReDoS vulnerability](https://snyk.io/vuln/npm:diff:20180305) in the [diff](https://npm.im/diff) package (a dependency of Mocha).
46
+
47
+ ## :lock: Security Fixes
48
+
49
+ - [#3266]: Bump `diff` to v3.5.0 ([@anishkny])
50
+
51
+ ## :nut_and_bolt: Other
52
+
53
+ - [#3011]: Expose `generateDiff()` in `Base` reporter ([@harrysarson])
54
+
55
+ [#3266]: https://github.com/mochajs/mocha/pull/3266
56
+ [#3011]: https://github.com/mochajs/mocha/issues/3011
57
+
58
+ [@anishkny]: https://github.com/anishkny
59
+ [@harrysarson]: https://github.com/harrysarson
60
+
61
+ # 5.0.2 / 2018-03-05
62
+
63
+ This release fixes a class of tests which report as *false positives*. **Certain tests will now break**, though they would have previously been reported as passing. Details below. Sorry for the inconvenience!
64
+
65
+ ## :bug: Fixes
66
+
67
+ - [#3226]: Do not swallow errors that are thrown asynchronously from passing tests ([@boneskull]). Example:
68
+
69
+ ```js
70
+ it('should actually fail, sorry!', function (done) {
71
+ // passing assertion
72
+ assert(true === true);
73
+
74
+ // test complete & is marked as passing
75
+ done();
76
+
77
+ // ...but something evil lurks within
78
+ setTimeout(() => {
79
+ throw new Error('chaos!');
80
+ }, 100);
81
+ });
82
+ ```
83
+
84
+ Previously to this version, Mocha would have *silently swallowed* the `chaos!` exception, and you wouldn't know. Well, *now you know*. Mocha cannot recover from this gracefully, so it will exit with a nonzero code.
85
+
86
+ **Maintainers of external reporters**: *If* a test of this class is encountered, the `Runner` instance will emit the `end` event *twice*; you *may* need to change your reporter to use `runner.once('end')` intead of `runner.on('end')`.
87
+ - [#3093]: Fix stack trace reformatting problem ([@outsideris])
88
+
89
+ ## :nut_and_bolt: Other
90
+
91
+ - [#3248]: Update `browser-stdout` to v1.3.1 ([@honzajavorek])
92
+
93
+ [#3248]: https://github.com/mochajs/mocha/issues/3248
94
+ [#3226]: https://github.com/mochajs/mocha/issues/3226
95
+ [#3093]: https://github.com/mochajs/mocha/issues/3093
96
+ [@honzajavorek]: https://github.com/honzajavorek
97
+
1
98
  # 5.0.1 / 2018-02-07
2
99
 
3
100
  ...your garden-variety patch release.
4
101
 
5
- :heart: Special thanks to [Wallaby.js](https://wallabyjs.com) for their continued support!
102
+ Special thanks to [Wallaby.js](https://wallabyjs.com) for their continued support! :heart:
6
103
 
7
104
  ## :bug: Fixes
8
-
105
+
9
106
  - [#1838]: `--delay` now works with `.only()` ([@silviom])
10
107
  - [#3119]: Plug memory leak present in v8 ([@boneskull])
11
108
 
12
109
  ## :book: Documentation
13
110
 
14
111
  - [#3132], [#3098]: Update `--glob` docs ([@outsideris])
15
- - [#3212]: Update [Wallaby.,js](https://wallabyjs.com)-related docs ([@ArtemGovorov])
112
+ - [#3212]: Update [Wallaby.js](https://wallabyjs.com)-related docs ([@ArtemGovorov])
16
113
  - [#3205]: Remove outdated cruft ([@boneskull])
17
114
 
18
115
  ## :nut_and_bolt: Other
@@ -24,10 +121,10 @@
24
121
  [#3119]: https://github.com/mochajs/mocha/issues/3119
25
122
  [#3132]: https://github.com/mochajs/mocha/issues/3132
26
123
  [#3098]: https://github.com/mochajs/mocha/issues/3098
27
- [#3212]: https://github.com/mochajs/mocha/pulls/3212
28
- [#3205]: https://github.com/mochajs/mocha/pulls/3205
29
- [#3224]: https://github.com/mochajs/mocha/pulls/3224
30
- [#3230]: https://github.com/mochajs/mocha/pulls/3230
124
+ [#3212]: https://github.com/mochajs/mocha/pull/3212
125
+ [#3205]: https://github.com/mochajs/mocha/pull/3205
126
+ [#3224]: https://github.com/mochajs/mocha/pull/3224
127
+ [#3230]: https://github.com/mochajs/mocha/pull/3230
31
128
  [@silviom]: https://github.com/silviom
32
129
  [@outsideris]: https://github.com/outsideris
33
130
  [@ArtemGovorov]: https://github.com/ArtemGovorov
@@ -76,7 +173,7 @@ Welcome [@vkarpov15] to the team!
76
173
  [#3148]: https://github.com/mochajs/mocha/issues/3148
77
174
  [#3181]: https://github.com/mochajs/mocha/issues/3181
78
175
  [#3187]: https://github.com/mochajs/mocha/issues/3187
79
- [#3202]: https://github.com/mochajs/mocha/pull/3148
176
+ [#3202]: https://github.com/mochajs/mocha/pull/3202
80
177
  [#2352]: https://github.com/mochajs/mocha/issues/2352
81
178
  [#3137]: https://github.com/mochajs/mocha/issues/3137
82
179
  [#3134]: https://github.com/mochajs/mocha/issues/3134
@@ -287,9 +384,9 @@ For more info, please [read this article](https://boneskull.com/mocha-v4-nears-r
287
384
  - Various CI-and-test-related fixes and improvements ([@boneskull], [@dasilvacontin], [@PopradiArpad], [@Munter], [@ScottFreeCode])
288
385
  - "Officially" support Node.js 8 ([@elergy])
289
386
 
290
- [#2860]: https://github.com/mochajs/mocha/pulls/2860
291
- [#2696]: https://github.com/mochajs/mocha/pulls/2696
292
- [#2813]: https://github.com/mochajs/mocha/pulls/2813
387
+ [#2860]: https://github.com/mochajs/mocha/pull/2860
388
+ [#2696]: https://github.com/mochajs/mocha/pull/2696
389
+ [#2813]: https://github.com/mochajs/mocha/pull/2813
293
390
  [@charlierudolph]: https://github.com/charlierudolph
294
391
  [@PopradiArpad]: https://github.com/PopradiArpad
295
392
  [@kungapal]: https://github.com/kungapal
@@ -311,7 +408,7 @@ For more info, please [read this article](https://boneskull.com/mocha-v4-nears-r
311
408
  [@makepanic]: https://github.com/makepanic
312
409
  [@Munter]: https://github.com/Munter
313
410
 
314
- [#2778]: https://github.com/mochajs/mocha/pulls/2778
411
+ [#2778]: https://github.com/mochajs/mocha/pull/2778
315
412
  [#2802]: https://github.com/mochajs/mocha/issues/2802
316
413
  [#2820]: https://github.com/mochajs/mocha/pull/2820
317
414
 
package/README.md CHANGED
@@ -1,39 +1,3 @@
1
- # Mocha needs YOU!
2
-
3
- *Did you know* Mocha [is a dependency of over 100,000 projects](https://libraries.io/npm/mocha) published to npm alone?
4
-
5
- **Despite this, we're currently unable to merge most pull requests due to lack of maintenance resources.**
6
-
7
- **Are you interested in triaging issues or reviewing open PRs? Have some time to hack on its codebase?** If you would like to help maintain Mocha, please contact `@boneskull` on [Gitter](https://gitter.im/mochajs/mocha).
8
-
9
- *Thank you* :kissing_heart: to all of you interested in helping. These are Mocha's immediate needs:
10
-
11
- 1. Increase test coverage on Node.js and browser
12
- - Increase integration coverage for all reporters
13
- - `html` reporter must be tested in browser
14
- - ~~Basic console reporters (*not* `nyan`, `landing`, etc.) must be tested in **both** browser and Node.js contexts~~
15
- - ~~Filesystem-based reporters must be tested in Node.js context~~
16
- - **UPDATE - May 24 2017**: Thanks to [community contributions](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md#mag-coverage), the coverage on most reporters has increased dramatically! The `html` reporter is still in [dire need of coverage](https://coveralls.io/builds/11674428/source?filename=lib%2Freporters%2Fhtml.js).
17
- - Increase coverage against all interfaces (`exports` in particular). Ideally this becomes a "matrix" where we repeat sets of integration tests across all interfaces.
18
- - Refactor non-Node.js-specific tests to allow them to run in a browser context. Node.js-specific tests include those which *require* the CLI or filesystem. Most everything else is fair game.
19
- 1. Review current open pull requests
20
- - We need individuals familiar with Mocha's codebase. Got questions? Ask them in [our chat room](https://gitter.im/mochajs/mocha).
21
- - Pull requests **must** have supporting tests. The only exceptions are pure cosmetic or non-functional changes.
22
- - Pull request contributors must sign [the CLA](https://cla.js.foundation/mochajs/mocha).
23
- 1. Close old, inactive issues and pull requests
24
- - ~~A bot should do this. We need a bot. Got a bot?~~ We now use GitHub's own [probot-stale](https://www.npmjs.com/package/probot-stale).
25
- 1. Triage issues
26
- - If we run into "critical" bugs, they need fixing.
27
- - "Critical" means Mocha is broken w/o workarounds for a *large percentage* of users
28
- - Otherwise: respond to issues, close new dupe issues, confirm bugs, ask for more info, etc.
29
-
30
- Once we gain ground on the above items, we can work together formalize our contribution guidelines and governance. For further info & ideas, please see our [projects](https://github.com/mochajs/mocha/projects/).
31
-
32
- *You needn't be a maintainer to submit a pull request for test coverage!*
33
-
34
- -- @boneskull, *Jan 17 2016*
35
-
36
- <br><br>
37
1
  <p align="center">
38
2
  <img src="https://cldup.com/xFVFxOioAU.svg" alt="Mocha test framework"/>
39
3
  </p>
@@ -47,11 +11,12 @@ Once we gain ground on the above items, we can work together formalize our contr
47
11
 
48
12
  ## Links
49
13
 
50
- - [Documentation](http://mochajs.org)
51
- - [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)
52
- - [Google Group](http://groups.google.com/group/mochajs)
53
- - [Wiki](https://github.com/mochajs/mocha/wiki)
54
- - Mocha [Extensions and reporters](https://github.com/mochajs/mocha/wiki)
14
+ - **[Documentation](https://mochajs.org)**
15
+ - **[Release Notes / History / Changes](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)**
16
+ - [Code of Conduct](https://github.com/mochajs/mocha/blob/master/.github/CODE_OF_CONDUCT.md)
17
+ - [Gitter Chatroom](https://gitter.im/mochajs/mocha) (ask questions here!)
18
+ - [Google Group](https://groups.google.com/group/mochajs)
19
+ - [Issue Tracker](https://github.com/mochajs/mocha/issues)
55
20
 
56
21
  ## Backers
57
22
 
@@ -113,6 +78,25 @@ Does your company use Mocha? Ask your manager or marketing team if your company
113
78
  [![MochaJS Backer](https://opencollective.com/mochajs/sponsor/18/avatar)](https://opencollective.com/mochajs/sponsor/18/website)
114
79
  [![MochaJS Backer](https://opencollective.com/mochajs/sponsor/19/avatar)](https://opencollective.com/mochajs/sponsor/19/website)
115
80
 
81
+ ## Development
82
+
83
+ You might want to know that:
84
+
85
+ - Mocha is the *most-depended-upon* module on npm (source: [libraries.io](https://libraries.io/search?order=desc&platforms=NPM&sort=dependents_count)), and
86
+ - Mocha is an *independent* open-source project, maintained exclusively by volunteers.
87
+
88
+ You might want to help:
89
+
90
+ - New to contributing to Mocha? Check out this list of [good first issues](https://github.com/mochajs/mocha/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-issue)
91
+ - Mocha could use a hand with [these issues](https://github.com/mochajs/mocha/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)
92
+ - The [maintainer's handbook](https://github.com/mochajs/mocha/blob/master/MAINTAINERS.md) explains how things get done
93
+
94
+ Finally, come [chat with the maintainers](https://gitter.im/mochajs/contributors) on Gitter if you want to help with:
95
+
96
+ - Triaging issues, answering questions
97
+ - Review, merging, and closing pull requests
98
+ - Other project-maintenance-y things
99
+
116
100
  ## License
117
101
 
118
102
  [MIT](LICENSE)
@@ -113,6 +113,8 @@ module.exports = function (suites, context, mocha) {
113
113
  suites.shift();
114
114
  } else if (typeof opts.fn === 'undefined' && !suite.pending) {
115
115
  throw new Error('Suite "' + suite.fullTitle() + '" was defined but no callback was supplied. Supply a callback or explicitly skip the suite.');
116
+ } else if (!opts.fn && suite.pending) {
117
+ suites.shift();
116
118
  }
117
119
 
118
120
  return suite;
@@ -166,6 +166,22 @@ function stringifyDiffObjs (err) {
166
166
  }
167
167
  }
168
168
 
169
+ /**
170
+ * Returns a diff between 2 strings with coloured ANSI output.
171
+ *
172
+ * The diff will be either inline or unified dependant on the value
173
+ * of `Base.inlineDiff`.
174
+ *
175
+ * @param {string} actual
176
+ * @param {string} expected
177
+ * @return {string} Diff
178
+ */
179
+ var generateDiff = exports.generateDiff = function (actual, expected) {
180
+ return exports.inlineDiffs
181
+ ? inlineDiff(actual, expected)
182
+ : unifiedDiff(actual, expected);
183
+ };
184
+
169
185
  /**
170
186
  * Output the given `failures` as a list.
171
187
  *
@@ -215,11 +231,7 @@ exports.list = function (failures) {
215
231
  var match = message.match(/^([^:]+): expected/);
216
232
  msg = '\n ' + color('error message', match ? match[1] : msg);
217
233
 
218
- if (exports.inlineDiffs) {
219
- msg += inlineDiff(err);
220
- } else {
221
- msg += unifiedDiff(err);
222
- }
234
+ msg += generateDiff(err.actual, err.expected);
223
235
  }
224
236
 
225
237
  // indent stack trace
@@ -302,7 +314,7 @@ function Base (runner) {
302
314
  failures.push(test);
303
315
  });
304
316
 
305
- runner.on('end', function () {
317
+ runner.once('end', function () {
306
318
  stats.end = new Date();
307
319
  stats.duration = stats.end - stats.start;
308
320
  });
@@ -368,14 +380,15 @@ function pad (str, len) {
368
380
  }
369
381
 
370
382
  /**
371
- * Returns an inline diff between 2 strings with coloured ANSI output
383
+ * Returns an inline diff between 2 strings with coloured ANSI output.
372
384
  *
373
385
  * @api private
374
- * @param {Error} err with actual/expected
386
+ * @param {String} actual
387
+ * @param {String} expected
375
388
  * @return {string} Diff
376
389
  */
377
- function inlineDiff (err) {
378
- var msg = errorDiff(err);
390
+ function inlineDiff (actual, expected) {
391
+ var msg = errorDiff(actual, expected);
379
392
 
380
393
  // linenos
381
394
  var lines = msg.split('\n');
@@ -401,13 +414,14 @@ function inlineDiff (err) {
401
414
  }
402
415
 
403
416
  /**
404
- * Returns a unified diff between two strings.
417
+ * Returns a unified diff between two strings with coloured ANSI output.
405
418
  *
406
419
  * @api private
407
- * @param {Error} err with actual/expected
420
+ * @param {String} actual
421
+ * @param {String} expected
408
422
  * @return {string} The diff.
409
423
  */
410
- function unifiedDiff (err) {
424
+ function unifiedDiff (actual, expected) {
411
425
  var indent = ' ';
412
426
  function cleanUp (line) {
413
427
  if (line[0] === '+') {
@@ -427,7 +441,7 @@ function unifiedDiff (err) {
427
441
  function notBlank (line) {
428
442
  return typeof line !== 'undefined' && line !== null;
429
443
  }
430
- var msg = diff.createPatch('string', err.actual, err.expected);
444
+ var msg = diff.createPatch('string', actual, expected);
431
445
  var lines = msg.split('\n').splice(5);
432
446
  return '\n ' +
433
447
  colorLines('diff added', '+ expected') + ' ' +
@@ -440,11 +454,12 @@ function unifiedDiff (err) {
440
454
  * Return a character diff for `err`.
441
455
  *
442
456
  * @api private
443
- * @param {Error} err
444
- * @return {string}
457
+ * @param {String} actual
458
+ * @param {String} expected
459
+ * @return {string} the diff
445
460
  */
446
- function errorDiff (err) {
447
- return diff.diffWordsWithSpace(err.actual, err.expected).map(function (str) {
461
+ function errorDiff (actual, expected) {
462
+ return diff.diffWordsWithSpace(actual, expected).map(function (str) {
448
463
  if (str.added) {
449
464
  return colorLines('diff added', str.value);
450
465
  }
@@ -56,7 +56,7 @@ function Dot (runner) {
56
56
  process.stdout.write(color('fail', Base.symbols.bang));
57
57
  });
58
58
 
59
- runner.on('end', function () {
59
+ runner.once('end', function () {
60
60
  console.log();
61
61
  self.epilogue();
62
62
  });
@@ -39,7 +39,7 @@ function List (runner) {
39
39
  console.log(JSON.stringify(['fail', test]));
40
40
  });
41
41
 
42
- runner.on('end', function () {
42
+ runner.once('end', function () {
43
43
  process.stdout.write(JSON.stringify(['end', self.stats]));
44
44
  });
45
45
  }
@@ -43,7 +43,7 @@ function JSONReporter (runner) {
43
43
  pending.push(test);
44
44
  });
45
45
 
46
- runner.on('end', function () {
46
+ runner.once('end', function () {
47
47
  var obj = {
48
48
  stats: self.stats,
49
49
  tests: tests.map(clean),
@@ -81,7 +81,7 @@ function Landing (runner) {
81
81
  stream.write('\u001b[0m');
82
82
  });
83
83
 
84
- runner.on('end', function () {
84
+ runner.once('end', function () {
85
85
  cursor.show();
86
86
  console.log();
87
87
  self.epilogue();
@@ -54,7 +54,7 @@ function List (runner) {
54
54
  console.log(color('fail', ' %d) %s'), ++n, test.fullTitle());
55
55
  });
56
56
 
57
- runner.on('end', self.epilogue.bind(self));
57
+ runner.once('end', self.epilogue.bind(self));
58
58
  }
59
59
 
60
60
  /**
@@ -91,7 +91,7 @@ function Markdown (runner) {
91
91
  buf += '```\n\n';
92
92
  });
93
93
 
94
- runner.on('end', function () {
94
+ runner.once('end', function () {
95
95
  process.stdout.write('# TOC\n');
96
96
  process.stdout.write(generateTOC(runner.suite));
97
97
  process.stdout.write(buf);
@@ -29,7 +29,7 @@ function Min (runner) {
29
29
  process.stdout.write('\u001b[1;3H');
30
30
  });
31
31
 
32
- runner.on('end', this.epilogue.bind(this));
32
+ runner.once('end', this.epilogue.bind(this));
33
33
  }
34
34
 
35
35
  /**
@@ -52,7 +52,7 @@ function NyanCat (runner) {
52
52
  self.draw();
53
53
  });
54
54
 
55
- runner.on('end', function () {
55
+ runner.once('end', function () {
56
56
  Base.cursor.show();
57
57
  for (var i = 0; i < self.numberOfLines; i++) {
58
58
  write('\n');
@@ -80,7 +80,7 @@ function Progress (runner, options) {
80
80
 
81
81
  // tests are complete, output some stats
82
82
  // and the failures if any
83
- runner.on('end', function () {
83
+ runner.once('end', function () {
84
84
  cursor.show();
85
85
  console.log();
86
86
  self.epilogue();
@@ -72,7 +72,7 @@ function Spec (runner) {
72
72
  console.log(indent() + color('fail', ' %d) %s'), ++n, test.title);
73
73
  });
74
74
 
75
- runner.on('end', self.epilogue.bind(self));
75
+ runner.once('end', self.epilogue.bind(self));
76
76
  }
77
77
 
78
78
  /**
@@ -51,7 +51,7 @@ function TAP (runner) {
51
51
  }
52
52
  });
53
53
 
54
- runner.on('end', function () {
54
+ runner.once('end', function () {
55
55
  console.log('# tests ' + (passes + failures));
56
56
  console.log('# pass ' + passes);
57
57
  console.log('# fail ' + failures);
@@ -78,7 +78,7 @@ function XUnit (runner, options) {
78
78
  tests.push(test);
79
79
  });
80
80
 
81
- runner.on('end', function () {
81
+ runner.once('end', function () {
82
82
  self.write(tag('testsuite', {
83
83
  name: suiteName,
84
84
  tests: stats.tests,
package/lib/runnable.js CHANGED
@@ -103,7 +103,7 @@ Runnable.prototype.slow = function (ms) {
103
103
  if (typeof ms === 'string') {
104
104
  ms = milliseconds(ms);
105
105
  }
106
- debug('timeout %d', ms);
106
+ debug('slow %d', ms);
107
107
  this._slow = ms;
108
108
  return this;
109
109
  };
@@ -142,6 +142,24 @@ Runnable.prototype.isPending = function () {
142
142
  return this.pending || (this.parent && this.parent.isPending());
143
143
  };
144
144
 
145
+ /**
146
+ * Return `true` if this Runnable has failed.
147
+ * @return {boolean}
148
+ * @private
149
+ */
150
+ Runnable.prototype.isFailed = function () {
151
+ return !this.isPending() && this.state === 'failed';
152
+ };
153
+
154
+ /**
155
+ * Return `true` if this Runnable has passed.
156
+ * @return {boolean}
157
+ * @private
158
+ */
159
+ Runnable.prototype.isPassed = function () {
160
+ return !this.isPending() && this.state === 'passed';
161
+ };
162
+
145
163
  /**
146
164
  * Set or get number of retries.
147
165
  *
package/lib/runner.js CHANGED
@@ -265,10 +265,10 @@ Runner.prototype.failHook = function (hook, err) {
265
265
  hook.title = hook.originalTitle + ' for "' + hook.ctx.currentTest.title + '"';
266
266
  }
267
267
 
268
- this.fail(hook, err);
269
268
  if (this.suite.bail()) {
270
269
  this.emit('end');
271
270
  }
271
+ this.fail(hook, err);
272
272
  };
273
273
 
274
274
  /**
@@ -726,21 +726,25 @@ Runner.prototype.uncaught = function (err) {
726
726
 
727
727
  runnable.clearTimeout();
728
728
 
729
- // Ignore errors if complete or pending
730
- if (runnable.state || runnable.isPending()) {
729
+ // Ignore errors if already failed or pending
730
+ // See #3226
731
+ if (runnable.isFailed() || runnable.isPending()) {
731
732
  return;
732
733
  }
734
+ // we cannot recover gracefully if a Runnable has already passed
735
+ // then fails asynchronously
736
+ var alreadyPassed = runnable.isPassed();
737
+ // this will change the state to "failed" regardless of the current value
733
738
  this.fail(runnable, err);
739
+ if (!alreadyPassed) {
740
+ // recover from test
741
+ if (runnable.type === 'test') {
742
+ this.emit('test end', runnable);
743
+ this.hookUp('afterEach', this.next);
744
+ return;
745
+ }
734
746
 
735
- // recover from test
736
- if (runnable.type === 'test') {
737
- this.emit('test end', runnable);
738
- this.hookUp('afterEach', this.next);
739
- return;
740
- }
741
-
742
- // recover from hooks
743
- if (runnable.type === 'hook') {
747
+ // recover from hooks
744
748
  var errSuite = this.suite;
745
749
  // if hook failure is in afterEach block
746
750
  if (runnable.fullTitle().indexOf('after each') > -1) {