mocha 7.1.2 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -2
- package/bin/mocha +7 -2
- package/browser-entry.js +11 -0
- package/lib/cli/cli.js +4 -1
- package/lib/cli/collect-files.js +2 -1
- package/lib/cli/config.js +6 -5
- package/lib/cli/options.js +3 -3
- package/lib/cli/run-helpers.js +85 -26
- package/lib/cli/run.js +15 -2
- package/lib/errors.js +179 -9
- package/lib/hook.js +8 -0
- package/lib/interfaces/common.js +6 -3
- package/lib/mocha.js +171 -12
- package/lib/reporters/doc.js +6 -0
- package/lib/reporters/json-stream.js +1 -0
- package/lib/reporters/json.js +1 -0
- package/lib/reporters/landing.js +8 -0
- package/lib/runnable.js +21 -17
- package/lib/runner.js +161 -54
- package/lib/suite.js +29 -3
- package/lib/test.js +20 -2
- package/lib/utils.js +14 -3
- package/mocha.js +639 -106
- package/package.json +41 -32
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
# 7.2.0 / 2020-05-22
|
|
2
|
+
|
|
3
|
+
## :tada: Enhancements
|
|
4
|
+
|
|
5
|
+
- [#4234](https://github.com/mochajs/mocha/issues/4234): Add ability to run tests in a mocha instance multiple times ([**@nicojs**](https://github.com/nicojs))
|
|
6
|
+
- [#4219](https://github.com/mochajs/mocha/issues/4219): Exposing filename in JSON, doc, and json-stream reporters ([**@Daniel0113**](https://github.com/Daniel0113))
|
|
7
|
+
- [#4244](https://github.com/mochajs/mocha/issues/4244): Add Root Hook Plugins ([**@boneskull**](https://github.com/boneskull))
|
|
8
|
+
|
|
9
|
+
## :bug: Fixes
|
|
10
|
+
|
|
11
|
+
- [#4258](https://github.com/mochajs/mocha/issues/4258): Fix missing dot in name of configuration file ([**@sonicdoe**](https://github.com/sonicdoe))
|
|
12
|
+
- [#4194](https://github.com/mochajs/mocha/issues/4194): Check if module.paths really exists ([**@ematipico**](https://github.com/ematipico))
|
|
13
|
+
- [#4256](https://github.com/mochajs/mocha/issues/4256): `--forbid-only` does not recognize `it.only` when `before` crashes ([**@arvidOtt**](https://github.com/arvidOtt))
|
|
14
|
+
- [#4152](https://github.com/mochajs/mocha/issues/4152): Bug with multiple async done() calls ([**@boneskull**](https://github.com/boneskull))
|
|
15
|
+
- [#4275](https://github.com/mochajs/mocha/issues/4275): Improper warnings for invalid reporters ([**@boneskull**](https://github.com/boneskull))
|
|
16
|
+
- [#4288](https://github.com/mochajs/mocha/issues/4288): Broken hook.spec.js test for IE11 ([**@boneskull**](https://github.com/boneskull))
|
|
17
|
+
|
|
18
|
+
## :book: Documentation
|
|
19
|
+
|
|
20
|
+
- [#4081](https://github.com/mochajs/mocha/issues/4081): Insufficient white space for API docs in view on mobile ([**@HyunSangHan**](https://github.com/HyunSangHan))
|
|
21
|
+
- [#4255](https://github.com/mochajs/mocha/issues/4255): Update mocha-docdash for UI fixes on API docs ([**@craigtaub**](https://github.com/craigtaub))
|
|
22
|
+
- [#4235](https://github.com/mochajs/mocha/issues/4235): Enable emoji on website; enable normal ul elements ([**@boneskull**](https://github.com/boneskull))
|
|
23
|
+
- [#4272](https://github.com/mochajs/mocha/issues/4272): Fetch sponsors at build time, show ALL non-skeevy sponsors ([**@boneskull**](https://github.com/boneskull))
|
|
24
|
+
|
|
25
|
+
## :nut_and_bolt: Other
|
|
26
|
+
|
|
27
|
+
- [#4249](https://github.com/mochajs/mocha/issues/4249): Refactoring improving encapsulation ([**@arvidOtt**](https://github.com/arvidOtt))
|
|
28
|
+
- [#4242](https://github.com/mochajs/mocha/issues/4242): CI add job names, add Node.js v14 to matrix ([**@boneskull**](https://github.com/boneskull))
|
|
29
|
+
- [#4237](https://github.com/mochajs/mocha/issues/4237): Refactor validatePlugins to throw coded errors ([**@boneskull**](https://github.com/boneskull))
|
|
30
|
+
- [#4236](https://github.com/mochajs/mocha/issues/4236): Better debug output ([**@boneskull**](https://github.com/boneskull))
|
|
31
|
+
|
|
1
32
|
# 7.1.2 / 2020-04-26
|
|
2
33
|
|
|
3
34
|
## :nut_and_bolt: Other
|
|
@@ -546,7 +577,7 @@ This release fixes a class of tests which report as _false positives_. **Certain
|
|
|
546
577
|
|
|
547
578
|
- [#3226](https://github.com/mochajs/mocha/issues/3226): Do not swallow errors that are thrown asynchronously from passing tests ([@boneskull](https://github.com/boneskull)). Example:
|
|
548
579
|
|
|
549
|
-
|
|
580
|
+
\`\`\`js
|
|
550
581
|
it('should actually fail, sorry!', function (done) {
|
|
551
582
|
// passing assertion
|
|
552
583
|
assert(true === true);
|
|
@@ -559,7 +590,7 @@ This release fixes a class of tests which report as _false positives_. **Certain
|
|
|
559
590
|
throw new Error('chaos!');
|
|
560
591
|
}, 100);
|
|
561
592
|
});
|
|
562
|
-
|
|
593
|
+
\`\`\`
|
|
563
594
|
|
|
564
595
|
Previously to this version, Mocha would have _silently swallowed_ the `chaos!` exception, and you wouldn't know. Well, _now you know_. Mocha cannot recover from this gracefully, so it will exit with a nonzero code.
|
|
565
596
|
|
package/bin/mocha
CHANGED
|
@@ -34,7 +34,7 @@ debug('loaded opts', opts);
|
|
|
34
34
|
*/
|
|
35
35
|
const disableTimeouts = value => {
|
|
36
36
|
if (impliesNoTimeouts(value)) {
|
|
37
|
-
debug(
|
|
37
|
+
debug('option %s disabled timeouts', value);
|
|
38
38
|
mochaArgs.timeout = 0;
|
|
39
39
|
delete mochaArgs.timeouts;
|
|
40
40
|
delete mochaArgs.t;
|
|
@@ -108,7 +108,11 @@ if (Object.keys(nodeArgs).length) {
|
|
|
108
108
|
unparse(mochaArgs, {alias: aliases})
|
|
109
109
|
);
|
|
110
110
|
|
|
111
|
-
debug(
|
|
111
|
+
debug(
|
|
112
|
+
'forking child process via command: %s %s',
|
|
113
|
+
process.execPath,
|
|
114
|
+
args.join(' ')
|
|
115
|
+
);
|
|
112
116
|
|
|
113
117
|
const proc = spawn(process.execPath, args, {
|
|
114
118
|
stdio: 'inherit'
|
|
@@ -130,5 +134,6 @@ if (Object.keys(nodeArgs).length) {
|
|
|
130
134
|
proc.kill('SIGTERM'); // if that didn't work, we're probably in an infinite loop, so make it die.
|
|
131
135
|
});
|
|
132
136
|
} else {
|
|
137
|
+
debug('running Mocha in-process');
|
|
133
138
|
require('../lib/cli/cli').main(unparse(mochaArgs, {alias: aliases}));
|
|
134
139
|
}
|
package/browser-entry.js
CHANGED
|
@@ -52,6 +52,17 @@ process.removeListener = function(e, fn) {
|
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Implements listenerCount for 'uncaughtException'.
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
process.listenerCount = function(name) {
|
|
60
|
+
if (name === 'uncaughtException') {
|
|
61
|
+
return uncaughtExceptionHandlers.length;
|
|
62
|
+
}
|
|
63
|
+
return 0;
|
|
64
|
+
};
|
|
65
|
+
|
|
55
66
|
/**
|
|
56
67
|
* Implements uncaughtException listener.
|
|
57
68
|
*/
|
package/lib/cli/cli.js
CHANGED
|
@@ -19,6 +19,7 @@ const {loadOptions, YARGS_PARSER_CONFIG} = require('./options');
|
|
|
19
19
|
const commands = require('./commands');
|
|
20
20
|
const ansi = require('ansi-colors');
|
|
21
21
|
const {repository, homepage, version, gitter} = require('../../package.json');
|
|
22
|
+
const {cwd} = require('../utils');
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* - Accepts an `Array` of arguments
|
|
@@ -30,7 +31,9 @@ const {repository, homepage, version, gitter} = require('../../package.json');
|
|
|
30
31
|
exports.main = (argv = process.argv.slice(2)) => {
|
|
31
32
|
debug('entered main with raw args', argv);
|
|
32
33
|
// ensure we can require() from current working directory
|
|
33
|
-
module.paths
|
|
34
|
+
if (typeof module.paths !== 'undefined') {
|
|
35
|
+
module.paths.push(cwd(), path.resolve('node_modules'));
|
|
36
|
+
}
|
|
34
37
|
|
|
35
38
|
Error.stackTraceLimit = Infinity; // configurable via --stack-trace-limit?
|
|
36
39
|
|
package/lib/cli/collect-files.js
CHANGED
|
@@ -5,6 +5,7 @@ const ansi = require('ansi-colors');
|
|
|
5
5
|
const debug = require('debug')('mocha:cli:run:helpers');
|
|
6
6
|
const minimatch = require('minimatch');
|
|
7
7
|
const utils = require('../utils');
|
|
8
|
+
const {NO_FILES_MATCH_PATTERN} = require('../errors').constants;
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Exports a function that collects test files from CLI parameters.
|
|
@@ -34,7 +35,7 @@ module.exports = ({ignore, extension, file, recursive, sort, spec} = {}) => {
|
|
|
34
35
|
try {
|
|
35
36
|
newFiles = utils.lookupFiles(arg, extension, recursive);
|
|
36
37
|
} catch (err) {
|
|
37
|
-
if (err.code ===
|
|
38
|
+
if (err.code === NO_FILES_MATCH_PATTERN) {
|
|
38
39
|
unmatched.push({message: err.message, pattern: err.pattern});
|
|
39
40
|
return;
|
|
40
41
|
}
|
package/lib/cli/config.js
CHANGED
|
@@ -12,6 +12,7 @@ const fs = require('fs');
|
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const debug = require('debug')('mocha:cli:config');
|
|
14
14
|
const findUp = require('find-up');
|
|
15
|
+
const utils = require('../utils');
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* These are the valid config files, in order of precedence;
|
|
@@ -43,11 +44,11 @@ const parsers = (exports.parsers = {
|
|
|
43
44
|
js: filepath => {
|
|
44
45
|
const cwdFilepath = path.resolve(filepath);
|
|
45
46
|
try {
|
|
46
|
-
debug(
|
|
47
|
+
debug('parsers: load using cwd-relative path: "%s"', cwdFilepath);
|
|
47
48
|
return require(cwdFilepath);
|
|
48
49
|
} catch (err) {
|
|
49
50
|
if (isModuleNotFoundError(err)) {
|
|
50
|
-
debug(
|
|
51
|
+
debug('parsers: retry load as module-relative path: "%s"', filepath);
|
|
51
52
|
return require(filepath);
|
|
52
53
|
} else {
|
|
53
54
|
throw err; // rethrow
|
|
@@ -70,7 +71,7 @@ const parsers = (exports.parsers = {
|
|
|
70
71
|
*/
|
|
71
72
|
exports.loadConfig = filepath => {
|
|
72
73
|
let config = {};
|
|
73
|
-
debug(
|
|
74
|
+
debug('loadConfig: trying to parse config at %s', filepath);
|
|
74
75
|
|
|
75
76
|
const ext = path.extname(filepath);
|
|
76
77
|
try {
|
|
@@ -93,10 +94,10 @@ exports.loadConfig = filepath => {
|
|
|
93
94
|
* @param {string} [cwd] - Current working directory
|
|
94
95
|
* @returns {string|null} Filepath to config, if found
|
|
95
96
|
*/
|
|
96
|
-
exports.findConfig = (cwd =
|
|
97
|
+
exports.findConfig = (cwd = utils.cwd()) => {
|
|
97
98
|
const filepath = findUp.sync(exports.CONFIG_FILES, {cwd});
|
|
98
99
|
if (filepath) {
|
|
99
|
-
debug(
|
|
100
|
+
debug('findConfig: found config file %s', filepath);
|
|
100
101
|
}
|
|
101
102
|
return filepath;
|
|
102
103
|
};
|
package/lib/cli/options.js
CHANGED
|
@@ -244,16 +244,16 @@ const loadPkgRc = (args = {}) => {
|
|
|
244
244
|
try {
|
|
245
245
|
const pkg = JSON.parse(fs.readFileSync(filepath, 'utf8'));
|
|
246
246
|
if (pkg.mocha) {
|
|
247
|
-
debug(`
|
|
247
|
+
debug('`mocha` prop of package.json parsed: %O', pkg.mocha);
|
|
248
248
|
result = pkg.mocha;
|
|
249
249
|
} else {
|
|
250
|
-
debug(
|
|
250
|
+
debug('no config found in %s', filepath);
|
|
251
251
|
}
|
|
252
252
|
} catch (err) {
|
|
253
253
|
if (args.package) {
|
|
254
254
|
throw new Error(`Unable to read/parse ${filepath}: ${err}`);
|
|
255
255
|
}
|
|
256
|
-
debug(
|
|
256
|
+
debug('failed to read default package.json at %s; ignoring', filepath);
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
259
|
return result;
|
package/lib/cli/run-helpers.js
CHANGED
|
@@ -12,8 +12,9 @@ const path = require('path');
|
|
|
12
12
|
const debug = require('debug')('mocha:cli:run:helpers');
|
|
13
13
|
const watchRun = require('./watch-run');
|
|
14
14
|
const collectFiles = require('./collect-files');
|
|
15
|
-
|
|
16
|
-
const
|
|
15
|
+
const {type} = require('../utils');
|
|
16
|
+
const {format} = require('util');
|
|
17
|
+
const {createInvalidPluginError, createUnsupportedError} = require('../errors');
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Exits Mocha when tests + code under test has finished execution (default)
|
|
@@ -73,20 +74,60 @@ exports.list = str =>
|
|
|
73
74
|
Array.isArray(str) ? exports.list(str.join(',')) : str.split(/ *, */);
|
|
74
75
|
|
|
75
76
|
/**
|
|
76
|
-
* `require()` the modules as required by `--require <require
|
|
77
|
+
* `require()` the modules as required by `--require <require>`.
|
|
78
|
+
*
|
|
79
|
+
* Returns array of `mochaHooks` exports, if any.
|
|
77
80
|
* @param {string[]} requires - Modules to require
|
|
81
|
+
* @returns {Promise<MochaRootHookObject|MochaRootHookFunction>} Any root hooks
|
|
78
82
|
* @private
|
|
79
83
|
*/
|
|
80
|
-
exports.handleRequires = (requires = []) =>
|
|
81
|
-
requires.
|
|
84
|
+
exports.handleRequires = async (requires = []) =>
|
|
85
|
+
requires.reduce((acc, mod) => {
|
|
82
86
|
let modpath = mod;
|
|
83
|
-
|
|
87
|
+
// this is relative to cwd
|
|
88
|
+
if (fs.existsSync(mod) || fs.existsSync(`${mod}.js`)) {
|
|
84
89
|
modpath = path.resolve(mod);
|
|
85
|
-
debug(
|
|
90
|
+
debug('resolved required file %s to %s', mod, modpath);
|
|
86
91
|
}
|
|
87
|
-
require(modpath);
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
const requiredModule = require(modpath);
|
|
93
|
+
if (type(requiredModule) === 'object' && requiredModule.mochaHooks) {
|
|
94
|
+
const mochaHooksType = type(requiredModule.mochaHooks);
|
|
95
|
+
if (/function$/.test(mochaHooksType) || mochaHooksType === 'object') {
|
|
96
|
+
debug('found root hooks in required file %s', mod);
|
|
97
|
+
acc.push(requiredModule.mochaHooks);
|
|
98
|
+
} else {
|
|
99
|
+
throw createUnsupportedError(
|
|
100
|
+
'mochaHooks must be an object or a function returning (or fulfilling with) an object'
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
debug('loaded required module "%s"', mod);
|
|
105
|
+
return acc;
|
|
106
|
+
}, []);
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Loads root hooks as exported via `mochaHooks` from required files.
|
|
110
|
+
* These can be sync/async functions returning objects, or just objects.
|
|
111
|
+
* Flattens to a single object.
|
|
112
|
+
* @param {Array<MochaRootHookObject|MochaRootHookFunction>} rootHooks - Array of root hooks
|
|
113
|
+
* @private
|
|
114
|
+
* @returns {MochaRootHookObject}
|
|
115
|
+
*/
|
|
116
|
+
exports.loadRootHooks = async rootHooks => {
|
|
117
|
+
const rootHookObjects = await Promise.all(
|
|
118
|
+
rootHooks.map(async hook => (/function$/.test(type(hook)) ? hook() : hook))
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
return rootHookObjects.reduce(
|
|
122
|
+
(acc, hook) => {
|
|
123
|
+
acc.beforeAll = acc.beforeAll.concat(hook.beforeAll || []);
|
|
124
|
+
acc.beforeEach = acc.beforeEach.concat(hook.beforeEach || []);
|
|
125
|
+
acc.afterAll = acc.afterAll.concat(hook.afterAll || []);
|
|
126
|
+
acc.afterEach = acc.afterEach.concat(hook.afterEach || []);
|
|
127
|
+
return acc;
|
|
128
|
+
},
|
|
129
|
+
{beforeAll: [], beforeEach: [], afterAll: [], afterEach: []}
|
|
130
|
+
);
|
|
90
131
|
};
|
|
91
132
|
|
|
92
133
|
/**
|
|
@@ -101,9 +142,10 @@ exports.handleRequires = (requires = []) => {
|
|
|
101
142
|
*/
|
|
102
143
|
const singleRun = async (mocha, {exit}, fileCollectParams) => {
|
|
103
144
|
const files = collectFiles(fileCollectParams);
|
|
104
|
-
debug('
|
|
145
|
+
debug('single run with %d file(s)', files.length);
|
|
105
146
|
mocha.files = files;
|
|
106
147
|
|
|
148
|
+
// handles ESM modules
|
|
107
149
|
await mocha.loadFilesAsync();
|
|
108
150
|
return mocha.run(exit ? exitMocha : exitMochaLater);
|
|
109
151
|
};
|
|
@@ -146,35 +188,52 @@ exports.runMocha = async (mocha, options) => {
|
|
|
146
188
|
};
|
|
147
189
|
|
|
148
190
|
/**
|
|
149
|
-
* Used for `--reporter` and `--ui`. Ensures there's only one, and asserts
|
|
150
|
-
*
|
|
151
|
-
* @
|
|
152
|
-
* interfaces from loading.
|
|
191
|
+
* Used for `--reporter` and `--ui`. Ensures there's only one, and asserts that
|
|
192
|
+
* it actually exists. This must be run _after_ requires are processed (see
|
|
193
|
+
* {@link handleRequires}), as it'll prevent interfaces from loading otherwise.
|
|
153
194
|
* @param {Object} opts - Options object
|
|
154
|
-
* @param {
|
|
155
|
-
* @param {Object} [map] - An object perhaps having key `key
|
|
195
|
+
* @param {"reporter"|"interface"} pluginType - Type of plugin.
|
|
196
|
+
* @param {Object} [map] - An object perhaps having key `key`. Used as a cache
|
|
197
|
+
* of sorts; `Mocha.reporters` is one, where each key corresponds to a reporter
|
|
198
|
+
* name
|
|
156
199
|
* @private
|
|
157
200
|
*/
|
|
158
|
-
exports.validatePlugin = (opts,
|
|
159
|
-
|
|
160
|
-
|
|
201
|
+
exports.validatePlugin = (opts, pluginType, map = {}) => {
|
|
202
|
+
/**
|
|
203
|
+
* This should be a unique identifier; either a string (present in `map`),
|
|
204
|
+
* or a resolvable (via `require.resolve`) module ID/path.
|
|
205
|
+
* @type {string}
|
|
206
|
+
*/
|
|
207
|
+
const pluginId = opts[pluginType];
|
|
208
|
+
|
|
209
|
+
if (Array.isArray(pluginId)) {
|
|
210
|
+
throw createInvalidPluginError(
|
|
211
|
+
`"--${pluginType}" can only be specified once`,
|
|
212
|
+
pluginType
|
|
213
|
+
);
|
|
161
214
|
}
|
|
162
215
|
|
|
163
|
-
const unknownError =
|
|
216
|
+
const unknownError = err =>
|
|
217
|
+
createInvalidPluginError(
|
|
218
|
+
format('Could not load %s "%s":\n\n %O', pluginType, pluginId, err),
|
|
219
|
+
pluginType,
|
|
220
|
+
pluginId
|
|
221
|
+
);
|
|
164
222
|
|
|
165
|
-
if
|
|
223
|
+
// if this exists, then it's already loaded, so nothing more to do.
|
|
224
|
+
if (!map[pluginId]) {
|
|
166
225
|
try {
|
|
167
|
-
opts[
|
|
226
|
+
opts[pluginType] = require(pluginId);
|
|
168
227
|
} catch (err) {
|
|
169
228
|
if (err.code === 'MODULE_NOT_FOUND') {
|
|
170
229
|
// Try to load reporters from a path (absolute or relative)
|
|
171
230
|
try {
|
|
172
|
-
opts[
|
|
231
|
+
opts[pluginType] = require(path.resolve(pluginId));
|
|
173
232
|
} catch (err) {
|
|
174
|
-
throw unknownError();
|
|
233
|
+
throw unknownError(err);
|
|
175
234
|
}
|
|
176
235
|
} else {
|
|
177
|
-
throw unknownError();
|
|
236
|
+
throw unknownError(err);
|
|
178
237
|
}
|
|
179
238
|
}
|
|
180
239
|
}
|
package/lib/cli/run.js
CHANGED
|
@@ -18,6 +18,7 @@ const {
|
|
|
18
18
|
list,
|
|
19
19
|
handleRequires,
|
|
20
20
|
validatePlugin,
|
|
21
|
+
loadRootHooks,
|
|
21
22
|
runMocha
|
|
22
23
|
} = require('./run-helpers');
|
|
23
24
|
const {ONE_AND_DONES, ONE_AND_DONE_ARGS} = require('./one-and-dones');
|
|
@@ -285,12 +286,24 @@ exports.builder = yargs =>
|
|
|
285
286
|
);
|
|
286
287
|
}
|
|
287
288
|
|
|
289
|
+
if (argv.opts) {
|
|
290
|
+
throw createUnsupportedError(
|
|
291
|
+
`--opts: configuring Mocha via 'mocha.opts' is DEPRECATED and no longer supported.
|
|
292
|
+
Please use a configuration file instead.`
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return true;
|
|
297
|
+
})
|
|
298
|
+
.middleware(async argv => {
|
|
288
299
|
// load requires first, because it can impact "plugin" validation
|
|
289
|
-
handleRequires(argv.require);
|
|
300
|
+
const rawRootHooks = await handleRequires(argv.require);
|
|
290
301
|
validatePlugin(argv, 'reporter', Mocha.reporters);
|
|
291
302
|
validatePlugin(argv, 'ui', Mocha.interfaces);
|
|
292
303
|
|
|
293
|
-
|
|
304
|
+
if (rawRootHooks.length) {
|
|
305
|
+
argv.rootHooks = await loadRootHooks(rawRootHooks);
|
|
306
|
+
}
|
|
294
307
|
})
|
|
295
308
|
.array(types.array)
|
|
296
309
|
.boolean(types.boolean)
|
package/lib/errors.js
CHANGED
|
@@ -1,10 +1,73 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
|
|
3
|
+
var format = require('util').format;
|
|
4
|
+
|
|
2
5
|
/**
|
|
6
|
+
* Factory functions to create throwable error objects
|
|
3
7
|
* @module Errors
|
|
4
8
|
*/
|
|
9
|
+
|
|
5
10
|
/**
|
|
6
|
-
*
|
|
11
|
+
* When Mocha throw exceptions (or otherwise errors), it attempts to assign a
|
|
12
|
+
* `code` property to the `Error` object, for easier handling. These are the
|
|
13
|
+
* potential values of `code`.
|
|
7
14
|
*/
|
|
15
|
+
var constants = {
|
|
16
|
+
/**
|
|
17
|
+
* An unrecoverable error.
|
|
18
|
+
*/
|
|
19
|
+
FATAL: 'ERR_MOCHA_FATAL',
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The type of an argument to a function call is invalid
|
|
23
|
+
*/
|
|
24
|
+
INVALID_ARG_TYPE: 'ERR_MOCHA_INVALID_ARG_TYPE',
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The value of an argument to a function call is invalid
|
|
28
|
+
*/
|
|
29
|
+
INVALID_ARG_VALUE: 'ERR_MOCHA_INVALID_ARG_VALUE',
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Something was thrown, but it wasn't an `Error`
|
|
33
|
+
*/
|
|
34
|
+
INVALID_EXCEPTION: 'ERR_MOCHA_INVALID_EXCEPTION',
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* An interface (e.g., `Mocha.interfaces`) is unknown or invalid
|
|
38
|
+
*/
|
|
39
|
+
INVALID_INTERFACE: 'ERR_MOCHA_INVALID_INTERFACE',
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A reporter (.e.g, `Mocha.reporters`) is unknown or invalid
|
|
43
|
+
*/
|
|
44
|
+
INVALID_REPORTER: 'ERR_MOCHA_INVALID_REPORTER',
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* `done()` was called twice in a `Test` or `Hook` callback
|
|
48
|
+
*/
|
|
49
|
+
MULTIPLE_DONE: 'ERR_MOCHA_MULTIPLE_DONE',
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* No files matched the pattern provided by the user
|
|
53
|
+
*/
|
|
54
|
+
NO_FILES_MATCH_PATTERN: 'ERR_MOCHA_NO_FILES_MATCH_PATTERN',
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Known, but unsupported behavior of some kind
|
|
58
|
+
*/
|
|
59
|
+
UNSUPPORTED: 'ERR_MOCHA_UNSUPPORTED',
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Invalid state transition occuring in `Mocha` instance
|
|
63
|
+
*/
|
|
64
|
+
INSTANCE_ALREADY_RUNNING: 'ERR_MOCHA_INSTANCE_ALREADY_RUNNING',
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Invalid state transition occuring in `Mocha` instance
|
|
68
|
+
*/
|
|
69
|
+
INSTANCE_ALREADY_DISPOSED: 'ERR_MOCHA_INSTANCE_ALREADY_DISPOSED'
|
|
70
|
+
};
|
|
8
71
|
|
|
9
72
|
/**
|
|
10
73
|
* Creates an error object to be thrown when no files to be tested could be found using specified pattern.
|
|
@@ -16,7 +79,7 @@
|
|
|
16
79
|
*/
|
|
17
80
|
function createNoFilesMatchPatternError(message, pattern) {
|
|
18
81
|
var err = new Error(message);
|
|
19
|
-
err.code =
|
|
82
|
+
err.code = constants.NO_FILES_MATCH_PATTERN;
|
|
20
83
|
err.pattern = pattern;
|
|
21
84
|
return err;
|
|
22
85
|
}
|
|
@@ -31,7 +94,7 @@ function createNoFilesMatchPatternError(message, pattern) {
|
|
|
31
94
|
*/
|
|
32
95
|
function createInvalidReporterError(message, reporter) {
|
|
33
96
|
var err = new TypeError(message);
|
|
34
|
-
err.code =
|
|
97
|
+
err.code = constants.INVALID_REPORTER;
|
|
35
98
|
err.reporter = reporter;
|
|
36
99
|
return err;
|
|
37
100
|
}
|
|
@@ -46,7 +109,7 @@ function createInvalidReporterError(message, reporter) {
|
|
|
46
109
|
*/
|
|
47
110
|
function createInvalidInterfaceError(message, ui) {
|
|
48
111
|
var err = new Error(message);
|
|
49
|
-
err.code =
|
|
112
|
+
err.code = constants.INVALID_INTERFACE;
|
|
50
113
|
err.interface = ui;
|
|
51
114
|
return err;
|
|
52
115
|
}
|
|
@@ -60,7 +123,7 @@ function createInvalidInterfaceError(message, ui) {
|
|
|
60
123
|
*/
|
|
61
124
|
function createUnsupportedError(message) {
|
|
62
125
|
var err = new Error(message);
|
|
63
|
-
err.code =
|
|
126
|
+
err.code = constants.UNSUPPORTED;
|
|
64
127
|
return err;
|
|
65
128
|
}
|
|
66
129
|
|
|
@@ -88,7 +151,7 @@ function createMissingArgumentError(message, argument, expected) {
|
|
|
88
151
|
*/
|
|
89
152
|
function createInvalidArgumentTypeError(message, argument, expected) {
|
|
90
153
|
var err = new TypeError(message);
|
|
91
|
-
err.code =
|
|
154
|
+
err.code = constants.INVALID_ARG_TYPE;
|
|
92
155
|
err.argument = argument;
|
|
93
156
|
err.expected = expected;
|
|
94
157
|
err.actual = typeof argument;
|
|
@@ -107,7 +170,7 @@ function createInvalidArgumentTypeError(message, argument, expected) {
|
|
|
107
170
|
*/
|
|
108
171
|
function createInvalidArgumentValueError(message, argument, value, reason) {
|
|
109
172
|
var err = new TypeError(message);
|
|
110
|
-
err.code =
|
|
173
|
+
err.code = constants.INVALID_ARG_VALUE;
|
|
111
174
|
err.argument = argument;
|
|
112
175
|
err.value = value;
|
|
113
176
|
err.reason = typeof reason !== 'undefined' ? reason : 'is invalid';
|
|
@@ -123,12 +186,113 @@ function createInvalidArgumentValueError(message, argument, value, reason) {
|
|
|
123
186
|
*/
|
|
124
187
|
function createInvalidExceptionError(message, value) {
|
|
125
188
|
var err = new Error(message);
|
|
126
|
-
err.code =
|
|
189
|
+
err.code = constants.INVALID_EXCEPTION;
|
|
190
|
+
err.valueType = typeof value;
|
|
191
|
+
err.value = value;
|
|
192
|
+
return err;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Creates an error object to be thrown when an unrecoverable error occurs.
|
|
197
|
+
*
|
|
198
|
+
* @public
|
|
199
|
+
* @param {string} message - Error message to be displayed.
|
|
200
|
+
* @returns {Error} instance detailing the error condition
|
|
201
|
+
*/
|
|
202
|
+
function createFatalError(message, value) {
|
|
203
|
+
var err = new Error(message);
|
|
204
|
+
err.code = constants.FATAL;
|
|
127
205
|
err.valueType = typeof value;
|
|
128
206
|
err.value = value;
|
|
129
207
|
return err;
|
|
130
208
|
}
|
|
131
209
|
|
|
210
|
+
/**
|
|
211
|
+
* Dynamically creates a plugin-type-specific error based on plugin type
|
|
212
|
+
* @param {string} message - Error message
|
|
213
|
+
* @param {"reporter"|"interface"} pluginType - Plugin type. Future: expand as needed
|
|
214
|
+
* @param {string} [pluginId] - Name/path of plugin, if any
|
|
215
|
+
* @throws When `pluginType` is not known
|
|
216
|
+
* @public
|
|
217
|
+
* @returns {Error}
|
|
218
|
+
*/
|
|
219
|
+
function createInvalidPluginError(message, pluginType, pluginId) {
|
|
220
|
+
switch (pluginType) {
|
|
221
|
+
case 'reporter':
|
|
222
|
+
return createInvalidReporterError(message, pluginId);
|
|
223
|
+
case 'interface':
|
|
224
|
+
return createInvalidInterfaceError(message, pluginId);
|
|
225
|
+
default:
|
|
226
|
+
throw new Error('unknown pluginType "' + pluginType + '"');
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Creates an error object to be thrown when a mocha object's `run` method is executed while it is already disposed.
|
|
232
|
+
* @param {string} message The error message to be displayed.
|
|
233
|
+
* @param {boolean} cleanReferencesAfterRun the value of `cleanReferencesAfterRun`
|
|
234
|
+
* @param {Mocha} instance the mocha instance that throw this error
|
|
235
|
+
*/
|
|
236
|
+
function createMochaInstanceAlreadyDisposedError(
|
|
237
|
+
message,
|
|
238
|
+
cleanReferencesAfterRun,
|
|
239
|
+
instance
|
|
240
|
+
) {
|
|
241
|
+
var err = new Error(message);
|
|
242
|
+
err.code = constants.INSTANCE_ALREADY_DISPOSED;
|
|
243
|
+
err.cleanReferencesAfterRun = cleanReferencesAfterRun;
|
|
244
|
+
err.instance = instance;
|
|
245
|
+
return err;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Creates an error object to be thrown when a mocha object's `run` method is called while a test run is in progress.
|
|
250
|
+
* @param {string} message The error message to be displayed.
|
|
251
|
+
*/
|
|
252
|
+
function createMochaInstanceAlreadyRunningError(message, instance) {
|
|
253
|
+
var err = new Error(message);
|
|
254
|
+
err.code = constants.INSTANCE_ALREADY_RUNNING;
|
|
255
|
+
err.instance = instance;
|
|
256
|
+
return err;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/*
|
|
260
|
+
* Creates an error object to be thrown when done() is called multiple times in a test
|
|
261
|
+
*
|
|
262
|
+
* @public
|
|
263
|
+
* @param {Runnable} runnable - Original runnable
|
|
264
|
+
* @param {Error} [originalErr] - Original error, if any
|
|
265
|
+
* @returns {Error} instance detailing the error condition
|
|
266
|
+
*/
|
|
267
|
+
function createMultipleDoneError(runnable, originalErr) {
|
|
268
|
+
var title;
|
|
269
|
+
try {
|
|
270
|
+
title = format('<%s>', runnable.fullTitle());
|
|
271
|
+
if (runnable.parent.root) {
|
|
272
|
+
title += ' (of root suite)';
|
|
273
|
+
}
|
|
274
|
+
} catch (ignored) {
|
|
275
|
+
title = format('<%s> (of unknown suite)', runnable.title);
|
|
276
|
+
}
|
|
277
|
+
var message = format(
|
|
278
|
+
'done() called multiple times in %s %s',
|
|
279
|
+
runnable.type ? runnable.type : 'unknown runnable',
|
|
280
|
+
title
|
|
281
|
+
);
|
|
282
|
+
if (runnable.file) {
|
|
283
|
+
message += format(' of file %s', runnable.file);
|
|
284
|
+
}
|
|
285
|
+
if (originalErr) {
|
|
286
|
+
message += format('; in addition, done() received error: %s', originalErr);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
var err = new Error(message);
|
|
290
|
+
err.code = constants.MULTIPLE_DONE;
|
|
291
|
+
err.valueType = typeof originalErr;
|
|
292
|
+
err.value = originalErr;
|
|
293
|
+
return err;
|
|
294
|
+
}
|
|
295
|
+
|
|
132
296
|
module.exports = {
|
|
133
297
|
createInvalidArgumentTypeError: createInvalidArgumentTypeError,
|
|
134
298
|
createInvalidArgumentValueError: createInvalidArgumentValueError,
|
|
@@ -137,5 +301,11 @@ module.exports = {
|
|
|
137
301
|
createInvalidReporterError: createInvalidReporterError,
|
|
138
302
|
createMissingArgumentError: createMissingArgumentError,
|
|
139
303
|
createNoFilesMatchPatternError: createNoFilesMatchPatternError,
|
|
140
|
-
createUnsupportedError: createUnsupportedError
|
|
304
|
+
createUnsupportedError: createUnsupportedError,
|
|
305
|
+
createInvalidPluginError: createInvalidPluginError,
|
|
306
|
+
createMochaInstanceAlreadyDisposedError: createMochaInstanceAlreadyDisposedError,
|
|
307
|
+
createMochaInstanceAlreadyRunningError: createMochaInstanceAlreadyRunningError,
|
|
308
|
+
createFatalError: createFatalError,
|
|
309
|
+
createMultipleDoneError: createMultipleDoneError,
|
|
310
|
+
constants: constants
|
|
141
311
|
};
|
package/lib/hook.js
CHANGED
|
@@ -27,6 +27,14 @@ function Hook(title, fn) {
|
|
|
27
27
|
*/
|
|
28
28
|
inherits(Hook, Runnable);
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Resets the state for a next run.
|
|
32
|
+
*/
|
|
33
|
+
Hook.prototype.reset = function() {
|
|
34
|
+
Runnable.prototype.reset.call(this);
|
|
35
|
+
delete this._error;
|
|
36
|
+
};
|
|
37
|
+
|
|
30
38
|
/**
|
|
31
39
|
* Get or set the test `err`.
|
|
32
40
|
*
|