Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More-Granular Bailing #836

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ test-bail:
@./bin/mocha \
--reporter $(REPORTER) \
--bail \
test/acceptance/misc/bail
test/acceptance/misc/bail*

test-async-only:
@./bin/mocha \
Expand Down
13 changes: 11 additions & 2 deletions lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,12 @@ Runner.prototype.hook = function(name, fn){
, self = this
, timer;

// if we're bailing, only run hooks if this suite cause it, otherwise, skip
if (suite.failures && suite.bail() && !suite.failSource) return fn();

function next(i) {
var hook = hooks[i];
if (!hook) return fn();
if (self.failures && suite.bail()) return fn();
self.currentRunnable = hook;

self.emit('hook', hook);
Expand Down Expand Up @@ -371,7 +373,7 @@ Runner.prototype.runTests = function(suite, fn){

function next(err) {
// if we bail after first err
if (self.failures && suite._bail) return fn();
if (suite.failures && suite._bail) return fn();

// next test
test = tests.shift();
Expand Down Expand Up @@ -443,13 +445,20 @@ Runner.prototype.runSuite = function(suite, fn){
}

function done() {
debug('suite done %s', suite.fullTitle());
self.suite = suite;
self.hook('afterAll', function(){
debug('suite end %s', suite.fullTitle());
self.emit('suite end', suite);
fn();
});
}

this.on('fail', function(){
suite.failSource = true;
suite.fail();
});

this.hook('beforeAll', function(){
self.runTests(suite, next);
});
Expand Down
22 changes: 21 additions & 1 deletion lib/suite.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ function Suite(title, ctx) {
this.suites = [];
this.tests = [];
this.pending = false;
this.failures = false;
this._beforeEach = [];
this._beforeAll = [];
this._afterEach = [];
Expand Down Expand Up @@ -120,7 +121,7 @@ Suite.prototype.slow = function(ms){
/**
* Sets whether to bail after first error.
*
* @parma {Boolean} bail
* @param {Boolean} bail
* @return {Suite|Number} for chaining
* @api private
*/
Expand All @@ -132,6 +133,25 @@ Suite.prototype.bail = function(bail){
return this;
};

/**
* Mark this suite as having failures, as well as any child suites.
* This is bookkeeping for fine-grained bailing.
*
* @return {Suite|Number} for chaining
* @api private
*/

Suite.prototype.fail = function(){
if (this.bail()) {
debug('setting suite failure');
this.failures = true;
utils.forEach(this.suites, function(suite) {
suite.fail();
});
}
return this;
}

/**
* Run `fn(test[, done])` before running tests.
*
Expand Down
100 changes: 100 additions & 0 deletions test/acceptance/misc/bail2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
describe("Granular bail tests: ", function () {

var runs = 0;

this.bail(false); // override any previous bail setting

describe("bailing suite: ", function () {
this.bail(true);
it("should fail", function () {
throw new Error("this is ok");
});

it("should not get here", function () {
throw new Error("we should have bailed");
});
});

describe("second bailing suite: ", function () {
this.bail(true);

it("should have run no successful tests by now", function () {
runs += 1;
runs.should.eql(1);
});

it("should fail", function () {
throw new Error("this is ok");
});

it("should not get here", function () {
throw new Error("we should have bailed");
});

});

describe("non-bailing suite: ", function () {
var bail = this.bail();
it("should run this test, the second successful test", function () {
runs += 1;
runs.should.eql(2);
});

it("this suite should not bail", function () {
bail.should.equal(false);
});

it("should run this and fail", function () {
throw new Error("this is ok");
});

it("should run this test, the third test", function () {
runs += 1;
runs.should.eql(3);
});

});

describe("third bailing suite: ", function () {
this.bail(true);

after(function () {
runs += 1;
runs.should.eql(6);
});

before(function () {
runs += 1;
});

it("should have run 4 successful tests by now", function () {
runs += 1;
runs.should.eql(5);
});

it("should fail", function () {
throw new Error("this is ok");
});

it("should not get here", function () {
throw new Error("we should have bailed");
});

describe("child suite: ", function () {

after(function () {
throw new Error("we should have bailed");
});

before(function () {
throw new Error("we should have bailed");
});

it("should fail", function () {
throw new Error("we should have bailed");
});
});

});

});