diff --git a/docs/index.md b/docs/index.md index 2e256c8910..d58d518985 100644 --- a/docs/index.md +++ b/docs/index.md @@ -635,6 +635,30 @@ before(function() { }); ``` +This will skip all `it`, `beforeEach/afterEach`, and `describe` blocks within the suite. `before/after` hooks are skipped unless they are defined at the same level as the hook containing `this.skip()`. + +```js +describe('outer', function () { + before(function () { + this.skip(); + }); + + after(function () { + // will be executed + }); + + describe('inner', function () { + before(function () { + // will be skipped + }); + + after(function () { + // will be skipped + }); + }); +}); +``` + > Before Mocha v3.0.0, `this.skip()` was not supported in asynchronous tests and hooks. ## Retry Tests diff --git a/lib/runner.js b/lib/runner.js index 8e1bdf3958..572e0be234 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -319,6 +319,9 @@ Runner.prototype.hook = function(name, fn) { suite.tests.forEach(function(test) { test.pending = true; }); + suite.suites.forEach(function(suite) { + suite.pending = true; + }); // a pending hook won't be executed twice. hook.pending = true; } diff --git a/test/integration/fixtures/pending/skip-async-before-hooks.fixture.js b/test/integration/fixtures/pending/skip-async-before-hooks.fixture.js new file mode 100644 index 0000000000..113fef5f8c --- /dev/null +++ b/test/integration/fixtures/pending/skip-async-before-hooks.fixture.js @@ -0,0 +1,60 @@ +'use strict'; + +describe('outer suite', function () { + + before(function () { + console.log('outer before'); + }); + + it('should run this test', function () { }); + + describe('inner suite', function () { + + before(function (done) { + console.log('inner before'); + var self = this; + setTimeout(function () { + self.skip(); + done(); + }, 0); + }); + + beforeEach(function () { + throw new Error('beforeEach should not run'); + }); + + afterEach(function () { + throw new Error('afterEach should not run'); + }); + + it('should not run this test', function () { + throw new Error('inner suite test should not run'); + }); + + after(function () { + console.log('inner after'); + }); + + describe('skipped suite', function () { + before(function () { + console.log('skipped before'); + }); + + it('should not run this test', function () { + throw new Error('skipped suite test should not run'); + }); + + after(function () { + console.log('skipped after'); + }); + }); + + }); + + it('should run this test', function () { }); + + after(function () { + console.log('outer after'); + }); + +}); diff --git a/test/integration/fixtures/pending/skip-async-before-nested.fixture.js b/test/integration/fixtures/pending/skip-async-before-nested.fixture.js new file mode 100644 index 0000000000..8bab69c369 --- /dev/null +++ b/test/integration/fixtures/pending/skip-async-before-nested.fixture.js @@ -0,0 +1,41 @@ +describe('skip in before with nested describes', function () { + before(function (done) { + var self = this; + setTimeout(function () { + self.skip(); + done(); + }, 0); + }); + + it('should never run this test', function () { + throw new Error('never run this test'); + }); + + describe('nested describe', function () { + before(function () { + throw new Error('first level before should not run'); + }); + + it('should never run this test', function () { + throw new Error('never run this test'); + }); + + after(function () { + throw new Error('first level after should not run'); + }); + + describe('nested again', function () { + before(function () { + throw new Error('second level before should not run'); + }); + + it('should never run this test', function () { + throw new Error('never run this test'); + }); + + after(function () { + throw new Error('second level after should not run'); + }); + }); + }); +}); diff --git a/test/integration/fixtures/pending/skip-async-before.fixture.js b/test/integration/fixtures/pending/skip-async-before.fixture.js index efeaa93899..5e47bf7bd9 100644 --- a/test/integration/fixtures/pending/skip-async-before.fixture.js +++ b/test/integration/fixtures/pending/skip-async-before.fixture.js @@ -1,18 +1,23 @@ 'use strict'; -describe('skip in before', function () { - before(function (done) { - var self = this; - setTimeout(function () { - self.skip(); - }, 50); - }); +describe('outer describe', function () { + it('should run this test', function () {}); - it('should never run this test', function () { - throw new Error('never thrown'); - }); + describe('skip in before', function () { + before(function (done) { + var self = this; + setTimeout(function () { + self.skip(); + }, 0); + }); - it('should never run this test', function () { - throw new Error('never thrown'); + it('should never run this test', function () { + throw new Error('never run this test'); + }); + it('should never run this test', function () { + throw new Error('never run this test'); + }); }); + + it('should run this test', function () {}); }); diff --git a/test/integration/fixtures/pending/skip-async-beforeEach.fixture.js b/test/integration/fixtures/pending/skip-async-beforeEach.fixture.js index d6225564ba..a4f4d24324 100644 --- a/test/integration/fixtures/pending/skip-async-beforeEach.fixture.js +++ b/test/integration/fixtures/pending/skip-async-beforeEach.fixture.js @@ -5,14 +5,17 @@ describe('skip in beforeEach', function () { var self = this; setTimeout(function () { self.skip(); - }, 50); + done(); + }, 0); }); - it('should never run this test', function () { - throw new Error('never thrown'); + it('should skip this test', function () { + throw new Error('never run this test'); }); - - it('should never run this test', function () { - throw new Error('never thrown'); + it('should not reach this test', function () { + throw new Error('never run this test'); + }); + it('should not reach this test', function () { + throw new Error('never run this test'); }); }); diff --git a/test/integration/fixtures/pending/skip-async-spec.fixture.js b/test/integration/fixtures/pending/skip-async-spec.fixture.js index 44707b026c..00af28eadb 100644 --- a/test/integration/fixtures/pending/skip-async-spec.fixture.js +++ b/test/integration/fixtures/pending/skip-async-spec.fixture.js @@ -5,10 +5,8 @@ describe('skip in test', function () { var self = this; setTimeout(function () { self.skip(); - }, 50); + }, 0); }); - it('should run other tests in the suite', function () { - // Do nothing - }); + it('should run other tests in the suite', function () {}); }); diff --git a/test/integration/fixtures/pending/skip-sync-before-hooks.fixture.js b/test/integration/fixtures/pending/skip-sync-before-hooks.fixture.js new file mode 100644 index 0000000000..1649656202 --- /dev/null +++ b/test/integration/fixtures/pending/skip-sync-before-hooks.fixture.js @@ -0,0 +1,57 @@ +'use strict'; + +describe('outer suite', function () { + + before(function () { + console.log('outer before'); + }); + + it('should run this test', function () { }); + + describe('inner suite', function () { + before(function () { + this.skip(); + }); + + before(function () { + console.log('inner before'); + }); + + beforeEach(function () { + throw new Error('beforeEach should not run'); + }); + + afterEach(function () { + throw new Error('afterEach should not run'); + }); + + after(function () { + console.log('inner after'); + }); + + it('should never run this test', function () { + throw new Error('inner suite test should not run'); + }); + + describe('skipped suite', function () { + before(function () { + console.log('skipped before'); + }); + + it('should never run this test', function () { + throw new Error('skipped suite test should not run'); + }); + + after(function () { + console.log('skipped after'); + }); + }); + }); + + it('should run this test', function () { }); + + after(function () { + console.log('outer after'); + }) + +}); diff --git a/test/integration/fixtures/pending/skip-sync-before-nested.fixture.js b/test/integration/fixtures/pending/skip-sync-before-nested.fixture.js new file mode 100644 index 0000000000..06f774503d --- /dev/null +++ b/test/integration/fixtures/pending/skip-sync-before-nested.fixture.js @@ -0,0 +1,39 @@ +'use strict'; + +describe('skip in before with nested describes', function () { + before(function () { + this.skip(); + }); + + it('should never run this test', function () { + throw new Error('never run this test'); + }); + + describe('nested describe', function () { + before(function () { + throw new Error('first level before should not run'); + }); + + it('should never run this test', function () { + throw new Error('never run this test'); + }); + + after(function () { + throw new Error('first level after should not run'); + }); + + describe('nested again', function () { + before(function () { + throw new Error('second level before should not run'); + }); + + it('should never run this test', function () { + throw new Error('never run this test'); + }); + + after(function () { + throw new Error('second level after should not run'); + }); + }); + }); +}); diff --git a/test/integration/fixtures/pending/skip-sync-before.fixture.js b/test/integration/fixtures/pending/skip-sync-before.fixture.js index 5e3b208efa..5a5332f388 100644 --- a/test/integration/fixtures/pending/skip-sync-before.fixture.js +++ b/test/integration/fixtures/pending/skip-sync-before.fixture.js @@ -1,15 +1,20 @@ 'use strict'; -describe('skip in before', function () { - before(function () { - this.skip(); - }); +describe('outer describe', function () { + it('should run this test', function () {}); - it('should never run this test', function () { - throw new Error('never thrown'); - }); + describe('skip in before', function () { + before(function () { + this.skip(); + }); - it('should never run this test', function () { - throw new Error('never thrown'); + it('should never run this test', function () { + throw new Error('never run this test'); + }); + it('should never run this test', function () { + throw new Error('never run this test'); + }); }); + + it('should run this test', function () {}); }); diff --git a/test/integration/fixtures/pending/skip-sync-beforeEach.fixture.js b/test/integration/fixtures/pending/skip-sync-beforeEach.fixture.js index 0bd155ba55..2312265613 100644 --- a/test/integration/fixtures/pending/skip-sync-beforeEach.fixture.js +++ b/test/integration/fixtures/pending/skip-sync-beforeEach.fixture.js @@ -6,10 +6,10 @@ describe('skip in beforeEach', function () { }); it('should never run this test', function () { - throw new Error('never thrown'); + throw new Error('never run this test'); }); it('should never run this test', function () { - throw new Error('never thrown'); + throw new Error('never run this test'); }); }); diff --git a/test/integration/fixtures/pending/skip-sync-spec.fixture.js b/test/integration/fixtures/pending/skip-sync-spec.fixture.js index 1d22f0b77d..9178fce033 100644 --- a/test/integration/fixtures/pending/skip-sync-spec.fixture.js +++ b/test/integration/fixtures/pending/skip-sync-spec.fixture.js @@ -3,10 +3,8 @@ describe('skip in test', function () { it('should skip immediately', function () { this.skip(); - throw new Error('never thrown'); + throw new Error('never run this test'); }); - it('should run other tests in the suite', function () { - // Do nothing - }); + it('should run other tests in the suite', function () {}); }); diff --git a/test/integration/pending.spec.js b/test/integration/pending.spec.js index 27601b7a0e..82fd75a76a 100644 --- a/test/integration/pending.spec.js +++ b/test/integration/pending.spec.js @@ -2,6 +2,8 @@ var assert = require('assert'); var run = require('./helpers').runMochaJSON; +var runMocha = require('./helpers').runMocha; +var splitRegExp = require('./helpers').splitRegExp; var args = []; describe('pending', function() { @@ -74,6 +76,64 @@ describe('pending', function() { return; } assert.equal(res.stats.pending, 2); + assert.equal(res.stats.passes, 2); + assert.equal(res.stats.failures, 0); + assert.equal(res.code, 0); + done(); + }); + }); + it('should run before and after hooks', function(done) { + runMocha( + 'pending/skip-sync-before-hooks.fixture.js', + args.concat(['--reporter', 'dot']), + function(err, res) { + if (err) { + done(err); + return; + } + + var lines = res.output + .split(splitRegExp) + .map(function(line) { + return line.trim(); + }) + .filter(function(line) { + return line.length; + }) + .slice(0, -1); + + var expected = [ + 'outer before', + 'inner before', + 'inner after', + 'outer after' + ]; + + assert.equal(res.pending, 2); + assert.equal(res.passing, 2); + assert.equal(res.failing, 0); + assert.equal(res.code, 0); + expected.forEach(function(line, i) { + assert.equal(true, lines[i].includes(line)); + }); + + done(); + } + ); + }); + }); + + describe('in before with nested describe', function() { + it('should skip all suite specs, even if nested', function(done) { + run('pending/skip-sync-before-nested.fixture.js', args, function( + err, + res + ) { + if (err) { + done(err); + return; + } + assert.equal(res.stats.pending, 3); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 0); assert.equal(res.code, 0); @@ -127,6 +187,64 @@ describe('pending', function() { return; } assert.equal(res.stats.pending, 2); + assert.equal(res.stats.passes, 2); + assert.equal(res.stats.failures, 0); + assert.equal(res.code, 0); + done(); + }); + }); + it('should run before and after hooks', function(done) { + runMocha( + 'pending/skip-async-before-hooks.fixture.js', + args.concat(['--reporter', 'dot']), + function(err, res) { + if (err) { + done(err); + return; + } + + var lines = res.output + .split(splitRegExp) + .map(function(line) { + return line.trim(); + }) + .filter(function(line) { + return line.length; + }) + .slice(0, -1); + + var expected = [ + 'outer before', + 'inner before', + 'inner after', + 'outer after' + ]; + + assert.equal(res.pending, 2); + assert.equal(res.passing, 2); + assert.equal(res.failing, 0); + assert.equal(res.code, 0); + expected.forEach(function(line, i) { + assert.equal(true, lines[i].includes(line)); + }); + + done(); + } + ); + }); + }); + + describe('in before with nested describe', function() { + it('should skip all suite specs, even if nested', function(done) { + run('pending/skip-async-before-nested.fixture.js', args, function( + err, + res + ) { + if (err) { + done(err); + return; + } + assert.equal(res.stats.pending, 3); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 0); assert.equal(res.code, 0); @@ -137,7 +255,7 @@ describe('pending', function() { describe('in beforeEach', function() { it('should skip all suite specs', function(done) { - run('pending/skip-sync-beforeEach.fixture.js', args, function( + run('pending/skip-async-beforeEach.fixture.js', args, function( err, res ) { @@ -145,10 +263,10 @@ describe('pending', function() { done(err); return; } - assert.equal(res.stats.pending, 2); + assert.equal(res.stats.pending, 1); assert.equal(res.stats.passes, 0); - assert.equal(res.stats.failures, 0); - assert.equal(res.code, 0); + assert.equal(res.stats.failures, 1); + assert.equal(res.code, 1); done(); }); });