diff --git a/lib/interfaces/bdd.js b/lib/interfaces/bdd.js index e33c9b0d77..8519a9a7b4 100644 --- a/lib/interfaces/bdd.js +++ b/lib/interfaces/bdd.js @@ -79,7 +79,7 @@ module.exports = function(suite) { var it = context.it = context.specify = function(title, fn) { var suite = suites[0]; - if (suite.pending) { + if (suite.isPending()) { fn = null; } var test = new Test(title, fn); diff --git a/lib/interfaces/tdd.js b/lib/interfaces/tdd.js index 8cb211ba39..d37936ae41 100644 --- a/lib/interfaces/tdd.js +++ b/lib/interfaces/tdd.js @@ -81,7 +81,7 @@ module.exports = function(suite) { */ context.test = function(title, fn) { var suite = suites[0]; - if (suite.pending) { + if (suite.isPending()) { fn = null; } var test = new Test(title, fn); diff --git a/lib/reporters/html.js b/lib/reporters/html.js index 7da2508e40..95fc1e9f73 100644 --- a/lib/reporters/html.js +++ b/lib/reporters/html.js @@ -155,7 +155,7 @@ function HTML(runner) { if (test.state === 'passed') { var url = self.testURL(test); el = fragment('
  • %e%ems

  • ', test.speed, test.title, test.duration, url); - } else if (test.pending) { + } else if (test.isPending()) { el = fragment('
  • %e

  • ', test.title); } else { el = fragment('
  • %e

  • ', test.title, self.testURL(test)); @@ -193,7 +193,7 @@ function HTML(runner) { // toggle code // TODO: defer - if (!test.pending) { + if (!test.isPending()) { var h2 = el.getElementsByTagName('h2')[0]; on(h2, 'click', function() { diff --git a/lib/reporters/xunit.js b/lib/reporters/xunit.js index 01d9d87824..875d592876 100644 --- a/lib/reporters/xunit.js +++ b/lib/reporters/xunit.js @@ -131,7 +131,7 @@ XUnit.prototype.test = function(test) { if (test.state === 'failed') { var err = test.err; this.write(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + '\n' + err.stack)))); - } else if (test.pending) { + } else if (test.isPending()) { this.write(tag('testcase', attrs, false, tag('skipped', {}, true))); } else { this.write(tag('testcase', attrs, true)); diff --git a/lib/runnable.js b/lib/runnable.js index 9ac45de3f8..707f9559b4 100644 --- a/lib/runnable.js +++ b/lib/runnable.js @@ -54,6 +54,7 @@ function Runnable(title, fn) { this._trace = new Error('done() called multiple times'); this._retries = -1; this._currentRetry = 0; + this.pending = false; } /** @@ -124,12 +125,21 @@ Runnable.prototype.enableTimeouts = function(enabled) { /** * Halt and mark as pending. * - * @api private + * @api public */ Runnable.prototype.skip = function() { throw new Pending(); }; +/** + * Check if this runnable or its parent suite is marked as pending. + * + * @api private + */ +Runnable.prototype.isPending = function() { + return this.pending || (this.parent && this.parent.isPending()); +}; + /** * Set number of retries. * @@ -302,7 +312,7 @@ Runnable.prototype.run = function(fn) { // sync or promise-returning try { - if (this.pending) { + if (this.isPending()) { done(); } else { callFn(this.fn); diff --git a/lib/runner.js b/lib/runner.js index e4d935e8c2..ba4d7df97c 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -507,12 +507,7 @@ Runner.prototype.runTests = function(suite, fn) { return; } - function parentPending(suite) { - return suite.pending || (suite.parent && parentPending(suite.parent)); - } - - // pending - if (test.pending || parentPending(test.parent)) { + if (test.isPending()) { self.emit('pending', test); self.emit('test end', test); return next(); @@ -521,7 +516,7 @@ Runner.prototype.runTests = function(suite, fn) { // execute test and hook(s) self.emit('test', self.test = test); self.hookDown('beforeEach', function(err, errSuite) { - if (suite.pending) { + if (suite.isPending()) { self.emit('pending', test); self.emit('test end', test); return next(); diff --git a/lib/suite.js b/lib/suite.js index 8e6f393e68..d43dd45604 100644 --- a/lib/suite.js +++ b/lib/suite.js @@ -28,9 +28,6 @@ exports = module.exports = Suite; exports.create = function(parent, title) { var suite = new Suite(title, parent.ctx); suite.parent = parent; - if (parent.pending) { - suite.pending = true; - } title = suite.fullTitle(); parent.addSuite(suite); return suite; @@ -176,6 +173,15 @@ Suite.prototype.bail = function(bail) { return this; }; +/** + * Check if this suite or its parent suite is marked as pending. + * + * @api private + */ +Suite.prototype.isPending = function() { + return this.pending || (this.parent && this.parent.isPending()); +}; + /** * Run `fn(test[, done])` before running tests. * @@ -185,7 +191,7 @@ Suite.prototype.bail = function(bail) { * @return {Suite} for chaining */ Suite.prototype.beforeAll = function(title, fn) { - if (this.pending) { + if (this.isPending()) { return this; } if (typeof title === 'function') { @@ -215,7 +221,7 @@ Suite.prototype.beforeAll = function(title, fn) { * @return {Suite} for chaining */ Suite.prototype.afterAll = function(title, fn) { - if (this.pending) { + if (this.isPending()) { return this; } if (typeof title === 'function') { @@ -245,7 +251,7 @@ Suite.prototype.afterAll = function(title, fn) { * @return {Suite} for chaining */ Suite.prototype.beforeEach = function(title, fn) { - if (this.pending) { + if (this.isPending()) { return this; } if (typeof title === 'function') { @@ -275,7 +281,7 @@ Suite.prototype.beforeEach = function(title, fn) { * @return {Suite} for chaining */ Suite.prototype.afterEach = function(title, fn) { - if (this.pending) { + if (this.isPending()) { return this; } if (typeof title === 'function') { diff --git a/test/suite.js b/test/suite.js index ac074c8d17..6588e24817 100644 --- a/test/suite.js +++ b/test/suite.js @@ -288,6 +288,11 @@ describe('Suite', function(){ this.first.suites.should.have.length(1); this.first.suites[0].should.equal(this.second); }); + + it('treats suite as pending if its parent is pending', function(){ + this.first.pending = true + this.second.isPending.should.be.true + }); }); // describe('.addTest()', function(){ diff --git a/test/test.js b/test/test.js index 1fcfea59bc..5dea7919db 100644 --- a/test/test.js +++ b/test/test.js @@ -1,4 +1,5 @@ var mocha = require('../') + , should = require('should') , Context = mocha.Context , Test = mocha.Test; @@ -52,4 +53,24 @@ describe('Test', function(){ this._test.clone().file.should.equal('bar'); }); }); + + describe('.isPending()', function(){ + beforeEach(function(){ + this._test = new Test('Is it skipped', function () {}); + }); + + it('should not be pending by default', function(){ + should(this._test.isPending()).not.be.ok(); + }); + + it('should be pending when marked as such', function(){ + this._test.pending = true; + should(this._test.isPending()).be.ok(); + }); + + it('should be pending when its parent is pending', function(){ + this._test.parent = { isPending: function(){ return true } }; + should(this._test.isPending()).be.ok(); + }); + }); });