mocha 2.4.5 → 2.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,111 @@
1
+ # 2.5.3 / 2016-05-25
2
+
3
+ - [#2112] - Fix HTML reporter regression causing duplicate error output ([@danielstjules] via 6d24063)
4
+ - [#2119] - Make HTML reporter failure/passed links preventDefault to avoid SPA's hash navigation ([@jimenglish81] via 9e93efc)
5
+
6
+ [@danielstjules]: https://github.com/danielstjules
7
+ [@jimenglish81]: https://github.com/jimenglish81
8
+ [#2112]: https://github.com/mochajs/mocha/pull/2112
9
+ [#2119]: https://github.com/mochajs/mocha/pull/2119
10
+
11
+ # 2.5.2 / 2016-05-24
12
+
13
+ - [#2178] - Avoid double and triple xUnit XML escaping ([@graingert] via 49b5ff1)
14
+
15
+ [@graingert]: https://github.com/graingert
16
+ [#2178]: https://github.com/mochajs/mocha/pull/2178
17
+
18
+ # 2.5.1 / 2016-05-23
19
+
20
+ - Fix [to-iso-string](https://npmjs.com/package/to-iso-string) dependency ([@boneskull] via bd9450b)
21
+
22
+ Thanks @entertainyou, @SimenB, @just-paja for the heads-up.
23
+
24
+ # 2.5.0 / 2016-05-23
25
+
26
+ > This has been awhile coming! We needed to feel confident that the next release wouldn't break browser compatibility (e.g. the last few patch releases).
27
+ >
28
+ > ### Browser Tests in CI
29
+ >
30
+ > We now run unit tests against PhantomJS v1.x and an assortment of browsers on [SauceLabs](https://saucelabs.com), including:
31
+ > - Internet Explorer v8.0
32
+ > - Chrome (latest)
33
+ > - Firefox (latest)
34
+ > - Safari (latest)
35
+ > - Microsoft Edge (latest)
36
+ >
37
+ > To accomplish this, we now run Mocha's unit tests (and a handful of integration tests) via [Karma](https://npmjs.com/package/karma) and a modified [karma-mocha](https://npmjs.com/package/karma-mocha). Along the way, we had to solve issue [#880] (apologies to @mderijcke and @sukima who had PRs addressing this), as well as replace most usages of [should](https://npmjs.com/package/should) with [expect.js](https://npmjs.com/package/expect.js) for IE8.
38
+ >
39
+ > Going forward, when sending PRs, your code will *only* run against PhantomJS v1.x (and not hit SauceLabs) [because security](https://docs.travis-ci.com/user/pull-requests/#Security-Restrictions-when-testing-Pull-Requests).
40
+ >
41
+ > ### Node.js 6.x
42
+ > Node.js 6.x "just worked" before, but now it's in the CI matrix, so it's "officially" supported. Mocha *still retains support* for Node.js 0.8.x.
43
+ >
44
+ > ### "Minor" Release
45
+ > You'll see mostly bug fixes below, but also a couple features--as such, it's a "minor" release.
46
+ >
47
+ > ### TYVM
48
+ >
49
+ > Thanks to everyone who contributed, and our fabulous [sponsors and backers](https://opencollective.com/mochajs)!
50
+
51
+ - [#2079] - Add browser checks to CI; update [browserify](https://npmjs.com/package/browserify) to v13.0.0 ([@dasilvacontin], [@ScottFreeCode], [@boneskull] via c04c1d7, 0b1e9b3, 0dde0fa, f8a3d86, 9e8cbaa)
52
+ - [#880] - Make Mocha browserifyable ([@boneskull] via 524862b)
53
+ - [#2121] - Update [glob](https://npmjs.com/package/glob) to v3.2.11 ([@astorije] via 7920fc4)
54
+ - [#2126] - Fix dupe error messages in stack trace filter ([@Turbo87] via 4301caa)
55
+ - [#2109] - Fix certain diffs when objects cannot be coerced into primitives ([@joshlory] via 61fbb7f)
56
+ - [#1827] - Fix TWBS/`mocha.css` collisions ([@irnc] via 0543798)
57
+ - [#1760], [#1936] - Fix `this.skip()` in HTML reporter ([@mislav] via cb4248b)
58
+ - [#2115] - Fix exceptions thrown from hooks in HTML reporter ([@danielstjules] via e290bc0)
59
+ - [#2089] - Handle Symbol values in `util.stringify()` ([@ryym] via ea61d05)
60
+ - [#2097] - Fix diff for objects overriding `Object.prototype.hasOwnProperty` ([@mantoni] via b20fdfe)
61
+ - [#2101] - Properly handle non-string "messages" thrown from assertion libraries ([@jkimbo] via 9c41051)
62
+ - [#2124] - Update [growl](https://npmjs.com/package/growl) ([@benjamine] via 9ae6a85)
63
+ - [#2162], [#2205] - JSDoc fixes ([@OlegTsyba] via 8031f20, [@ScottFreeCode] via f83b1d9)
64
+ - [#2132] - Remove Growl-related cruft ([@julienw] via 00d6469)
65
+ - [#2172] - Add [OpenCollective](https://opencollective.com) badge, sponsors & backers ([@xdamman], [@boneskull] via caee94f)
66
+ - [#1841] - Add new logo, banner assets ([@dasilvacontin] via 00fd0e1)
67
+ - [#2214] - Update `README.md` header ([@dasilvacontin] via c0f9be2)
68
+ - [#2236] - Better checks for Node.js v0.8 compatibility in CI ([@dasilvacontin] via ba5637d)
69
+ - [#2239] - Add Node.js v6.x to CI matrix ([@boneskull] via 3904da4)
70
+
71
+ [#880]: https://github.com/mochajs/mocha/issues/880
72
+ [#1841]: https://github.com/mochajs/mocha/pull/1841
73
+ [#2239]: https://github.com/mochajs/mocha/issues/2239
74
+ [#2153]: https://github.com/mochajs/mocha/pull/2153
75
+ [#2214]: https://github.com/mochajs/mocha/pull/2214
76
+ [#2236]: https://github.com/mochajs/mocha/pull/2236
77
+ [#2079]: https://github.com/mochajs/mocha/issues/2079
78
+ [#2231]: https://github.com/mochajs/mocha/pull/2231
79
+ [#2089]: https://github.com/mochajs/mocha/issues/2089
80
+ [#2097]: https://github.com/mochajs/mocha/pull/2097
81
+ [#1760]: https://github.com/mochajs/mocha/issues/1760
82
+ [#1936]: https://github.com/mochajs/mocha/issues/1936
83
+ [#2115]: https://github.com/mochajs/mocha/pull/2115
84
+ [#1827]: https://github.com/mochajs/mocha/pull/1827
85
+ [#2101]: https://github.com/mochajs/mocha/pull/2101
86
+ [#2124]: https://github.com/mochajs/mocha/pull/2124
87
+ [#2109]: https://github.com/mochajs/mocha/issues/2109
88
+ [#2162]: https://github.com/mochajs/mocha/pull/2162
89
+ [#2132]: https://github.com/mochajs/mocha/issues/2132
90
+ [#2126]: https://github.com/mochajs/mocha/issues/2126
91
+ [#2121]: https://github.com/mochajs/mocha/issues/2121
92
+ [#2205]: https://github.com/mochajs/mocha/pull/2205
93
+ [#2172]: https://github.com/mochajs/mocha/pull/2172
94
+ [@xdamman]: https://github.com/xdamman
95
+ [@Turbo87]: https://github.com/Turbo87
96
+ [@OlegTsyba]: https://github.com/OlegTsyba
97
+ [@ryym]: https://github.com/ryym
98
+ [@mantoni]: https://github.com/mantoni
99
+ [@mislav]: https://github.com/mislav
100
+ [@irnc]: https://github.com/irnc
101
+ [@jkimbo]: https://github.com/jkimbo
102
+ [@benjamine]: https://github.com/benjamine
103
+ [@joshlory]: https://github.com/joshlory
104
+ [@julienw]: https://github.com/julienw
105
+ [@ScottFreeCode]: https://github.com/ScottFreeCode
106
+ [@astorije]: https://github.com/astorije
107
+ [@dasilvacontin]: https://github.com/dasilvacontin
108
+
1
109
  2.4.5 / 2016-01-28
2
110
  ==================
3
111
 
package/bin/_mocha CHANGED
@@ -83,6 +83,7 @@ program
83
83
  .option('--globals <names>', 'allow the given comma-delimited global [names]', list, [])
84
84
  .option('--es_staging', 'enable all staged features')
85
85
  .option('--harmony<_classes,_generators,...>', 'all node --harmony* flags are available')
86
+ .option('--icu-data-dir', 'include ICU data')
86
87
  .option('--inline-diffs', 'display actual/expected differences inline within each string')
87
88
  .option('--interfaces', 'display available interfaces')
88
89
  .option('--no-deprecation', 'silence deprecation warnings')
@@ -430,26 +431,6 @@ function exit(code) {
430
431
 
431
432
  process.on('SIGINT', function() { runner.abort(); })
432
433
 
433
- // enable growl notifications
434
-
435
- function growl(runner, reporter) {
436
- var notify = require('growl');
437
-
438
- runner.on('end', function(){
439
- var stats = reporter.stats;
440
- if (stats.failures) {
441
- var msg = stats.failures + ' of ' + runner.total + ' tests failed';
442
- notify(msg, { name: 'mocha', title: 'Failed', image: images.fail });
443
- } else {
444
- notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {
445
- name: 'mocha'
446
- , title: 'Passed'
447
- , image: images.pass
448
- });
449
- }
450
- });
451
- }
452
-
453
434
  /**
454
435
  * Parse list.
455
436
  */
package/bin/mocha CHANGED
@@ -48,6 +48,7 @@ process.argv.slice(2).forEach(function(arg){
48
48
  default:
49
49
  if (0 == arg.indexOf('--harmony')) args.unshift(arg);
50
50
  else if (0 == arg.indexOf('--trace')) args.unshift(arg);
51
+ else if (0 == arg.indexOf('--icu-data-dir')) args.unshift(arg);
51
52
  else if (0 == arg.indexOf('--max-old-space-size')) args.unshift(arg);
52
53
  else args.push(arg);
53
54
  break;
@@ -5,7 +5,7 @@
5
5
  exports.EventEmitter = EventEmitter;
6
6
 
7
7
  /**
8
- * Object#hasOwnProperty reference.
8
+ * Object#toString reference.
9
9
  */
10
10
  var objToString = Object.prototype.toString;
11
11
 
@@ -14,7 +14,7 @@ var objToString = Object.prototype.toString;
14
14
  *
15
15
  * @api private
16
16
  * @param {*} val The value to test.
17
- * @return {boolean} true if the value is a boolean, otherwise false.
17
+ * @return {boolean} true if the value is an array, otherwise false.
18
18
  */
19
19
  function isArray(val) {
20
20
  return objToString.call(val) === '[object Array]';
@@ -79,7 +79,7 @@ module.exports = function(suite) {
79
79
 
80
80
  var it = context.it = context.specify = function(title, fn) {
81
81
  var suite = suites[0];
82
- if (suite.pending) {
82
+ if (suite.isPending()) {
83
83
  fn = null;
84
84
  }
85
85
  var test = new Test(title, fn);
@@ -75,7 +75,7 @@ module.exports = function(suites, context) {
75
75
  /**
76
76
  * Number of retry attempts
77
77
  *
78
- * @param {string} n
78
+ * @param {number} n
79
79
  */
80
80
  retries: function(n) {
81
81
  context.retries(n);
@@ -6,7 +6,7 @@ var Suite = require('../suite');
6
6
  var Test = require('../test');
7
7
 
8
8
  /**
9
- * TDD-style interface:
9
+ * Exports-style (as Node.js module) interface:
10
10
  *
11
11
  * exports.Array = {
12
12
  * '#indexOf()': {
@@ -81,7 +81,7 @@ module.exports = function(suite) {
81
81
  */
82
82
  context.test = function(title, fn) {
83
83
  var suite = suites[0];
84
- if (suite.pending) {
84
+ if (suite.isPending()) {
85
85
  fn = null;
86
86
  }
87
87
  var test = new Test(title, fn);
package/lib/mocha.js CHANGED
@@ -99,22 +99,6 @@ function Mocha(options) {
99
99
  if (options.slow) {
100
100
  this.slow(options.slow);
101
101
  }
102
-
103
- this.suite.on('pre-require', function(context) {
104
- exports.afterEach = context.afterEach || context.teardown;
105
- exports.after = context.after || context.suiteTeardown;
106
- exports.beforeEach = context.beforeEach || context.setup;
107
- exports.before = context.before || context.suiteSetup;
108
- exports.describe = context.describe || context.suite;
109
- exports.it = context.it || context.test;
110
- exports.setup = context.setup || context.beforeEach;
111
- exports.suiteSetup = context.suiteSetup || context.before;
112
- exports.suiteTeardown = context.suiteTeardown || context.after;
113
- exports.suite = context.suite || context.describe;
114
- exports.teardown = context.teardown || context.afterEach;
115
- exports.test = context.test || context.it;
116
- exports.run = context.run;
117
- });
118
102
  }
119
103
 
120
104
  /**
@@ -202,6 +186,23 @@ Mocha.prototype.ui = function(name) {
202
186
  }
203
187
  }
204
188
  this._ui = this._ui(this.suite);
189
+
190
+ this.suite.on('pre-require', function(context) {
191
+ exports.afterEach = context.afterEach || context.teardown;
192
+ exports.after = context.after || context.suiteTeardown;
193
+ exports.beforeEach = context.beforeEach || context.setup;
194
+ exports.before = context.before || context.suiteSetup;
195
+ exports.describe = context.describe || context.suite;
196
+ exports.it = context.it || context.test;
197
+ exports.setup = context.setup || context.beforeEach;
198
+ exports.suiteSetup = context.suiteSetup || context.before;
199
+ exports.suiteTeardown = context.suiteTeardown || context.after;
200
+ exports.suite = context.suite || context.describe;
201
+ exports.teardown = context.teardown || context.afterEach;
202
+ exports.test = context.test || context.it;
203
+ exports.run = context.run;
204
+ });
205
+
205
206
  return this;
206
207
  };
207
208
 
@@ -170,8 +170,8 @@ exports.list = function(failures) {
170
170
  var msg;
171
171
  var err = test.err;
172
172
  var message;
173
- if (err.message) {
174
- message = err.message;
173
+ if (err.message && typeof err.message.toString === 'function') {
174
+ message = err.message + '';
175
175
  } else if (typeof err.inspect === 'function') {
176
176
  message = err.inspect() + '';
177
177
  } else {
@@ -80,7 +80,8 @@ function HTML(runner) {
80
80
  }
81
81
 
82
82
  // pass toggle
83
- on(passesLink, 'click', function() {
83
+ on(passesLink, 'click', function(evt) {
84
+ evt.preventDefault();
84
85
  unhide();
85
86
  var name = (/pass/).test(report.className) ? '' : ' pass';
86
87
  report.className = report.className.replace(/fail|pass/g, '') + name;
@@ -90,7 +91,8 @@ function HTML(runner) {
90
91
  });
91
92
 
92
93
  // failure toggle
93
- on(failuresLink, 'click', function() {
94
+ on(failuresLink, 'click', function(evt) {
95
+ evt.preventDefault();
94
96
  unhide();
95
97
  var name = (/fail/).test(report.className) ? '' : ' fail';
96
98
  report.className = report.className.replace(/fail|pass/g, '') + name;
@@ -128,88 +130,82 @@ function HTML(runner) {
128
130
  stack.shift();
129
131
  });
130
132
 
131
- runner.on('fail', function(test) {
132
- // For type = 'test' its possible that the test failed due to multiple
133
- // done() calls. So report the issue here.
134
- if (test.type === 'hook'
135
- || test.type === 'test') {
136
- runner.emit('test end', test);
137
- }
133
+ runner.on('pass', function(test) {
134
+ var url = self.testURL(test);
135
+ var markup = '<li class="test pass %e"><h2>%e<span class="duration">%ems</span> '
136
+ + '<a href="%s" class="replay">‣</a></h2></li>';
137
+ var el = fragment(markup, test.speed, test.title, test.duration, url);
138
+ self.addCodeToggle(el, test.body);
139
+ appendToStack(el);
140
+ updateStats();
138
141
  });
139
142
 
140
- runner.on('test end', function(test) {
141
- // TODO: add to stats
142
- var percent = stats.tests / this.total * 100 | 0;
143
- if (progress) {
144
- progress.update(percent).draw(ctx);
143
+ runner.on('fail', function(test) {
144
+ var el = fragment('<li class="test fail"><h2>%e <a href="%e" class="replay">‣</a></h2></li>',
145
+ test.title, self.testURL(test));
146
+ var stackString; // Note: Includes leading newline
147
+ var message = test.err.toString();
148
+
149
+ // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
150
+ // check for the result of the stringifying.
151
+ if (message === '[object Error]') {
152
+ message = test.err.message;
145
153
  }
146
154
 
147
- // update stats
148
- var ms = new Date() - stats.start;
149
- text(passes, stats.passes);
150
- text(failures, stats.failures);
151
- text(duration, (ms / 1000).toFixed(2));
152
-
153
- // test
154
- var el;
155
- if (test.state === 'passed') {
156
- var url = self.testURL(test);
157
- el = fragment('<li class="test pass %e"><h2>%e<span class="duration">%ems</span> <a href="%s" class="replay">‣</a></h2></li>', test.speed, test.title, test.duration, url);
158
- } else if (test.pending) {
159
- el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
160
- } else {
161
- el = fragment('<li class="test fail"><h2>%e <a href="%e" class="replay">‣</a></h2></li>', test.title, self.testURL(test));
162
- var stackString; // Note: Includes leading newline
163
- var message = test.err.toString();
164
-
165
- // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
166
- // check for the result of the stringifying.
167
- if (message === '[object Error]') {
168
- message = test.err.message;
169
- }
170
-
171
- if (test.err.stack) {
172
- var indexOfMessage = test.err.stack.indexOf(test.err.message);
173
- if (indexOfMessage === -1) {
174
- stackString = test.err.stack;
175
- } else {
176
- stackString = test.err.stack.substr(test.err.message.length + indexOfMessage);
177
- }
178
- } else if (test.err.sourceURL && test.err.line !== undefined) {
179
- // Safari doesn't give you a stack. Let's at least provide a source line.
180
- stackString = '\n(' + test.err.sourceURL + ':' + test.err.line + ')';
181
- }
182
-
183
- stackString = stackString || '';
184
-
185
- if (test.err.htmlMessage && stackString) {
186
- el.appendChild(fragment('<div class="html-error">%s\n<pre class="error">%e</pre></div>', test.err.htmlMessage, stackString));
187
- } else if (test.err.htmlMessage) {
188
- el.appendChild(fragment('<div class="html-error">%s</div>', test.err.htmlMessage));
155
+ if (test.err.stack) {
156
+ var indexOfMessage = test.err.stack.indexOf(test.err.message);
157
+ if (indexOfMessage === -1) {
158
+ stackString = test.err.stack;
189
159
  } else {
190
- el.appendChild(fragment('<pre class="error">%e%e</pre>', message, stackString));
160
+ stackString = test.err.stack.substr(test.err.message.length + indexOfMessage);
191
161
  }
162
+ } else if (test.err.sourceURL && test.err.line !== undefined) {
163
+ // Safari doesn't give you a stack. Let's at least provide a source line.
164
+ stackString = '\n(' + test.err.sourceURL + ':' + test.err.line + ')';
192
165
  }
193
166
 
194
- // toggle code
195
- // TODO: defer
196
- if (!test.pending) {
197
- var h2 = el.getElementsByTagName('h2')[0];
167
+ stackString = stackString || '';
198
168
 
199
- on(h2, 'click', function() {
200
- pre.style.display = pre.style.display === 'none' ? 'block' : 'none';
201
- });
202
-
203
- var pre = fragment('<pre><code>%e</code></pre>', utils.clean(test.body));
204
- el.appendChild(pre);
205
- pre.style.display = 'none';
169
+ if (test.err.htmlMessage && stackString) {
170
+ el.appendChild(fragment('<div class="html-error">%s\n<pre class="error">%e</pre></div>',
171
+ test.err.htmlMessage, stackString));
172
+ } else if (test.err.htmlMessage) {
173
+ el.appendChild(fragment('<div class="html-error">%s</div>', test.err.htmlMessage));
174
+ } else {
175
+ el.appendChild(fragment('<pre class="error">%e%e</pre>', message, stackString));
206
176
  }
207
177
 
178
+ self.addCodeToggle(el, test.body);
179
+ appendToStack(el);
180
+ updateStats();
181
+ });
182
+
183
+ runner.on('pending', function(test) {
184
+ var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
185
+ appendToStack(el);
186
+ updateStats();
187
+ });
188
+
189
+ function appendToStack(el) {
208
190
  // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack.
209
191
  if (stack[0]) {
210
192
  stack[0].appendChild(el);
211
193
  }
212
- });
194
+ }
195
+
196
+ function updateStats() {
197
+ // TODO: add to stats
198
+ var percent = stats.tests / this.total * 100 | 0;
199
+ if (progress) {
200
+ progress.update(percent).draw(ctx);
201
+ }
202
+
203
+ // update stats
204
+ var ms = new Date() - stats.start;
205
+ text(passes, stats.passes);
206
+ text(failures, stats.failures);
207
+ text(duration, (ms / 1000).toFixed(2));
208
+ }
213
209
  }
214
210
 
215
211
  /**
@@ -247,6 +243,24 @@ HTML.prototype.testURL = function(test) {
247
243
  return makeUrl(test.fullTitle());
248
244
  };
249
245
 
246
+ /**
247
+ * Adds code toggle functionality for the provided test's list element.
248
+ *
249
+ * @param {HTMLLIElement} el
250
+ * @param {string} contents
251
+ */
252
+ HTML.prototype.addCodeToggle = function(el, contents) {
253
+ var h2 = el.getElementsByTagName('h2')[0];
254
+
255
+ on(h2, 'click', function() {
256
+ pre.style.display = pre.style.display === 'none' ? 'block' : 'none';
257
+ });
258
+
259
+ var pre = fragment('<pre><code>%e</code></pre>', utils.clean(contents));
260
+ el.appendChild(pre);
261
+ pre.style.display = 'none';
262
+ };
263
+
250
264
  /**
251
265
  * Display error `msg`.
252
266
  *
@@ -130,8 +130,8 @@ XUnit.prototype.test = function(test) {
130
130
 
131
131
  if (test.state === 'failed') {
132
132
  var err = test.err;
133
- this.write(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + '\n' + err.stack))));
134
- } else if (test.pending) {
133
+ this.write(tag('testcase', attrs, false, tag('failure', {}, false, escape(err.message) + '\n' + escape(err.stack))));
134
+ } else if (test.isPending()) {
135
135
  this.write(tag('testcase', attrs, false, tag('skipped', {}, true)));
136
136
  } else {
137
137
  this.write(tag('testcase', attrs, true));
@@ -164,11 +164,3 @@ function tag(name, attrs, close, content) {
164
164
  }
165
165
  return tag;
166
166
  }
167
-
168
- /**
169
- * Return cdata escaped CDATA `str`.
170
- */
171
-
172
- function cdata(str) {
173
- return '<![CDATA[' + escape(str) + ']]>';
174
- }
package/lib/runnable.js CHANGED
@@ -45,6 +45,7 @@ module.exports = Runnable;
45
45
  function Runnable(title, fn) {
46
46
  this.title = title;
47
47
  this.fn = fn;
48
+ this.body = (fn || '').toString();
48
49
  this.async = fn && fn.length;
49
50
  this.sync = !this.async;
50
51
  this._timeout = 2000;
@@ -54,6 +55,7 @@ function Runnable(title, fn) {
54
55
  this._trace = new Error('done() called multiple times');
55
56
  this._retries = -1;
56
57
  this._currentRetry = 0;
58
+ this.pending = false;
57
59
  }
58
60
 
59
61
  /**
@@ -124,12 +126,21 @@ Runnable.prototype.enableTimeouts = function(enabled) {
124
126
  /**
125
127
  * Halt and mark as pending.
126
128
  *
127
- * @api private
129
+ * @api public
128
130
  */
129
131
  Runnable.prototype.skip = function() {
130
132
  throw new Pending();
131
133
  };
132
134
 
135
+ /**
136
+ * Check if this runnable or its parent suite is marked as pending.
137
+ *
138
+ * @api private
139
+ */
140
+ Runnable.prototype.isPending = function() {
141
+ return this.pending || (this.parent && this.parent.isPending());
142
+ };
143
+
133
144
  /**
134
145
  * Set number of retries.
135
146
  *
@@ -302,7 +313,7 @@ Runnable.prototype.run = function(fn) {
302
313
 
303
314
  // sync or promise-returning
304
315
  try {
305
- if (this.pending) {
316
+ if (this.isPending()) {
306
317
  done();
307
318
  } else {
308
319
  callFn(this.fn);
package/lib/runner.js CHANGED
@@ -507,12 +507,7 @@ Runner.prototype.runTests = function(suite, fn) {
507
507
  return;
508
508
  }
509
509
 
510
- function parentPending(suite) {
511
- return suite.pending || (suite.parent && parentPending(suite.parent));
512
- }
513
-
514
- // pending
515
- if (test.pending || parentPending(test.parent)) {
510
+ if (test.isPending()) {
516
511
  self.emit('pending', test);
517
512
  self.emit('test end', test);
518
513
  return next();
@@ -521,7 +516,7 @@ Runner.prototype.runTests = function(suite, fn) {
521
516
  // execute test and hook(s)
522
517
  self.emit('test', self.test = test);
523
518
  self.hookDown('beforeEach', function(err, errSuite) {
524
- if (suite.pending) {
519
+ if (suite.isPending()) {
525
520
  self.emit('pending', test);
526
521
  self.emit('test end', test);
527
522
  return next();
package/lib/suite.js CHANGED
@@ -28,9 +28,6 @@ exports = module.exports = Suite;
28
28
  exports.create = function(parent, title) {
29
29
  var suite = new Suite(title, parent.ctx);
30
30
  suite.parent = parent;
31
- if (parent.pending) {
32
- suite.pending = true;
33
- }
34
31
  title = suite.fullTitle();
35
32
  parent.addSuite(suite);
36
33
  return suite;
@@ -176,6 +173,15 @@ Suite.prototype.bail = function(bail) {
176
173
  return this;
177
174
  };
178
175
 
176
+ /**
177
+ * Check if this suite or its parent suite is marked as pending.
178
+ *
179
+ * @api private
180
+ */
181
+ Suite.prototype.isPending = function() {
182
+ return this.pending || (this.parent && this.parent.isPending());
183
+ };
184
+
179
185
  /**
180
186
  * Run `fn(test[, done])` before running tests.
181
187
  *
@@ -185,7 +191,7 @@ Suite.prototype.bail = function(bail) {
185
191
  * @return {Suite} for chaining
186
192
  */
187
193
  Suite.prototype.beforeAll = function(title, fn) {
188
- if (this.pending) {
194
+ if (this.isPending()) {
189
195
  return this;
190
196
  }
191
197
  if (typeof title === 'function') {
@@ -215,7 +221,7 @@ Suite.prototype.beforeAll = function(title, fn) {
215
221
  * @return {Suite} for chaining
216
222
  */
217
223
  Suite.prototype.afterAll = function(title, fn) {
218
- if (this.pending) {
224
+ if (this.isPending()) {
219
225
  return this;
220
226
  }
221
227
  if (typeof title === 'function') {
@@ -245,7 +251,7 @@ Suite.prototype.afterAll = function(title, fn) {
245
251
  * @return {Suite} for chaining
246
252
  */
247
253
  Suite.prototype.beforeEach = function(title, fn) {
248
- if (this.pending) {
254
+ if (this.isPending()) {
249
255
  return this;
250
256
  }
251
257
  if (typeof title === 'function') {
@@ -275,7 +281,7 @@ Suite.prototype.beforeEach = function(title, fn) {
275
281
  * @return {Suite} for chaining
276
282
  */
277
283
  Suite.prototype.afterEach = function(title, fn) {
278
- if (this.pending) {
284
+ if (this.isPending()) {
279
285
  return this;
280
286
  }
281
287
  if (typeof title === 'function') {
package/lib/test.js CHANGED
@@ -22,7 +22,6 @@ function Test(title, fn) {
22
22
  Runnable.call(this, title, fn);
23
23
  this.pending = !fn;
24
24
  this.type = 'test';
25
- this.body = (fn || '').toString();
26
25
  }
27
26
 
28
27
  /**