From ea4acaa4b9e4ec4c99c6991a5172efbb377c60fd Mon Sep 17 00:00:00 2001 From: "Daniel St. Jules" Date: Mon, 11 Jan 2016 05:52:30 -0800 Subject: [PATCH] Fix #1604: Add support for async skip() --- lib/runner.js | 29 ++++++++++--- .../fixtures/pending/skip.async.before.js | 17 ++++++++ .../fixtures/pending/skip.async.beforeEach.js | 17 ++++++++ .../fixtures/pending/skip.async.spec.js | 11 +++++ test/integration/pending.js | 43 +++++++++++++++++++ 5 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 test/integration/fixtures/pending/skip.async.before.js create mode 100644 test/integration/fixtures/pending/skip.async.beforeEach.js create mode 100644 test/integration/fixtures/pending/skip.async.spec.js diff --git a/lib/runner.js b/lib/runner.js index 0979bbc2d3..02e5363c15 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -659,7 +659,15 @@ Runner.prototype.runSuite = function(suite, fn) { * @api private */ Runner.prototype.uncaught = function(err) { - if (err) { + var runnable = this.currentRunnable; + var pending; + + if (err instanceof Pending) { + if (runnable.type === 'test') { + runnable.pending = true; + } + pending = true; + } else if (err) { debug('uncaught exception %s', err !== function() { return this; }.call(err) ? err : (err.message || err)); @@ -669,8 +677,6 @@ Runner.prototype.uncaught = function(err) { } err.uncaught = true; - var runnable = this.currentRunnable; - if (!runnable) { runnable = new Runnable('Uncaught error outside test suite'); runnable.parent = this.suite; @@ -693,7 +699,16 @@ Runner.prototype.uncaught = function(err) { if (runnable.state) { return; } - this.fail(runnable, err); + + if (pending && runnable.type === 'test') { + // Async skip() call from test + this.emit('pending', runnable); + } else if (pending) { + // Async skip() call from hook + runnable.callback(err); + } else { + this.fail(runnable, err); + } // recover from test if (runnable.type === 'test') { @@ -717,8 +732,10 @@ Runner.prototype.uncaught = function(err) { return this.nextSuite(errSuite); } - // bail - this.emit('end'); + // bail on hooks if not skipped + if (!pending) { + this.emit('end'); + } }; /** diff --git a/test/integration/fixtures/pending/skip.async.before.js b/test/integration/fixtures/pending/skip.async.before.js new file mode 100644 index 0000000000..7cffbb4acb --- /dev/null +++ b/test/integration/fixtures/pending/skip.async.before.js @@ -0,0 +1,17 @@ +describe('skip in asynchronous before', function() { + before(function(done){ + var hook = this; + setTimeout(function() { + hook.skip(); + throw new Error('never thrown'); + }, 0); + }); + + it('should never run this test', function() { + throw new Error('never thrown'); + }); + + it('should never run this test', function() { + throw new Error('never thrown'); + }); +}); diff --git a/test/integration/fixtures/pending/skip.async.beforeEach.js b/test/integration/fixtures/pending/skip.async.beforeEach.js new file mode 100644 index 0000000000..eda33288db --- /dev/null +++ b/test/integration/fixtures/pending/skip.async.beforeEach.js @@ -0,0 +1,17 @@ +describe('skip in asynchronous beforeEach', function() { + beforeEach(function(done){ + var hook = this; + setTimeout(function() { + hook.skip(); + throw new Error('never thrown'); + }, 0); + }); + + it('should never run this test', function() { + throw new Error('never thrown'); + }); + + it('should never run this test', function() { + throw new Error('never thrown'); + }); +}); diff --git a/test/integration/fixtures/pending/skip.async.spec.js b/test/integration/fixtures/pending/skip.async.spec.js new file mode 100644 index 0000000000..78b6e046ef --- /dev/null +++ b/test/integration/fixtures/pending/skip.async.spec.js @@ -0,0 +1,11 @@ +describe('skip in asynchronous test', function() { + it('should skip when called from a test', function(done) { + var test = this; + setTimeout(function() { + test.skip(); + throw new Error('never thrown'); + }, 0); + }); + + it('should run other tests in the suite', function() {}); +}); diff --git a/test/integration/pending.js b/test/integration/pending.js index 01ebbdf6eb..fcb0cd54a1 100644 --- a/test/integration/pending.js +++ b/test/integration/pending.js @@ -60,4 +60,47 @@ describe('pending', function() { }); }); }); + + describe('asynchronous skip()', function() { + this.timeout(1000); + + describe('in spec', function() { + it('should immediately skip the spec and run all others', function(done) { + run('pending/skip.async.spec.js', args, function(err, res) { + assert(!err); + assert.equal(res.stats.pending, 1); + assert.equal(res.stats.passes, 1); + assert.equal(res.stats.failures, 0); + assert.equal(res.code, 0); + done(); + }); + }); + }); + + describe('in before', function() { + it('should skip all suite specs', function(done) { + run('pending/skip.async.before.js', args, function(err, res) { + assert(!err); + assert.equal(res.stats.pending, 2); + assert.equal(res.stats.passes, 0); + assert.equal(res.stats.failures, 0); + assert.equal(res.code, 0); + done(); + }); + }); + }); + + describe('in beforeEach', function() { + it('should skip all suite specs', function(done) { + run('pending/skip.async.beforeEach.js', args, function(err, res) { + assert(!err); + assert.equal(res.stats.pending, 2); + assert.equal(res.stats.passes, 0); + assert.equal(res.stats.failures, 0); + assert.equal(res.code, 0); + done(); + }); + }); + }); + }); });