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();
+ });
+ });
});