mocha 9.1.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 (76) hide show
  1. package/CHANGELOG.md +1015 -0
  2. package/LICENSE +22 -0
  3. package/README.md +70 -0
  4. package/assets/growl/error.png +0 -0
  5. package/assets/growl/ok.png +0 -0
  6. package/bin/_mocha +10 -0
  7. package/bin/mocha +142 -0
  8. package/browser-entry.js +216 -0
  9. package/index.js +3 -0
  10. package/lib/browser/growl.js +169 -0
  11. package/lib/browser/highlight-tags.js +39 -0
  12. package/lib/browser/parse-query.js +24 -0
  13. package/lib/browser/progress.js +123 -0
  14. package/lib/browser/template.html +20 -0
  15. package/lib/cli/cli.js +89 -0
  16. package/lib/cli/collect-files.js +92 -0
  17. package/lib/cli/commands.js +13 -0
  18. package/lib/cli/config.js +105 -0
  19. package/lib/cli/index.js +3 -0
  20. package/lib/cli/init.js +36 -0
  21. package/lib/cli/lookup-files.js +145 -0
  22. package/lib/cli/node-flags.js +85 -0
  23. package/lib/cli/one-and-dones.js +69 -0
  24. package/lib/cli/options.js +261 -0
  25. package/lib/cli/run-helpers.js +243 -0
  26. package/lib/cli/run-option-metadata.js +117 -0
  27. package/lib/cli/run.js +379 -0
  28. package/lib/cli/watch-run.js +380 -0
  29. package/lib/context.js +86 -0
  30. package/lib/errors.js +563 -0
  31. package/lib/hook.js +89 -0
  32. package/lib/interfaces/bdd.js +111 -0
  33. package/lib/interfaces/common.js +193 -0
  34. package/lib/interfaces/exports.js +60 -0
  35. package/lib/interfaces/index.js +6 -0
  36. package/lib/interfaces/qunit.js +98 -0
  37. package/lib/interfaces/tdd.js +106 -0
  38. package/lib/mocha.js +1374 -0
  39. package/lib/mocharc.json +10 -0
  40. package/lib/nodejs/buffered-worker-pool.js +172 -0
  41. package/lib/nodejs/esm-utils.js +109 -0
  42. package/lib/nodejs/file-unloader.js +15 -0
  43. package/lib/nodejs/growl.js +137 -0
  44. package/lib/nodejs/parallel-buffered-runner.js +433 -0
  45. package/lib/nodejs/reporters/parallel-buffered.js +165 -0
  46. package/lib/nodejs/serializer.js +412 -0
  47. package/lib/nodejs/worker.js +151 -0
  48. package/lib/pending.js +16 -0
  49. package/lib/plugin-loader.js +286 -0
  50. package/lib/reporters/base.js +537 -0
  51. package/lib/reporters/doc.js +95 -0
  52. package/lib/reporters/dot.js +81 -0
  53. package/lib/reporters/html.js +390 -0
  54. package/lib/reporters/index.js +19 -0
  55. package/lib/reporters/json-stream.js +92 -0
  56. package/lib/reporters/json.js +162 -0
  57. package/lib/reporters/landing.js +116 -0
  58. package/lib/reporters/list.js +78 -0
  59. package/lib/reporters/markdown.js +112 -0
  60. package/lib/reporters/min.js +52 -0
  61. package/lib/reporters/nyan.js +276 -0
  62. package/lib/reporters/progress.js +104 -0
  63. package/lib/reporters/spec.js +99 -0
  64. package/lib/reporters/tap.js +293 -0
  65. package/lib/reporters/xunit.js +217 -0
  66. package/lib/runnable.js +476 -0
  67. package/lib/runner.js +1269 -0
  68. package/lib/stats-collector.js +83 -0
  69. package/lib/suite.js +695 -0
  70. package/lib/test.js +113 -0
  71. package/lib/utils.js +641 -0
  72. package/mocha-es2018.js +19816 -0
  73. package/mocha.css +325 -0
  74. package/mocha.js +30844 -0
  75. package/mocha.js.map +1 -0
  76. package/package.json +200 -0
