mocha 8.1.0 → 8.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.
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const logSymbols = require('log-symbols');
3
4
  const debug = require('debug')('mocha:cli:watch');
4
5
  const path = require('path');
5
6
  const chokidar = require('chokidar');
@@ -32,6 +33,7 @@ exports.watchParallelRun = (
32
33
  fileCollectParams
33
34
  ) => {
34
35
  debug('creating parallel watcher');
36
+
35
37
  return createWatcher(mocha, {
36
38
  watchFiles,
37
39
  watchIgnore,
@@ -68,9 +70,6 @@ exports.watchParallelRun = (
68
70
  newMocha.lazyLoadFiles(true);
69
71
  return newMocha;
70
72
  },
71
- afterRun({watcher}) {
72
- blastCache(watcher);
73
- },
74
73
  fileCollectParams
75
74
  });
76
75
  };
@@ -91,7 +90,6 @@ exports.watchParallelRun = (
91
90
  */
92
91
  exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
93
92
  debug('creating serial watcher');
94
- // list of all test files
95
93
 
96
94
  return createWatcher(mocha, {
97
95
  watchFiles,
@@ -128,9 +126,6 @@ exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
128
126
 
129
127
  return newMocha;
130
128
  },
131
- afterRun({watcher}) {
132
- blastCache(watcher);
133
- },
134
129
  fileCollectParams
135
130
  });
136
131
  };
@@ -141,7 +136,6 @@ exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
141
136
  * @param {Object} opts
142
137
  * @param {BeforeWatchRun} [opts.beforeRun] - Function to call before
143
138
  * `mocha.run()`
144
- * @param {AfterWatchRun} [opts.afterRun] - Function to call after `mocha.run()`
145
139
  * @param {string[]} [opts.watchFiles] - List of paths and patterns to watch. If
146
140
  * not provided all files with an extension included in
147
141
  * `fileCollectionParams.extension` are watched. See first argument of
@@ -155,13 +149,17 @@ exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
155
149
  */
