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
@@ -0,0 +1,284 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Main entry point for handling filesystem-based configuration,
5
+ * whether that's a config file or `package.json` or whatever.
6
+ * @module lib/cli/options
7
+ * @private
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const ansi = require('ansi-colors');
12
+ const yargsParser = require('yargs-parser');
13
+ const {types, aliases} = require('./run-option-metadata');
14
+ const {ONE_AND_DONE_ARGS} = require('./one-and-dones');
15
+ const mocharc = require('../mocharc.json');
16
+ const {list} = require('./run-helpers');
17
+ const {loadConfig, findConfig} = require('./config');
18
+ const findUp = require('find-up');
19
+ const debug = require('debug')('mocha:cli:options');
20
+ const {isNodeFlag} = require('./node-flags');
21
+ const {createUnparsableFileError} = require('../errors');
22
+
23
+ /**
24
+ * The `yargs-parser` namespace
25
+ * @external yargsParser
26
+ * @see {@link https://npm.im/yargs-parser}
27
+ */
28
+
29
+ /**
30
+ * An object returned by a configured `yargs-parser` representing arguments
31
+ * @memberof external:yargsParser
32
+ * @interface Arguments
33
+ */
34
+
35
+ /**
36
+ * Base yargs parser configuration
37
+ * @private
38
+ */
39
+ const YARGS_PARSER_CONFIG = {
40
+ 'combine-arrays': true,
41
+ 'short-option-groups': false,
42
+ 'dot-notation': false,
43
+ 'strip-aliased': true
44
+ };
45
+
46
+ /**
47
+ * This is the config pulled from the `yargs` property of Mocha's
48
+ * `package.json`, but it also disables camel case expansion as to
49
+ * avoid outputting non-canonical keynames, as we need to do some
50
+ * lookups.
51
+ * @private
52
+ * @ignore
53
+ */
54
+ const configuration = Object.assign({}, YARGS_PARSER_CONFIG, {
55
+ 'camel-case-expansion': false
56
+ });
57
+
58
+ /**
59
+ * This is a really fancy way to:
60
+ * - `array`-type options: ensure unique values and evtl. split comma-delimited lists
61
+ * - `boolean`/`number`/`string`- options: use last element when given multiple times
62
+ * This is passed as the `coerce` option to `yargs-parser`
63
+ * @private
64
+ * @ignore
65
+ */
66
+ const globOptions = ['spec', 'ignore'];
67
+ const coerceOpts = Object.assign(
68
+ types.array.reduce(
69
+ (acc, arg) =>
70
+ Object.assign(acc, {
71
+ [arg]: v => Array.from(new Set(globOptions.includes(arg) ? v : list(v)))
72
+ }),
73
+ {}
74
+ ),
75
+ types.boolean
76
+ .concat(types.string, types.number)
77
+ .reduce(
78
+ (acc, arg) =>
79
+ Object.assign(acc, {[arg]: v => (Array.isArray(v) ? v.pop() : v)}),
80
+ {}
81
+ )
82
+ );
83
+
84
+ /**
85
+ * We do not have a case when multiple arguments are ever allowed after a flag
86
+ * (e.g., `--foo bar baz quux`), so we fix the number of arguments to 1 across
87
+ * the board of non-boolean options.
88
+ * This is passed as the `narg` option to `yargs-parser`
89
+ * @private
90
+ * @ignore
91
+ */
92
+ const nargOpts = types.array
93
+ .concat(types.string, types.number)
94
+ .reduce((acc, arg) => Object.assign(acc, {[arg]: 1}), {});
95
+
96
+ /**
97
+ * Wrapper around `yargs-parser` which applies our settings
98
+ * @param {string|string[]} args - Arguments to parse
99
+ * @param {Object} defaultValues - Default values of mocharc.json
100
+ * @param {...Object} configObjects - `configObjects` for yargs-parser
101
+ * @private
102
+ * @ignore
103
+ */
104
+ const parse = (args = [], defaultValues = {}, ...configObjects) => {
105
+ // save node-specific args for special handling.
106
+ // 1. when these args have a "=" they should be considered to have values
107
+ // 2. if they don't, they just boolean flags
108
+ // 3. to avoid explicitly defining the set of them, we tell yargs-parser they
109
+ // are ALL boolean flags.
110
+ // 4. we can then reapply the values after yargs-parser is done.
111
+ const nodeArgs = (Array.isArray(args) ? args : args.split(' ')).reduce(
112
+ (acc, arg) => {
113
+ const pair = arg.split('=');
114
+ let flag = pair[0];
115
+ if (isNodeFlag(flag, false)) {
116
+ flag = flag.replace(/^--?/, '');
117
+ return arg.includes('=')
118
+ ? acc.concat([[flag, pair[1]]])
119
+ : acc.concat([[flag, true]]);
120
+ }
121
+ return acc;
122
+ },
123
+ []
124
+ );
125
+
126
+ const result = yargsParser.detailed(args, {
127
+ configuration,
128
+ configObjects,
129
+ default: defaultValues,
130
+ coerce: coerceOpts,
131
+ narg: nargOpts,
132
+ alias: aliases,
133
+ string: types.string,
134
+ array: types.array,
135
+ number: types.number,
136
+ boolean: types.boolean.concat(nodeArgs.map(pair => pair[0]))
137
+ });
138
+ if (result.error) {
139
+ console.error(ansi.red(`Error: ${result.error.message}`));
140
+ process.exit(1);
141
+ }
142
+
143
+ // reapply "=" arg values from above
144
+ nodeArgs.forEach(([key, value]) => {
145
+ result.argv[key] = value;
146
+ });
147
+
148
+ return result.argv;
149
+ };
150
+
151
+ /**
152
+ * Given path to config file in `args.config`, attempt to load & parse config file.
153
+ * @param {Object} [args] - Arguments object
154
+ * @param {string|boolean} [args.config] - Path to config file or `false` to skip
155
+ * @public
156
+ * @alias module:lib/cli.loadRc
157
+ * @returns {external:yargsParser.Arguments|void} Parsed config, or nothing if `args.config` is `false`
158
+ */
159
+ const loadRc = (args = {}) => {
160
+ if (args.config !== false) {
161
+ const config = args.config || findConfig();
162
+ return config ? loadConfig(config) : {};
163
+ }
164
+ };
165
+
166
+ module.exports.loadRc = loadRc;
167
+
168
+ /**
169
+ * Given path to `package.json` in `args.package`, attempt to load config from `mocha` prop.
170
+ * @param {Object} [args] - Arguments object
171
+ * @param {string|boolean} [args.config] - Path to `package.json` or `false` to skip
172
+ * @public
173
+ * @alias module:lib/cli.loadPkgRc
174
+ * @returns {external:yargsParser.Arguments|void} Parsed config, or nothing if `args.package` is `false`
175
+ */
176
+ const loadPkgRc = (args = {}) => {
177
+ let result;
178
+ if (args.package === false) {
179
+ return result;
180
+ }
181
+ result = {};
182
+ const filepath = args.package || findUp.sync(mocharc.package);
183
+ if (filepath) {
184
+ let configData;
185
+ try {
186
+ configData = fs.readFileSync(filepath, 'utf8');
187
+ } catch (err) {
188
+ // If `args.package` was explicitly specified, throw an error
189
+ if (filepath == args.package) {
190
+ throw createUnparsableFileError(
191
+ `Unable to read ${filepath}: ${err}`,
192
+ filepath
193
+ );
194
+ } else {
195
+ debug('failed to read default package.json at %s; ignoring',
196
+ filepath);
197
+ return result;
198
+ }
199
+ }
200
+ try {
201
+ const pkg = JSON.parse(configData);
202
+ if (pkg.mocha) {
203
+ debug('`mocha` prop of package.json parsed: %O', pkg.mocha);
204
+ result = pkg.mocha;
205
+ } else {
206
+ debug('no config found in %s', filepath);
207
+ }
208
+ } catch (err) {
209
+ // If JSON failed to parse, throw an error.
210
+ throw createUnparsableFileError(
211
+ `Unable to parse ${filepath}: ${err}`,
212
+ filepath
213
+ );
214
+ }
215
+ }
216
+ return result;
217
+ };
218
+
219
+ module.exports.loadPkgRc = loadPkgRc;
220
+
221
+ /**
222
+ * Priority list:
223
+ *
224
+ * 1. Command-line args
225
+ * 2. `MOCHA_OPTIONS` environment variable.
226
+ * 3. RC file (`.mocharc.c?js`, `.mocharc.ya?ml`, `mocharc.json`)
227
+ * 4. `mocha` prop of `package.json`
228
+ * 5. default configuration (`lib/mocharc.json`)
229
+ *
230
+ * If a {@link module:lib/cli/one-and-dones.ONE_AND_DONE_ARGS "one-and-done" option} is present in the `argv` array, no external config files will be read.
231
+ * @summary Parses options read from `.mocharc.*` and `package.json`.
232
+ * @param {string|string[]} [argv] - Arguments to parse
233
+ * @public
234
+ * @alias module:lib/cli.loadOptions
235
+ * @returns {external:yargsParser.Arguments} Parsed args from everything
236
+ */
237
+ const loadOptions = (argv = []) => {
238
+ let args = parse(argv);
239
+ // short-circuit: look for a flag that would abort loading of options
240
+ if (
241
+ Array.from(ONE_AND_DONE_ARGS).reduce(
242
+ (acc, arg) => acc || arg in args,
243
+ false
244
+ )
245
+ ) {
246
+ return args;
247
+ }
248
+
249
+ const envConfig = parse(process.env.MOCHA_OPTIONS || '');
250
+ const rcConfig = loadRc(args);
251
+ const pkgConfig = loadPkgRc(args);
252
+
253
+ if (rcConfig) {
254
+ args.config = false;
255
+ args._ = args._.concat(rcConfig._ || []);
256
+ }
257
+ if (pkgConfig) {
258
+ args.package = false;
259
+ args._ = args._.concat(pkgConfig._ || []);
260
+ }
261
+
262
+ args = parse(
263
+ args._,
264
+ mocharc,
265
+ args,
266
+ envConfig,
267
+ rcConfig || {},
268
+ pkgConfig || {}
269
+ );
270
+
271
+ // recombine positional arguments and "spec"
272
+ if (args.spec) {
273
+ args._ = args._.concat(args.spec);
274
+ delete args.spec;
275
+ }
276
+
277
+ // make unique
278
+ args._ = Array.from(new Set(args._));
279
+
280
+ return args;
281
+ };
282
+
283
+ module.exports.loadOptions = loadOptions;
284
+ module.exports.YARGS_PARSER_CONFIG = YARGS_PARSER_CONFIG;
@@ -0,0 +1,304 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Helper scripts for the `run` command
5
+ * @see module:lib/cli/run
6
+ * @module
7
+ * @private
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const ansi = require('ansi-colors');
13
+ const debug = require('debug')('mocha:cli:run:helpers');
14
+ const {watchRun, watchParallelRun} = require('./watch-run');
15
+ const collectFiles = require('./collect-files');
16
+ const {format} = require('util');
17
+ const {createInvalidLegacyPluginError} = require('../errors');
18
+ const {requireOrImport} = require('../nodejs/esm-utils');
19
+ const PluginLoader = require('../plugin-loader');
20
+ const {UnmatchedFile} = require('./collect-files');
21
+
22
+ /**
23
+ * Exits Mocha when tests + code under test has finished execution (default)
24
+ * @param {number} clampedCode - Exit code; typically # of failures
25
+ * @ignore
26
+ * @private
27
+ */
28
+ const exitMochaLater = clampedCode => {
29
+ process.on('exit', () => {
30
+ process.exitCode = clampedCode;
31
+ });
32
+ };
33
+
34
+ /**
35
+ * Exits Mocha when Mocha itself has finished execution, regardless of
36
+ * what the tests or code under test is doing.
37
+ * @param {number} clampedCode - Exit code; typically # of failures
38
+ * @ignore
39
+ * @private
40
+ */
41
+ const exitMocha = clampedCode => {
42
+ let draining = 0;
43
+
44
+ // Eagerly set the process's exit code in case stream.write doesn't
45
+ // execute its callback before the process terminates.
46
+ process.exitCode = clampedCode;
47
+
48
+ // flush output for Node.js Windows pipe bug
49
+ // https://github.com/joyent/node/issues/6247 is just one bug example
50
+ // https://github.com/visionmedia/mocha/issues/333 has a good discussion
51
+ const done = () => {
52
+ if (!draining--) {
53
+ process.exit(clampedCode);
54
+ }
55
+ };
56
+
57
+ const streams = [process.stdout, process.stderr];
58
+
59
+ streams.forEach(stream => {
60
+ // submit empty write request and wait for completion
61
+ draining += 1;
62
+ stream.write('', done);
63
+ });
64
+
65
+ done();
66
+ };
67
+
68
+ /**
69
+ * Coerce a comma-delimited string (or array thereof) into a flattened array of
70
+ * strings
71
+ * @param {string|string[]} str - Value to coerce
72
+ * @returns {string[]} Array of strings
73
+ * @private
74
+ */
75
+ exports.list = str =>
76
+ Array.isArray(str) ? exports.list(str.join(',')) : str.split(/ *, */);
77
+
78
+ /**
79
+ * `require()` the modules as required by `--require <require>`.
80
+ *
81
+ * Returns array of `mochaHooks` exports, if any.
82
+ * @param {string[]} requires - Modules to require
83
+ * @returns {Promise<object>} Plugin implementations
84
+ * @private
85
+ */
86
+ exports.handleRequires = async (requires = [], {ignoredPlugins = []} = {}) => {
87
+ const pluginLoader = PluginLoader.create({ignore: ignoredPlugins});
88
+ for await (const mod of requires) {
89
+ let modpath = mod;
90
+ // this is relative to cwd
91
+ if (fs.existsSync(mod) || fs.existsSync(`${mod}.js`)) {
92
+ modpath = path.resolve(mod);
93
+ debug('resolved required file %s to %s', mod, modpath);
94
+ }
95
+ const requiredModule = await requireOrImport(modpath);
96
+ if (requiredModule && typeof requiredModule === 'object') {
97
+ if (pluginLoader.load(requiredModule)) {
98
+ debug('found one or more plugin implementations in %s', modpath);
99
+ }
100
+ }
101
+ debug('loaded required module "%s"', mod);
102
+ }
103
+ const plugins = await pluginLoader.finalize();
104
+ if (Object.keys(plugins).length) {
105
+ debug('finalized plugin implementations: %O', plugins);
106
+ }
107
+ return plugins;
108
+ };
109
+
110
+ /**
111
+ * Logs errors and exits the app if unmatched files exist
112
+ * @param {Mocha} mocha - Mocha instance
113
+ * @param {UnmatchedFile} unmatchedFiles - object containing unmatched file paths
114
+ * @returns {Promise<Runner>}
115
+ * @private
116
+ */
117
+ const handleUnmatchedFiles = (mocha, unmatchedFiles) => {
118
+ if (unmatchedFiles.length === 0) {
119
+ return;
120
+ }
121
+
122
+ unmatchedFiles.forEach(({pattern, absolutePath}) => {
123
+ console.error(
124
+ ansi.yellow(
125
+ `Warning: Cannot find any files matching pattern "${pattern}" at the absolute path "${absolutePath}"`
126
+ )
127
+ );
128
+ });
129
+ console.log(
130
+ 'No test file(s) found with the given pattern, exiting with code 1'
131
+ );
132
+
133
+ return mocha.run(exitMocha(1));
134
+ };
135
+
136
+ /**
137
+ * Collect and load test files, then run mocha instance.
138
+ * @param {Mocha} mocha - Mocha instance
139
+ * @param {Options} [opts] - Command line options
140
+ * @param {boolean} [opts.exit] - Whether or not to force-exit after tests are complete
141
+ * @param {boolean} [opts.passOnFailingTestSuite] - Whether or not to fail test run if tests were failed
142
+ * @param {Object} fileCollectParams - Parameters that control test
143
+ * file collection. See `lib/cli/collect-files.js`.
144
+ * @returns {Promise<Runner>}
145
+ * @private
146
+ */
147
+ const singleRun = async (
148
+ mocha,
149
+ {exit, passOnFailingTestSuite},
150
+ fileCollectParams
151
+ ) => {
152
+ const fileCollectionObj = collectFiles(fileCollectParams);
153
+
154
+ if (fileCollectionObj.unmatchedFiles.length > 0) {
155
+ return handleUnmatchedFiles(mocha, fileCollectionObj.unmatchedFiles);
156
+ }
157
+
158
+ debug('single run with %d file(s)', fileCollectionObj.files.length);
159
+ mocha.files = fileCollectionObj.files;
160
+
161
+ // handles ESM modules
162
+ await mocha.loadFilesAsync();
163
+ return mocha.run(
164
+ createExitHandler({exit, passOnFailingTestSuite})
165
+ );
166
+ };
167
+
168
+ /**
169
+ * Collect files and run tests (using `BufferedRunner`).
170
+ *
171
+ * This is `async` for consistency.
172
+ *
173
+ * @param {Mocha} mocha - Mocha instance
174
+ * @param {Options} options - Command line options
175
+ * @param {Object} fileCollectParams - Parameters that control test
176
+ * file collection. See `lib/cli/collect-files.js`.
177
+ * @returns {Promise<BufferedRunner>}
178
+ * @ignore
179
+ * @private
180
+ */
181
+ const parallelRun = async (mocha, options, fileCollectParams) => {
182
+ const fileCollectionObj = collectFiles(fileCollectParams);
183
+
184
+ if (fileCollectionObj.unmatchedFiles.length > 0) {
185
+ return handleUnmatchedFiles(mocha, fileCollectionObj.unmatchedFiles);
186
+ }
187
+
188
+ debug(
189
+ 'executing %d test file(s) in parallel mode',
190
+ fileCollectionObj.files.length
191
+ );
192
+ mocha.files = fileCollectionObj.files;
193
+
194
+ // note that we DO NOT load any files here; this is handled by the worker
195
+ return mocha.run(
196
+ createExitHandler(options)
197
+ );
198
+ };
199
+
200
+ /**
201
+ * Actually run tests. Delegates to one of four different functions:
202
+ * - `singleRun`: run tests in serial & exit
203
+ * - `watchRun`: run tests in serial, rerunning as files change
204
+ * - `parallelRun`: run tests in parallel & exit
205
+ * - `watchParallelRun`: run tests in parallel, rerunning as files change
206
+ * @param {Mocha} mocha - Mocha instance
207
+ * @param {Options} opts - Command line options
208
+ * @private
209
+ * @returns {Promise<Runner>}
210
+ */
211
+ exports.runMocha = async (mocha, options) => {
212
+ const {
213
+ watch = false,
214
+ extension = [],
215
+ ignore = [],
216
+ file = [],
217
+ parallel = false,
218
+ recursive = false,
219
+ sort = false,
220
+ spec = []
221
+ } = options;
222
+
223
+ const fileCollectParams = {
224
+ ignore,
225
+ extension,
226
+ file,
227
+ recursive,
228
+ sort,
229
+ spec
230
+ };
231
+
232
+ let run;
233
+ if (watch) {
234
+ run = parallel ? watchParallelRun : watchRun;
235
+ } else {
236
+ run = parallel ? parallelRun : singleRun;
237
+ }
238
+
239
+ return run(mocha, options, fileCollectParams);
240
+ };
241
+
242
+ /**
243
+ * Used for `--reporter` and `--ui`. Ensures there's only one, and asserts that
244
+ * it actually exists. This must be run _after_ requires are processed (see
245
+ * {@link handleRequires}), as it'll prevent interfaces from loading otherwise.
246
+ * @param {Object} opts - Options object
247
+ * @param {"reporter"|"ui"} pluginType - Type of plugin.
248
+ * @param {Object} [map] - Used as a cache of sorts;
249
+ * `Mocha.reporters` where each key corresponds to a reporter name,
250
+ * `Mocha.interfaces` where each key corresponds to an interface name.
251
+ * @private
252
+ */
253
+ exports.validateLegacyPlugin = (opts, pluginType, map = {}) => {
254
+ /**
255
+ * This should be a unique identifier; either a string (present in `map`),
256
+ * or a resolvable (via `require.resolve`) module ID/path.
257
+ * @type {string}
258
+ */
259
+ const pluginId = opts[pluginType];
260
+
261
+ if (Array.isArray(pluginId)) {
262
+ throw createInvalidLegacyPluginError(
263
+ `"--${pluginType}" can only be specified once`,
264
+ pluginType
265
+ );
266
+ }
267
+
268
+ const createUnknownError = err =>
269
+ createInvalidLegacyPluginError(
270
+ format('Could not load %s "%s":\n\n %O', pluginType, pluginId, err),
271
+ pluginType,
272
+ pluginId
273
+ );
274
+
275
+ // if this exists, then it's already loaded, so nothing more to do.
276
+ if (!map[pluginId]) {
277
+ let foundId;
278
+ try {
279
+ foundId = require.resolve(pluginId);
280
+ map[pluginId] = require(foundId);
281
+ } catch (err) {
282
+ if (foundId) throw createUnknownError(err);
283
+
284
+ // Try to load reporters from a cwd-relative path
285
+ try {
286
+ map[pluginId] = require(path.resolve(pluginId));
287
+ } catch (e) {
288
+ throw createUnknownError(e);
289
+ }
290
+ }
291
+ }
292
+ };
293
+
294
+ const createExitHandler = ({ exit, passOnFailingTestSuite }) => {
295
+ return code => {
296
+ const clampedCode = passOnFailingTestSuite
297
+ ? 0
298
+ : Math.min(code, 255);
299
+
300
+ return exit
301
+ ? exitMocha(clampedCode)
302
+ : exitMochaLater(clampedCode);
303
+ };
304
+ };
@@ -0,0 +1,116 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Metadata about various options of the `run` command
5
+ * @see module:lib/cli/run
6
+ * @module
7
+ * @private
8
+ */
9
+
10
+ /**
11
+ * Dictionary of yargs option types to list of options having said type
12
+ * @type {{string:string[]}}
13
+ * @private
14
+ */
15
+ const TYPES = (exports.types = {
16
+ array: [
17
+ 'extension',
18
+ 'file',
19
+ 'global',
20
+ 'ignore',
21
+ 'node-option',
22
+ 'reporter-option',
23
+ 'require',
24
+ 'spec',
25
+ 'watch-files',
26
+ 'watch-ignore'
27
+ ],
28
+ boolean: [
29
+ 'allow-uncaught',
30
+ 'async-only',
31
+ 'bail',
32
+ 'check-leaks',
33
+ 'color',
34
+ 'delay',
35
+ 'diff',
36
+ 'dry-run',
37
+ 'exit',
38
+ 'pass-on-failing-test-suite',
39
+ 'fail-zero',
40
+ 'forbid-only',
41
+ 'forbid-pending',
42
+ 'full-trace',
43
+ 'inline-diffs',
44
+ 'invert',
45
+ 'list-interfaces',
46
+ 'list-reporters',
47
+ 'no-colors',
48
+ 'parallel',
49
+ 'recursive',
50
+ 'sort',
51
+ 'watch'
52
+ ],
53
+ number: ['retries', 'jobs'],
54
+ string: [
55
+ 'config',
56
+ 'fgrep',
57
+ 'grep',
58
+ 'package',
59
+ 'reporter',
60
+ 'ui',
61
+ 'slow',
62
+ 'timeout'
63
+ ]
64
+ });
65
+
66
+ /**
67
+ * Option aliases keyed by canonical option name.
68
+ * Arrays used to reduce
69
+ * @type {{string:string[]}}
70
+ * @private
71
+ */
72
+ exports.aliases = {
73
+ 'async-only': ['A'],
74
+ bail: ['b'],
75
+ color: ['c', 'colors'],
76
+ fgrep: ['f'],
77
+ global: ['globals'],
78
+ grep: ['g'],
79
+ ignore: ['exclude'],
80
+ invert: ['i'],
81
+ jobs: ['j'],
82
+ 'no-colors': ['C'],
83
+ 'node-option': ['n'],
84
+ parallel: ['p'],
85
+ reporter: ['R'],
86
+ 'reporter-option': ['reporter-options', 'O'],
87
+ require: ['r'],
88
+ slow: ['s'],
89
+ sort: ['S'],
90
+ timeout: ['t', 'timeouts'],
91
+ ui: ['u'],
92
+ watch: ['w']
93
+ };
94
+
95
+ const ALL_MOCHA_FLAGS = Object.keys(TYPES).reduce((acc, key) => {
96
+ // gets all flags from each of the fields in `types`, adds those,
97
+ // then adds aliases of each flag (if any)
98
+ TYPES[key].forEach(flag => {
99
+ acc.add(flag);
100
+ const aliases = exports.aliases[flag] || [];
101
+ aliases.forEach(alias => {
102
+ acc.add(alias);
103
+ });
104
+ });
105
+ return acc;
106
+ }, new Set());
107
+
108
+ /**
109
+ * Returns `true` if the provided `flag` is known to Mocha.
110
+ * @param {string} flag - Flag to check
111
+ * @returns {boolean} If `true`, this is a Mocha flag
112
+ * @private
113
+ */
114
+ exports.isMochaFlag = flag => {
115
+ return ALL_MOCHA_FLAGS.has(flag.replace(/^--?/, ''));
116
+ };