mocha 5.1.1 → 6.0.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 (61) hide show
  1. package/CHANGELOG.md +686 -984
  2. package/README.md +2 -1
  3. package/{images → assets/growl}/error.png +0 -0
  4. package/{images → assets/growl}/ok.png +0 -0
  5. package/bin/_mocha +4 -595
  6. package/bin/mocha +121 -61
  7. package/bin/options.js +6 -39
  8. package/browser-entry.js +21 -17
  9. package/lib/browser/growl.js +165 -2
  10. package/lib/browser/progress.js +11 -11
  11. package/lib/{template.html → browser/template.html} +0 -0
  12. package/lib/browser/tty.js +2 -2
  13. package/lib/cli/cli.js +68 -0
  14. package/lib/cli/commands.js +13 -0
  15. package/lib/cli/config.js +79 -0
  16. package/lib/cli/index.js +9 -0
  17. package/lib/cli/init.js +37 -0
  18. package/lib/cli/node-flags.js +69 -0
  19. package/lib/cli/one-and-dones.js +70 -0
  20. package/lib/cli/options.js +330 -0
  21. package/lib/cli/run-helpers.js +337 -0
  22. package/lib/cli/run-option-metadata.js +76 -0
  23. package/lib/cli/run.js +297 -0
  24. package/lib/context.js +14 -14
  25. package/lib/errors.js +141 -0
  26. package/lib/growl.js +136 -0
  27. package/lib/hook.js +5 -16
  28. package/lib/interfaces/bdd.js +16 -13
  29. package/lib/interfaces/common.js +62 -18
  30. package/lib/interfaces/exports.js +5 -8
  31. package/lib/interfaces/qunit.js +10 -10
  32. package/lib/interfaces/tdd.js +12 -11
  33. package/lib/mocha.js +477 -256
  34. package/lib/mocharc.json +10 -0
  35. package/lib/pending.js +1 -5
  36. package/lib/reporters/base.js +95 -117
  37. package/lib/reporters/doc.js +23 -9
  38. package/lib/reporters/dot.js +19 -13
  39. package/lib/reporters/html.js +82 -47
  40. package/lib/reporters/json-stream.js +43 -23
  41. package/lib/reporters/json.js +32 -23
  42. package/lib/reporters/landing.js +16 -9
  43. package/lib/reporters/list.js +19 -11
  44. package/lib/reporters/markdown.js +18 -12
  45. package/lib/reporters/min.js +8 -4
  46. package/lib/reporters/nyan.js +42 -35
  47. package/lib/reporters/progress.js +12 -7
  48. package/lib/reporters/spec.js +23 -12
  49. package/lib/reporters/tap.js +250 -32
  50. package/lib/reporters/xunit.js +61 -35
  51. package/lib/runnable.js +152 -95
  52. package/lib/runner.js +296 -248
  53. package/lib/stats-collector.js +83 -0
  54. package/lib/suite.js +294 -75
  55. package/lib/test.js +16 -15
  56. package/lib/utils.js +419 -146
  57. package/mocha.js +4589 -2228
  58. package/package.json +137 -38
  59. package/lib/ms.js +0 -94
  60. package/lib/reporters/base.js.orig +0 -498
  61. package/lib/reporters/json.js.orig +0 -128
