Skip to content

Commit

Permalink
Merge pull request #1802 from ajaykodali/fix/1769-asynchronous-error-…
Browse files Browse the repository at this point in the history
…handling

Fix for async hook error handling issue
  • Loading branch information
danielstjules committed Aug 10, 2015
2 parents 6d20329 + ebc6aee commit 03af0fe
Show file tree
Hide file tree
Showing 12 changed files with 529 additions and 258 deletions.
36 changes: 32 additions & 4 deletions lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,7 @@ Runner.prototype.runTests = function(suite, fn) {
}

this.next = next;
this.hookErr = hookErr;
next();
};

Expand All @@ -552,6 +553,7 @@ Runner.prototype.runSuite = function(suite, fn) {
var i = 0;
var self = this;
var total = this.grepTotal(suite);
var afterAllHookCalled = false;

debug('run suite %s', suite.fullTitle());

Expand Down Expand Up @@ -597,12 +599,23 @@ Runner.prototype.runSuite = function(suite, fn) {

function done(errSuite) {
self.suite = suite;
self.hook('afterAll', function() {
self.emit('suite end', suite);
self.nextSuite = next;

if (afterAllHookCalled) {
fn(errSuite);
});
} else {
// mark that the afterAll block has been called once
// and so can be skipped if there is an error in it.
afterAllHookCalled = true;
self.hook('afterAll', function() {
self.emit('suite end', suite);
fn(errSuite);
});
}
}

this.nextSuite = next;

this.hook('beforeAll', function(err) {
if (err) {
return done();
Expand Down Expand Up @@ -648,7 +661,22 @@ Runner.prototype.uncaught = function(err) {
return;
}

// bail on hooks
// recover from hooks
if (runnable.type === 'hook') {
var errSuite = this.suite;
// if hook failure is in afterEach block
if (runnable.fullTitle().indexOf('after each') > -1) {
return this.hookErr(err, errSuite, true);
}
// if hook failure is in beforeEach block
if (runnable.fullTitle().indexOf('before each') > -1) {
return this.hookErr(err, errSuite, false);
}
// if hook failure is in after or before blocks
return this.nextSuite(errSuite);
}

// bail
this.emit('end');
};

Expand Down
19 changes: 19 additions & 0 deletions test/integration/fixtures/hooks/after.hook.async.error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
describe('spec 1', function () {
after(function (done) {
console.log('after');
process.nextTick(function () {
throw new Error('after hook error');
});
});
it('should be called because error is in after hook', function () {
console.log('test 1');
});
it('should be called because error is in after hook', function () {
console.log('test 2');
});
});
describe('spec 2', function () {
it('should be called, because hook error was in a sibling suite', function () {
console.log('test 3');
});
});
17 changes: 17 additions & 0 deletions test/integration/fixtures/hooks/after.hook.error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
describe('spec 1', function () {
after(function () {
console.log('after');
throw new Error('after hook error');
});
it('should be called because error is in after hook', function () {
console.log('test 1');
});
it('should be called because error is in after hook', function () {
console.log('test 2');
});
});
describe('spec 2', function () {
it('should be called, because hook error was in a sibling suite', function () {
console.log('test 3');
});
});
19 changes: 19 additions & 0 deletions test/integration/fixtures/hooks/afterEach.hook.async.error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
describe('spec 1', function () {
afterEach(function (done) {
console.log('after');
process.nextTick(function () {
throw new Error('after each hook error');
});
});
it('should be called because error is in after each hook', function () {
console.log('test 1');
});
it('should not be called', function () {
console.log('test 2');
});
});
describe('spec 2', function () {
it('should be called, because hook error was in a sibling suite', function () {
console.log('test 3');
});
});
17 changes: 17 additions & 0 deletions test/integration/fixtures/hooks/afterEach.hook.error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
describe('spec 1', function () {
afterEach(function () {
console.log('after');
throw new Error('after each hook error');
});
it('should be called because error is in after each hook', function () {
console.log('test 1');
});
it('should not be called', function () {
console.log('test 2');
});
});
describe('spec 2', function () {
it('should be called, because hook error was in a sibling suite', function () {
console.log('test 3');
});
});
19 changes: 19 additions & 0 deletions test/integration/fixtures/hooks/before.hook.async.error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
describe('spec 1', function () {
before(function (done) {
console.log('before');
process.nextTick(function () {
throw new Error('before hook error');
});
});
it('should not be called because of error in before hook', function () {
console.log('test 1');
});
it('should not be called because of error in before hook', function () {
console.log('test 2');
});
});
describe('spec 2', function () {
it('should be called, because hook error was in a sibling suite', function () {
console.log('test 3');
});
});
17 changes: 17 additions & 0 deletions test/integration/fixtures/hooks/before.hook.error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
describe('spec 1', function () {
before(function () {
console.log('before');
throw new Error('before hook error');
});
it('should not be called because of error in before hook', function () {
console.log('test 1');
});
it('should not be called because of error in before hook', function () {
console.log('test 2');
});
});
describe('spec 2', function () {
it('should be called, because hook error was in a sibling suite', function () {
console.log('test 3');
});
});
19 changes: 19 additions & 0 deletions test/integration/fixtures/hooks/beforeEach.hook.async.error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
describe('spec 1', function () {
beforeEach(function (done) {
console.log('before');
process.nextTick(function () {
throw new Error('before each hook error');
});
});
it('should not be called because of error in before each hook', function () {
console.log('test 1');
});
it('should not be called because of error in before each hook', function () {
console.log('test 2');
});
});
describe('spec 2', function () {
it('should be called, because hook error was in a sibling suite', function () {
console.log('test 3');
});
});
17 changes: 17 additions & 0 deletions test/integration/fixtures/hooks/beforeEach.hook.error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
describe('spec 1', function () {
beforeEach(function () {
console.log('before');
throw new Error('before each hook error');
});
it('should not be called because of error in before each hook', function () {
console.log('test 1');
});
it('should not be called because of error in before each hook', function () {
console.log('test 2');
});
});
describe('spec 2', function () {
it('should be called, because hook error was in a sibling suite', function () {
console.log('test 3');
});
});
139 changes: 139 additions & 0 deletions test/integration/fixtures/hooks/multiple.hook.async.error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
before(function () {
console.log('root before');
});
beforeEach(function () {
console.log('root before each');
});
describe('1', function () {
beforeEach(function () {
console.log('1 before each');
});

describe('1.1', function () {
before(function () {
console.log('1.1 before');
});
beforeEach(function (done) {
console.log('1.1 before each');
process.nextTick(function () {
throw new Error('1.1 before each hook failed');
});
});
it('1.1 test 1', function () {
console.log('1.1 test 1');
});
it('1.1 test 2', function () {
console.log('1.1 test 2');
});
afterEach(function () {
console.log('1.1 after each');
});
after(function (done) {
console.log('1.1 after');
process.nextTick(function () {
throw new Error('1.1 after hook failed');
});
});
});

describe('1.2', function () {
before(function () {
console.log('1.2 before');
});
beforeEach(function () {
console.log('1.2 before each');
});
it('1.2 test 1', function () {
console.log('1.2 test 1');
});
it('1.2 test 2', function () {
console.log('1.2 test 2');
});
afterEach(function (done) {
console.log('1.2 after each');
process.nextTick(function () {
throw new Error('1.2 after each hook failed');
});
});
after(function () {
console.log('1.2 after');
});
});

afterEach(function () {
console.log('1 after each');
});

after(function () {
console.log('1 after');
});
});

describe('2', function () {
beforeEach(function (done) {
console.log('2 before each');
process.nextTick(function () {
throw new Error('2 before each hook failed');
});
});

describe('2.1', function () {
before(function () {
console.log('2.1 before');
});
beforeEach(function () {
console.log('2.1 before each');
});
it('2.1 test 1', function () {
console.log('2.1 test 1');
});
it('2.1 test 2', function () {
console.log('2.1 test 2');
});
afterEach(function () {
console.log('2.1 after each');
});
after(function () {
console.log('2.1 after');
});
});

describe('2.2', function () {
before(function () {
console.log('2.2 before');
});
beforeEach(function () {
console.log('2.2 before each');
});
it('2.2 test 1', function () {
console.log('2.2 test 1');
});
it('2.2 test 2', function () {
console.log('2.2 test 2');
});
afterEach(function () {
console.log('2.2 after each');
});
after(function () {
console.log('2.2 after');
});
});

afterEach(function (done) {
console.log('2 after each');
process.nextTick(function () {
throw new Error('2 after each hook failed');
});
});

after(function () {
console.log('2 after');
});
});

after(function () {
console.log('root after');
});
afterEach(function () {
console.log('root after each');
});
Loading

0 comments on commit 03af0fe

Please sign in to comment.