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.
- package/CHANGELOG.md +1015 -0
- package/LICENSE +22 -0
- package/README.md +70 -0
- package/assets/growl/error.png +0 -0
- package/assets/growl/ok.png +0 -0
- package/bin/_mocha +10 -0
- package/bin/mocha +142 -0
- package/browser-entry.js +216 -0
- package/index.js +3 -0
- package/lib/browser/growl.js +169 -0
- package/lib/browser/highlight-tags.js +39 -0
- package/lib/browser/parse-query.js +24 -0
- package/lib/browser/progress.js +123 -0
- package/lib/browser/template.html +20 -0
- package/lib/cli/cli.js +89 -0
- package/lib/cli/collect-files.js +92 -0
- package/lib/cli/commands.js +13 -0
- package/lib/cli/config.js +105 -0
- package/lib/cli/index.js +3 -0
- package/lib/cli/init.js +36 -0
- package/lib/cli/lookup-files.js +145 -0
- package/lib/cli/node-flags.js +85 -0
- package/lib/cli/one-and-dones.js +69 -0
- package/lib/cli/options.js +261 -0
- package/lib/cli/run-helpers.js +243 -0
- package/lib/cli/run-option-metadata.js +117 -0
- package/lib/cli/run.js +379 -0
- package/lib/cli/watch-run.js +380 -0
- package/lib/context.js +86 -0
- package/lib/errors.js +563 -0
- package/lib/hook.js +89 -0
- package/lib/interfaces/bdd.js +111 -0
- package/lib/interfaces/common.js +193 -0
- package/lib/interfaces/exports.js +60 -0
- package/lib/interfaces/index.js +6 -0
- package/lib/interfaces/qunit.js +98 -0
- package/lib/interfaces/tdd.js +106 -0
- package/lib/mocha.js +1374 -0
- package/lib/mocharc.json +10 -0
- package/lib/nodejs/buffered-worker-pool.js +172 -0
- package/lib/nodejs/esm-utils.js +109 -0
- package/lib/nodejs/file-unloader.js +15 -0
- package/lib/nodejs/growl.js +137 -0
- package/lib/nodejs/parallel-buffered-runner.js +433 -0
- package/lib/nodejs/reporters/parallel-buffered.js +165 -0
- package/lib/nodejs/serializer.js +412 -0
- package/lib/nodejs/worker.js +151 -0
- package/lib/pending.js +16 -0
- package/lib/plugin-loader.js +286 -0
- package/lib/reporters/base.js +537 -0
- package/lib/reporters/doc.js +95 -0
- package/lib/reporters/dot.js +81 -0
- package/lib/reporters/html.js +390 -0
- package/lib/reporters/index.js +19 -0
- package/lib/reporters/json-stream.js +92 -0
- package/lib/reporters/json.js +162 -0
- package/lib/reporters/landing.js +116 -0
- package/lib/reporters/list.js +78 -0
- package/lib/reporters/markdown.js +112 -0
- package/lib/reporters/min.js +52 -0
- package/lib/reporters/nyan.js +276 -0
- package/lib/reporters/progress.js +104 -0
- package/lib/reporters/spec.js +99 -0
- package/lib/reporters/tap.js +293 -0
- package/lib/reporters/xunit.js +217 -0
- package/lib/runnable.js +476 -0
- package/lib/runner.js +1269 -0
- package/lib/stats-collector.js +83 -0
- package/lib/suite.js +695 -0
- package/lib/test.js +113 -0
- package/lib/utils.js +641 -0
- package/mocha-es2018.js +19816 -0
- package/mocha.css +325 -0
- package/mocha.js +30844 -0
- package/mocha.js.map +1 -0
- 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
|
+
};
|