@@ -0,0 +1,83 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Provides a factory function for a {@link StatsCollector} object.
5
+ * @module
6
+ */
7
+
8
+ var constants = require('./runner').constants;
9
+ var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
10
+ var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
11
+ var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN;
12
+ var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;
13
+ var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
14
+ var EVENT_RUN_END = constants.EVENT_RUN_END;
15
+ var EVENT_TEST_END = constants.EVENT_TEST_END;
16
+
17
+ /**
18
+ * Test statistics collector.
19
+ *
20
+ * @public
21
+ * @typedef {Object} StatsCollector
22
+ * @property {number} suites - integer count of suites run.
23
+ * @property {number} tests - integer count of tests run.
24
+ * @property {number} passes - integer count of passing tests.
25
+ * @property {number} pending - integer count of pending tests.
26
+ * @property {number} failures - integer count of failed tests.
27
+ * @property {Date} start - time when testing began.
28
+ * @property {Date} end - time when testing concluded.
29
+ * @property {number} duration - number of msecs that testing took.
30
+ */
31
+
32
+ var Date = global.Date;
33
+
34
+ /**
35
+ * Provides stats such as test duration, number of tests passed / failed etc., by listening for events emitted by `runner`.
36
+ *
37
+ * @private
38
+ * @param {Runner} runner - Runner instance
39
+ * @throws {TypeError} If falsy `runner`
40
+ */
41
+ function createStatsCollector(runner) {
42
+ /**
43
+ * @type StatsCollector
44
+ */
45
+ var stats = {
46
+ suites: 0,
47
+ tests: 0,
48
+ passes: 0,
49
+ pending: 0,
50
+ failures: 0
51
+ };
52
+
53
+ if (!runner) {
54
+ throw new TypeError('Missing runner argument');
55
+ }
56
+
57
+ runner.stats = stats;
58
+
59
+ runner.once(EVENT_RUN_BEGIN, function() {
60
+ stats.start = new Date();
61
+ });
62
+ runner.on(EVENT_SUITE_BEGIN, function(suite) {
63
+ suite.root || stats.suites++;
64
+ });
65
+ runner.on(EVENT_TEST_PASS, function() {
66
+ stats.passes++;
67
+ });
68
+ runner.on(EVENT_TEST_FAIL, function() {
69
+ stats.failures++;
70
+ });
71
+ runner.on(EVENT_TEST_PENDING, function() {
72
+ stats.pending++;
73
+ });
74
+ runner.on(EVENT_TEST_END, function() {
75
+ stats.tests++;
76
+ });
77
+ runner.once(EVENT_RUN_END, function() {
78
+ stats.end = new Date();
79
+ stats.duration = stats.end - stats.start;
80
+ });
81
+ }
82
+
83
+ module.exports = createStatsCollector;
package/lib/suite.js CHANGED
@@ -1,7 +1,4 @@
1
1
  'use strict';
2
- /**
3
- * @module Suite
4
- */
5
2
 
6
3
  /**
7
4
  * Module dependencies.
@@ -11,7 +8,9 @@ var Hook = require('./hook');
11
8
  var utils = require('./utils');
12
9
  var inherits = utils.inherits;
13
10
  var debug = require('debug')('mocha:suite');
14
- var milliseconds = require('./ms');
11
+ var milliseconds = require('ms');
12
+ var errors = require('./errors');
13
+ var createInvalidArgumentTypeError = errors.createInvalidArgumentTypeError;
15
14
 
16
15
  /**
17
16
  * Expose `Suite`.
@@ -20,18 +19,14 @@ var milliseconds = require('./ms');
20
19
  exports = module.exports = Suite;
21
20
 
22
21
  /**
23
- * Create a new `Suite` with the given `title` and parent `Suite`. When a suite
24
- * with the same title is already present, that suite is returned to provide
25
- * nicer reporter and more flexible meta-testing.
22
+ * Create a new `Suite` with the given `title` and parent `Suite`.
26
23
  *
27
- * @memberof Mocha
28
24
  * @public
29
- * @api public
30
- * @param {Suite} parent
31
- * @param {string} title
25
+ * @param {Suite} parent - Parent suite (required!)
26
+ * @param {string} title - Title
32
27
  * @return {Suite}
33
28
  */
