mocha 2.2.5 → 2.3.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/HISTORY.md +1034 -0
- package/bin/.eslintrc +3 -0
- package/bin/_mocha +12 -15
- package/bin/mocha +3 -10
- package/bin/options.js +6 -5
- package/lib/browser/debug.js +3 -3
- package/lib/browser/events.js +42 -26
- package/lib/browser/progress.js +37 -45
- package/lib/browser/tty.js +4 -5
- package/lib/context.js +26 -32
- package/lib/hook.js +5 -7
- package/lib/interfaces/bdd.js +21 -26
- package/lib/interfaces/common.js +33 -15
- package/lib/interfaces/exports.js +7 -7
- package/lib/interfaces/qunit.js +16 -17
- package/lib/interfaces/tdd.js +24 -28
- package/lib/mocha.js +140 -99
- package/lib/ms.js +43 -24
- package/lib/pending.js +2 -3
- package/lib/reporters/base.js +159 -138
- package/lib/reporters/doc.js +13 -13
- package/lib/reporters/dot.js +23 -19
- package/lib/reporters/html-cov.js +25 -19
- package/lib/reporters/html.js +130 -91
- package/lib/reporters/index.js +19 -17
- package/lib/reporters/json-cov.js +39 -41
- package/lib/reporters/json-stream.js +14 -17
- package/lib/reporters/json.js +16 -19
- package/lib/reporters/landing.js +20 -24
- package/lib/reporters/list.js +14 -16
- package/lib/reporters/markdown.js +17 -20
- package/lib/reporters/min.js +4 -5
- package/lib/reporters/nyan.js +49 -48
- package/lib/reporters/progress.js +20 -23
- package/lib/reporters/spec.js +23 -22
- package/lib/reporters/tap.js +15 -19
- package/lib/reporters/xunit.js +83 -63
- package/lib/runnable.js +134 -94
- package/lib/runner.js +291 -167
- package/lib/suite.js +105 -95
- package/lib/template.html +1 -1
- package/lib/test.js +3 -4
- package/lib/utils.js +227 -199
- package/mocha.css +35 -0
- package/mocha.js +8324 -2471
- package/package.json +250 -10
- package/lib/browser/escape-string-regexp.js +0 -11
- package/lib/browser/fs.js +0 -0
- package/lib/browser/glob.js +0 -0
- package/lib/browser/path.js +0 -0
package/lib/runner.js
CHANGED
|
@@ -2,16 +2,19 @@
|
|
|
2
2
|
* Module dependencies.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
var EventEmitter = require('events').EventEmitter
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
var EventEmitter = require('events').EventEmitter;
|
|
6
|
+
var Pending = require('./pending');
|
|
7
|
+
var utils = require('./utils');
|
|
8
|
+
var inherits = utils.inherits;
|
|
9
|
+
var debug = require('debug')('mocha:runner');
|
|
10
|
+
var Runnable = require('./runnable');
|
|
11
|
+
var filter = utils.filter;
|
|
12
|
+
var indexOf = utils.indexOf;
|
|
13
|
+
var keys = utils.keys;
|
|
14
|
+
var stackFilter = utils.stackTraceFilter();
|
|
15
|
+
var stringify = utils.stringify;
|
|
16
|
+
var type = utils.type;
|
|
17
|
+
var undefinedError = utils.undefinedError;
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* Non-enumerable globals.
|
|
@@ -51,23 +54,28 @@ module.exports = Runner;
|
|
|
51
54
|
* - `fail` (test, err) test failed
|
|
52
55
|
* - `pending` (test) test pending
|
|
53
56
|
*
|
|
57
|
+
* @api public
|
|
54
58
|
* @param {Suite} suite Root suite
|
|
55
59
|
* @param {boolean} [delay] Whether or not to delay execution of root suite
|
|
56
|
-
*
|
|
57
|
-
* @api public
|
|
60
|
+
* until ready.
|
|
58
61
|
*/
|
|
59
|
-
|
|
60
62
|
function Runner(suite, delay) {
|
|
61
63
|
var self = this;
|
|
62
64
|
this._globals = [];
|
|
63
65
|
this._abort = false;
|
|
64
66
|
this._delay = delay;
|
|
65
67
|
this.suite = suite;
|
|
68
|
+
this.started = false;
|
|
66
69
|
this.total = suite.total();
|
|
67
70
|
this.failures = 0;
|
|
68
|
-
this.on('test end', function(test){
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
this.on('test end', function(test) {
|
|
72
|
+
self.checkGlobals(test);
|
|
73
|
+
});
|
|
74
|
+
this.on('hook end', function(hook) {
|
|
75
|
+
self.checkGlobals(hook);
|
|
76
|
+
});
|
|
77
|
+
this._defaultGrep = /.*/;
|
|
78
|
+
this.grep(this._defaultGrep);
|
|
71
79
|
this.globals(this.globalProps().concat(extraGlobals()));
|
|
72
80
|
}
|
|
73
81
|
|
|
@@ -77,14 +85,12 @@ function Runner(suite, delay) {
|
|
|
77
85
|
* @param {Function} fn
|
|
78
86
|
* @api private
|
|
79
87
|
*/
|
|
80
|
-
|
|
81
88
|
Runner.immediately = global.setImmediate || process.nextTick;
|
|
82
89
|
|
|
83
90
|
/**
|
|
84
91
|
* Inherit from `EventEmitter.prototype`.
|
|
85
92
|
*/
|
|
86
|
-
|
|
87
|
-
Runner.prototype.__proto__ = EventEmitter.prototype;
|
|
93
|
+
inherits(Runner, EventEmitter);
|
|
88
94
|
|
|
89
95
|
/**
|
|
90
96
|
* Run tests with full titles matching `re`. Updates runner.total
|
|
@@ -94,9 +100,11 @@ Runner.prototype.__proto__ = EventEmitter.prototype;
|
|
|
94
100
|
* @param {Boolean} invert
|
|
95
101
|
* @return {Runner} for chaining
|
|
96
102
|
* @api public
|
|
103
|
+
* @param {RegExp} re
|
|
104
|
+
* @param {boolean} invert
|
|
105
|
+
* @return {Runner} Runner instance.
|
|
97
106
|
*/
|
|
98
|
-
|
|
99
|
-
Runner.prototype.grep = function(re, invert){
|
|
107
|
+
Runner.prototype.grep = function(re, invert) {
|
|
100
108
|
debug('grep %s', re);
|
|
101
109
|
this._grep = re;
|
|
102
110
|
this._invert = invert;
|
|
@@ -111,16 +119,21 @@ Runner.prototype.grep = function(re, invert){
|
|
|
111
119
|
* @param {Suite} suite
|
|
112
120
|
* @return {Number}
|
|
113
121
|
* @api public
|
|
122
|
+
* @param {Suite} suite
|
|
123
|
+
* @return {number}
|
|
114
124
|
*/
|
|
115
|
-
|
|
116
125
|
Runner.prototype.grepTotal = function(suite) {
|
|
117
126
|
var self = this;
|
|
118
127
|
var total = 0;
|
|
119
128
|
|
|
120
|
-
suite.eachTest(function(test){
|
|
129
|
+
suite.eachTest(function(test) {
|
|
121
130
|
var match = self._grep.test(test.fullTitle());
|
|
122
|
-
if (self._invert)
|
|
123
|
-
|
|
131
|
+
if (self._invert) {
|
|
132
|
+
match = !match;
|
|
133
|
+
}
|
|
134
|
+
if (match) {
|
|
135
|
+
total++;
|
|
136
|
+
}
|
|
124
137
|
});
|
|
125
138
|
|
|
126
139
|
return total;
|
|
@@ -132,13 +145,14 @@ Runner.prototype.grepTotal = function(suite) {
|
|
|
132
145
|
* @return {Array}
|
|
133
146
|
* @api private
|
|
134
147
|
*/
|
|
135
|
-
|
|
136
148
|
Runner.prototype.globalProps = function() {
|
|
137
|
-
var props =
|
|
149
|
+
var props = keys(global);
|
|
138
150
|
|
|
139
151
|
// non-enumerables
|
|
140
152
|
for (var i = 0; i < globals.length; ++i) {
|
|
141
|
-
if (~
|
|
153
|
+
if (~indexOf(props, globals[i])) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
142
156
|
props.push(globals[i]);
|
|
143
157
|
}
|
|
144
158
|
|
|
@@ -151,10 +165,13 @@ Runner.prototype.globalProps = function() {
|
|
|
151
165
|
* @param {Array} arr
|
|
152
166
|
* @return {Runner} for chaining
|
|
153
167
|
* @api public
|
|
168
|
+
* @param {Array} arr
|
|
169
|
+
* @return {Runner} Runner instance.
|
|
154
170
|
*/
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
171
|
+
Runner.prototype.globals = function(arr) {
|
|
172
|
+
if (!arguments.length) {
|
|
173
|
+
return this._globals;
|
|
174
|
+
}
|
|
158
175
|
debug('globals %j', arr);
|
|
159
176
|
this._globals = this._globals.concat(arr);
|
|
160
177
|
return this;
|
|
@@ -165,9 +182,10 @@ Runner.prototype.globals = function(arr){
|
|
|
165
182
|
*
|
|
166
183
|
* @api private
|
|
167
184
|
*/
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
185
|
+
Runner.prototype.checkGlobals = function(test) {
|
|
186
|
+
if (this.ignoreLeaks) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
171
189
|
var ok = this._globals;
|
|
172
190
|
|
|
173
191
|
var globals = this.globalProps();
|
|
@@ -177,7 +195,9 @@ Runner.prototype.checkGlobals = function(test){
|
|
|
177
195
|
ok = ok.concat(test._allowedGlobals || []);
|
|
178
196
|
}
|
|
179
197
|
|
|
180
|
-
if(this.prevGlobalsLength
|
|
198
|
+
if (this.prevGlobalsLength === globals.length) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
181
201
|
this.prevGlobalsLength = globals.length;
|
|
182
202
|
|
|
183
203
|
leaks = filterLeaks(ok, globals);
|
|
@@ -193,16 +213,15 @@ Runner.prototype.checkGlobals = function(test){
|
|
|
193
213
|
/**
|
|
194
214
|
* Fail the given `test`.
|
|
195
215
|
*
|
|
216
|
+
* @api private
|
|
196
217
|
* @param {Test} test
|
|
197
218
|
* @param {Error} err
|
|
198
|
-
* @api private
|
|
199
219
|
*/
|
|
200
|
-
|
|
201
220
|
Runner.prototype.fail = function(test, err) {
|
|
202
221
|
++this.failures;
|
|
203
222
|
test.state = 'failed';
|
|
204
223
|
|
|
205
|
-
if (!(err instanceof Error)) {
|
|
224
|
+
if (!(err instanceof Error || err && typeof err.message === 'string')) {
|
|
206
225
|
err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)');
|
|
207
226
|
}
|
|
208
227
|
|
|
@@ -229,12 +248,16 @@ Runner.prototype.fail = function(test, err) {
|
|
|
229
248
|
* suite and subsuites, but executes other `after each`
|
|
230
249
|
* hooks
|
|
231
250
|
*
|
|
251
|
+
* @api private
|
|
232
252
|
* @param {Hook} hook
|
|
233
253
|
* @param {Error} err
|
|
234
|
-
* @api private
|
|
235
254
|
*/
|
|
255
|
+
Runner.prototype.failHook = function(hook, err) {
|
|
256
|
+
if (hook.ctx && hook.ctx.currentTest) {
|
|
257
|
+
hook.originalTitle = hook.originalTitle || hook.title;
|
|
258
|
+
hook.title = hook.originalTitle + ' for "' + hook.ctx.currentTest.title + '"';
|
|
259
|
+
}
|
|
236
260
|
|
|
237
|
-
Runner.prototype.failHook = function(hook, err){
|
|
238
261
|
this.fail(hook, err);
|
|
239
262
|
if (this.suite.bail()) {
|
|
240
263
|
this.emit('end');
|
|
@@ -244,34 +267,38 @@ Runner.prototype.failHook = function(hook, err){
|
|
|
244
267
|
/**
|
|
245
268
|
* Run hook `name` callbacks and then invoke `fn()`.
|
|
246
269
|
*
|
|
247
|
-
* @param {String} name
|
|
248
|
-
* @param {Function} function
|
|
249
270
|
* @api private
|
|
271
|
+
* @param {string} name
|
|
272
|
+
* @param {Function} fn
|
|
250
273
|
*/
|
|
251
274
|
|
|
252
|
-
Runner.prototype.hook = function(name, fn){
|
|
253
|
-
var suite = this.suite
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
, timer;
|
|
275
|
+
Runner.prototype.hook = function(name, fn) {
|
|
276
|
+
var suite = this.suite;
|
|
277
|
+
var hooks = suite['_' + name];
|
|
278
|
+
var self = this;
|
|
257
279
|
|
|
258
280
|
function next(i) {
|
|
259
281
|
var hook = hooks[i];
|
|
260
|
-
if (!hook)
|
|
282
|
+
if (!hook) {
|
|
283
|
+
return fn();
|
|
284
|
+
}
|
|
261
285
|
self.currentRunnable = hook;
|
|
262
286
|
|
|
263
287
|
hook.ctx.currentTest = self.test;
|
|
264
288
|
|
|
265
289
|
self.emit('hook', hook);
|
|
266
290
|
|
|
267
|
-
hook.
|
|
268
|
-
|
|
269
|
-
|
|
291
|
+
if (!hook.listeners('error').length) {
|
|
292
|
+
hook.on('error', function(err) {
|
|
293
|
+
self.failHook(hook, err);
|
|
294
|
+
});
|
|
295
|
+
}
|
|
270
296
|
|
|
271
|
-
hook.run(function(err){
|
|
272
|
-
hook.removeAllListeners('error');
|
|
297
|
+
hook.run(function(err) {
|
|
273
298
|
var testError = hook.error();
|
|
274
|
-
if (testError)
|
|
299
|
+
if (testError) {
|
|
300
|
+
self.fail(self.test, testError);
|
|
301
|
+
}
|
|
275
302
|
if (err) {
|
|
276
303
|
if (err instanceof Pending) {
|
|
277
304
|
suite.pending = true;
|
|
@@ -288,7 +315,7 @@ Runner.prototype.hook = function(name, fn){
|
|
|
288
315
|
});
|
|
289
316
|
}
|
|
290
317
|
|
|
291
|
-
Runner.immediately(function(){
|
|
318
|
+
Runner.immediately(function() {
|
|
292
319
|
next(0);
|
|
293
320
|
});
|
|
294
321
|
};
|
|
@@ -297,15 +324,14 @@ Runner.prototype.hook = function(name, fn){
|
|
|
297
324
|
* Run hook `name` for the given array of `suites`
|
|
298
325
|
* in order, and callback `fn(err, errSuite)`.
|
|
299
326
|
*
|
|
300
|
-
* @
|
|
327
|
+
* @api private
|
|
328
|
+
* @param {string} name
|
|
301
329
|
* @param {Array} suites
|
|
302
330
|
* @param {Function} fn
|
|
303
|
-
* @api private
|
|
304
331
|
*/
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
var
|
|
308
|
-
, orig = this.suite;
|
|
332
|
+
Runner.prototype.hooks = function(name, suites, fn) {
|
|
333
|
+
var self = this;
|
|
334
|
+
var orig = this.suite;
|
|
309
335
|
|
|
310
336
|
function next(suite) {
|
|
311
337
|
self.suite = suite;
|
|
@@ -315,7 +341,7 @@ Runner.prototype.hooks = function(name, suites, fn){
|
|
|
315
341
|
return fn();
|
|
316
342
|
}
|
|
317
343
|
|
|
318
|
-
self.hook(name, function(err){
|
|
344
|
+
self.hook(name, function(err) {
|
|
319
345
|
if (err) {
|
|
320
346
|
var errSuite = self.suite;
|
|
321
347
|
self.suite = orig;
|
|
@@ -336,8 +362,7 @@ Runner.prototype.hooks = function(name, suites, fn){
|
|
|
336
362
|
* @param {Function} fn
|
|
337
363
|
* @api private
|
|
338
364
|
*/
|
|
339
|
-
|
|
340
|
-
Runner.prototype.hookUp = function(name, fn){
|
|
365
|
+
Runner.prototype.hookUp = function(name, fn) {
|
|
341
366
|
var suites = [this.suite].concat(this.parents()).reverse();
|
|
342
367
|
this.hooks(name, suites, fn);
|
|
343
368
|
};
|
|
@@ -349,8 +374,7 @@ Runner.prototype.hookUp = function(name, fn){
|
|
|
349
374
|
* @param {Function} fn
|
|
350
375
|
* @api private
|
|
351
376
|
*/
|
|
352
|
-
|
|
353
|
-
Runner.prototype.hookDown = function(name, fn){
|
|
377
|
+
Runner.prototype.hookDown = function(name, fn) {
|
|
354
378
|
var suites = [this.suite].concat(this.parents());
|
|
355
379
|
this.hooks(name, suites, fn);
|
|
356
380
|
};
|
|
@@ -362,11 +386,13 @@ Runner.prototype.hookDown = function(name, fn){
|
|
|
362
386
|
* @return {Array}
|
|
363
387
|
* @api private
|
|
364
388
|
*/
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
var
|
|
368
|
-
|
|
369
|
-
|
|
389
|
+
Runner.prototype.parents = function() {
|
|
390
|
+
var suite = this.suite;
|
|
391
|
+
var suites = [];
|
|
392
|
+
while (suite.parent) {
|
|
393
|
+
suite = suite.parent;
|
|
394
|
+
suites.push(suite);
|
|
395
|
+
}
|
|
370
396
|
return suites;
|
|
371
397
|
};
|
|
372
398
|
|
|
@@ -376,15 +402,20 @@ Runner.prototype.parents = function(){
|
|
|
376
402
|
* @param {Function} fn
|
|
377
403
|
* @api private
|
|
378
404
|
*/
|
|
405
|
+
Runner.prototype.runTest = function(fn) {
|
|
406
|
+
var self = this;
|
|
407
|
+
var test = this.test;
|
|
379
408
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
if (this.asyncOnly) test.asyncOnly = true;
|
|
409
|
+
if (this.asyncOnly) {
|
|
410
|
+
test.asyncOnly = true;
|
|
411
|
+
}
|
|
385
412
|
|
|
413
|
+
if (this.allowUncaught) {
|
|
414
|
+
test.allowUncaught = true;
|
|
415
|
+
return test.run(fn);
|
|
416
|
+
}
|
|
386
417
|
try {
|
|
387
|
-
test.on('error', function(err){
|
|
418
|
+
test.on('error', function(err) {
|
|
388
419
|
self.fail(test, err);
|
|
389
420
|
});
|
|
390
421
|
test.run(fn);
|
|
@@ -394,21 +425,18 @@ Runner.prototype.runTest = function(fn){
|
|
|
394
425
|
};
|
|
395
426
|
|
|
396
427
|
/**
|
|
397
|
-
* Run tests in the given `suite` and invoke
|
|
398
|
-
* the callback `fn()` when complete.
|
|
428
|
+
* Run tests in the given `suite` and invoke the callback `fn()` when complete.
|
|
399
429
|
*
|
|
430
|
+
* @api private
|
|
400
431
|
* @param {Suite} suite
|
|
401
432
|
* @param {Function} fn
|
|
402
|
-
* @api private
|
|
403
433
|
*/
|
|
434
|
+
Runner.prototype.runTests = function(suite, fn) {
|
|
435
|
+
var self = this;
|
|
436
|
+
var tests = suite.tests.slice();
|
|
437
|
+
var test;
|
|
404
438
|
|
|
405
|
-
|
|
406
|
-
var self = this
|
|
407
|
-
, tests = suite.tests.slice()
|
|
408
|
-
, test;
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
function hookErr(err, errSuite, after) {
|
|
439
|
+
function hookErr(_, errSuite, after) {
|
|
412
440
|
// before/after Each hook for errSuite failed:
|
|
413
441
|
var orig = self.suite;
|
|
414
442
|
|
|
@@ -421,7 +449,9 @@ Runner.prototype.runTests = function(suite, fn){
|
|
|
421
449
|
self.hookUp('afterEach', function(err2, errSuite2) {
|
|
422
450
|
self.suite = orig;
|
|
423
451
|
// some hooks may fail even now
|
|
424
|
-
if (err2)
|
|
452
|
+
if (err2) {
|
|
453
|
+
return hookErr(err2, errSuite2, true);
|
|
454
|
+
}
|
|
425
455
|
// report error suite
|
|
426
456
|
fn(errSuite);
|
|
427
457
|
});
|
|
@@ -434,22 +464,47 @@ Runner.prototype.runTests = function(suite, fn){
|
|
|
434
464
|
|
|
435
465
|
function next(err, errSuite) {
|
|
436
466
|
// if we bail after first err
|
|
437
|
-
if (self.failures && suite._bail)
|
|
467
|
+
if (self.failures && suite._bail) {
|
|
468
|
+
return fn();
|
|
469
|
+
}
|
|
438
470
|
|
|
439
|
-
if (self._abort)
|
|
471
|
+
if (self._abort) {
|
|
472
|
+
return fn();
|
|
473
|
+
}
|
|
440
474
|
|
|
441
|
-
if (err)
|
|
475
|
+
if (err) {
|
|
476
|
+
return hookErr(err, errSuite, true);
|
|
477
|
+
}
|
|
442
478
|
|
|
443
479
|
// next test
|
|
444
480
|
test = tests.shift();
|
|
445
481
|
|
|
446
482
|
// all done
|
|
447
|
-
if (!test)
|
|
483
|
+
if (!test) {
|
|
484
|
+
return fn();
|
|
485
|
+
}
|
|
448
486
|
|
|
449
487
|
// grep
|
|
450
488
|
var match = self._grep.test(test.fullTitle());
|
|
451
|
-
if (self._invert)
|
|
452
|
-
|
|
489
|
+
if (self._invert) {
|
|
490
|
+
match = !match;
|
|
491
|
+
}
|
|
492
|
+
if (!match) {
|
|
493
|
+
// Run immediately only if we have defined a grep. When we
|
|
494
|
+
// define a grep — It can cause maximum callstack error if
|
|
495
|
+
// the grep is doing a large recursive loop by neglecting
|
|
496
|
+
// all tests. The run immediately function also comes with
|
|
497
|
+
// a performance cost. So we don't want to run immediately
|
|
498
|
+
// if we run the whole test suite, because running the whole
|
|
499
|
+
// test suite don't do any immediate recursive loops. Thus,
|
|
500
|
+
// allowing a JS runtime to breathe.
|
|
501
|
+
if (self._grep !== self._defaultGrep) {
|
|
502
|
+
Runner.immediately(next);
|
|
503
|
+
} else {
|
|
504
|
+
next();
|
|
505
|
+
}
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
453
508
|
|
|
454
509
|
// pending
|
|
455
510
|
if (test.pending) {
|
|
@@ -460,17 +515,17 @@ Runner.prototype.runTests = function(suite, fn){
|
|
|
460
515
|
|
|
461
516
|
// execute test and hook(s)
|
|
462
517
|
self.emit('test', self.test = test);
|
|
463
|
-
self.hookDown('beforeEach', function(err, errSuite){
|
|
464
|
-
|
|
518
|
+
self.hookDown('beforeEach', function(err, errSuite) {
|
|
465
519
|
if (suite.pending) {
|
|
466
520
|
self.emit('pending', test);
|
|
467
521
|
self.emit('test end', test);
|
|
468
522
|
return next();
|
|
469
523
|
}
|
|
470
|
-
if (err)
|
|
471
|
-
|
|
524
|
+
if (err) {
|
|
525
|
+
return hookErr(err, errSuite, false);
|
|
526
|
+
}
|
|
472
527
|
self.currentRunnable = self.test;
|
|
473
|
-
self.runTest(function(err){
|
|
528
|
+
self.runTest(function(err) {
|
|
474
529
|
test = self.test;
|
|
475
530
|
|
|
476
531
|
if (err) {
|
|
@@ -497,60 +552,88 @@ Runner.prototype.runTests = function(suite, fn){
|
|
|
497
552
|
}
|
|
498
553
|
|
|
499
554
|
this.next = next;
|
|
555
|
+
this.hookErr = hookErr;
|
|
500
556
|
next();
|
|
501
557
|
};
|
|
502
558
|
|
|
503
559
|
/**
|
|
504
|
-
* Run the given `suite` and invoke the
|
|
505
|
-
* callback `fn()` when complete.
|
|
560
|
+
* Run the given `suite` and invoke the callback `fn()` when complete.
|
|
506
561
|
*
|
|
562
|
+
* @api private
|
|
507
563
|
* @param {Suite} suite
|
|
508
564
|
* @param {Function} fn
|
|
509
|
-
* @api private
|
|
510
565
|
*/
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
var
|
|
514
|
-
|
|
515
|
-
|
|
566
|
+
Runner.prototype.runSuite = function(suite, fn) {
|
|
567
|
+
var i = 0;
|
|
568
|
+
var self = this;
|
|
569
|
+
var total = this.grepTotal(suite);
|
|
570
|
+
var afterAllHookCalled = false;
|
|
516
571
|
|
|
517
572
|
debug('run suite %s', suite.fullTitle());
|
|
518
573
|
|
|
519
|
-
if (!total
|
|
574
|
+
if (!total || (self.failures && suite._bail)) {
|
|
575
|
+
return fn();
|
|
576
|
+
}
|
|
520
577
|
|
|
521
578
|
this.emit('suite', this.suite = suite);
|
|
522
579
|
|
|
523
580
|
function next(errSuite) {
|
|
524
581
|
if (errSuite) {
|
|
525
582
|
// current suite failed on a hook from errSuite
|
|
526
|
-
if (errSuite
|
|
583
|
+
if (errSuite === suite) {
|
|
527
584
|
// if errSuite is current suite
|
|
528
585
|
// continue to the next sibling suite
|
|
529
586
|
return done();
|
|
530
|
-
} else {
|
|
531
|
-
// errSuite is among the parents of current suite
|
|
532
|
-
// stop execution of errSuite and all sub-suites
|
|
533
|
-
return done(errSuite);
|
|
534
587
|
}
|
|
588
|
+
// errSuite is among the parents of current suite
|
|
589
|
+
// stop execution of errSuite and all sub-suites
|
|
590
|
+
return done(errSuite);
|
|
535
591
|
}
|
|
536
592
|
|
|
537
|
-
if (self._abort)
|
|
593
|
+
if (self._abort) {
|
|
594
|
+
return done();
|
|
595
|
+
}
|
|
538
596
|
|
|
539
597
|
var curr = suite.suites[i++];
|
|
540
|
-
if (!curr)
|
|
541
|
-
|
|
598
|
+
if (!curr) {
|
|
599
|
+
return done();
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// Avoid grep neglecting large number of tests causing a
|
|
603
|
+
// huge recursive loop and thus a maximum call stack error.
|
|
604
|
+
// See comment in `this.runTests()` for more information.
|
|
605
|
+
if (self._grep !== self._defaultGrep) {
|
|
606
|
+
Runner.immediately(function() {
|
|
607
|
+
self.runSuite(curr, next);
|
|
608
|
+
});
|
|
609
|
+
} else {
|
|
610
|
+
self.runSuite(curr, next);
|
|
611
|
+
}
|
|
542
612
|
}
|
|
543
613
|
|
|
544
614
|
function done(errSuite) {
|
|
545
615
|
self.suite = suite;
|
|
546
|
-
self.
|
|
547
|
-
|
|
616
|
+
self.nextSuite = next;
|
|
617
|
+
|
|
618
|
+
if (afterAllHookCalled) {
|
|
548
619
|
fn(errSuite);
|
|
549
|
-
}
|
|
620
|
+
} else {
|
|
621
|
+
// mark that the afterAll block has been called once
|
|
622
|
+
// and so can be skipped if there is an error in it.
|
|
623
|
+
afterAllHookCalled = true;
|
|
624
|
+
self.hook('afterAll', function() {
|
|
625
|
+
self.emit('suite end', suite);
|
|
626
|
+
fn(errSuite);
|
|
627
|
+
});
|
|
628
|
+
}
|
|
550
629
|
}
|
|
551
630
|
|
|
552
|
-
this.
|
|
553
|
-
|
|
631
|
+
this.nextSuite = next;
|
|
632
|
+
|
|
633
|
+
this.hook('beforeAll', function(err) {
|
|
634
|
+
if (err) {
|
|
635
|
+
return done();
|
|
636
|
+
}
|
|
554
637
|
self.runTests(suite, next);
|
|
555
638
|
});
|
|
556
639
|
};
|
|
@@ -561,35 +644,66 @@ Runner.prototype.runSuite = function(suite, fn){
|
|
|
561
644
|
* @param {Error} err
|
|
562
645
|
* @api private
|
|
563
646
|
*/
|
|
564
|
-
|
|
565
|
-
Runner.prototype.uncaught = function(err){
|
|
647
|
+
Runner.prototype.uncaught = function(err) {
|
|
566
648
|
if (err) {
|
|
567
|
-
debug('uncaught exception %s', err !== function
|
|
649
|
+
debug('uncaught exception %s', err !== function() {
|
|
568
650
|
return this;
|
|
569
|
-
}.call(err) ? err : (
|
|
651
|
+
}.call(err) ? err : (err.message || err));
|
|
570
652
|
} else {
|
|
571
653
|
debug('uncaught undefined exception');
|
|
572
|
-
err =
|
|
654
|
+
err = undefinedError();
|
|
573
655
|
}
|
|
574
656
|
err.uncaught = true;
|
|
575
657
|
|
|
576
658
|
var runnable = this.currentRunnable;
|
|
577
|
-
|
|
659
|
+
|
|
660
|
+
if (!runnable) {
|
|
661
|
+
runnable = new Runnable('Uncaught error outside test suite');
|
|
662
|
+
runnable.parent = this.suite;
|
|
663
|
+
|
|
664
|
+
if (this.started) {
|
|
665
|
+
this.fail(runnable, err);
|
|
666
|
+
} else {
|
|
667
|
+
// Can't recover from this failure
|
|
668
|
+
this.emit('start');
|
|
669
|
+
this.fail(runnable, err);
|
|
670
|
+
this.emit('end');
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
578
675
|
|
|
579
676
|
runnable.clearTimeout();
|
|
580
677
|
|
|
581
678
|
// Ignore errors if complete
|
|
582
|
-
if (runnable.state)
|
|
679
|
+
if (runnable.state) {
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
583
682
|
this.fail(runnable, err);
|
|
584
683
|
|
|
585
684
|
// recover from test
|
|
586
|
-
if ('test'
|
|
685
|
+
if (runnable.type === 'test') {
|
|
587
686
|
this.emit('test end', runnable);
|
|
588
687
|
this.hookUp('afterEach', this.next);
|
|
589
688
|
return;
|
|
590
689
|
}
|
|
591
690
|
|
|
592
|
-
|
|
691
|
+
// recover from hooks
|
|
692
|
+
if (runnable.type === 'hook') {
|
|
693
|
+
var errSuite = this.suite;
|
|
694
|
+
// if hook failure is in afterEach block
|
|
695
|
+
if (runnable.fullTitle().indexOf('after each') > -1) {
|
|
696
|
+
return this.hookErr(err, errSuite, true);
|
|
697
|
+
}
|
|
698
|
+
// if hook failure is in beforeEach block
|
|
699
|
+
if (runnable.fullTitle().indexOf('before each') > -1) {
|
|
700
|
+
return this.hookErr(err, errSuite, false);
|
|
701
|
+
}
|
|
702
|
+
// if hook failure is in after or before blocks
|
|
703
|
+
return this.nextSuite(errSuite);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// bail
|
|
593
707
|
this.emit('end');
|
|
594
708
|
};
|
|
595
709
|
|
|
@@ -600,21 +714,23 @@ Runner.prototype.uncaught = function(err){
|
|
|
600
714
|
* @param {Function} fn
|
|
601
715
|
* @return {Runner} for chaining
|
|
602
716
|
* @api public
|
|
717
|
+
* @param {Function} fn
|
|
718
|
+
* @return {Runner} Runner instance.
|
|
603
719
|
*/
|
|
720
|
+
Runner.prototype.run = function(fn) {
|
|
721
|
+
var self = this;
|
|
722
|
+
var rootSuite = this.suite;
|
|
604
723
|
|
|
605
|
-
|
|
606
|
-
var self = this,
|
|
607
|
-
rootSuite = this.suite;
|
|
608
|
-
|
|
609
|
-
fn = fn || function(){};
|
|
724
|
+
fn = fn || function() {};
|
|
610
725
|
|
|
611
|
-
function uncaught(err){
|
|
726
|
+
function uncaught(err) {
|
|
612
727
|
self.uncaught(err);
|
|
613
728
|
}
|
|
614
729
|
|
|
615
730
|
function start() {
|
|
731
|
+
self.started = true;
|
|
616
732
|
self.emit('start');
|
|
617
|
-
self.runSuite(rootSuite, function(){
|
|
733
|
+
self.runSuite(rootSuite, function() {
|
|
618
734
|
debug('finished running');
|
|
619
735
|
self.emit('end');
|
|
620
736
|
});
|
|
@@ -623,7 +739,7 @@ Runner.prototype.run = function(fn){
|
|
|
623
739
|
debug('start');
|
|
624
740
|
|
|
625
741
|
// callback
|
|
626
|
-
this.on('end', function(){
|
|
742
|
+
this.on('end', function() {
|
|
627
743
|
debug('end');
|
|
628
744
|
process.removeListener('uncaughtException', uncaught);
|
|
629
745
|
fn(self.failures);
|
|
@@ -637,8 +753,7 @@ Runner.prototype.run = function(fn){
|
|
|
637
753
|
// might be nice to debounce some dots while we wait.
|
|
638
754
|
this.emit('waiting', rootSuite);
|
|
639
755
|
rootSuite.once('run', start);
|
|
640
|
-
}
|
|
641
|
-
else {
|
|
756
|
+
} else {
|
|
642
757
|
start();
|
|
643
758
|
}
|
|
644
759
|
|
|
@@ -646,47 +761,58 @@ Runner.prototype.run = function(fn){
|
|
|
646
761
|
};
|
|
647
762
|
|
|
648
763
|
/**
|
|
649
|
-
* Cleanly abort execution
|
|
764
|
+
* Cleanly abort execution.
|
|
650
765
|
*
|
|
651
|
-
* @return {Runner} for chaining
|
|
652
766
|
* @api public
|
|
767
|
+
* @return {Runner} Runner instance.
|
|
653
768
|
*/
|
|
654
|
-
Runner.prototype.abort = function(){
|
|
769
|
+
Runner.prototype.abort = function() {
|
|
655
770
|
debug('aborting');
|
|
656
771
|
this._abort = true;
|
|
772
|
+
|
|
773
|
+
return this;
|
|
657
774
|
};
|
|
658
775
|
|
|
659
776
|
/**
|
|
660
777
|
* Filter leaks with the given globals flagged as `ok`.
|
|
661
778
|
*
|
|
779
|
+
* @api private
|
|
662
780
|
* @param {Array} ok
|
|
663
781
|
* @param {Array} globals
|
|
664
782
|
* @return {Array}
|
|
665
|
-
* @api private
|
|
666
783
|
*/
|
|
667
|
-
|
|
668
784
|
function filterLeaks(ok, globals) {
|
|
669
|
-
return filter(globals, function(key){
|
|
785
|
+
return filter(globals, function(key) {
|
|
670
786
|
// Firefox and Chrome exposes iframes as index inside the window object
|
|
671
|
-
if (/^d+/.test(key))
|
|
787
|
+
if (/^d+/.test(key)) {
|
|
788
|
+
return false;
|
|
789
|
+
}
|
|
672
790
|
|
|
673
791
|
// in firefox
|
|
674
792
|
// if runner runs in an iframe, this iframe's window.getInterface method not init at first
|
|
675
793
|
// it is assigned in some seconds
|
|
676
|
-
if (global.navigator && /^getInterface
|
|
794
|
+
if (global.navigator && (/^getInterface/).test(key)) {
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
677
797
|
|
|
678
798
|
// an iframe could be approached by window[iframeIndex]
|
|
679
799
|
// in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak
|
|
680
|
-
if (global.navigator && /^\d
|
|
800
|
+
if (global.navigator && (/^\d+/).test(key)) {
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
681
803
|
|
|
682
804
|
// Opera and IE expose global variables for HTML element IDs (issue #243)
|
|
683
|
-
if (/^mocha-/.test(key))
|
|
805
|
+
if (/^mocha-/.test(key)) {
|
|
806
|
+
return false;
|
|
807
|
+
}
|
|
684
808
|
|
|
685
|
-
var matched = filter(ok, function(ok){
|
|
686
|
-
if (~ok.indexOf('*'))
|
|
687
|
-
|
|
809
|
+
var matched = filter(ok, function(ok) {
|
|
810
|
+
if (~ok.indexOf('*')) {
|
|
811
|
+
return key.indexOf(ok.split('*')[0]) === 0;
|
|
812
|
+
}
|
|
813
|
+
return key === ok;
|
|
688
814
|
});
|
|
689
|
-
return matched.length
|
|
815
|
+
return !matched.length && (!global.navigator || key !== 'onerror');
|
|
690
816
|
});
|
|
691
817
|
}
|
|
692
818
|
|
|
@@ -696,21 +822,19 @@ function filterLeaks(ok, globals) {
|
|
|
696
822
|
* @return {Array}
|
|
697
823
|
* @api private
|
|
698
824
|
*/
|
|
699
|
-
|
|
700
825
|
function extraGlobals() {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
});
|
|
826
|
+
if (typeof process === 'object' && typeof process.version === 'string') {
|
|
827
|
+
var parts = process.version.split('.');
|
|
828
|
+
var nodeVersion = utils.reduce(parts, function(a, v) {
|
|
829
|
+
return a << 8 | v;
|
|
830
|
+
});
|
|
707
831
|
|
|
708
|
-
|
|
832
|
+
// 'errno' was renamed to process._errno in v0.9.11.
|
|
709
833
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
834
|
+
if (nodeVersion < 0x00090B) {
|
|
835
|
+
return ['errno'];
|
|
836
|
+
}
|
|
837
|
+
}
|
|
714
838
|
|
|
715
|
-
|
|
839
|
+
return [];
|
|
716
840
|
}
|