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

Gracefully exit on SIGINT #1063

Merged
merged 1 commit into from
Dec 7, 2013
Merged
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
4 changes: 3 additions & 1 deletion bin/_mocha
Original file line number Diff line number Diff line change
Expand Up @@ -348,12 +348,14 @@ if (program.watch) {
// load

mocha.files = files;
mocha.run(program.exit ? process.exit : exitLater);
var runner = mocha.run(program.exit ? process.exit : exitLater);

function exitLater(code) {
process.on('exit', function() { process.exit(code) })
}

process.on('SIGINT', function() { runner.abort(); })

// enable growl notifications

function growl(runner, reporter) {
Expand Down
26 changes: 21 additions & 5 deletions lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ module.exports = Runner;
function Runner(suite) {
var self = this;
this._globals = [];
this._aborting = false;
this.suite = suite;
this.total = suite.total();
this.failures = 0;
Expand Down Expand Up @@ -205,12 +206,12 @@ Runner.prototype.fail = function(test, err){
* - If bail, then exit
* - Failed `before` hook skips all tests in a suite and subsuites,
* but jumps to corresponding `after` hook
* - Failed `before each` hook skips remaining tests in a
* - Failed `before each` hook skips remaining tests in a
* suite and jumps to corresponding `after each` hook,
* which is run only once
* - Failed `after` hook does not alter
* execution order
* - Failed `after each` hook skips remaining tests in a
* - Failed `after each` hook skips remaining tests in a
* suite and subsuites, but executes other `after each`
* hooks
*
Expand Down Expand Up @@ -259,7 +260,7 @@ Runner.prototype.hook = function(name, fn){
var testError = hook.error();
if (testError) self.fail(self.test, testError);
if (err) {
self.failHook(hook, err);
self.failHook(hook, err);

// stop executing hooks, notify callee of hook err
return fn(err);
Expand Down Expand Up @@ -397,7 +398,7 @@ Runner.prototype.runTests = function(suite, fn){
// for failed 'after each' hook start from errSuite parent,
// otherwise start from errSuite itself
self.suite = after ? errSuite.parent : errSuite;

if (self.suite) {
// call hookUp afterEach
self.hookUp('afterEach', function(err2, errSuite2) {
Expand All @@ -408,7 +409,7 @@ Runner.prototype.runTests = function(suite, fn){
fn(errSuite);
});
} else {
// there is no need calling other 'after each' hooks
// there is no need calling other 'after each' hooks
self.suite = orig;
fn(errSuite);
}
Expand All @@ -418,6 +419,8 @@ Runner.prototype.runTests = function(suite, fn){
// if we bail after first err
if (self.failures && suite._bail) return fn();

if (self._aborting) return fn();

if (err) return hookErr(err, errSuite, true);

// next test
Expand Down Expand Up @@ -500,6 +503,8 @@ Runner.prototype.runSuite = function(suite, fn){
}
}

if (self._aborting) return done();

var curr = suite.suites[i++];
if (!curr) return done();
self.runSuite(curr, next);
Expand Down Expand Up @@ -584,6 +589,17 @@ Runner.prototype.run = function(fn){
return this;
};

/**
* Cleanly abort execution
*
* @return {Runner} for chaining
* @api public
*/
Runner.prototype.abort = function(){
debug('aborting');
this._aborting = true;
}

/**
* Filter leaks with the given globals flagged as `ok`.
*
Expand Down
27 changes: 27 additions & 0 deletions test/acceptance/misc/many.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Useful for testing SIGINT handler
// use env.big_number to tune iterations so that you have time to ctrl+c

describe('a load of tests', function(){
it('should fail the first test', function(){
throw new Error('this should appear in the summary');
})

var iterations = (process.env.big_number || 1e7);
function work() {
var a = 0;
for(var i=0; i<iterations; ++i) {
a += i;
}
}

function addTest() {
it('should pass test ' + i, function(){
work();
})
}

for(var i=0; i<500; ++i) {
addTest();
}

})