mocha 7.1.1 → 8.0.1
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 +110 -2
- package/bin/mocha +24 -4
- package/browser-entry.js +11 -0
- package/lib/browser/growl.js +2 -1
- package/lib/cli/cli.js +6 -3
- package/lib/cli/collect-files.js +14 -8
- package/lib/cli/config.js +6 -6
- package/lib/cli/init.js +1 -2
- package/lib/cli/node-flags.js +2 -2
- package/lib/cli/options.js +14 -90
- package/lib/cli/run-helpers.js +133 -36
- package/lib/cli/run-option-metadata.js +4 -2
- package/lib/cli/run.js +71 -11
- package/lib/cli/watch-run.js +202 -50
- package/lib/context.js +0 -15
- package/lib/errors.js +202 -9
- package/lib/esm-utils.js +11 -6
- package/lib/hook.js +32 -0
- package/lib/interfaces/common.js +16 -10
- package/lib/mocha.js +289 -123
- package/lib/mocharc.json +0 -1
- package/lib/nodejs/buffered-worker-pool.js +174 -0
- package/lib/{growl.js → nodejs/growl.js} +3 -2
- package/lib/nodejs/parallel-buffered-runner.js +293 -0
- package/lib/nodejs/reporters/parallel-buffered.js +133 -0
- package/lib/nodejs/serializer.js +402 -0
- package/lib/nodejs/worker.js +154 -0
- package/lib/reporters/base.js +2 -2
- 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 +11 -3
- package/lib/reporters/tap.js +1 -2
- package/lib/reporters/xunit.js +3 -2
- package/lib/runnable.js +38 -72
- package/lib/runner.js +185 -85
- package/lib/suite.js +60 -27
- package/lib/test.js +48 -3
- package/lib/utils.js +32 -40
- package/mocha.js +2418 -2199
- package/package.json +71 -56
package/lib/cli/watch-run.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const debug = require('debug')('mocha:cli:watch');
|
|
3
4
|
const path = require('path');
|
|
4
5
|
const chokidar = require('chokidar');
|
|
5
6
|
const Context = require('../context');
|
|
@@ -12,6 +13,64 @@ const collectFiles = require('./collect-files');
|
|
|
12
13
|
* @private
|
|
13
14
|
*/
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Run Mocha in parallel "watch" mode
|
|
18
|
+
* @param {Mocha} mocha - Mocha instance
|
|
19
|
+
* @param {Object} opts - Options
|
|
20
|
+
* @param {string[]} [opts.watchFiles] - List of paths and patterns to
|
|
21
|
+
* watch. If not provided all files with an extension included in
|
|
22
|
+
* `fileColletionParams.extension` are watched. See first argument of
|
|
23
|
+
* `chokidar.watch`.
|
|
24
|
+
* @param {string[]} opts.watchIgnore - List of paths and patterns to
|
|
25
|
+
* exclude from watching. See `ignored` option of `chokidar`.
|
|
26
|
+
* @param {FileCollectionOptions} fileCollectParams - Parameters that control test
|
|
27
|
+
* @private
|
|
28
|
+
*/
|
|
29
|
+
exports.watchParallelRun = (
|
|
30
|
+
mocha,
|
|
31
|
+
{watchFiles, watchIgnore},
|
|
32
|
+
fileCollectParams
|
|
33
|
+
) => {
|
|
34
|
+
debug('creating parallel watcher');
|
|
35
|
+
return createWatcher(mocha, {
|
|
36
|
+
watchFiles,
|
|
37
|
+
watchIgnore,
|
|
38
|
+
beforeRun({mocha}) {
|
|
39
|
+
// I don't know why we're cloning the root suite.
|
|
40
|
+
const rootSuite = mocha.suite.clone();
|
|
41
|
+
|
|
42
|
+
// this `require` is needed because the require cache has been cleared. the dynamic
|
|
43
|
+
// exports set via the below call to `mocha.ui()` won't work properly if a
|
|
44
|
+
// test depends on this module (see `required-tokens.spec.js`).
|
|
45
|
+
const Mocha = require('../mocha');
|
|
46
|
+
|
|
47
|
+
// ... and now that we've gotten a new module, we need to use it again due
|
|
48
|
+
// to `mocha.ui()` call
|
|
49
|
+
const newMocha = new Mocha(mocha.options);
|
|
50
|
+
// don't know why this is needed
|
|
51
|
+
newMocha.suite = rootSuite;
|
|
52
|
+
// nor this
|
|
53
|
+
newMocha.suite.ctx = new Context();
|
|
54
|
+
|
|
55
|
+
// reset the list of files
|
|
56
|
+
newMocha.files = collectFiles(fileCollectParams);
|
|
57
|
+
|
|
58
|
+
// because we've swapped out the root suite (see the `run` inner function
|
|
59
|
+
// in `createRerunner`), we need to call `mocha.ui()` again to set up the context/globals.
|
|
60
|
+
newMocha.ui(newMocha.options.ui);
|
|
61
|
+
|
|
62
|
+
// in parallel mode, the main Mocha process doesn't actually load the
|
|
63
|
+
// files. this flag prevents `mocha.run()` from autoloading.
|
|
64
|
+
newMocha.lazyLoadFiles(true);
|
|
65
|
+
return newMocha;
|
|
66
|
+
},
|
|
67
|
+
afterRun({watcher}) {
|
|
68
|
+
blastCache(watcher);
|
|
69
|
+
},
|
|
70
|
+
fileCollectParams
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
|
|
15
74
|
/**
|
|
16
75
|
* Run Mocha in "watch" mode
|
|
17
76
|
* @param {Mocha} mocha - Mocha instance
|
|
@@ -22,27 +81,88 @@ const collectFiles = require('./collect-files');
|
|
|
22
81
|
* `chokidar.watch`.
|
|
23
82
|
* @param {string[]} opts.watchIgnore - List of paths and patterns to
|
|
24
83
|
* exclude from watching. See `ignored` option of `chokidar`.
|
|
25
|
-
* @param {
|
|
84
|
+
* @param {FileCollectionOptions} fileCollectParams - Parameters that control test
|
|
26
85
|
* file collection. See `lib/cli/collect-files.js`.
|
|
27
|
-
* @param {string[]} fileCollectParams.extension - List of extensions
|
|
28
|
-
* to watch if `opts.watchFiles` is not given.
|
|
29
86
|
* @private
|
|
30
87
|
*/
|
|
31
|
-
|
|
88
|
+
exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
|
|
89
|
+
debug('creating serial watcher');
|
|
90
|
+
// list of all test files
|
|
91
|
+
|
|
92
|
+
return createWatcher(mocha, {
|
|
93
|
+
watchFiles,
|
|
94
|
+
watchIgnore,
|
|
95
|
+
beforeRun({mocha}) {
|
|
96
|
+
mocha.unloadFiles();
|
|
97
|
+
|
|
98
|
+
// I don't know why we're cloning the root suite.
|
|
99
|
+
const rootSuite = mocha.suite.clone();
|
|
100
|
+
|
|
101
|
+
// this `require` is needed because the require cache has been cleared. the dynamic
|
|
102
|
+
// exports set via the below call to `mocha.ui()` won't work properly if a
|
|
103
|
+
// test depends on this module (see `required-tokens.spec.js`).
|
|
104
|
+
const Mocha = require('../mocha');
|
|
105
|
+
|
|
106
|
+
// ... and now that we've gotten a new module, we need to use it again due
|
|
107
|
+
// to `mocha.ui()` call
|
|
108
|
+
const newMocha = new Mocha(mocha.options);
|
|
109
|
+
// don't know why this is needed
|
|
110
|
+
newMocha.suite = rootSuite;
|
|
111
|
+
// nor this
|
|
112
|
+
newMocha.suite.ctx = new Context();
|
|
113
|
+
|
|
114
|
+
// reset the list of files
|
|
115
|
+
newMocha.files = collectFiles(fileCollectParams);
|
|
116
|
+
|
|
117
|
+
// because we've swapped out the root suite (see the `run` inner function
|
|
118
|
+
// in `createRerunner`), we need to call `mocha.ui()` again to set up the context/globals.
|
|
119
|
+
newMocha.ui(newMocha.options.ui);
|
|
120
|
+
|
|
121
|
+
return newMocha;
|
|
122
|
+
},
|
|
123
|
+
afterRun({watcher}) {
|
|
124
|
+
blastCache(watcher);
|
|
125
|
+
},
|
|
126
|
+
fileCollectParams
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Bootstraps a chokidar watcher. Handles keyboard input & signals
|
|
132
|
+
* @param {Mocha} mocha - Mocha instance
|
|
133
|
+
* @param {Object} opts
|
|
134
|
+
* @param {BeforeWatchRun} [opts.beforeRun] - Function to call before
|
|
135
|
+
* `mocha.run()`
|
|
136
|
+
* @param {AfterWatchRun} [opts.afterRun] - Function to call after `mocha.run()`
|
|
137
|
+
* @param {string[]} [opts.watchFiles] - List of paths and patterns to watch. If
|
|
138
|
+
* not provided all files with an extension included in
|
|
139
|
+
* `fileColletionParams.extension` are watched. See first argument of
|
|
140
|
+
* `chokidar.watch`.
|
|
141
|
+
* @param {string[]} [opts.watchIgnore] - List of paths and patterns to exclude
|
|
142
|
+
* from watching. See `ignored` option of `chokidar`.
|
|
143
|
+
* @param {FileCollectionOptions} opts.fileCollectParams - List of extensions to watch if `opts.watchFiles` is not given.
|
|
144
|
+
* @returns {FSWatcher}
|
|
145
|
+
* @ignore
|
|
146
|
+
* @private
|
|
147
|
+
*/
|
|
148
|
+
const createWatcher = (
|
|
149
|
+
mocha,
|
|
150
|
+
{watchFiles, watchIgnore, beforeRun, afterRun, fileCollectParams}
|
|
151
|
+
) => {
|
|
32
152
|
if (!watchFiles) {
|
|
33
153
|
watchFiles = fileCollectParams.extension.map(ext => `**/*.${ext}`);
|
|
34
154
|
}
|
|
35
155
|
|
|
156
|
+
debug('ignoring files matching: %s', watchIgnore);
|
|
157
|
+
|
|
36
158
|
const watcher = chokidar.watch(watchFiles, {
|
|
37
159
|
ignored: watchIgnore,
|
|
38
160
|
ignoreInitial: true
|
|
39
161
|
});
|
|
40
162
|
|
|
41
|
-
const rerunner = createRerunner(mocha,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
});
|
|
45
|
-
mocha.files = collectFiles(fileCollectParams);
|
|
163
|
+
const rerunner = createRerunner(mocha, watcher, {
|
|
164
|
+
beforeRun,
|
|
165
|
+
afterRun
|
|
46
166
|
});
|
|
47
167
|
|
|
48
168
|
watcher.on('ready', () => {
|
|
@@ -53,7 +173,6 @@ module.exports = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
|
|
|
53
173
|
rerunner.scheduleRun();
|
|
54
174
|
});
|
|
55
175
|
|
|
56
|
-
console.log();
|
|
57
176
|
hideCursor();
|
|
58
177
|
process.on('exit', () => {
|
|
59
178
|
showCursor();
|
|
@@ -74,36 +193,43 @@ module.exports = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
|
|
|
74
193
|
.toLowerCase();
|
|
75
194
|
if (str === 'rs') rerunner.scheduleRun();
|
|
76
195
|
});
|
|
196
|
+
|
|
197
|
+
return watcher;
|
|
77
198
|
};
|
|
78
199
|
|
|
79
200
|
/**
|
|
80
|
-
* Create an object that allows you to rerun tests on the mocha
|
|
81
|
-
* instance. `beforeRun` is called everytime before `mocha.run()` is
|
|
82
|
-
* called.
|
|
201
|
+
* Create an object that allows you to rerun tests on the mocha instance.
|
|
83
202
|
*
|
|
84
203
|
* @param {Mocha} mocha - Mocha instance
|
|
85
|
-
* @param {
|
|
204
|
+
* @param {FSWatcher} watcher - chokidar `FSWatcher` instance
|
|
205
|
+
* @param {Object} [opts] - Options!
|
|
206
|
+
* @param {BeforeWatchRun} [opts.beforeRun] - Function to call before `mocha.run()`
|
|
207
|
+
* @param {AfterWatchRun} [opts.afterRun] - Function to call after `mocha.run()`
|
|
208
|
+
* @returns {Rerunner}
|
|
209
|
+
* @ignore
|
|
210
|
+
* @private
|
|
86
211
|
*/
|
|
87
|
-
const createRerunner = (mocha, beforeRun) => {
|
|
212
|
+
const createRerunner = (mocha, watcher, {beforeRun, afterRun} = {}) => {
|
|
88
213
|
// Set to a `Runner` when mocha is running. Set to `null` when mocha is not
|
|
89
214
|
// running.
|
|
90
215
|
let runner = null;
|
|
91
216
|
|
|
217
|
+
// true if a file has changed during a test run
|
|
92
218
|
let rerunScheduled = false;
|
|
93
219
|
|
|
94
220
|
const run = () => {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
221
|
+
mocha = beforeRun ? beforeRun({mocha, watcher}) : mocha;
|
|
222
|
+
|
|
223
|
+
runner = mocha.run(() => {
|
|
224
|
+
debug('finished watch run');
|
|
225
|
+
runner = null;
|
|
226
|
+
afterRun && afterRun({mocha, watcher});
|
|
227
|
+
if (rerunScheduled) {
|
|
228
|
+
rerun();
|
|
229
|
+
} else {
|
|
230
|
+
debug('waiting for changes...');
|
|
231
|
+
}
|
|
232
|
+
});
|
|
107
233
|
};
|
|
108
234
|
|
|
109
235
|
const scheduleRun = () => {
|
|
@@ -136,32 +262,18 @@ const createRerunner = (mocha, beforeRun) => {
|
|
|
136
262
|
*
|
|
137
263
|
* @param watcher - Instance of a chokidar watcher
|
|
138
264
|
* @return {string[]} - List of absolute paths
|
|
265
|
+
* @ignore
|
|
266
|
+
* @private
|
|
139
267
|
*/
|
|
140
268
|
const getWatchedFiles = watcher => {
|
|
141
269
|
const watchedDirs = watcher.getWatched();
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
watchedDirs[dir].map(file => path.join(dir, file))
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Reset the internal state of the mocha instance so that tests can be rerun.
|
|
153
|
-
*
|
|
154
|
-
* @param {Mocha} mocha - Mocha instance
|
|
155
|
-
* @private
|
|
156
|
-
*/
|
|
157
|
-
const resetMocha = mocha => {
|
|
158
|
-
mocha.unloadFiles();
|
|
159
|
-
mocha.suite = mocha.suite.clone();
|
|
160
|
-
mocha.suite.ctx = new Context();
|
|
161
|
-
// Registers a callback on `mocha.suite` that wires new context to the DSL
|
|
162
|
-
// (e.g. `describe`) that is exposed as globals when the test files are
|
|
163
|
-
// reloaded.
|
|
164
|
-
mocha.ui(mocha.options.ui);
|
|
270
|
+
return Object.keys(watchedDirs).reduce(
|
|
271
|
+
(acc, dir) => [
|
|
272
|
+
...acc,
|
|
273
|
+
...watchedDirs[dir].map(file => path.join(dir, file))
|
|
274
|
+
],
|
|
275
|
+
[]
|
|
276
|
+
);
|
|
165
277
|
};
|
|
166
278
|
|
|
167
279
|
/**
|
|
@@ -189,3 +301,43 @@ const showCursor = () => {
|
|
|
189
301
|
const eraseLine = () => {
|
|
190
302
|
process.stdout.write('\u001b[2K');
|
|
191
303
|
};
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Blast all of the watched files out of `require.cache`
|
|
307
|
+
* @param {FSWatcher} watcher - chokidar FSWatcher
|
|
308
|
+
* @ignore
|
|
309
|
+
* @private
|
|
310
|
+
*/
|
|
311
|
+
const blastCache = watcher => {
|
|
312
|
+
const files = getWatchedFiles(watcher);
|
|
313
|
+
files.forEach(file => {
|
|
314
|
+
delete require.cache[file];
|
|
315
|
+
});
|
|
316
|
+
debug('deleted %d file(s) from the require cache', files.length);
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Callback to be run before `mocha.run()` is called.
|
|
321
|
+
* Optionally, it can return a new `Mocha` instance.
|
|
322
|
+
* @callback BeforeWatchRun
|
|
323
|
+
* @private
|
|
324
|
+
* @param {{mocha: Mocha, watcher: FSWatcher}} options
|
|
325
|
+
* @returns {Mocha}
|
|
326
|
+
*/
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Callback to be run after `mocha.run()` completes. Typically used to clear
|
|
330
|
+
* require cache.
|
|
331
|
+
* @callback AfterWatchRun
|
|
332
|
+
* @private
|
|
333
|
+
* @param {{mocha: Mocha, watcher: FSWatcher}} options
|
|
334
|
+
* @returns {void}
|
|
335
|
+
*/
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Object containing run control methods
|
|
339
|
+
* @typedef {Object} Rerunner
|
|
340
|
+
* @private
|
|
341
|
+
* @property {Function} run - Calls `mocha.run()`
|
|
342
|
+
* @property {Function} scheduleRun - Schedules another call to `run`
|
|
343
|
+
*/
|
package/lib/context.js
CHANGED
|
@@ -45,21 +45,6 @@ Context.prototype.timeout = function(ms) {
|
|
|
45
45
|
return this;
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
-
/**
|
|
49
|
-
* Set test timeout `enabled`.
|
|
50
|
-
*
|
|
51
|
-
* @private
|
|
52
|
-
* @param {boolean} enabled
|
|
53
|
-
* @return {Context} self
|
|
54
|
-
*/
|
|
55
|
-
Context.prototype.enableTimeouts = function(enabled) {
|
|
56
|
-
if (!arguments.length) {
|
|
57
|
-
return this.runnable().enableTimeouts();
|
|
58
|
-
}
|
|
59
|
-
this.runnable().enableTimeouts(enabled);
|
|
60
|
-
return this;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
48
|
/**
|
|
64
49
|
* Set or get test slowness threshold `ms`.
|
|
65
50
|
*
|
package/lib/errors.js
CHANGED
|
@@ -1,10 +1,78 @@
|
|
|
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
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Use of `only()` w/ `--forbid-only` results in this error.
|
|
73
|
+
*/
|
|
74
|
+
FORBIDDEN_EXCLUSIVITY: 'ERR_MOCHA_FORBIDDEN_EXCLUSIVITY'
|
|
75
|
+
};
|
|
8
76
|
|
|
9
77
|
/**
|
|
10
78
|
* Creates an error object to be thrown when no files to be tested could be found using specified pattern.
|
|
@@ -16,7 +84,7 @@
|
|
|
16
84
|
*/
|
|
17
85
|
function createNoFilesMatchPatternError(message, pattern) {
|
|
18
86
|
var err = new Error(message);
|
|
19
|
-
err.code =
|
|
87
|
+
err.code = constants.NO_FILES_MATCH_PATTERN;
|
|
20
88
|
err.pattern = pattern;
|
|
21
89
|
return err;
|
|
22
90
|
}
|
|
@@ -31,7 +99,7 @@ function createNoFilesMatchPatternError(message, pattern) {
|
|
|
31
99
|
*/
|
|
32
100
|
function createInvalidReporterError(message, reporter) {
|
|
33
101
|
var err = new TypeError(message);
|
|
34
|
-
err.code =
|
|
102
|
+
err.code = constants.INVALID_REPORTER;
|
|
35
103
|
err.reporter = reporter;
|
|
36
104
|
return err;
|
|
37
105
|
}
|
|
@@ -46,7 +114,7 @@ function createInvalidReporterError(message, reporter) {
|
|
|
46
114
|
*/
|
|
47
115
|
function createInvalidInterfaceError(message, ui) {
|
|
48
116
|
var err = new Error(message);
|
|
49
|
-
err.code =
|
|
117
|
+
err.code = constants.INVALID_INTERFACE;
|
|
50
118
|
err.interface = ui;
|
|
51
119
|
return err;
|
|
52
120
|
}
|
|
@@ -60,7 +128,7 @@ function createInvalidInterfaceError(message, ui) {
|
|
|
60
128
|
*/
|
|
61
129
|
function createUnsupportedError(message) {
|
|
62
130
|
var err = new Error(message);
|
|
63
|
-
err.code =
|
|
131
|
+
err.code = constants.UNSUPPORTED;
|
|
64
132
|
return err;
|
|
65
133
|
}
|
|
66
134
|
|
|
@@ -88,7 +156,7 @@ function createMissingArgumentError(message, argument, expected) {
|
|
|
88
156
|
*/
|
|
89
157
|
function createInvalidArgumentTypeError(message, argument, expected) {
|
|
90
158
|
var err = new TypeError(message);
|
|
91
|
-
err.code =
|
|
159
|
+
err.code = constants.INVALID_ARG_TYPE;
|
|
92
160
|
err.argument = argument;
|
|
93
161
|
err.expected = expected;
|
|
94
162
|
err.actual = typeof argument;
|
|
@@ -107,7 +175,7 @@ function createInvalidArgumentTypeError(message, argument, expected) {
|
|
|
107
175
|
*/
|
|
108
176
|
function createInvalidArgumentValueError(message, argument, value, reason) {
|
|
109
177
|
var err = new TypeError(message);
|
|
110
|
-
err.code =
|
|
178
|
+
err.code = constants.INVALID_ARG_VALUE;
|
|
111
179
|
err.argument = argument;
|
|
112
180
|
err.value = value;
|
|
113
181
|
err.reason = typeof reason !== 'undefined' ? reason : 'is invalid';
|
|
@@ -123,12 +191,130 @@ function createInvalidArgumentValueError(message, argument, value, reason) {
|
|
|
123
191
|
*/
|
|
124
192
|
function createInvalidExceptionError(message, value) {
|
|
125
193
|
var err = new Error(message);
|
|
126
|
-
err.code =
|
|
194
|
+
err.code = constants.INVALID_EXCEPTION;
|
|
127
195
|
err.valueType = typeof value;
|
|
128
196
|
err.value = value;
|
|
129
197
|
return err;
|
|
130
198
|
}
|
|
131
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Creates an error object to be thrown when an unrecoverable error occurs.
|
|
202
|
+
*
|
|
203
|
+
* @public
|
|
204
|
+
* @param {string} message - Error message to be displayed.
|
|
205
|
+
* @returns {Error} instance detailing the error condition
|
|
206
|
+
*/
|
|
207
|
+
function createFatalError(message, value) {
|
|
208
|
+
var err = new Error(message);
|
|
209
|
+
err.code = constants.FATAL;
|
|
210
|
+
err.valueType = typeof value;
|
|
211
|
+
err.value = value;
|
|
212
|
+
return err;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Dynamically creates a plugin-type-specific error based on plugin type
|
|
217
|
+
* @param {string} message - Error message
|
|
218
|
+
* @param {"reporter"|"interface"} pluginType - Plugin type. Future: expand as needed
|
|
219
|
+
* @param {string} [pluginId] - Name/path of plugin, if any
|
|
220
|
+
* @throws When `pluginType` is not known
|
|
221
|
+
* @public
|
|
222
|
+
* @returns {Error}
|
|
223
|
+
*/
|
|
224
|
+
function createInvalidPluginError(message, pluginType, pluginId) {
|
|
225
|
+
switch (pluginType) {
|
|
226
|
+
case 'reporter':
|
|
227
|
+
return createInvalidReporterError(message, pluginId);
|
|
228
|
+
case 'interface':
|
|
229
|
+
return createInvalidInterfaceError(message, pluginId);
|
|
230
|
+
default:
|
|
231
|
+
throw new Error('unknown pluginType "' + pluginType + '"');
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Creates an error object to be thrown when a mocha object's `run` method is executed while it is already disposed.
|
|
237
|
+
* @param {string} message The error message to be displayed.
|
|
238
|
+
* @param {boolean} cleanReferencesAfterRun the value of `cleanReferencesAfterRun`
|
|
239
|
+
* @param {Mocha} instance the mocha instance that throw this error
|
|
240
|
+
*/
|
|
241
|
+
function createMochaInstanceAlreadyDisposedError(
|
|
242
|
+
message,
|
|
243
|
+
cleanReferencesAfterRun,
|
|
244
|
+
instance
|
|
245
|
+
) {
|
|
246
|
+
var err = new Error(message);
|
|
247
|
+
err.code = constants.INSTANCE_ALREADY_DISPOSED;
|
|
248
|
+
err.cleanReferencesAfterRun = cleanReferencesAfterRun;
|
|
249
|
+
err.instance = instance;
|
|
250
|
+
return err;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Creates an error object to be thrown when a mocha object's `run` method is called while a test run is in progress.
|
|
255
|
+
* @param {string} message The error message to be displayed.
|
|
256
|
+
*/
|
|
257
|
+
function createMochaInstanceAlreadyRunningError(message, instance) {
|
|
258
|
+
var err = new Error(message);
|
|
259
|
+
err.code = constants.INSTANCE_ALREADY_RUNNING;
|
|
260
|
+
err.instance = instance;
|
|
261
|
+
return err;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/*
|
|
265
|
+
* Creates an error object to be thrown when done() is called multiple times in a test
|
|
266
|
+
*
|
|
267
|
+
* @public
|
|
268
|
+
* @param {Runnable} runnable - Original runnable
|
|
269
|
+
* @param {Error} [originalErr] - Original error, if any
|
|
270
|
+
* @returns {Error} instance detailing the error condition
|
|
271
|
+
*/
|
|
272
|
+
function createMultipleDoneError(runnable, originalErr) {
|
|
273
|
+
var title;
|
|
274
|
+
try {
|
|
275
|
+
title = format('<%s>', runnable.fullTitle());
|
|
276
|
+
if (runnable.parent.root) {
|
|
277
|
+
title += ' (of root suite)';
|
|
278
|
+
}
|
|
279
|
+
} catch (ignored) {
|
|
280
|
+
title = format('<%s> (of unknown suite)', runnable.title);
|
|
281
|
+
}
|
|
282
|
+
var message = format(
|
|
283
|
+
'done() called multiple times in %s %s',
|
|
284
|
+
runnable.type ? runnable.type : 'unknown runnable',
|
|
285
|
+
title
|
|
286
|
+
);
|
|
287
|
+
if (runnable.file) {
|
|
288
|
+
message += format(' of file %s', runnable.file);
|
|
289
|
+
}
|
|
290
|
+
if (originalErr) {
|
|
291
|
+
message += format('; in addition, done() received error: %s', originalErr);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
var err = new Error(message);
|
|
295
|
+
err.code = constants.MULTIPLE_DONE;
|
|
296
|
+
err.valueType = typeof originalErr;
|
|
297
|
+
err.value = originalErr;
|
|
298
|
+
return err;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Creates an error object to be thrown when `.only()` is used with
|
|
303
|
+
* `--forbid-only`.
|
|
304
|
+
* @public
|
|
305
|
+
* @param {Mocha} mocha - Mocha instance
|
|
306
|
+
* @returns {Error} Error with code {@link constants.FORBIDDEN_EXCLUSIVITY}
|
|
307
|
+
*/
|
|
308
|
+
function createForbiddenExclusivityError(mocha) {
|
|
309
|
+
var err = new Error(
|
|
310
|
+
mocha.isWorker
|
|
311
|
+
? '`.only` is not supported in parallel mode'
|
|
312
|
+
: '`.only` forbidden by --forbid-only'
|
|
313
|
+
);
|
|
314
|
+
err.code = constants.FORBIDDEN_EXCLUSIVITY;
|
|
315
|
+
return err;
|
|
316
|
+
}
|
|
317
|
+
|
|
132
318
|
module.exports = {
|
|
133
319
|
createInvalidArgumentTypeError: createInvalidArgumentTypeError,
|
|
134
320
|
createInvalidArgumentValueError: createInvalidArgumentValueError,
|
|
@@ -137,5 +323,12 @@ module.exports = {
|
|
|
137
323
|
createInvalidReporterError: createInvalidReporterError,
|
|
138
324
|
createMissingArgumentError: createMissingArgumentError,
|
|
139
325
|
createNoFilesMatchPatternError: createNoFilesMatchPatternError,
|
|
140
|
-
createUnsupportedError: createUnsupportedError
|
|
326
|
+
createUnsupportedError: createUnsupportedError,
|
|
327
|
+
createInvalidPluginError: createInvalidPluginError,
|
|
328
|
+
createMochaInstanceAlreadyDisposedError: createMochaInstanceAlreadyDisposedError,
|
|
329
|
+
createMochaInstanceAlreadyRunningError: createMochaInstanceAlreadyRunningError,
|
|
330
|
+
createFatalError: createFatalError,
|
|
331
|
+
createMultipleDoneError: createMultipleDoneError,
|
|
332
|
+
createForbiddenExclusivityError: createForbiddenExclusivityError,
|
|
333
|
+
constants: constants
|
|
141
334
|
};
|
package/lib/esm-utils.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
const url = require('url');
|
|
2
1
|
const path = require('path');
|
|
2
|
+
const url = require('url');
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
|
|
4
|
+
const formattedImport = async file => {
|
|
5
|
+
if (path.isAbsolute(file)) {
|
|
6
|
+
return import(url.pathToFileURL(file));
|
|
7
|
+
}
|
|
8
|
+
return import(file);
|
|
9
|
+
};
|
|
6
10
|
|
|
11
|
+
exports.requireOrImport = async file => {
|
|
7
12
|
if (path.extname(file) === '.mjs') {
|
|
8
|
-
return
|
|
13
|
+
return formattedImport(file);
|
|
9
14
|
}
|
|
10
15
|
// This is currently the only known way of figuring out whether a file is CJS or ESM.
|
|
11
16
|
// If Node.js or the community establish a better procedure for that, we can fix this code.
|
|
@@ -15,7 +20,7 @@ const requireOrImport = async file => {
|
|
|
15
20
|
return require(file);
|
|
16
21
|
} catch (err) {
|
|
17
22
|
if (err.code === 'ERR_REQUIRE_ESM') {
|
|
18
|
-
return
|
|
23
|
+
return formattedImport(file);
|
|
19
24
|
} else {
|
|
20
25
|
throw err;
|
|
21
26
|
}
|
|
@@ -25,7 +30,7 @@ const requireOrImport = async file => {
|
|
|
25
30
|
exports.loadFilesAsync = async (files, preLoadFunc, postLoadFunc) => {
|
|
26
31
|
for (const file of files) {
|
|
27
32
|
preLoadFunc(file);
|
|
28
|
-
const result = await requireOrImport(file);
|
|
33
|
+
const result = await exports.requireOrImport(path.resolve(file));
|
|
29
34
|
postLoadFunc(file, result);
|
|
30
35
|
}
|
|
31
36
|
};
|
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
|
*
|
|
@@ -44,3 +52,27 @@ Hook.prototype.error = function(err) {
|
|
|
44
52
|
|
|
45
53
|
this._error = err;
|
|
46
54
|
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Returns an object suitable for IPC.
|
|
58
|
+
* Functions are represented by keys beginning with `$$`.
|
|
59
|
+
* @private
|
|
60
|
+
* @returns {Object}
|
|
61
|
+
*/
|
|
62
|
+
Hook.prototype.serialize = function serialize() {
|
|
63
|
+
return {
|
|
64
|
+
$$isPending: this.isPending(),
|
|
65
|
+
$$titlePath: this.titlePath(),
|
|
66
|
+
ctx: {
|
|
67
|
+
currentTest: {
|
|
68
|
+
title: this.ctx && this.ctx.currentTest && this.ctx.currentTest.title
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
parent: {
|
|
72
|
+
root: this.parent.root,
|
|
73
|
+
title: this.parent.title
|
|
74
|
+
},
|
|
75
|
+
title: this.title,
|
|
76
|
+
type: this.type
|
|
77
|
+
};
|
|
78
|
+
};
|