mocha 7.0.1 → 7.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.
package/lib/errors.js CHANGED
@@ -1,10 +1,73 @@
1
1
  'use strict';
2
+
3
+ var format = require('util').format;
4
+
2
5
  /**
6
+ * Factory functions to create throwable error objects
3
7
  * @module Errors
4
8
  */
9
+
5
10
  /**
6
- * Factory functions to create throwable error objects
11
+ * When Mocha throw exceptions (or otherwise errors), it attempts to assign a
12
+ * `code` property to the `Error` object, for easier handling. These are the
13
+ * potential values of `code`.
7
14
  */
15
+ var constants = {
16
+ /**
17
+ * An unrecoverable error.
18
+ */
19
+ FATAL: 'ERR_MOCHA_FATAL',
20
+
21
+ /**
22
+ * The type of an argument to a function call is invalid
23
+ */
24
+ INVALID_ARG_TYPE: 'ERR_MOCHA_INVALID_ARG_TYPE',
25
+
26
+ /**
27
+ * The value of an argument to a function call is invalid
28
+ */
29
+ INVALID_ARG_VALUE: 'ERR_MOCHA_INVALID_ARG_VALUE',
30
+
31
+ /**
32
+ * Something was thrown, but it wasn't an `Error`
33
+ */
34
+ INVALID_EXCEPTION: 'ERR_MOCHA_INVALID_EXCEPTION',
35
+
36
+ /**
37
+ * An interface (e.g., `Mocha.interfaces`) is unknown or invalid
38
+ */
39
+ INVALID_INTERFACE: 'ERR_MOCHA_INVALID_INTERFACE',
40
+
41
+ /**
42
+ * A reporter (.e.g, `Mocha.reporters`) is unknown or invalid
43
+ */
44
+ INVALID_REPORTER: 'ERR_MOCHA_INVALID_REPORTER',
45
+
46
+ /**
47
+ * `done()` was called twice in a `Test` or `Hook` callback
48
+ */
49
+ MULTIPLE_DONE: 'ERR_MOCHA_MULTIPLE_DONE',
50
+
51
+ /**
52
+ * No files matched the pattern provided by the user
53
+ */
54
+ NO_FILES_MATCH_PATTERN: 'ERR_MOCHA_NO_FILES_MATCH_PATTERN',
55
+
56
+ /**
57
+ * Known, but unsupported behavior of some kind
58
+ */
59
+ UNSUPPORTED: 'ERR_MOCHA_UNSUPPORTED',
60
+
61
+ /**
62
+ * Invalid state transition occuring in `Mocha` instance
63
+ */
64
+ INSTANCE_ALREADY_RUNNING: 'ERR_MOCHA_INSTANCE_ALREADY_RUNNING',
65
+
66
+ /**
67
+ * Invalid state transition occuring in `Mocha` instance
68
+ */
69
+ INSTANCE_ALREADY_DISPOSED: 'ERR_MOCHA_INSTANCE_ALREADY_DISPOSED'
70
+ };
8
71
 
9
72
  /**
10
73
  * Creates an error object to be thrown when no files to be tested could be found using specified pattern.
@@ -16,7 +79,7 @@
16
79
  */
17
80
  function createNoFilesMatchPatternError(message, pattern) {
18
81
  var err = new Error(message);
19
- err.code = 'ERR_MOCHA_NO_FILES_MATCH_PATTERN';
82
+ err.code = constants.NO_FILES_MATCH_PATTERN;
20
83
  err.pattern = pattern;
21
84
  return err;
22
85
  }