@@ -0,0 +1,85 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Some settings and code related to Mocha's handling of Node.js/V8 flags.
5
+ * @private
6
+ * @module
7
+ */
8
+
9
+ const nodeFlags = process.allowedNodeEnvironmentFlags;
10
+ const {isMochaFlag} = require('./run-option-metadata');
11
+ const unparse = require('yargs-unparser');
12
+
13
+ /**
14
+ * These flags are considered "debug" flags.
15
+ * @see {@link impliesNoTimeouts}
16
+ * @private
17
+ */
18
+ const debugFlags = new Set(['inspect', 'inspect-brk']);
19
+
20
+ /**
21
+ * Mocha has historical support for various `node` and V8 flags which might not
22
+ * appear in `process.allowedNodeEnvironmentFlags`.
23
+ * These include:
24
+ * - `--preserve-symlinks`
25
+ * - `--harmony-*`
26
+ * - `--gc-global`
27
+ * - `--trace-*`
28
+ * - `--es-staging`
29
+ * - `--use-strict`
30
+ * - `--v8-*` (but *not* `--v8-options`)
31
+ * @summary Whether or not to pass a flag along to the `node` executable.
32
+ * @param {string} flag - Flag to test
33
+ * @param {boolean} [bareword=true] - If `false`, we expect `flag` to have one or two leading dashes.
34
+ * @returns {boolean} If the flag is considered a "Node" flag.
35
+ * @private
36
+ */
37
+ exports.isNodeFlag = (flag, bareword = true) => {
38
+ if (!bareword) {
39
+ // check if the flag begins with dashes; if not, not a node flag.
40
+ if (!/^--?/.test(flag)) {
41
+ return false;
42
+ }
43
+ // strip the leading dashes to match against subsequent checks
44
+ flag = flag.replace(/^--?/, '');
45
+ }
46
+ return (
47
+ // check actual node flags from `process.allowedNodeEnvironmentFlags`,
48
+ // then historical support for various V8 and non-`NODE_OPTIONS` flags
49
+ // and also any V8 flags with `--v8-` prefix
50
+ (!isMochaFlag(flag) && nodeFlags && nodeFlags.has(flag)) ||
51
+ debugFlags.has(flag) ||
52
+ /(?:preserve-symlinks(?:-main)?|harmony(?:[_-]|$)|(?:trace[_-].+$)|gc[_-]global$|es[_-]staging$|use[_-]strict$|v8[_-](?!options).+?$)/.test(
53
+ flag
54
+ )
55
+ );
56
+ };
57
+
58
+ /**
59
+ * Returns `true` if the flag is a "debug-like" flag. These require timeouts
60
+ * to be suppressed, or pausing the debugger on breakpoints will cause test failures.
61
+ * @param {string} flag - Flag to test
62
+ * @returns {boolean}
63
+ * @private
64
+ */
65
+ exports.impliesNoTimeouts = flag => debugFlags.has(flag);
66
+
67
+ /**
68
+ * All non-strictly-boolean arguments to node--those with values--must specify those values using `=`, e.g., `--inspect=0.0.0.0`.
69
+ * Unparse these arguments using `yargs-unparser` (which would result in `--inspect 0.0.0.0`), then supply `=` where we have values.
70
+ * There's probably an easier or more robust way to do this; fixes welcome
71
+ * @param {Object} opts - Arguments object
72
+ * @returns {string[]} Unparsed arguments using `=` to specify values
73
+ * @private
74
+ */
75
+ exports.unparseNodeFlags = opts => {
76
+ var args = unparse(opts);
77
+ return args.length
78
+ ? args
79
+ .join(' ')
80
+ .split(/\b/)
81
+ .map(arg => (arg === ' ' ? '=' : arg))
82
+ .join('')
83
+ .split(' ')
84
+ : [];
85
+ };
@@ -0,0 +1,69 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Contains "command" code for "one-and-dones"--options passed
5
+ * to Mocha which cause it to just dump some info and exit.
6
+ * See {@link module:lib/cli/one-and-dones.ONE_AND_DONE_ARGS ONE_AND_DONE_ARGS} for more info.
7
+ * @module
8
+ * @private
9
+ */
10
+
11
+ const Mocha = require('../mocha');
12
+
13
+ /**
14
+ * Dumps a sorted list of the enumerable, lower-case keys of some object
15
+ * to `STDOUT`.
16
+ * @param {Object} obj - Object, ostensibly having some enumerable keys
17
+ * @ignore
18
+ * @private
19
+ */
20
+ const showKeys = obj => {
21
+ console.log();
22
+ const keys = Object.keys(obj);
23
+ const maxKeyLength = keys.reduce((max, key) => Math.max(max, key.length), 0);
24
+ keys
25
+ .filter(
26
+ key => /^[a-z]/.test(key) && !obj[key].browserOnly && !obj[key].abstract
27
+ )
28
+ .sort()
29
+ .forEach(key => {
30
+ const description = obj[key].description;
31
+ console.log(
32
+ ` ${key.padEnd(maxKeyLength + 1)}${
33
+ description ? `- ${description}` : ''
34
+ }`
35
+ );
36
+ });
37
+ console.log();
38
+ };
39
+
40
+ /**
41
+ * Handlers for one-and-done options
42
+ * @namespace
43
+ * @private
44
+ */
45
+ exports.ONE_AND_DONES = {
46
+ /**
47
+ * Dump list of built-in interfaces
48
+ * @private
49
+ */
50
+ 'list-interfaces': () => {
51
+ showKeys(Mocha.interfaces);
52
+ },
53
+ /**
54
+ * Dump list of built-in reporters
55
+ * @private
56
+ */
57
+ 'list-reporters': () => {
58
+ showKeys(Mocha.reporters);
59
+ }
60
+ };
61
+
62
+ /**
63
+ * A Set of all one-and-done options
64
+ * @type Set<string>
65
+ * @private
66
+ */
67
+ exports.ONE_AND_DONE_ARGS = new Set(
68
+ ['help', 'h', 'version', 'V'].concat(Object.keys(exports.ONE_AND_DONES))
69
+ );
@@ -0,0 +1,261 @@
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
+ try {
185
+ const pkg = JSON.parse(fs.readFileSync(filepath, 'utf8'));
186
+ if (pkg.mocha) {
187
+ debug('`mocha` prop of package.json parsed: %O', pkg.mocha);
188
+ result = pkg.mocha;
189
+ } else {
190
+ debug('no config found in %s', filepath);
191
+ }
192
+ } catch (err) {
193
+ if (args.package) {
194
+ throw createUnparsableFileError(
195
+ `Unable to read/parse ${filepath}: ${err}`,
196
+ filepath
197
+ );
198
+ }
199
+ debug('failed to read default package.json at %s; ignoring', filepath);
200
+ }
201
+ }
202
+ return result;
203
+ };
204
+
205
+ module.exports.loadPkgRc = loadPkgRc;
206
+
207
+ /**
208
+ * Priority list:
209
+ *
210
+ * 1. Command-line args
211
+ * 2. RC file (`.mocharc.c?js`, `.mocharc.ya?ml`, `mocharc.json`)
212
+ * 3. `mocha` prop of `package.json`
213
+ * 4. default configuration (`lib/mocharc.json`)
214
+ *
215
+ * 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.
216
+ * @summary Parses options read from `.mocharc.*` and `package.json`.
217
+ * @param {string|string[]} [argv] - Arguments to parse
218
+ * @public
219
+ * @alias module:lib/cli.loadOptions
220
+ * @returns {external:yargsParser.Arguments} Parsed args from everything
221
+ */
222
+ const loadOptions = (argv = []) => {
223
+ let args = parse(argv);
224
+ // short-circuit: look for a flag that would abort loading of options
225
+ if (
226
+ Array.from(ONE_AND_DONE_ARGS).reduce(
227
+ (acc, arg) => acc || arg in args,
228
+ false
229
+ )
230
+ ) {
231
+ return args;
232
+ }
233
+
234
+ const rcConfig = loadRc(args);
235
+ const pkgConfig = loadPkgRc(args);
236
+
237
+ if (rcConfig) {
238
+ args.config = false;
239
+ args._ = args._.concat(rcConfig._ || []);
240
+ }
241
+ if (pkgConfig) {
242
+ args.package = false;
243
+ args._ = args._.concat(pkgConfig._ || []);
244
+ }
245
+
246
+ args = parse(args._, mocharc, args, rcConfig || {}, pkgConfig || {});
247
+
248
+ // recombine positional arguments and "spec"
249
+ if (args.spec) {
250
+ args._ = args._.concat(args.spec);
251
+ delete args.spec;
252
+ }
253
+
254
+ // make unique
255
+ args._ = Array.from(new Set(args._));
256
+
257
+ return args;
258
+ };
259
+
260
+ module.exports.loadOptions = loadOptions;
261
+ module.exports.YARGS_PARSER_CONFIG = YARGS_PARSER_CONFIG;
@@ -0,0 +1,243 @@
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 debug = require('debug')('mocha:cli:run:helpers');
13
+ const {watchRun, watchParallelRun} = require('./watch-run');
14
+ const collectFiles = require('./collect-files');
15
+ const {format} = require('util');
16
+ const {createInvalidLegacyPluginError} = require('../errors');
17
+ const {requireOrImport} = require('../nodejs/esm-utils');
18
+ const PluginLoader = require('../plugin-loader');
19
+
20
+ /**
21
+ * Exits Mocha when tests + code under test has finished execution (default)
22
+ * @param {number} code - Exit code; typically # of failures
23
+ * @ignore
24
+ * @private
25
+ */
26
+ const exitMochaLater = code => {
27
+ process.on('exit', () => {
28
+ process.exitCode = Math.min(code, 255);
29
+ });
30
+ };
31
+
32
+ /**
33
+ * Exits Mocha when Mocha itself has finished execution, regardless of
34
+ * what the tests or code under test is doing.
35
+ * @param {number} code - Exit code; typically # of failures
36
+ * @ignore
37
+ * @private
38
+ */
39
+ const exitMocha = code => {
40
+ const clampedCode = Math.min(code, 255);
41
+ let draining = 0;
42
+
43
+ // Eagerly set the process's exit code in case stream.write doesn't
44
+ // execute its callback before the process terminates.
45
+ process.exitCode = clampedCode;
46
+
47
+ // flush output for Node.js Windows pipe bug
48
+ // https://github.com/joyent/node/issues/6247 is just one bug example
49
+ // https://github.com/visionmedia/mocha/issues/333 has a good discussion
50
+ const done = () => {
51
+ if (!draining--) {
52
+ process.exit(clampedCode);
53
+ }
54
+ };
55
+
56
+ const streams = [process.stdout, process.stderr];
57
+
58
+ streams.forEach(stream => {
59
+ // submit empty write request and wait for completion
60
+ draining += 1;
61
+ stream.write('', done);
62
+ });
63
+
64
+ done();
65
+ };
66
+
67
+ /**
68
+ * Coerce a comma-delimited string (or array thereof) into a flattened array of
69
+ * strings
70
+ * @param {string|string[]} str - Value to coerce
71
+ * @returns {string[]} Array of strings
72
+ * @private
73
+ */
74
+ exports.list = str =>
75
+ Array.isArray(str) ? exports.list(str.join(',')) : str.split(/ *, */);
76
+
77
+ /**
78
+ * `require()` the modules as required by `--require <require>`.
79
+ *
80
+ * Returns array of `mochaHooks` exports, if any.
81
+ * @param {string[]} requires - Modules to require
82
+ * @returns {Promise<object>} Plugin implementations
83
+ * @private
84
+ */
85
+ exports.handleRequires = async (requires = [], {ignoredPlugins = []} = {}) => {
86
+ const pluginLoader = PluginLoader.create({ignore: ignoredPlugins});
87
+ for await (const mod of requires) {
88
+ let modpath = mod;
89
+ // this is relative to cwd
90
+ if (fs.existsSync(mod) || fs.existsSync(`${mod}.js`)) {
91
+ modpath = path.resolve(mod);
92
+ debug('resolved required file %s to %s', mod, modpath);
93
+ }
94
+ const requiredModule = await requireOrImport(modpath);
95
+ if (requiredModule && typeof requiredModule === 'object') {
96
+ if (pluginLoader.load(requiredModule)) {
97
+ debug('found one or more plugin implementations in %s', modpath);
98
+ }
99
+ }
100
+ debug('loaded required module "%s"', mod);
101
+ }
102
+ const plugins = await pluginLoader.finalize();
103
+ if (Object.keys(plugins).length) {
104
+ debug('finalized plugin implementations: %O', plugins);
105
+ }
106
+ return plugins;
107
+ };
108
+
109
+ /**
110
+ * Collect and load test files, then run mocha instance.
111
+ * @param {Mocha} mocha - Mocha instance
112
+ * @param {Options} [opts] - Command line options
113
+ * @param {boolean} [opts.exit] - Whether or not to force-exit after tests are complete
114
+ * @param {Object} fileCollectParams - Parameters that control test
115
+ * file collection. See `lib/cli/collect-files.js`.
116
+ * @returns {Promise<Runner>}
117
+ * @private
118
+ */
119
+ const singleRun = async (mocha, {exit}, fileCollectParams) => {
120
+ const files = collectFiles(fileCollectParams);
121
+ debug('single run with %d file(s)', files.length);
122
+ mocha.files = files;
123
+
124
+ // handles ESM modules
125
+ await mocha.loadFilesAsync();
126
+ return mocha.run(exit ? exitMocha : exitMochaLater);
127
+ };
128
+
129
+ /**
130
+ * Collect files and run tests (using `BufferedRunner`).
131
+ *
132
+ * This is `async` for consistency.
133
+ *
134
+ * @param {Mocha} mocha - Mocha instance
135
+ * @param {Options} options - Command line options
136
+ * @param {Object} fileCollectParams - Parameters that control test
137
+ * file collection. See `lib/cli/collect-files.js`.
138
+ * @returns {Promise<BufferedRunner>}
139
+ * @ignore
140
+ * @private
141
+ */
142
+ const parallelRun = async (mocha, options, fileCollectParams) => {
143
+ const files = collectFiles(fileCollectParams);
144
+ debug('executing %d test file(s) in parallel mode', files.length);
145
+ mocha.files = files;
146
+
147
+ // note that we DO NOT load any files here; this is handled by the worker
148
+ return mocha.run(options.exit ? exitMocha : exitMochaLater);
149
+ };
150
+
151
+ /**
152
+ * Actually run tests. Delegates to one of four different functions:
153
+ * - `singleRun`: run tests in serial & exit
154
+ * - `watchRun`: run tests in serial, rerunning as files change
155
+ * - `parallelRun`: run tests in parallel & exit
156
+ * - `watchParallelRun`: run tests in parallel, rerunning as files change
157
+ * @param {Mocha} mocha - Mocha instance
158
+ * @param {Options} opts - Command line options
159
+ * @private
160
+ * @returns {Promise<Runner>}
161
+ */
162
+ exports.runMocha = async (mocha, options) => {
163
+ const {
164
+ watch = false,
165
+ extension = [],
166
+ ignore = [],
167
+ file = [],
168
+ parallel = false,
169
+ recursive = false,
170
+ sort = false,
171
+ spec = []
172
+ } = options;
173
+
174
+ const fileCollectParams = {
175
+ ignore,
176
+ extension,
177
+ file,
178
+ recursive,
179
+ sort,
180
+ spec
181
+ };
182
+
183
+ let run;
184
+ if (watch) {
185
+ run = parallel ? watchParallelRun : watchRun;
186
+ } else {
187
+ run = parallel ? parallelRun : singleRun;
188
+ }
189
+
190
+ return run(mocha, options, fileCollectParams);
191
+ };
192
+
193
+ /**
194
+ * Used for `--reporter` and `--ui`. Ensures there's only one, and asserts that
195
+ * it actually exists. This must be run _after_ requires are processed (see
196
+ * {@link handleRequires}), as it'll prevent interfaces from loading otherwise.
197
+ * @param {Object} opts - Options object
198
+ * @param {"reporter"|"ui"} pluginType - Type of plugin.
199
+ * @param {Object} [map] - Used as a cache of sorts;
200
+ * `Mocha.reporters` where each key corresponds to a reporter name,
201
+ * `Mocha.interfaces` where each key corresponds to an interface name.
202
+ * @private
203
+ */
204
+ exports.validateLegacyPlugin = (opts, pluginType, map = {}) => {
205
+ /**
206
+ * This should be a unique identifier; either a string (present in `map`),
207
+ * or a resolvable (via `require.resolve`) module ID/path.
208
+ * @type {string}
209
+ */
210
+ const pluginId = opts[pluginType];
211
+
212
+ if (Array.isArray(pluginId)) {
213
+ throw createInvalidLegacyPluginError(
214
+ `"--${pluginType}" can only be specified once`,
215
+ pluginType
216
+ );
217
+ }
218
+
219
+ const createUnknownError = err =>
220
+ createInvalidLegacyPluginError(
221
+ format('Could not load %s "%s":\n\n %O', pluginType, pluginId, err),
222
+ pluginType,
223
+ pluginId
224
+ );
225
+
226
+ // if this exists, then it's already loaded, so nothing more to do.
227
+ if (!map[pluginId]) {
228
+ try {
229
+ map[pluginId] = require(pluginId);
230
+ } catch (err) {
231
+ if (err.code === 'MODULE_NOT_FOUND') {
232
+ // Try to load reporters from a path (absolute or relative)
233
+ try {
234
+ map[pluginId] = require(path.resolve(pluginId));
235
+ } catch (err) {
236
+ throw createUnknownError(err);
237
+ }
238
+ } else {
239
+ throw createUnknownError(err);
240
+ }
241
+ }
242
+ }
243
+ };