156
150
  const createWatcher = (
157
151
  mocha,
158
- {watchFiles, watchIgnore, beforeRun, afterRun, fileCollectParams}
152
+ {watchFiles, watchIgnore, beforeRun, fileCollectParams}
159
153
  ) => {
160
154
  if (!watchFiles) {
161
155
  watchFiles = fileCollectParams.extension.map(ext => `**/*.${ext}`);
162
156
  }
163
157
 
164
158
  debug('ignoring files matching: %s', watchIgnore);
159
+ let globalFixtureContext;
160
+
161
+ // we handle global fixtures manually
162
+ mocha.enableGlobalSetup(false).enableGlobalTeardown(false);
165
163
 
166
164
  const watcher = chokidar.watch(watchFiles, {
167
165
  ignored: watchIgnore,
@@ -169,11 +167,14 @@ const createWatcher = (
169
167
  });
170
168
 
171
169
  const rerunner = createRerunner(mocha, watcher, {
172
- beforeRun,
173
- afterRun
170
+ beforeRun
174
171
  });
175
172
 
176
- watcher.on('ready', () => {
173
+ watcher.on('ready', async () => {
174
+ if (!globalFixtureContext) {
175
+ debug('triggering global setup');
176
+ globalFixtureContext = await mocha.runGlobalSetup();
177
+ }
177
178
  rerunner.run();
178
179
  });
179
180
 
@@ -185,10 +186,39 @@ const createWatcher = (
185
186
  process.on('exit', () => {
186
187
  showCursor();
187
188
  });
188
- process.on('SIGINT', () => {
189
+
190
+ // this is for testing.
191
+ // win32 cannot gracefully shutdown via a signal from a parent
192
+ // process; a `SIGINT` from a parent will cause the process
193
+ // to immediately exit. during normal course of operation, a user
194
+ // will type Ctrl-C and the listener will be invoked, but this
195
+ // is not possible in automated testing.
196
+ // there may be another way to solve this, but it too will be a hack.
197
+ // for our watch tests on win32 we must _fork_ mocha with an IPC channel
198
+ if (process.connected) {
199
+ process.on('message', msg => {
200
+ if (msg === 'SIGINT') {
201
+ process.emit('SIGINT');
202
+ }
203
+ });
204
+ }
205
+
206
+ let exiting = false;
207
+ process.on('SIGINT', async () => {
189
208
  showCursor();
190
- console.log('\n');
191
- process.exit(128 + 2);
209
+ console.error(`${logSymbols.warning} [mocha] cleaning up, please wait...`);
210
+ if (!exiting) {
211
+ exiting = true;
212
+ if (mocha.hasGlobalTeardownFixtures()) {
213
+ debug('running global teardown');
214
+ try {
215
+ await mocha.runGlobalTeardown(globalFixtureContext);
216
+ } catch (err) {
217
+ console.error(err);
218
+ }
219
+ }
220
+ process.exit(130);
221
+ }
192
222
  });
193
223
 
194
224
  // Keyboard shortcut for restarting when "rs\n" is typed (ala Nodemon)
@@ -212,12 +242,11 @@ const createWatcher = (
212
242
  * @param {FSWatcher} watcher - chokidar `FSWatcher` instance
213
243
  * @param {Object} [opts] - Options!
214
244
  * @param {BeforeWatchRun} [opts.beforeRun] - Function to call before `mocha.run()`
215
- * @param {AfterWatchRun} [opts.afterRun] - Function to call after `mocha.run()`
216
245
  * @returns {Rerunner}
217
246
  * @ignore
218
247
  * @private
219
248
  */
220
- const createRerunner = (mocha, watcher, {beforeRun, afterRun} = {}) => {
249
+ const createRerunner = (mocha, watcher, {beforeRun} = {}) => {
221
250
  // Set to a `Runner` when mocha is running. Set to `null` when mocha is not
222
251
  // running.
223
252
  let runner = null;
@@ -226,16 +255,15 @@ const createRerunner = (mocha, watcher, {beforeRun, afterRun} = {}) => {
226
255
  let rerunScheduled = false;
227
256
 
228
257
  const run = () => {
229
- mocha = beforeRun ? beforeRun({mocha, watcher}) : mocha;
230
-
258
+ mocha = beforeRun ? beforeRun({mocha, watcher}) || mocha : mocha;
231
259
  runner = mocha.run(() => {
232
260
  debug('finished watch run');
233
261
  runner = null;
234
- afterRun && afterRun({mocha, watcher});
262
+ blastCache(watcher);
235
263
  if (rerunScheduled) {
236
264
  rerun();
237
265
  } else {
238
- debug('waiting for changes...');
266
+ console.error(`${logSymbols.info} [mocha] waiting for changes...`);
239
267
  }
240
268
  });
241
269
  };
@@ -333,15 +361,6 @@ const blastCache = watcher => {
333
361
  * @returns {Mocha}
334
362
  */
335
363
 
336
- /**
337
- * Callback to be run after `mocha.run()` completes. Typically used to clear
338
- * require cache.
339
- * @callback AfterWatchRun
340
- * @private
341
- * @param {{mocha: Mocha, watcher: FSWatcher}} options
342
- * @returns {void}
343
- */
344
-
345
364
  /**
346
365
  * Object containing run control methods
347
366
  * @typedef {Object} Rerunner
package/lib/errors.js CHANGED
@@ -1,12 +1,57 @@
1
1
  'use strict';
2
2
 
3
- var format = require('util').format;
3
+ const {format} = require('util');
4
4
 
5
5
  /**
6
- * Factory functions to create throwable error objects
7
- * @module Errors
6
+ * Contains error codes, factory functions to create throwable error objects,
7
+ * and warning/deprecation functions.
8
+ * @module
8
9
  */
9
10
 
11
+ /**
12
+ * process.emitWarning or a polyfill
13
+ * @see https://nodejs.org/api/process.html#process_process_emitwarning_warning_options
14
+ * @ignore
15
+ */
16
+ const emitWarning = (msg, type) => {
17
+ if (process.emitWarning) {
18
+ process.emitWarning(msg, type);
19
+ } else {
20
+ process.nextTick(function() {
21
+ console.warn(type + ': ' + msg);
22
+ });
23
+ }
24
+ };
25
+
26
+ /**
27
+ * Show a deprecation warning. Each distinct message is only displayed once.
28
+ * Ignores empty messages.
29
+ *
30
+ * @param {string} [msg] - Warning to print
31
+ * @private
32
+ */
33
+ const deprecate = msg => {
34
+ msg = String(msg);
35
+ if (msg && !deprecate.cache[msg]) {
36
+ deprecate.cache[msg] = true;
37
+ emitWarning(msg, 'DeprecationWarning');
38
+ }
39
+ };
40
+ deprecate.cache = {};
41
+
42
+ /**
43
+ * Show a generic warning.
44
+ * Ignores empty messages.
45
+ *
46
+ * @param {string} [msg] - Warning to print
47
+ * @private
48
+ */
49
+ const warn = msg => {
50
+ if (msg) {
51
+ emitWarning(msg);
52
+ }
53
+ };
54
+
10
55
  /**
11
56
  * When Mocha throw exceptions (or otherwise errors), it attempts to assign a
12
57
  * `code` property to the `Error` object, for easier handling. These are the
@@ -71,7 +116,17 @@ var constants = {
71
116
  /**
72
117
  * Use of `only()` w/ `--forbid-only` results in this error.
73
118
  */
74
- FORBIDDEN_EXCLUSIVITY: 'ERR_MOCHA_FORBIDDEN_EXCLUSIVITY'
119
+ FORBIDDEN_EXCLUSIVITY: 'ERR_MOCHA_FORBIDDEN_EXCLUSIVITY',
120
+
121
+ /**
122
+ * To be thrown when a user-defined plugin implementation (e.g., `mochaHooks`) is invalid
123
+ */
124
+ INVALID_PLUGIN_IMPLEMENTATION: 'ERR_MOCHA_INVALID_PLUGIN_IMPLEMENTATION',
125
+
126
+ /**
127
+ * To be thrown when a builtin or third-party plugin definition (the _definition_ of `mochaHooks`) is invalid
128
+ */
129
+ INVALID_PLUGIN_DEFINITION: 'ERR_MOCHA_INVALID_PLUGIN_DEFINITION'
75
130
  };
76
131
 
77
132
  /**
@@ -221,7 +276,7 @@ function createFatalError(message, value) {
221
276
  * @public
222
277
  * @returns {Error}
223
278
  */
224
- function createInvalidPluginError(message, pluginType, pluginId) {
279
+ function createInvalidLegacyPluginError(message, pluginType, pluginId) {
225
280
  switch (pluginType) {
226
281
  case 'reporter':
227
282
  return createInvalidReporterError(message, pluginId);
@@ -232,6 +287,21 @@ function createInvalidPluginError(message, pluginType, pluginId) {
232
287
  }
233
288
  }
234
289
 
290
+ /**
291
+ * **DEPRECATED**. Use {@link createInvalidLegacyPluginError} instead Dynamically creates a plugin-type-specific error based on plugin type
292
+ * @deprecated
293
+ * @param {string} message - Error message
294
+ * @param {"reporter"|"interface"} pluginType - Plugin type. Future: expand as needed
295
+ * @param {string} [pluginId] - Name/path of plugin, if any
296
+ * @throws When `pluginType` is not known
297
+ * @public
298
+ * @returns {Error}
299
+ */
300
+ function createInvalidPluginError(...args) {
301
+ deprecate('Use createInvalidLegacyPluginError() instead');
302
+ return createInvalidLegacyPluginError(...args);
303
+ }
304
+
235
305
  /**
236
306
  * Creates an error object to be thrown when a mocha object's `run` method is executed while it is already disposed.
237
307
  * @param {string} message The error message to be displayed.
@@ -315,20 +385,59 @@ function createForbiddenExclusivityError(mocha) {
315
385
  return err;
316
386
  }
317
387
 
388
+ /**
389
+ * Creates an error object to be thrown when a plugin definition is invalid
390
+ * @param {string} msg - Error message
391
+ * @param {PluginDefinition} [pluginDef] - Problematic plugin definition
392
+ * @public
393
+ * @returns {Error} Error with code {@link constants.INVALID_PLUGIN_DEFINITION}
394
+ */
395
+ function createInvalidPluginDefinitionError(msg, pluginDef) {
396
+ const err = new Error(msg);
397
+ err.code = constants.INVALID_PLUGIN_DEFINITION;
398
+ err.pluginDef = pluginDef;
399
+ return err;
400
+ }
401
+
402
+ /**
403
+ * Creates an error object to be thrown when a plugin implementation (user code) is invalid
404
+ * @param {string} msg - Error message
405
+ * @param {Object} [opts] - Plugin definition and user-supplied implementation
406
+ * @param {PluginDefinition} [opts.pluginDef] - Plugin Definition
407
+ * @param {*} [opts.pluginImpl] - Plugin Implementation (user-supplied)
408
+ * @public
409
+ * @returns {Error} Error with code {@link constants.INVALID_PLUGIN_DEFINITION}
410
+ */
411
+ function createInvalidPluginImplementationError(
412
+ msg,
413
+ {pluginDef, pluginImpl} = {}
414
+ ) {
415
+ const err = new Error(msg);
416
+ err.code = constants.INVALID_PLUGIN_IMPLEMENTATION;
417
+ err.pluginDef = pluginDef;
418
+ err.pluginImpl = pluginImpl;
419
+ return err;
420
+ }
421
+
318
422
  module.exports = {
319
- createInvalidArgumentTypeError: createInvalidArgumentTypeError,
320
- createInvalidArgumentValueError: createInvalidArgumentValueError,
321
- createInvalidExceptionError: createInvalidExceptionError,
322
- createInvalidInterfaceError: createInvalidInterfaceError,
323
- createInvalidReporterError: createInvalidReporterError,
324
- createMissingArgumentError: createMissingArgumentError,
325
- createNoFilesMatchPatternError: createNoFilesMatchPatternError,
326
- createUnsupportedError: createUnsupportedError,
327
- createInvalidPluginError: createInvalidPluginError,
328
- createMochaInstanceAlreadyDisposedError: createMochaInstanceAlreadyDisposedError,
329
- createMochaInstanceAlreadyRunningError: createMochaInstanceAlreadyRunningError,
330
- createFatalError: createFatalError,
331
- createMultipleDoneError: createMultipleDoneError,
332
- createForbiddenExclusivityError: createForbiddenExclusivityError,
333
- constants: constants
423
+ constants,
424
+ createFatalError,
425
+ createForbiddenExclusivityError,
426
+ createInvalidArgumentTypeError,
427
+ createInvalidArgumentValueError,
428
+ createInvalidExceptionError,
429
+ createInvalidInterfaceError,
430
+ createInvalidLegacyPluginError,
431
+ createInvalidPluginDefinitionError,
432
+ createInvalidPluginError,
433
+ createInvalidPluginImplementationError,
434
+ createInvalidReporterError,
435
+ createMissingArgumentError,
436
+ createMochaInstanceAlreadyDisposedError,
437
+ createMochaInstanceAlreadyRunningError,
438
+ createMultipleDoneError,
439
+ createNoFilesMatchPatternError,
440
+ createUnsupportedError,
441
+ deprecate,
442
+ warn
334
443
  };
package/lib/hook.js CHANGED
@@ -1,7 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var Runnable = require('./runnable');
4
- var inherits = require('./utils').inherits;
4
+ const {inherits, constants} = require('./utils');
5
+ const {MOCHA_ID_PROP_NAME} = constants;
5
6
 
6
7
  /**
7
8
  * Expose `Hook`.
@@ -63,16 +64,20 @@ Hook.prototype.serialize = function serialize() {
63
64
  return {
64
65
  $$isPending: this.isPending(),
65
66
  $$titlePath: this.titlePath(),
66
- ctx: {
67
- currentTest: {
68
- title: this.ctx && this.ctx.currentTest && this.ctx.currentTest.title
69
- }
70
- },
67
+ ctx:
68
+ this.ctx && this.ctx.currentTest
69
+ ? {
70
+ currentTest: {
71
+ title: this.ctx.currentTest.title,
72
+ [MOCHA_ID_PROP_NAME]: this.ctx.currentTest.id
73
+ }
74
+ }
75
+ : {},
71
76
  parent: {
72
- root: this.parent.root,
73
- title: this.parent.title
77
+ [MOCHA_ID_PROP_NAME]: this.parent.id
74
78
  },
75
79
  title: this.title,
76
- type: this.type
80
+ type: this.type,
81
+ [MOCHA_ID_PROP_NAME]: this.id
77
82
  };
78
83
  };