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
package/lib/context.js CHANGED
@@ -11,18 +11,18 @@ module.exports = Context;
11
11
  /**
12
12
  * Initialize a new `Context`.
13
13
  *
14
- * @api private
14
+ * @private
15
15
  */
16
- function Context () {}
16
+ function Context() {}
17
17
 
18
18
  /**
19
19
  * Set or get the context `Runnable` to `runnable`.
20
20
  *
21
- * @api private
21
+ * @private
22
22
  * @param {Runnable} runnable
23
23
  * @return {Context} context
24
24
  */
25
- Context.prototype.runnable = function (runnable) {
25
+ Context.prototype.runnable = function(runnable) {
26
26
  if (!arguments.length) {
27
27
  return this._runnable;
28
28
  }
@@ -33,11 +33,11 @@ Context.prototype.runnable = function (runnable) {
33
33
  /**
34
34
  * Set or get test timeout `ms`.
35
35
  *
36
- * @api private
36
+ * @private
37
37
  * @param {number} ms
38
38
  * @return {Context} self
39
39
  */
40
- Context.prototype.timeout = function (ms) {
40
+ Context.prototype.timeout = function(ms) {
41
41
  if (!arguments.length) {
42
42
  return this.runnable().timeout();
43
43
  }
@@ -48,11 +48,11 @@ Context.prototype.timeout = function (ms) {
48
48
  /**
49
49
  * Set test timeout `enabled`.
50
50
  *
51
- * @api private
51
+ * @private
52
52
  * @param {boolean} enabled
53
53
  * @return {Context} self
54
54
  */
55
- Context.prototype.enableTimeouts = function (enabled) {
55
+ Context.prototype.enableTimeouts = function(enabled) {
56
56
  if (!arguments.length) {
57
57
  return this.runnable().enableTimeouts();
58
58
  }
@@ -63,11 +63,11 @@ Context.prototype.enableTimeouts = function (enabled) {
63
63
  /**
64
64
  * Set or get test slowness threshold `ms`.
65
65
  *
66
- * @api private
66
+ * @private
67
67
  * @param {number} ms
68
68
  * @return {Context} self
69
69
  */
70
- Context.prototype.slow = function (ms) {
70
+ Context.prototype.slow = function(ms) {
71
71
  if (!arguments.length) {
72
72
  return this.runnable().slow();
73
73
  }
@@ -78,21 +78,21 @@ Context.prototype.slow = function (ms) {
78
78
  /**
79
79
  * Mark a test as skipped.
80
80
  *
81
- * @api private
81
+ * @private
82
82
  * @throws Pending
83
83
  */
84
- Context.prototype.skip = function () {
84
+ Context.prototype.skip = function() {
85
85
  this.runnable().skip();
86
86
  };
87
87
 
88
88
  /**
89
89
  * Set or get a number of allowed retries on failed tests
90
90
  *
91
- * @api private
91
+ * @private
92
92
  * @param {number} n
93
93
  * @return {Context} self
94
94
  */
95
- Context.prototype.retries = function (n) {
95
+ Context.prototype.retries = function(n) {
96
96
  if (!arguments.length) {
97
97
  return this.runnable().retries();
98
98
  }
package/lib/errors.js ADDED
@@ -0,0 +1,141 @@
1
+ 'use strict';
2
+ /**
3
+ * @module Errors
4
+ */
5
+ /**
6
+ * Factory functions to create throwable error objects
7
+ */
8
+
9
+ /**
10
+ * Creates an error object to be thrown when no files to be tested could be found using specified pattern.
11
+ *
12
+ * @public
13
+ * @param {string} message - Error message to be displayed.
14
+ * @param {string} pattern - User-specified argument value.
15
+ * @returns {Error} instance detailing the error condition
16
+ */
17
+ function createNoFilesMatchPatternError(message, pattern) {
18
+ var err = new Error(message);
19
+ err.code = 'ERR_MOCHA_NO_FILES_MATCH_PATTERN';
20
+ err.pattern = pattern;
21
+ return err;
22
+ }
23
+
24
+ /**
25
+ * Creates an error object to be thrown when the reporter specified in the options was not found.
26
+ *
27
+ * @public
28
+ * @param {string} message - Error message to be displayed.
29
+ * @param {string} reporter - User-specified reporter value.
30
+ * @returns {Error} instance detailing the error condition
31
+ */
32
+ function createInvalidReporterError(message, reporter) {
33
+ var err = new TypeError(message);
34
+ err.code = 'ERR_MOCHA_INVALID_REPORTER';
35
+ err.reporter = reporter;
36
+ return err;
37
+ }
38
+
39
+ /**
40
+ * Creates an error object to be thrown when the interface specified in the options was not found.
41
+ *
42
+ * @public
43
+ * @param {string} message - Error message to be displayed.
44
+ * @param {string} ui - User-specified interface value.
45
+ * @returns {Error} instance detailing the error condition
46
+ */
47
+ function createInvalidInterfaceError(message, ui) {
48
+ var err = new Error(message);
49
+ err.code = 'ERR_MOCHA_INVALID_INTERFACE';
50
+ err.interface = ui;
51
+ return err;
52
+ }
53
+
54
+ /**
55
+ * Creates an error object to be thrown when a behavior, option, or parameter is unsupported.
56
+ *
57
+ * @public
58
+ * @param {string} message - Error message to be displayed.
59
+ * @returns {Error} instance detailing the error condition
60
+ */
61
+ function createUnsupportedError(message) {
62
+ var err = new Error(message);
63
+ err.code = 'ERR_MOCHA_UNSUPPORTED';
64
+ return err;
65
+ }
66
+
67
+ /**
68
+ * Creates an error object to be thrown when an argument is missing.
69
+ *
70
+ * @public
71
+ * @param {string} message - Error message to be displayed.
72
+ * @param {string} argument - Argument name.
73
+ * @param {string} expected - Expected argument datatype.
74
+ * @returns {Error} instance detailing the error condition
75
+ */
76
+ function createMissingArgumentError(message, argument, expected) {
77
+ return createInvalidArgumentTypeError(message, argument, expected);
78
+ }
79
+
80
+ /**
81
+ * Creates an error object to be thrown when an argument did not use the supported type
82
+ *
83
+ * @public
84
+ * @param {string} message - Error message to be displayed.
85
+ * @param {string} argument - Argument name.
86
+ * @param {string} expected - Expected argument datatype.
87
+ * @returns {Error} instance detailing the error condition
88
+ */
89
+ function createInvalidArgumentTypeError(message, argument, expected) {
90
+ var err = new TypeError(message);
91
+ err.code = 'ERR_MOCHA_INVALID_ARG_TYPE';
92
+ err.argument = argument;
93
+ err.expected = expected;
94
+ err.actual = typeof argument;
95
+ return err;
96
+ }
97
+
98
+ /**
99
+ * Creates an error object to be thrown when an argument did not use the supported value
100
+ *
101
+ * @public
102
+ * @param {string} message - Error message to be displayed.
103
+ * @param {string} argument - Argument name.
104
+ * @param {string} value - Argument value.
105
+ * @param {string} [reason] - Why value is invalid.
106
+ * @returns {Error} instance detailing the error condition
107
+ */
108
+ function createInvalidArgumentValueError(message, argument, value, reason) {
109
+ var err = new TypeError(message);
110
+ err.code = 'ERR_MOCHA_INVALID_ARG_VALUE';
111
+ err.argument = argument;
112
+ err.value = value;
113
+ err.reason = typeof reason !== 'undefined' ? reason : 'is invalid';
114
+ return err;
115
+ }
116
+
117
+ /**
118
+ * Creates an error object to be thrown when an exception was caught, but the `Error` is falsy or undefined.
119
+ *
120
+ * @public
121
+ * @param {string} message - Error message to be displayed.
122
+ * @returns {Error} instance detailing the error condition
123
+ */
124
+ function createInvalidExceptionError(message, value) {
125
+ var err = new Error(message);
126
+ err.code = 'ERR_MOCHA_INVALID_EXCEPTION';
127
+ err.valueType = typeof value;
128
+ err.value = value;
129
+ return err;
130
+ }
131
+
132
+ module.exports = {
133
+ createInvalidArgumentTypeError: createInvalidArgumentTypeError,
134
+ createInvalidArgumentValueError: createInvalidArgumentValueError,
135
+ createInvalidExceptionError: createInvalidExceptionError,
136
+ createInvalidInterfaceError: createInvalidInterfaceError,
137
+ createInvalidReporterError: createInvalidReporterError,
138
+ createMissingArgumentError: createMissingArgumentError,
139
+ createNoFilesMatchPatternError: createNoFilesMatchPatternError,
140
+ createUnsupportedError: createUnsupportedError
141
+ };
package/lib/growl.js ADDED
@@ -0,0 +1,136 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Desktop Notifications module.
5
+ * @module Growl
6
+ */
7
+
8
+ const os = require('os');
9
+ const path = require('path');
10
+ const {sync: which} = require('which');
11
+ const {EVENT_RUN_END} = require('./runner').constants;
12
+
13
+ /**
14
+ * @summary
15
+ * Checks if Growl notification support seems likely.
16
+ *
17
+ * @description
18
+ * Glosses over the distinction between an unsupported platform
19
+ * and one that lacks prerequisite software installations.
20
+ *
21
+ * @public
22
+ * @see {@link https://github.com/tj/node-growl/blob/master/README.md|Prerequisite Installs}
23
+ * @see {@link Mocha#growl}
24
+ * @see {@link Mocha#isGrowlCapable}
25
+ * @return {boolean} whether Growl notification support can be expected
26
+ */
27
+ exports.isCapable = () => {
28
+ if (!process.browser) {
29
+ return getSupportBinaries().reduce(
30
+ (acc, binary) => acc || Boolean(which(binary, {nothrow: true})),
31
+ false
32
+ );
33
+ }
34
+ return false;
35
+ };
36
+
37
+ /**
38
+ * Implements desktop notifications as a pseudo-reporter.
39
+ *
40
+ * @public
41
+ * @see {@link Mocha#_growl}
42
+ * @param {Runner} runner - Runner instance.
43
+ */
44
+ exports.notify = runner => {
45
+ runner.once(EVENT_RUN_END, () => {
46
+ display(runner);
47
+ });
48
+ };
49
+
50
+ /**
51
+ * Displays the notification.
52
+ *
53
+ * @private
54
+ * @param {Runner} runner - Runner instance.
55
+ */
56
+ const display = runner => {
57
+ const growl = require('growl');
58
+ const stats = runner.stats;
59
+ const symbol = {
60
+ cross: '\u274C',
61
+ tick: '\u2705'
62
+ };
63
+ let _message;
64
+ let message;
65
+ let title;
66
+
67
+ if (stats.failures) {
68
+ _message = `${stats.failures} of ${stats.tests} tests failed`;
69
+ message = `${symbol.cross} ${_message}`;
70
+ title = 'Failed';
71
+ } else {
72
+ _message = `${stats.passes} tests passed in ${stats.duration}ms`;
73
+ message = `${symbol.tick} ${_message}`;
74
+ title = 'Passed';
75
+ }
76
+
77
+ // Send notification
78
+ const options = {
79
+ image: logo(),
80
+ name: 'mocha',
81
+ title
82
+ };
83
+ growl(message, options, onCompletion);
84
+ };
85
+
86
+ /**
87
+ * @summary
88
+ * Callback for result of attempted Growl notification.
89
+ *
90
+ * @description
91
+ * Despite its appearance, this is <strong>not</strong> an Error-first
92
+ * callback -- all parameters are populated regardless of success.
93
+ *
94
+ * @private
95
+ * @callback Growl~growlCB
96
+ * @param {*} err - Error object, or <code>null</code> if successful.
97
+ */
98
+ function onCompletion(err) {
99
+ if (err) {
100
+ // As notifications are tangential to our purpose, just log the error.
101
+ const message =
102
+ err.code === 'ENOENT' ? 'prerequisite software not found' : err.message;
103
+ console.error('notification error:', message);
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Returns Mocha logo image path.
109
+ *
110
+ * @private
111
+ * @return {string} Pathname of Mocha logo
112
+ */
113
+ const logo = () => {
114
+ return path.join(__dirname, '..', 'assets', 'mocha-logo-96.png');
115
+ };
116
+
117
+ /**
118
+ * @summary
119
+ * Gets platform-specific Growl support binaries.
120
+ *
121
+ * @description
122
+ * Somewhat brittle dependency on `growl` package implementation, but it
123
+ * rarely changes.
124
+ *
125
+ * @private
126
+ * @see {@link https://github.com/tj/node-growl/blob/master/lib/growl.js#L28-L126|setupCmd}
127
+ * @return {string[]} names of Growl support binaries
128
+ */
129
+ const getSupportBinaries = () => {
130
+ const binaries = {
131
+ Darwin: ['terminal-notifier', 'growlnotify'],
132
+ Linux: ['notify-send', 'growl'],
133
+ Windows_NT: ['growlnotify.exe']
134
+ };
135
+ return binaries[os.type()] || [];
136
+ };
package/lib/hook.js CHANGED
@@ -1,11 +1,4 @@
1
1
  'use strict';
2
- /**
3
- * @module Hook
4
- *
5
- */
6
- /**
7
- * Module dependencies.
8
- */
9
2
 
10
3
  var Runnable = require('./runnable');
11
4
  var inherits = require('./utils').inherits;
@@ -17,17 +10,14 @@ var inherits = require('./utils').inherits;
17
10
  module.exports = Hook;
18
11
 
19
12
  /**
20
- * Initialize a new `Hook` with the given `title` and callback `fn`. Derived from
21
- * `Runnable`.
13
+ * Initialize a new `Hook` with the given `title` and callback `fn`
22
14
  *
23
- * @memberof Mocha
24
- * @public
25
15
  * @class
16
+ * @extends Runnable
26
17
  * @param {String} title
27
18
  * @param {Function} fn
28
- * @api private
29
19
  */
30
- function Hook (title, fn) {
20
+ function Hook(title, fn) {
31
21
  Runnable.call(this, title, fn);
32
22
  this.type = 'hook';
33
23
  }
@@ -40,13 +30,12 @@ inherits(Hook, Runnable);
40
30
  /**
41
31
  * Get or set the test `err`.
42
32
  *
43
- * @memberof Mocha.Hook
33
+ * @memberof Hook
44
34
  * @public
45
35
  * @param {Error} err
46
36
  * @return {Error}
47
- * @api public
48
37
  */
49
- Hook.prototype.error = function (err) {
38
+ Hook.prototype.error = function(err) {
50
39
  if (!arguments.length) {
51
40
  err = this._error;
52
41
  this._error = null;
@@ -1,10 +1,8 @@
1
1
  'use strict';
2
2
 
3
- /**
4
- * Module dependencies.
5
- */
6
-
7
3
  var Test = require('../test');
4
+ var EVENT_FILE_PRE_REQUIRE = require('../suite').constants
5
+ .EVENT_FILE_PRE_REQUIRE;
8
6
 
9
7
  /**
10
8
  * BDD-style interface:
@@ -23,10 +21,10 @@ var Test = require('../test');
23
21
  *
24
22
  * @param {Suite} suite Root suite.
25
23
  */
26
- module.exports = function (suite) {
24
+ module.exports = function bddInterface(suite) {
27
25
  var suites = [suite];
28
26
 
29
- suite.on('pre-require', function (context, file, mocha) {
27
+ suite.on(EVENT_FILE_PRE_REQUIRE, function(context, file, mocha) {
30
28
  var common = require('./common')(suites, context, mocha);
31
29
 
32
30
  context.before = common.before;
@@ -40,7 +38,7 @@ module.exports = function (suite) {
40
38
  * and/or tests.
41
39
  */
42
40
 
43
- context.describe = context.context = function (title, fn) {
41
+ context.describe = context.context = function(title, fn) {
44
42
  return common.suite.create({
45
43
  title: title,
46
44
  file: file,
@@ -52,7 +50,10 @@ module.exports = function (suite) {
52
50
  * Pending describe.
53
51
  */
54
52
 
55
- context.xdescribe = context.xcontext = context.describe.skip = function (title, fn) {
53
+ context.xdescribe = context.xcontext = context.describe.skip = function(
54
+ title,
55
+ fn
56
+ ) {
56
57
  return common.suite.skip({
57
58
  title: title,
58
59
  file: file,
@@ -64,7 +65,7 @@ module.exports = function (suite) {
64
65
  * Exclusive suite.
65
66
  */
66
67
 
67
- context.describe.only = function (title, fn) {
68
+ context.describe.only = function(title, fn) {
68
69
  return common.suite.only({
69
70
  title: title,
70
71
  file: file,
@@ -78,7 +79,7 @@ module.exports = function (suite) {
78
79
  * acting as a thunk.
79
80
  */
80
81
 
81
- context.it = context.specify = function (title, fn) {
82
+ context.it = context.specify = function(title, fn) {
82
83
  var suite = suites[0];
83
84
  if (suite.isPending()) {
84
85
  fn = null;
@@ -93,7 +94,7 @@ module.exports = function (suite) {
93
94
  * Exclusive test-case.
94
95
  */
95
96
 
96
- context.it.only = function (title, fn) {
97
+ context.it.only = function(title, fn) {
97
98
  return common.test.only(mocha, context.it(title, fn));
98
99
  };
99
100
 
@@ -101,15 +102,17 @@ module.exports = function (suite) {
101
102
  * Pending test case.
102
103
  */
103
104
 
104
- context.xit = context.xspecify = context.it.skip = function (title) {
105
+ context.xit = context.xspecify = context.it.skip = function(title) {
105
106
  return context.it(title);
106
107
  };
107
108
 
108
109
  /**
109
110
  * Number of attempts to retry.
110
111
  */
111
- context.it.retries = function (n) {
112
+ context.it.retries = function(n) {
112
113
  context.retries(n);
113
114
  };
114
115
  });
115
116
  };
117
+
118
+ module.exports.description = 'BDD or RSpec style [default]';
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  var Suite = require('../suite');
4
+ var utils = require('../utils');
5
+ var errors = require('../errors');
6
+ var createMissingArgumentError = errors.createMissingArgumentError;
4
7
 
5
8
  /**
6
9
  * Functions common to more than one interface.
@@ -10,7 +13,23 @@ var Suite = require('../suite');
10
13
  * @param {Mocha} mocha
11
14
  * @return {Object} An object containing common functions.
12
15
  */
13
- module.exports = function (suites, context, mocha) {
16
+ module.exports = function(suites, context, mocha) {
17
+ /**
18
+ * Check if the suite should be tested.
19
+ *
20
+ * @private
21
+ * @param {Suite} suite - suite to check
22
+ * @returns {boolean}
23
+ */
24
+ function shouldBeTested(suite) {
25
+ return (
26
+ !mocha.options.grep ||
27
+ (mocha.options.grep &&
28
+ mocha.options.grep.test(suite.fullTitle()) &&
29
+ !mocha.options.invert)
30
+ );
31
+ }
32
+
14
33
  return {
15
34
  /**
16
35
  * This is only present if flag --delay is passed into Mocha. It triggers
@@ -19,8 +38,8 @@ module.exports = function (suites, context, mocha) {
19
38
  * @param {Suite} suite The root suite.
20
39
  * @return {Function} A function which runs the root suite
21
40
  */
22
- runWithSuite: function runWithSuite (suite) {
23
- return function run () {
41
+ runWithSuite: function runWithSuite(suite) {
42
+ return function run() {
24
43
  suite.run();
25
44
  };
26
45
  },
@@ -31,7 +50,7 @@ module.exports = function (suites, context, mocha) {
31
50
  * @param {string} name
32
51
  * @param {Function} fn
33
52
  */
34
- before: function (name, fn) {
53
+ before: function(name, fn) {
35
54
  suites[0].beforeAll(name, fn);
36
55
  },
37
56
 
@@ -41,7 +60,7 @@ module.exports = function (suites, context, mocha) {
41
60
  * @param {string} name
42
61
  * @param {Function} fn
43
62
  */
44
- after: function (name, fn) {
63
+ after: function(name, fn) {
45
64
  suites[0].afterAll(name, fn);
46
65
  },
47
66
 
@@ -51,7 +70,7 @@ module.exports = function (suites, context, mocha) {
51
70
  * @param {string} name
52
71
  * @param {Function} fn
53
72
  */
54
- beforeEach: function (name, fn) {
73
+ beforeEach: function(name, fn) {
55
74
  suites[0].beforeEach(name, fn);
56
75
  },
57
76
 
@@ -61,7 +80,7 @@ module.exports = function (suites, context, mocha) {
61
80
  * @param {string} name
62
81
  * @param {Function} fn
63
82
  */
64
- afterEach: function (name, fn) {
83
+ afterEach: function(name, fn) {
65
84
  suites[0].afterEach(name, fn);
66
85
  },
67
86
 
@@ -73,7 +92,7 @@ module.exports = function (suites, context, mocha) {
73
92
  * @param {Object} opts
74
93
  * @returns {Suite}
75
94
  */
76
- only: function only (opts) {
95
+ only: function only(opts) {
77
96
  opts.isOnly = true;
78
97
  return this.create(opts);
79
98
  },
@@ -85,13 +104,14 @@ module.exports = function (suites, context, mocha) {
85
104
  * @param {Object} opts
86
105
  * @returns {Suite}
87
106
  */
88
- skip: function skip (opts) {
107
+ skip: function skip(opts) {
89
108
  opts.pending = true;
90
109
  return this.create(opts);
91
110
  },
92
111
 
93
112
  /**
94
113
  * Creates a suite.
114
+ *
95
115
  * @param {Object} opts Options
96
116
  * @param {string} opts.title Title of Suite
97
117
  * @param {Function} [opts.fn] Suite Function (not always applicable)
@@ -100,19 +120,44 @@ module.exports = function (suites, context, mocha) {
100
120
  * @param {boolean} [opts.isOnly] Is Suite exclusive?
101
121
  * @returns {Suite}
102
122
  */
103
- create: function create (opts) {
123
+ create: function create(opts) {
104
124
  var suite = Suite.create(suites[0], opts.title);
105
125
  suite.pending = Boolean(opts.pending);
106
126
  suite.file = opts.file;
107
127
  suites.unshift(suite);
108
128
  if (opts.isOnly) {
109
- suite.parent._onlySuites = suite.parent._onlySuites.concat(suite);
129
+ if (mocha.options.forbidOnly && shouldBeTested(suite)) {
130
+ throw new Error('`.only` forbidden');
131
+ }
132
+
133
+ suite.parent.appendOnlySuite(suite);
134
+ }
135
+ if (suite.pending) {
136
+ if (mocha.options.forbidPending && shouldBeTested(suite)) {
137
+ throw new Error('Pending test forbidden');
138
+ }
110
139
  }
111
140
  if (typeof opts.fn === 'function') {
112
- opts.fn.call(suite);
141
+ var result = opts.fn.call(suite);
142
+ if (typeof result !== 'undefined') {
143
+ utils.deprecate(
144
+ 'Suites ignore return values. Suite "' +
145
+ suite.fullTitle() +
146
+ '" in ' +
147
+ suite.file +
148
+ ' returned a value; this may be a bug in your test code'
149
+ );
150
+ }
113
151
  suites.shift();
114
152
  } else if (typeof opts.fn === 'undefined' && !suite.pending) {
115
- throw new Error('Suite "' + suite.fullTitle() + '" was defined but no callback was supplied. Supply a callback or explicitly skip the suite.');
153
+ throw createMissingArgumentError(
154
+ 'Suite "' +
155
+ suite.fullTitle() +
156
+ '" was defined but no callback was supplied. ' +
157
+ 'Supply a callback or explicitly skip the suite.',
158
+ 'callback',
159
+ 'function'
160
+ );
116
161
  } else if (!opts.fn && suite.pending) {
117
162
  suites.shift();
118
163
  }
@@ -122,7 +167,6 @@ module.exports = function (suites, context, mocha) {
122
167
  },
123
168
 
124
169
  test: {
125
-
126
170
  /**
127
171
  * Exclusive test-case.
128
172
  *
@@ -130,8 +174,8 @@ module.exports = function (suites, context, mocha) {
130
174
  * @param {Function} test
131
175
  * @returns {*}
132
176
  */
133
- only: function (mocha, test) {
134
- test.parent._onlyTests = test.parent._onlyTests.concat(test);
177
+ only: function(mocha, test) {
178
+ test.parent.appendOnlyTest(test);
135
179
  return test;
136
180
  },
137
181
 
@@ -140,7 +184,7 @@ module.exports = function (suites, context, mocha) {
140
184
  *
141
185
  * @param {string} title
142
186
  */
143
- skip: function (title) {
187
+ skip: function(title) {
144
188
  context.test(title);
145
189
  },
146
190
 
@@ -149,7 +193,7 @@ module.exports = function (suites, context, mocha) {
149
193
  *
150
194
  * @param {number} n
151
195
  */
152
- retries: function (n) {
196
+ retries: function(n) {
153
197
  context.retries(n);
154
198
  }
155
199
  }