diff --git a/lib/runnable.js b/lib/runnable.js index d89a7dd5d7..52ee900b22 100644 --- a/lib/runnable.js +++ b/lib/runnable.js @@ -133,7 +133,7 @@ Runnable.prototype.enableTimeouts = function(enabled) { * @api public */ Runnable.prototype.skip = function() { - throw new Pending(); + throw new Pending('sync skip'); }; /** @@ -298,14 +298,19 @@ Runnable.prototype.run = function(fn) { if (this.async) { this.resetTimeout(); + // allows skip() to be used in an explicit async context + this.skip = function asyncSkip() { + done(new Pending('async skip call')); + // halt execution. the Runnable will be marked pending + // by the previous call, and the uncaught handler will ignore + // the failure. + throw new Pending('async skip; aborting execution'); + }; + if (this.allowUncaught) { return callFnAsync(this.fn); } try { - // allows skip() to be used in an explicit async context - this.skip = function() { - done(new Pending()); - }; callFnAsync(this.fn); } catch (err) { done(utils.getError(err)); diff --git a/lib/runner.js b/lib/runner.js index 8831c8e1cb..f7cc2515ec 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -309,6 +309,8 @@ Runner.prototype.hook = function(name, fn) { suite.tests.forEach(function(test) { test.pending = true; }); + // a pending hook won't be executed twice. + hook.pending = true; } } else { self.failHook(hook, err); @@ -695,8 +697,8 @@ Runner.prototype.uncaught = function(err) { runnable.clearTimeout(); - // Ignore errors if complete - if (runnable.state) { + // Ignore errors if complete or pending + if (runnable.state || runnable.isPending()) { return; } this.fail(runnable, err);