mocha-compat 3.6.4 → 10.8.2

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