mocha 3.0.2 → 3.2.0

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