diff --git a/lib/runner.js b/lib/runner.js index 6aefb34cce..67e6fbabdb 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -600,9 +600,17 @@ Runner.prototype.runTests = function(suite, fn) { } test.state = 'passed'; - self.emit('pass', test); - self.emit('test end', test); - self.hookUp('afterEach', next); + + // For supporting conditional fail in afterEach hook, + // run emit pass after an afterEach hook. + // See, https://github.com/mochajs/mocha/wiki/HOW-TO:-Conditionally-fail-a-test-after-completion + self.hookUp('afterEach', function(err, errSuite) { + if (test.state === 'passed') { + self.emit('pass', test); + } + self.emit('test end', test); + next(err, errSuite); + }); }); }); } diff --git a/test/integration/fixtures/hooks/afterEach-hook-conditionally-fail.fixture.js b/test/integration/fixtures/hooks/afterEach-hook-conditionally-fail.fixture.js new file mode 100644 index 0000000000..c127886efd --- /dev/null +++ b/test/integration/fixtures/hooks/afterEach-hook-conditionally-fail.fixture.js @@ -0,0 +1,21 @@ +'use strict'; + +describe('something', function() { + it('should one', function() { + this.ok = true; + }); + + it('should two', function() { + this.ok = false; + }); + + it('should three', function() { + this.ok = true; + }); + + afterEach(function() { + if (!this.ok) { + this.test.error(new Error('something went wrong')); + } + }); +}); diff --git a/test/integration/fixtures/multiple-done.fixture.js b/test/integration/fixtures/multiple-done.fixture.js index f1b471c678..900192b0b9 100644 --- a/test/integration/fixtures/multiple-done.fixture.js +++ b/test/integration/fixtures/multiple-done.fixture.js @@ -1,16 +1,13 @@ 'use strict'; -// The suite below should result in an additional error, but does -// not. Uncomment once this bug is resolved. - -// describe('suite', function() { -// beforeEach(function(done) { -// done(); -// done(); -// }); +describe('suite', function() { + beforeEach(function(done) { + done(); + done(); + }); -// it('test', function() {}); -// }); + it('test', function() {}); +}); it('should fail in a test-case', function (done) { process.nextTick(function () { diff --git a/test/integration/hook-err.spec.js b/test/integration/hook-err.spec.js index 493e91004c..0602166318 100644 --- a/test/integration/hook-err.spec.js +++ b/test/integration/hook-err.spec.js @@ -39,7 +39,7 @@ describe('hook error handling', function() { describe('after each hook error', function() { before(run('hooks/afterEach-hook-error.fixture.js')); it('should verify results', function() { - assert.deepEqual(lines, ['test 1', 'after', bang + 'test 3']); + assert.deepEqual(lines, ['test 1', 'after', bang, 'test 3']); }); }); @@ -62,7 +62,8 @@ describe('hook error handling', function() { '1-2 before each', '1-2 test 1', '1-2 after each', - bang + '1 after each', + bang, + '1 after each', 'root after each', '1-2 after', '1 after', diff --git a/test/integration/hooks.spec.js b/test/integration/hooks.spec.js index 316d522771..bfc1596f13 100644 --- a/test/integration/hooks.spec.js +++ b/test/integration/hooks.spec.js @@ -1,13 +1,13 @@ 'use strict'; var assert = require('assert'); -var runMocha = require('./helpers').runMocha; +var helpers = require('./helpers'); var splitRegExp = require('./helpers').splitRegExp; var args = ['--reporter', 'dot']; describe('hooks', function() { it('are ran in correct order', function(done) { - runMocha('cascade.fixture.js', args, function(err, res) { + helpers.runMocha('cascade.fixture.js', args, function(err, res) { var lines, expected; if (err) { @@ -49,4 +49,20 @@ describe('hooks', function() { done(); }); }); + + it('can fail a test in an afterEach hook', function(done) { + helpers.runMochaJSON( + 'hooks/afterEach-hook-conditionally-fail.fixture.js', + args, + function(err, res) { + if (err) { + done(err); + return; + } + assert.equal(res.stats.passes, 2); + assert.equal(res.stats.failures, 1); + done(); + } + ); + }); }); diff --git a/test/integration/multiple-done.spec.js b/test/integration/multiple-done.spec.js index 781871a631..a97e3528f4 100644 --- a/test/integration/multiple-done.spec.js +++ b/test/integration/multiple-done.spec.js @@ -17,7 +17,7 @@ describe('multiple calls to done()', function() { it('results in failures', function() { assert.equal(res.stats.pending, 0, 'wrong "pending" count'); assert.equal(res.stats.passes, 1, 'wrong "passes" count'); - assert.equal(res.stats.failures, 1, 'wrong "failures" count'); + assert.equal(res.stats.failures, 2, 'wrong "failures" count'); }); it('throws a descriptive error', function() { @@ -35,7 +35,7 @@ describe('multiple calls to done()', function() { it('results in failures', function() { assert.equal(res.stats.pending, 0, 'wrong "pending" count'); - assert.equal(res.stats.passes, 1, 'wrong "passes" count'); + assert.equal(res.stats.passes, 0, 'wrong "passes" count'); assert.equal(res.stats.failures, 1, 'wrong "failures" count'); }); diff --git a/test/integration/uncaught.spec.js b/test/integration/uncaught.spec.js index f82edbe9d3..121ff312f3 100644 --- a/test/integration/uncaught.spec.js +++ b/test/integration/uncaught.spec.js @@ -51,17 +51,13 @@ describe('uncaught exceptions', function() { return; } assert.equal(res.stats.pending, 0); - assert.equal(res.stats.passes, 1); + assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 1); assert.equal( res.failures[0].title, 'should bail if a successful test asynchronously fails' ); - assert.equal( - res.passes[0].title, - 'should bail if a successful test asynchronously fails' - ); assert.equal(res.code, 1); done();