34
- exports.create = function (parent, title) {
29
+ Suite.create = function(parent, title) {
35
30
  var suite = new Suite(title, parent.ctx);
36
31
  suite.parent = parent;
37
32
  title = suite.fullTitle();
@@ -40,20 +35,28 @@ exports.create = function (parent, title) {
40
35
  };
41
36
 
42
37
  /**
43
- * Initialize a new `Suite` with the given `title` and `ctx`. Derived from [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
38
+ * Constructs a new `Suite` instance with the given `title`, `ctx`, and `isRoot`.
44
39
  *
45
- * @memberof Mocha
46
40
  * @public
47
41
  * @class
48
- * @param {string} title
49
- * @param {Context} parentContext
42
+ * @extends EventEmitter
43
+ * @see {@link https://nodejs.org/api/events.html#events_class_eventemitter|EventEmitter}
44
+ * @param {string} title - Suite title.
45
+ * @param {Context} parentContext - Parent context instance.
46
+ * @param {boolean} [isRoot=false] - Whether this is the root suite.
50
47
  */
51
- function Suite (title, parentContext) {
48
+ function Suite(title, parentContext, isRoot) {
52
49
  if (!utils.isString(title)) {
53
- throw new Error('Suite `title` should be a "string" but "' + typeof title + '" was given instead.');
50
+ throw createInvalidArgumentTypeError(
51
+ 'Suite argument "title" must be a string. Received type "' +
52
+ typeof title +
53
+ '"',
54
+ 'title',
55
+ 'string'
56
+ );
54
57
  }
55
58
  this.title = title;
56
- function Context () {}
59
+ function Context() {}
57
60
  Context.prototype = parentContext;
58
61
  this.ctx = new Context();
59
62
  this.suites = [];
@@ -63,7 +66,7 @@ function Suite (title, parentContext) {
63
66
  this._beforeAll = [];
64
67
  this._afterEach = [];
65
68
  this._afterAll = [];
66
- this.root = !title;
69
+ this.root = isRoot === true;
67
70
  this._timeout = 2000;
68
71
  this._enableTimeouts = true;
69
72
  this._slow = 75;
@@ -72,6 +75,16 @@ function Suite (title, parentContext) {
72
75
  this._onlyTests = [];
73
76
  this._onlySuites = [];
74
77
  this.delayed = false;
78
+
79
+ this.on('newListener', function(event) {
80
+ if (deprecatedEvents[event]) {
81
+ utils.deprecate(
82
+ 'Event "' +
83
+ event +
84
+ '" is deprecated. Please let the Mocha team know about your use case: https://git.io/v6Lwm'
85
+ );
86
+ }
87
+ });
75
88
  }
76
89
 
77
90
  /**
@@ -82,10 +95,10 @@ inherits(Suite, EventEmitter);
82
95
  /**
83
96
  * Return a clone of this `Suite`.
84
97
  *
85
- * @api private
98
+ * @private
86
99
  * @return {Suite}
87
100
  */
88
- Suite.prototype.clone = function () {
101
+ Suite.prototype.clone = function() {
89
102
  var suite = new Suite(this.title);
90
103
  debug('clone');
91
104
  suite.ctx = this.ctx;
@@ -100,11 +113,11 @@ Suite.prototype.clone = function () {
100
113
  /**
101
114
  * Set or get timeout `ms` or short-hand such as "2s".
102
115
  *
103
- * @api private
116
+ * @private
104
117
  * @param {number|string} ms
105
118
  * @return {Suite|number} for chaining
106
119
  */
107
- Suite.prototype.timeout = function (ms) {
120
+ Suite.prototype.timeout = function(ms) {
108
121
  if (!arguments.length) {
109
122
  return this._timeout;
110
123
  }
@@ -122,11 +135,11 @@ Suite.prototype.timeout = function (ms) {
122
135
  /**
123
136
  * Set or get number of times to retry a failed test.
124
137
  *
125
- * @api private
138
+ * @private
126
139
  * @param {number|string} n
127
140
  * @return {Suite|number} for chaining
128
141
  */
129
- Suite.prototype.retries = function (n) {
142
+ Suite.prototype.retries = function(n) {
130
143
  if (!arguments.length) {
131
144
  return this._retries;
132
145
  }
@@ -136,13 +149,13 @@ Suite.prototype.retries = function (n) {
136
149
  };
137
150
 
138
151
  /**
139
- * Set or get timeout to `enabled`.
140
- *
141
- * @api private
142
- * @param {boolean} enabled
143
- * @return {Suite|boolean} self or enabled
144
- */
145
- Suite.prototype.enableTimeouts = function (enabled) {
152
+ * Set or get timeout to `enabled`.
153
+ *
154
+ * @private
155
+ * @param {boolean} enabled
156
+ * @return {Suite|boolean} self or enabled
157
+ */
158
+ Suite.prototype.enableTimeouts = function(enabled) {
146
159
  if (!arguments.length) {
147
160
  return this._enableTimeouts;
148
161
  }
@@ -154,11 +167,11 @@ Suite.prototype.enableTimeouts = function (enabled) {
154
167
  /**
155
168
  * Set or get slow `ms` or short-hand such as "2s".
156
169
  *
157
- * @api private
170
+ * @private
158
171
  * @param {number|string} ms
159
172
  * @return {Suite|number} for chaining
160
173
  */
161
- Suite.prototype.slow = function (ms) {
174
+ Suite.prototype.slow = function(ms) {
162
175
  if (!arguments.length) {
163
176
  return this._slow;
164
177
  }
@@ -173,11 +186,11 @@ Suite.prototype.slow = function (ms) {
173
186
  /**
174
187
  * Set or get whether to bail after first error.
175
188
  *
176
- * @api private
189
+ * @private
177
190
  * @param {boolean} bail
178
191
  * @return {Suite|number} for chaining
179
192
  */
180
- Suite.prototype.bail = function (bail) {
193
+ Suite.prototype.bail = function(bail) {
181
194
  if (!arguments.length) {
182
195
  return this._bail;
183
196
  }
@@ -189,9 +202,9 @@ Suite.prototype.bail = function (bail) {
189
202
  /**
190
203
  * Check if this suite or its parent suite is marked as pending.
191
204
  *
192
- * @api private
205
+ * @private
193
206
  */
194
- Suite.prototype.isPending = function () {
207
+ Suite.prototype.isPending = function() {
195
208
  return this.pending || (this.parent && this.parent.isPending());
196
209
  };
197
210
 
@@ -202,7 +215,7 @@ Suite.prototype.isPending = function () {
202
215
  * @param {Function} fn - Hook callback
203
216
  * @returns {Hook} A new hook
204
217
  */
205
- Suite.prototype._createHook = function (title, fn) {
218
+ Suite.prototype._createHook = function(title, fn) {
206
219
  var hook = new Hook(title, fn);
207
220
  hook.parent = this;
208
221
  hook.timeout(this.timeout());
@@ -217,12 +230,12 @@ Suite.prototype._createHook = function (title, fn) {
217
230
  /**
218
231
  * Run `fn(test[, done])` before running tests.
219
232
  *
220
- * @api private
233
+ * @private
221
234
  * @param {string} title
222
235
  * @param {Function} fn
223
236
  * @return {Suite} for chaining
224
237
  */
225
- Suite.prototype.beforeAll = function (title, fn) {
238
+ Suite.prototype.beforeAll = function(title, fn) {
226
239
  if (this.isPending()) {
227
240
  return this;
228
241
  }
@@ -234,19 +247,19 @@ Suite.prototype.beforeAll = function (title, fn) {
234
247
 
235
248
  var hook = this._createHook(title, fn);
236
249
  this._beforeAll.push(hook);
237
- this.emit('beforeAll', hook);
250
+ this.emit(constants.EVENT_SUITE_ADD_HOOK_BEFORE_ALL, hook);
238
251
  return this;
239
252
  };
240
253
 
241
254
  /**
242
255
  * Run `fn(test[, done])` after running tests.
243
256
  *
244
- * @api private
257
+ * @private
245
258
  * @param {string} title
246
259
  * @param {Function} fn
247
260
  * @return {Suite} for chaining
248
261
  */
249
- Suite.prototype.afterAll = function (title, fn) {
262
+ Suite.prototype.afterAll = function(title, fn) {
250
263
  if (this.isPending()) {
251
264
  return this;
252
265
  }
@@ -258,19 +271,19 @@ Suite.prototype.afterAll = function (title, fn) {
258
271
 
259
272
  var hook = this._createHook(title, fn);
260
273
  this._afterAll.push(hook);
261
- this.emit('afterAll', hook);
274
+ this.emit(constants.EVENT_SUITE_ADD_HOOK_AFTER_ALL, hook);
262
275
  return this;
263
276
  };
264
277
 
265
278
  /**
266
279
  * Run `fn(test[, done])` before each test case.
267
280
  *
268
- * @api private
281
+ * @private
269
282
  * @param {string} title
270
283
  * @param {Function} fn
271
284
  * @return {Suite} for chaining
272
285
  */
273
- Suite.prototype.beforeEach = function (title, fn) {
286
+ Suite.prototype.beforeEach = function(title, fn) {
274
287
  if (this.isPending()) {
275
288
  return this;
276
289
  }
@@ -282,19 +295,19 @@ Suite.prototype.beforeEach = function (title, fn) {
282
295
 
283
296
  var hook = this._createHook(title, fn);
284
297
  this._beforeEach.push(hook);
285
- this.emit('beforeEach', hook);
298
+ this.emit(constants.EVENT_SUITE_ADD_HOOK_BEFORE_EACH, hook);
286
299
  return this;
287
300
  };
288
301
 
289
302
  /**
290
303
  * Run `fn(test[, done])` after each test case.
291
304
  *
292
- * @api private
305
+ * @private
293
306
  * @param {string} title
294
307
  * @param {Function} fn
295
308
  * @return {Suite} for chaining
296
309
  */
297
- Suite.prototype.afterEach = function (title, fn) {
310
+ Suite.prototype.afterEach = function(title, fn) {
298
311
  if (this.isPending()) {
299
312
  return this;
300
313
  }
@@ -306,37 +319,38 @@ Suite.prototype.afterEach = function (title, fn) {
306
319
 
307
320
  var hook = this._createHook(title, fn);
308
321
  this._afterEach.push(hook);
309
- this.emit('afterEach', hook);
322
+ this.emit(constants.EVENT_SUITE_ADD_HOOK_AFTER_EACH, hook);
310
323
  return this;
311
324
  };
312
325
 
313
326
  /**
314
327
  * Add a test `suite`.
315
328
  *
316
- * @api private
329
+ * @private
317
330
  * @param {Suite} suite
318
331
  * @return {Suite} for chaining
319
332
  */
320
- Suite.prototype.addSuite = function (suite) {
333
+ Suite.prototype.addSuite = function(suite) {
321
334
  suite.parent = this;
335
+ suite.root = false;
322
336
  suite.timeout(this.timeout());
323
337
  suite.retries(this.retries());
324
338
  suite.enableTimeouts(this.enableTimeouts());
325
339
  suite.slow(this.slow());
326
340
  suite.bail(this.bail());
327
341
  this.suites.push(suite);
328
- this.emit('suite', suite);
342
+ this.emit(constants.EVENT_SUITE_ADD_SUITE, suite);
329
343
  return this;
330
344
  };
331
345
 
332
346
  /**
333
347
  * Add a `test` to this suite.
334
348
  *
335
- * @api private
349
+ * @private
336
350
  * @param {Test} test
337
351
  * @return {Suite} for chaining
338
352
  */
339
- Suite.prototype.addTest = function (test) {
353
+ Suite.prototype.addTest = function(test) {
340
354
  test.parent = this;
341
355
  test.timeout(this.timeout());
342
356
  test.retries(this.retries());
@@ -344,7 +358,7 @@ Suite.prototype.addTest = function (test) {
344
358
  test.slow(this.slow());
345
359
  test.ctx = this.ctx;
346
360
  this.tests.push(test);
347
- this.emit('test', test);
361
+ this.emit(constants.EVENT_SUITE_ADD_TEST, test);
348
362
  return this;
349
363
  };
350
364
 
@@ -352,12 +366,11 @@ Suite.prototype.addTest = function (test) {
352
366
  * Return the full title generated by recursively concatenating the parent's
353
367
  * full title.
354
368
  *
355
- * @memberof Mocha.Suite
369
+ * @memberof Suite
356
370
  * @public
357
- * @api public
358
371
  * @return {string}
359
372
  */
360
- Suite.prototype.fullTitle = function () {
373
+ Suite.prototype.fullTitle = function() {
361
374
  return this.titlePath().join(' ');
362
375
  };
363
376
 
@@ -365,12 +378,11 @@ Suite.prototype.fullTitle = function () {
365
378
  * Return the title path generated by recursively concatenating the parent's
366
379
  * title path.
367
380
  *
368
- * @memberof Mocha.Suite
381
+ * @memberof Suite
369
382
  * @public
370
- * @api public
371
383
  * @return {string}
372
384
  */
373
- Suite.prototype.titlePath = function () {
385
+ Suite.prototype.titlePath = function() {
374
386
  var result = [];
375
387
  if (this.parent) {
376
388
  result = result.concat(this.parent.titlePath());
@@ -384,28 +396,29 @@ Suite.prototype.titlePath = function () {
384
396
  /**
385
397
  * Return the total number of tests.
386
398
  *
387
- * @memberof Mocha.Suite
399
+ * @memberof Suite
388
400
  * @public
389
- * @api public
390
401
  * @return {number}
391
402
  */
392
- Suite.prototype.total = function () {
393
- return this.suites.reduce(function (sum, suite) {
394
- return sum + suite.total();
395
- }, 0) + this.tests.length;
403
+ Suite.prototype.total = function() {
404
+ return (
405
+ this.suites.reduce(function(sum, suite) {
406
+ return sum + suite.total();
407
+ }, 0) + this.tests.length
408
+ );
396
409
  };
397
410
 
398
411
  /**
399
412
  * Iterates through each suite recursively to find all tests. Applies a
400
413
  * function in the format `fn(test)`.
401
414
  *
402
- * @api private
415
+ * @private
403
416
  * @param {Function} fn
404
417
  * @return {Suite}
405
418
  */
406
- Suite.prototype.eachTest = function (fn) {
419
+ Suite.prototype.eachTest = function(fn) {
407
420
  this.tests.forEach(fn);
408
- this.suites.forEach(function (suite) {
421
+ this.suites.forEach(function(suite) {
409
422
  suite.eachTest(fn);
410
423
  });
411
424
  return this;
@@ -413,9 +426,215 @@ Suite.prototype.eachTest = function (fn) {
413
426
 
414
427
  /**
415
428
  * This will run the root suite if we happen to be running in delayed mode.
429
+ * @private
416
430
  */
417
- Suite.prototype.run = function run () {
431
+ Suite.prototype.run = function run() {
418
432
  if (this.root) {
419
- this.emit('run');
433
+ this.emit(constants.EVENT_ROOT_SUITE_RUN);
434
+ }
435
+ };
436
+
437
+ /**
438
+ * Determines whether a suite has an `only` test or suite as a descendant.
439
+ *
440
+ * @private
441
+ * @returns {Boolean}
442
+ */
443
+ Suite.prototype.hasOnly = function hasOnly() {
444
+ return (
445
+ this._onlyTests.length > 0 ||
446
+ this._onlySuites.length > 0 ||
447
+ this.suites.some(function(suite) {
448
+ return suite.hasOnly();
449
+ })
450
+ );
451
+ };
452
+
453
+ /**
454
+ * Filter suites based on `isOnly` logic.
455
+ *
456
+ * @private
457
+ * @returns {Boolean}
458
+ */
459
+ Suite.prototype.filterOnly = function filterOnly() {
460
+ if (this._onlyTests.length) {
461
+ // If the suite contains `only` tests, run those and ignore any nested suites.
462
+ this.tests = this._onlyTests;
463
+ this.suites = [];
464
+ } else {
465
+ // Otherwise, do not run any of the tests in this suite.
466
+ this.tests = [];
467
+ this._onlySuites.forEach(function(onlySuite) {
468
+ // If there are other `only` tests/suites nested in the current `only` suite, then filter that `only` suite.
469
+ // Otherwise, all of the tests on this `only` suite should be run, so don't filter it.
470
+ if (onlySuite.hasOnly()) {
471
+ onlySuite.filterOnly();
472
+ }
473
+ });
474
+ // Run the `only` suites, as well as any other suites that have `only` tests/suites as descendants.
475
+ var onlySuites = this._onlySuites;
476
+ this.suites = this.suites.filter(function(childSuite) {
477
+ return onlySuites.indexOf(childSuite) !== -1 || childSuite.filterOnly();
478
+ });
420
479
  }
480
+ // Keep the suite only if there is something to run
481
+ return this.tests.length > 0 || this.suites.length > 0;
421
482
  };
483
+
484
+ /**
485
+ * Adds a suite to the list of subsuites marked `only`.
486
+ *
487
+ * @private
488
+ * @param {Suite} suite
489
+ */
490
+ Suite.prototype.appendOnlySuite = function(suite) {
491
+ this._onlySuites.push(suite);
492
+ };
493
+
494
+ /**
495
+ * Adds a test to the list of tests marked `only`.
496
+ *
497
+ * @private
498
+ * @param {Test} test
499
+ */
500
+ Suite.prototype.appendOnlyTest = function(test) {
501
+ this._onlyTests.push(test);
502
+ };
503
+
504
+ /**
505
+ * Returns the array of hooks by hook name; see `HOOK_TYPE_*` constants.
506
+ * @private
507
+ */
508
+ Suite.prototype.getHooks = function getHooks(name) {
509
+ return this['_' + name];
510
+ };
511
+
512
+ /**
513
+ * Cleans up the references to all the deferred functions
514
+ * (before/after/beforeEach/afterEach) and tests of a Suite.
515
+ * These must be deleted otherwise a memory leak can happen,
516
+ * as those functions may reference variables from closures,
517
+ * thus those variables can never be garbage collected as long
518
+ * as the deferred functions exist.
519
+ *
520
+ * @private
521
+ */
522
+ Suite.prototype.cleanReferences = function cleanReferences() {
523
+ function cleanArrReferences(arr) {
524
+ for (var i = 0; i < arr.length; i++) {
525
+ delete arr[i].fn;
526
+ }
527
+ }
528
+
529
+ if (Array.isArray(this._beforeAll)) {
530
+ cleanArrReferences(this._beforeAll);
531
+ }
532
+
533
+ if (Array.isArray(this._beforeEach)) {
534
+ cleanArrReferences(this._beforeEach);
535
+ }
536
+
537
+ if (Array.isArray(this._afterAll)) {
538
+ cleanArrReferences(this._afterAll);
539
+ }
540
+
541
+ if (Array.isArray(this._afterEach)) {
542
+ cleanArrReferences(this._afterEach);
543
+ }
544
+
545
+ for (var i = 0; i < this.tests.length; i++) {
546
+ delete this.tests[i].fn;
547
+ }
548
+ };
549
+
550
+ var constants = utils.defineConstants(
551
+ /**
552
+ * {@link Suite}-related constants.
553
+ * @public
554
+ * @memberof Suite
555
+ * @alias constants
556
+ * @readonly
557
+ * @static
558
+ * @enum {string}
559
+ */
560
+ {
561
+ /**
562
+ * Event emitted after a test file has been loaded Not emitted in browser.
563
+ */
564
+ EVENT_FILE_POST_REQUIRE: 'post-require',
565
+ /**
566
+ * Event emitted before a test file has been loaded. In browser, this is emitted once an interface has been selected.
567
+ */
568
+ EVENT_FILE_PRE_REQUIRE: 'pre-require',
569
+ /**
570
+ * Event emitted immediately after a test file has been loaded. Not emitted in browser.
571
+ */
572
+ EVENT_FILE_REQUIRE: 'require',
573
+ /**
574
+ * Event emitted when `global.run()` is called (use with `delay` option)
575
+ */
576
+ EVENT_ROOT_SUITE_RUN: 'run',
577
+
578
+ /**
579
+ * Namespace for collection of a `Suite`'s "after all" hooks
580
+ */
581
+ HOOK_TYPE_AFTER_ALL: 'afterAll',
582
+ /**
583
+ * Namespace for collection of a `Suite`'s "after each" hooks
584
+ */
585
+ HOOK_TYPE_AFTER_EACH: 'afterEach',
586
+ /**
587
+ * Namespace for collection of a `Suite`'s "before all" hooks
588
+ */
589
+ HOOK_TYPE_BEFORE_ALL: 'beforeAll',
590
+ /**
591
+ * Namespace for collection of a `Suite`'s "before all" hooks
592
+ */
593
+ HOOK_TYPE_BEFORE_EACH: 'beforeEach',
594
+
595
+ // the following events are all deprecated
596
+
597
+ /**
598
+ * Emitted after an "after all" `Hook` has been added to a `Suite`. Deprecated
599
+ */
600
+ EVENT_SUITE_ADD_HOOK_AFTER_ALL: 'afterAll',
601
+ /**
602
+ * Emitted after an "after each" `Hook` has been added to a `Suite` Deprecated
603
+ */
604
+ EVENT_SUITE_ADD_HOOK_AFTER_EACH: 'afterEach',
605
+ /**
606
+ * Emitted after an "before all" `Hook` has been added to a `Suite` Deprecated
607
+ */
608
+ EVENT_SUITE_ADD_HOOK_BEFORE_ALL: 'beforeAll',
609
+ /**
610
+ * Emitted after an "before each" `Hook` has been added to a `Suite` Deprecated
611
+ */
612
+ EVENT_SUITE_ADD_HOOK_BEFORE_EACH: 'beforeEach',
613
+ /**
614
+ * Emitted after a child `Suite` has been added to a `Suite`. Deprecated
615
+ */
616
+ EVENT_SUITE_ADD_SUITE: 'suite',
617
+ /**
618
+ * Emitted after a `Test` has been added to a `Suite`. Deprecated
619
+ */
620
+ EVENT_SUITE_ADD_TEST: 'test'
621
+ }
622
+ );
623
+
624
+ /**
625
+ * @summary There are no known use cases for these events.
626
+ * @desc This is a `Set`-like object having all keys being the constant's string value and the value being `true`.
627
+ * @todo Remove eventually
628
+ * @type {Object<string,boolean>}
629
+ * @ignore
630
+ */
631
+ var deprecatedEvents = Object.keys(constants)
632
+ .filter(function(constant) {
633
+ return constant.substring(0, 15) === 'EVENT_SUITE_ADD';
634
+ })
635
+ .reduce(function(acc, constant) {
636
+ acc[constants[constant]] = true;
637
+ return acc;
638
+ }, utils.createMap());
639
+
640
+ Suite.constants = constants;