@@ -31,7 +94,7 @@ function createNoFilesMatchPatternError(message, pattern) {
31
94
  */
32
95
  function createInvalidReporterError(message, reporter) {
33
96
  var err = new TypeError(message);
34
- err.code = 'ERR_MOCHA_INVALID_REPORTER';
97
+ err.code = constants.INVALID_REPORTER;
35
98
  err.reporter = reporter;
36
99
  return err;
37
100
  }
@@ -46,7 +109,7 @@ function createInvalidReporterError(message, reporter) {
46
109
  */
47
110
  function createInvalidInterfaceError(message, ui) {
48
111
  var err = new Error(message);
49
- err.code = 'ERR_MOCHA_INVALID_INTERFACE';
112
+ err.code = constants.INVALID_INTERFACE;
50
113
  err.interface = ui;
51
114
  return err;
52
115
  }
@@ -60,7 +123,7 @@ function createInvalidInterfaceError(message, ui) {
60
123
  */
61
124
  function createUnsupportedError(message) {
62
125
  var err = new Error(message);
63
- err.code = 'ERR_MOCHA_UNSUPPORTED';
126
+ err.code = constants.UNSUPPORTED;
64
127
  return err;
65
128
  }
66
129
 
@@ -88,7 +151,7 @@ function createMissingArgumentError(message, argument, expected) {
88
151
  */
89
152
  function createInvalidArgumentTypeError(message, argument, expected) {
90
153
  var err = new TypeError(message);
91
- err.code = 'ERR_MOCHA_INVALID_ARG_TYPE';
154
+ err.code = constants.INVALID_ARG_TYPE;
92
155
  err.argument = argument;
93
156
  err.expected = expected;
94
157
  err.actual = typeof argument;
@@ -107,7 +170,7 @@ function createInvalidArgumentTypeError(message, argument, expected) {
107
170
  */
108
171
  function createInvalidArgumentValueError(message, argument, value, reason) {
109
172
  var err = new TypeError(message);
110
- err.code = 'ERR_MOCHA_INVALID_ARG_VALUE';
173
+ err.code = constants.INVALID_ARG_VALUE;
111
174
  err.argument = argument;
112
175
  err.value = value;
113
176
  err.reason = typeof reason !== 'undefined' ? reason : 'is invalid';
@@ -123,12 +186,113 @@ function createInvalidArgumentValueError(message, argument, value, reason) {
123
186
  */
124
187
  function createInvalidExceptionError(message, value) {
125
188
  var err = new Error(message);
126
- err.code = 'ERR_MOCHA_INVALID_EXCEPTION';
189
+ err.code = constants.INVALID_EXCEPTION;
190
+ err.valueType = typeof value;
191
+ err.value = value;
192
+ return err;
193
+ }
194
+
195
+ /**
196
+ * Creates an error object to be thrown when an unrecoverable error occurs.
197
+ *
198
+ * @public
199
+ * @param {string} message - Error message to be displayed.
200
+ * @returns {Error} instance detailing the error condition
201
+ */
202
+ function createFatalError(message, value) {
203
+ var err = new Error(message);
204
+ err.code = constants.FATAL;
127
205
  err.valueType = typeof value;
128
206
  err.value = value;
129
207
  return err;
130
208
  }
131
209
 
210
+ /**
211
+ * Dynamically creates a plugin-type-specific error based on plugin type
212
+ * @param {string} message - Error message
213
+ * @param {"reporter"|"interface"} pluginType - Plugin type. Future: expand as needed
214
+ * @param {string} [pluginId] - Name/path of plugin, if any
215
+ * @throws When `pluginType` is not known
216
+ * @public
217
+ * @returns {Error}
218
+ */
219
+ function createInvalidPluginError(message, pluginType, pluginId) {
220
+ switch (pluginType) {
221
+ case 'reporter':
222
+ return createInvalidReporterError(message, pluginId);
223
+ case 'interface':
224
+ return createInvalidInterfaceError(message, pluginId);
225
+ default:
226
+ throw new Error('unknown pluginType "' + pluginType + '"');
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Creates an error object to be thrown when a mocha object's `run` method is executed while it is already disposed.
232
+ * @param {string} message The error message to be displayed.
233
+ * @param {boolean} cleanReferencesAfterRun the value of `cleanReferencesAfterRun`
234
+ * @param {Mocha} instance the mocha instance that throw this error
235
+ */
236
+ function createMochaInstanceAlreadyDisposedError(
237
+ message,
238
+ cleanReferencesAfterRun,
239
+ instance
240
+ ) {
241
+ var err = new Error(message);
242
+ err.code = constants.INSTANCE_ALREADY_DISPOSED;
243
+ err.cleanReferencesAfterRun = cleanReferencesAfterRun;
244
+ err.instance = instance;
245
+ return err;
246
+ }
247
+
248
+ /**
249
+ * Creates an error object to be thrown when a mocha object's `run` method is called while a test run is in progress.
250
+ * @param {string} message The error message to be displayed.
251
+ */
252
+ function createMochaInstanceAlreadyRunningError(message, instance) {
253
+ var err = new Error(message);
254
+ err.code = constants.INSTANCE_ALREADY_RUNNING;
255
+ err.instance = instance;
256
+ return err;
257
+ }
258
+
259
+ /*
260
+ * Creates an error object to be thrown when done() is called multiple times in a test
261
+ *
262
+ * @public
263
+ * @param {Runnable} runnable - Original runnable
264
+ * @param {Error} [originalErr] - Original error, if any
265
+ * @returns {Error} instance detailing the error condition
266
+ */
267
+ function createMultipleDoneError(runnable, originalErr) {
268
+ var title;
269
+ try {
270
+ title = format('<%s>', runnable.fullTitle());
271
+ if (runnable.parent.root) {
272
+ title += ' (of root suite)';
273
+ }
274
+ } catch (ignored) {
275
+ title = format('<%s> (of unknown suite)', runnable.title);
276
+ }
277
+ var message = format(
278
+ 'done() called multiple times in %s %s',
279
+ runnable.type ? runnable.type : 'unknown runnable',
280
+ title
281
+ );
282
+ if (runnable.file) {
283
+ message += format(' of file %s', runnable.file);
284
+ }
285
+ if (originalErr) {
286
+ message += format('; in addition, done() received error: %s', originalErr);
287
+ }
288
+
289
+ var err = new Error(message);
290
+ err.code = constants.MULTIPLE_DONE;
291
+ err.valueType = typeof originalErr;
292
+ err.value = originalErr;
293
+ return err;
294
+ }
295
+
132
296
  module.exports = {
133
297
  createInvalidArgumentTypeError: createInvalidArgumentTypeError,
134
298
  createInvalidArgumentValueError: createInvalidArgumentValueError,
@@ -137,5 +301,11 @@ module.exports = {
137
301
  createInvalidReporterError: createInvalidReporterError,
138
302
  createMissingArgumentError: createMissingArgumentError,
139
303
  createNoFilesMatchPatternError: createNoFilesMatchPatternError,
140
- createUnsupportedError: createUnsupportedError
304
+ createUnsupportedError: createUnsupportedError,
305
+ createInvalidPluginError: createInvalidPluginError,
306
+ createMochaInstanceAlreadyDisposedError: createMochaInstanceAlreadyDisposedError,
307
+ createMochaInstanceAlreadyRunningError: createMochaInstanceAlreadyRunningError,
308
+ createFatalError: createFatalError,
309
+ createMultipleDoneError: createMultipleDoneError,
310
+ constants: constants
141
311
  };
@@ -0,0 +1,31 @@
1
+ const url = require('url');
2
+ const path = require('path');
3
+
4
+ const requireOrImport = async file => {
5
+ file = path.resolve(file);
6
+
7
+ if (path.extname(file) === '.mjs') {
8
+ return import(url.pathToFileURL(file));
9
+ }
10
+ // This is currently the only known way of figuring out whether a file is CJS or ESM.
11
+ // If Node.js or the community establish a better procedure for that, we can fix this code.
12
+ // Another option here would be to always use `import()`, as this also supports CJS, but I would be
13
+ // wary of using it for _all_ existing test files, till ESM is fully stable.
14
+ try {
15
+ return require(file);
16
+ } catch (err) {
17
+ if (err.code === 'ERR_REQUIRE_ESM') {
18
+ return import(url.pathToFileURL(file));
19
+ } else {
20
+ throw err;
21
+ }
22
+ }
23
+ };
24
+
25
+ exports.loadFilesAsync = async (files, preLoadFunc, postLoadFunc) => {
26
+ for (const file of files) {
27
+ preLoadFunc(file);
28
+ const result = await requireOrImport(file);
29
+ postLoadFunc(file, result);
30
+ }
31
+ };
package/lib/hook.js CHANGED
@@ -27,6 +27,14 @@ function Hook(title, fn) {
27
27
  */
28
28
  inherits(Hook, Runnable);
29
29
 
30
+ /**
31
+ * Resets the state for a next run.
32
+ */
33
+ Hook.prototype.reset = function() {
34
+ Runnable.prototype.reset.call(this);
35
+ delete this._error;
36
+ };
37
+
30
38
  /**
31
39
  * Get or set the test `err`.
32
40
  *
@@ -3,6 +3,7 @@
3
3
  var Suite = require('../suite');
4
4
  var errors = require('../errors');
5
5
  var createMissingArgumentError = errors.createMissingArgumentError;
6
+ var createUnsupportedError = errors.createUnsupportedError;
6
7
 
7
8
  /**
8
9
  * Functions common to more than one interface.
@@ -126,14 +127,14 @@ module.exports = function(suites, context, mocha) {
126
127
  suites.unshift(suite);
127
128
  if (opts.isOnly) {
128
129
  if (mocha.options.forbidOnly && shouldBeTested(suite)) {
129
- throw new Error('`.only` forbidden');
130
+ throw createUnsupportedError('`.only` forbidden');
130
131
  }
131
132
 
132
133
  suite.parent.appendOnlySuite(suite);
133
134
  }
134
135
  if (suite.pending) {
135
136
  if (mocha.options.forbidPending && shouldBeTested(suite)) {
136
- throw new Error('Pending test forbidden');
137
+ throw createUnsupportedError('Pending test forbidden');
137
138
  }
138
139
  }
139
140
  if (typeof opts.fn === 'function') {
@@ -165,7 +166,9 @@ module.exports = function(suites, context, mocha) {
165
166
  * @returns {*}
166
167
  */
167
168
  only: function(mocha, test) {
168
- test.parent.appendOnlyTest(test);
169
+ if (mocha.options.forbidOnly)
170
+ throw createUnsupportedError('`.only` forbidden');
171
+ test.markOnly();
169
172
  return test;
170
173
  },
171
174