mocha 6.1.0 → 6.1.4
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 +1776 -1751
- package/LICENSE +22 -22
- package/README.md +105 -105
- package/bin/_mocha +10 -10
- package/bin/mocha +149 -149
- package/bin/options.js +10 -10
- package/browser-entry.js +191 -191
- package/index.js +3 -3
- package/lib/browser/growl.js +168 -168
- package/lib/browser/progress.js +119 -119
- package/lib/browser/template.html +18 -18
- package/lib/browser/tty.js +13 -13
- package/lib/cli/cli.js +69 -69
- package/lib/cli/commands.js +13 -13
- package/lib/cli/config.js +101 -101
- package/lib/cli/index.js +9 -9
- package/lib/cli/init.js +37 -37
- package/lib/cli/node-flags.js +86 -86
- package/lib/cli/one-and-dones.js +70 -70
- package/lib/cli/options.js +347 -347
- package/lib/cli/run-helpers.js +337 -337
- package/lib/cli/run-option-metadata.js +76 -76
- package/lib/cli/run.js +297 -297
- package/lib/context.js +101 -101
- package/lib/errors.js +141 -141
- package/lib/growl.js +136 -136
- package/lib/hook.js +46 -46
- package/lib/interfaces/bdd.js +118 -118
- package/lib/interfaces/common.js +191 -191
- package/lib/interfaces/exports.js +60 -60
- package/lib/interfaces/index.js +6 -6
- package/lib/interfaces/qunit.js +99 -99
- package/lib/interfaces/tdd.js +107 -107
- package/lib/mocha.js +843 -843
- package/lib/mocharc.json +10 -10
- package/lib/pending.js +12 -12
- package/lib/reporters/base.js +491 -491
- package/lib/reporters/doc.js +85 -85
- package/lib/reporters/dot.js +81 -81
- package/lib/reporters/html.js +390 -390
- package/lib/reporters/index.js +19 -19
- package/lib/reporters/json-stream.js +90 -90
- package/lib/reporters/json.js +135 -135
- package/lib/reporters/landing.js +108 -108
- package/lib/reporters/list.js +78 -78
- package/lib/reporters/markdown.js +112 -112
- package/lib/reporters/min.js +52 -52
- package/lib/reporters/nyan.js +276 -276
- package/lib/reporters/progress.js +104 -104
- package/lib/reporters/spec.js +99 -99
- package/lib/reporters/tap.js +294 -294
- package/lib/reporters/xunit.js +216 -216
- package/lib/runnable.js +496 -496
- package/lib/runner.js +1049 -1049
- package/lib/stats-collector.js +83 -83
- package/lib/suite.js +642 -642
- package/lib/test.js +51 -51
- package/lib/utils.js +897 -897
- package/mocha.css +326 -326
- package/mocha.js +8170 -8476
- package/package.json +630 -628
package/lib/cli/run-helpers.js
CHANGED
|
@@ -1,337 +1,337 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Helper scripts for the `run` command
|
|
5
|
-
* @see module:lib/cli/run
|
|
6
|
-
* @module
|
|
7
|
-
* @private
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const fs = require('fs');
|
|
11
|
-
const path = require('path');
|
|
12
|
-
const ansi = require('ansi-colors');
|
|
13
|
-
const debug = require('debug')('mocha:cli:run:helpers');
|
|
14
|
-
const minimatch = require('minimatch');
|
|
15
|
-
const Context = require('../context');
|
|
16
|
-
const Mocha = require('../mocha');
|
|
17
|
-
const utils = require('../utils');
|
|
18
|
-
|
|
19
|
-
const cwd = (exports.cwd = process.cwd());
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Exits Mocha when tests + code under test has finished execution (default)
|
|
23
|
-
* @param {number} code - Exit code; typically # of failures
|
|
24
|
-
* @ignore
|
|
25
|
-
* @private
|
|
26
|
-
*/
|
|
27
|
-
const exitMochaLater = code => {
|
|
28
|
-
process.on('exit', () => {
|
|
29
|
-
process.exitCode = Math.min(code, 255);
|
|
30
|
-
});
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Exits Mocha when Mocha itself has finished execution, regardless of
|
|
35
|
-
* what the tests or code under test is doing.
|
|
36
|
-
* @param {number} code - Exit code; typically # of failures
|
|
37
|
-
* @ignore
|
|
38
|
-
* @private
|
|
39
|
-
*/
|
|
40
|
-
const exitMocha = code => {
|
|
41
|
-
const clampedCode = Math.min(code, 255);
|
|
42
|
-
let draining = 0;
|
|
43
|
-
|
|
44
|
-
// Eagerly set the process's exit code in case stream.write doesn't
|
|
45
|
-
// execute its callback before the process terminates.
|
|
46
|
-
process.exitCode = clampedCode;
|
|
47
|
-
|
|
48
|
-
// flush output for Node.js Windows pipe bug
|
|
49
|
-
// https://github.com/joyent/node/issues/6247 is just one bug example
|
|
50
|
-
// https://github.com/visionmedia/mocha/issues/333 has a good discussion
|
|
51
|
-
const done = () => {
|
|
52
|
-
if (!draining--) {
|
|
53
|
-
process.exit(clampedCode);
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const streams = [process.stdout, process.stderr];
|
|
58
|
-
|
|
59
|
-
streams.forEach(stream => {
|
|
60
|
-
// submit empty write request and wait for completion
|
|
61
|
-
draining += 1;
|
|
62
|
-
stream.write('', done);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
done();
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Hide the cursor.
|
|
70
|
-
* @ignore
|
|
71
|
-
* @private
|
|
72
|
-
*/
|
|
73
|
-
const hideCursor = () => {
|
|
74
|
-
process.stdout.write('\u001b[?25l');
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Show the cursor.
|
|
79
|
-
* @ignore
|
|
80
|
-
* @private
|
|
81
|
-
*/
|
|
82
|
-
const showCursor = () => {
|
|
83
|
-
process.stdout.write('\u001b[?25h');
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Stop cursor business
|
|
88
|
-
* @private
|
|
89
|
-
*/
|
|
90
|
-
const stop = () => {
|
|
91
|
-
process.stdout.write('\u001b[2K');
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Coerce a comma-delimited string (or array thereof) into a flattened array of
|
|
96
|
-
* strings
|
|
97
|
-
* @param {string|string[]} str - Value to coerce
|
|
98
|
-
* @returns {string[]} Array of strings
|
|
99
|
-
* @private
|
|
100
|
-
*/
|
|
101
|
-
exports.list = str =>
|
|
102
|
-
Array.isArray(str) ? exports.list(str.join(',')) : str.split(/ *, */);
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* `require()` the modules as required by `--require <require>`
|
|
106
|
-
* @param {string[]} requires - Modules to require
|
|
107
|
-
* @private
|
|
108
|
-
*/
|
|
109
|
-
exports.handleRequires = (requires = []) => {
|
|
110
|
-
requires.forEach(mod => {
|
|
111
|
-
let modpath = mod;
|
|
112
|
-
if (fs.existsSync(mod, {cwd}) || fs.existsSync(`${mod}.js`, {cwd})) {
|
|
113
|
-
modpath = path.resolve(mod);
|
|
114
|
-
debug(`resolved ${mod} to ${modpath}`);
|
|
115
|
-
}
|
|
116
|
-
require(modpath);
|
|
117
|
-
debug(`loaded require "${mod}"`);
|
|
118
|
-
});
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Smash together an array of test files in the correct order
|
|
123
|
-
* @param {Object} [opts] - Options
|
|
124
|
-
* @param {string[]} [opts.extension] - File extensions to use
|
|
125
|
-
* @param {string[]} [opts.spec] - Files, dirs, globs to run
|
|
126
|
-
* @param {string[]} [opts.exclude] - Files, dirs, globs to exclude
|
|
127
|
-
* @param {boolean} [opts.recursive=false] - Find files recursively
|
|
128
|
-
* @param {boolean} [opts.sort=false] - Sort test files
|
|
129
|
-
* @returns {string[]} List of files to test
|
|
130
|
-
* @private
|
|
131
|
-
*/
|
|
132
|
-
exports.handleFiles = ({
|
|
133
|
-
exclude = [],
|
|
134
|
-
extension = [],
|
|
135
|
-
file = [],
|
|
136
|
-
recursive = false,
|
|
137
|
-
sort = false,
|
|
138
|
-
spec = []
|
|
139
|
-
} = {}) => {
|
|
140
|
-
let files = [];
|
|
141
|
-
const unmatched = [];
|
|
142
|
-
spec.forEach(arg => {
|
|
143
|
-
let newFiles;
|
|
144
|
-
try {
|
|
145
|
-
newFiles = utils.lookupFiles(arg, extension, recursive);
|
|
146
|
-
} catch (err) {
|
|
147
|
-
if (err.code === 'ERR_MOCHA_NO_FILES_MATCH_PATTERN') {
|
|
148
|
-
unmatched.push({message: err.message, pattern: err.pattern});
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
throw err;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (typeof newFiles !== 'undefined') {
|
|
156
|
-
if (typeof newFiles === 'string') {
|
|
157
|
-
newFiles = [newFiles];
|
|
158
|
-
}
|
|
159
|
-
newFiles = newFiles.filter(fileName =>
|
|
160
|
-
exclude.every(pattern => !minimatch(fileName, pattern))
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
files = files.concat(newFiles);
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
if (!files.length) {
|
|
168
|
-
// give full message details when only 1 file is missing
|
|
169
|
-
const noneFoundMsg =
|
|
170
|
-
unmatched.length === 1
|
|
171
|
-
? `Error: No test files found: ${JSON.stringify(unmatched[0].pattern)}` // stringify to print escaped characters raw
|
|
172
|
-
: 'Error: No test files found';
|
|
173
|
-
console.error(ansi.red(noneFoundMsg));
|
|
174
|
-
process.exit(1);
|
|
175
|
-
} else {
|
|
176
|
-
// print messages as an warning
|
|
177
|
-
unmatched.forEach(warning => {
|
|
178
|
-
console.warn(ansi.yellow(`Warning: ${warning.message}`));
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const fileArgs = file.map(filepath => path.resolve(filepath));
|
|
183
|
-
files = files.map(filepath => path.resolve(filepath));
|
|
184
|
-
|
|
185
|
-
// ensure we don't sort the stuff from fileArgs; order is important!
|
|
186
|
-
if (sort) {
|
|
187
|
-
files.sort();
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// add files given through --file to be ran first
|
|
191
|
-
files = fileArgs.concat(files);
|
|
192
|
-
debug('files (in order): ', files);
|
|
193
|
-
return files;
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Give Mocha files and tell it to run
|
|
198
|
-
* @param {Mocha} mocha - Mocha instance
|
|
199
|
-
* @param {Options} [opts] - Options
|
|
200
|
-
* @param {string[]} [opts.files] - List of test files
|
|
201
|
-
* @param {boolean} [opts.exit] - Whether or not to force-exit after tests are complete
|
|
202
|
-
* @returns {Runner}
|
|
203
|
-
* @private
|
|
204
|
-
*/
|
|
205
|
-
exports.singleRun = (mocha, {files = [], exit = false} = {}) => {
|
|
206
|
-
mocha.files = files;
|
|
207
|
-
return mocha.run(exit ? exitMocha : exitMochaLater);
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Run Mocha in "watch" mode
|
|
212
|
-
* @param {Mocha} mocha - Mocha instance
|
|
213
|
-
* @param {Object} [opts] - Options
|
|
214
|
-
* @param {string[]} [opts.extension] - List of extensions to watch
|
|
215
|
-
* @param {string|RegExp} [opts.grep] - Grep for test titles
|
|
216
|
-
* @param {string} [opts.ui=bdd] - User interface
|
|
217
|
-
* @param {string[]} [files] - Array of test files
|
|
218
|
-
* @private
|
|
219
|
-
*/
|
|
220
|
-
exports.watchRun = (
|
|
221
|
-
mocha,
|
|
222
|
-
{extension = ['js'], grep = '', ui = 'bdd', files = []} = {}
|
|
223
|
-
) => {
|
|
224
|
-
let runner;
|
|
225
|
-
|
|
226
|
-
console.log();
|
|
227
|
-
hideCursor();
|
|
228
|
-
process.on('SIGINT', () => {
|
|
229
|
-
showCursor();
|
|
230
|
-
console.log('\n');
|
|
231
|
-
process.exit(130);
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
const watchFiles = utils.files(cwd, extension);
|
|
235
|
-
let runAgain = false;
|
|
236
|
-
|
|
237
|
-
const loadAndRun = () => {
|
|
238
|
-
try {
|
|
239
|
-
mocha.files = files;
|
|
240
|
-
runAgain = false;
|
|
241
|
-
runner = mocha.run(() => {
|
|
242
|
-
runner = null;
|
|
243
|
-
if (runAgain) {
|
|
244
|
-
rerun();
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
} catch (e) {
|
|
248
|
-
console.log(e.stack);
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
const purge = () => {
|
|
253
|
-
watchFiles.forEach(Mocha.unloadFile);
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
loadAndRun();
|
|
257
|
-
|
|
258
|
-
const rerun = () => {
|
|
259
|
-
purge();
|
|
260
|
-
stop();
|
|
261
|
-
if (!grep) {
|
|
262
|
-
mocha.grep(null);
|
|
263
|
-
}
|
|
264
|
-
mocha.suite = mocha.suite.clone();
|
|
265
|
-
mocha.suite.ctx = new Context();
|
|
266
|
-
mocha.ui(ui);
|
|
267
|
-
loadAndRun();
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
utils.watch(watchFiles, () => {
|
|
271
|
-
runAgain = true;
|
|
272
|
-
if (runner) {
|
|
273
|
-
runner.abort();
|
|
274
|
-
} else {
|
|
275
|
-
rerun();
|
|
276
|
-
}
|
|
277
|
-
});
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* Actually run tests
|
|
282
|
-
* @param {Mocha} mocha - Mocha instance
|
|
283
|
-
* @param {Object} [opts] - Options
|
|
284
|
-
* @param {boolean} [opts.watch=false] - Enable watch mode
|
|
285
|
-
* @param {string[]} [opts.extension] - List of extensions to watch
|
|
286
|
-
* @param {string|RegExp} [opts.grep] - Grep for test titles
|
|
287
|
-
* @param {string} [opts.ui=bdd] - User interface
|
|
288
|
-
* @param {boolean} [opts.exit=false] - Force-exit Mocha when tests done
|
|
289
|
-
* @param {string[]} [files] - Array of test files
|
|
290
|
-
* @private
|
|
291
|
-
*/
|
|
292
|
-
exports.runMocha = (
|
|
293
|
-
mocha,
|
|
294
|
-
{watch = false, extension = ['js'], grep = '', ui = 'bdd', exit = false} = {},
|
|
295
|
-
files = []
|
|
296
|
-
) => {
|
|
297
|
-
if (watch) {
|
|
298
|
-
exports.watchRun(mocha, {extension, grep, ui, files});
|
|
299
|
-
} else {
|
|
300
|
-
exports.singleRun(mocha, {files, exit});
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Used for `--reporter` and `--ui`. Ensures there's only one, and asserts
|
|
306
|
-
* that it actually exists.
|
|
307
|
-
* @todo XXX This must get run after requires are processed, as it'll prevent
|
|
308
|
-
* interfaces from loading.
|
|
309
|
-
* @param {Object} opts - Options object
|
|
310
|
-
* @param {string} key - Resolvable module name or path
|
|
311
|
-
* @param {Object} [map] - An object perhaps having key `key`
|
|
312
|
-
* @private
|
|
313
|
-
*/
|
|
314
|
-
exports.validatePlugin = (opts, key, map = {}) => {
|
|
315
|
-
if (Array.isArray(opts[key])) {
|
|
316
|
-
throw new TypeError(`"--${key} <${key}>" can only be specified once`);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
const unknownError = () => new Error(`Unknown "${key}": ${opts[key]}`);
|
|
320
|
-
|
|
321
|
-
if (!map[opts[key]]) {
|
|
322
|
-
try {
|
|
323
|
-
opts[key] = require(opts[key]);
|
|
324
|
-
} catch (err) {
|
|
325
|
-
if (err.code === 'MODULE_NOT_FOUND') {
|
|
326
|
-
// Try to load reporters from a path (absolute or relative)
|
|
327
|
-
try {
|
|
328
|
-
opts[key] = require(path.resolve(process.cwd(), opts[key]));
|
|
329
|
-
} catch (err) {
|
|
330
|
-
throw unknownError();
|
|
331
|
-
}
|
|
332
|
-
} else {
|
|
333
|
-
throw unknownError();
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Helper scripts for the `run` command
|
|
5
|
+
* @see module:lib/cli/run
|
|
6
|
+
* @module
|
|
7
|
+
* @private
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const ansi = require('ansi-colors');
|
|
13
|
+
const debug = require('debug')('mocha:cli:run:helpers');
|
|
14
|
+
const minimatch = require('minimatch');
|
|
15
|
+
const Context = require('../context');
|
|
16
|
+
const Mocha = require('../mocha');
|
|
17
|
+
const utils = require('../utils');
|
|
18
|
+
|
|
19
|
+
const cwd = (exports.cwd = process.cwd());
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Exits Mocha when tests + code under test has finished execution (default)
|
|
23
|
+
* @param {number} code - Exit code; typically # of failures
|
|
24
|
+
* @ignore
|
|
25
|
+
* @private
|
|
26
|
+
*/
|
|
27
|
+
const exitMochaLater = code => {
|
|
28
|
+
process.on('exit', () => {
|
|
29
|
+
process.exitCode = Math.min(code, 255);
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Exits Mocha when Mocha itself has finished execution, regardless of
|
|
35
|
+
* what the tests or code under test is doing.
|
|
36
|
+
* @param {number} code - Exit code; typically # of failures
|
|
37
|
+
* @ignore
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
const exitMocha = code => {
|
|
41
|
+
const clampedCode = Math.min(code, 255);
|
|
42
|
+
let draining = 0;
|
|
43
|
+
|
|
44
|
+
// Eagerly set the process's exit code in case stream.write doesn't
|
|
45
|
+
// execute its callback before the process terminates.
|
|
46
|
+
process.exitCode = clampedCode;
|
|
47
|
+
|
|
48
|
+
// flush output for Node.js Windows pipe bug
|
|
49
|
+
// https://github.com/joyent/node/issues/6247 is just one bug example
|
|
50
|
+
// https://github.com/visionmedia/mocha/issues/333 has a good discussion
|
|
51
|
+
const done = () => {
|
|
52
|
+
if (!draining--) {
|
|
53
|
+
process.exit(clampedCode);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const streams = [process.stdout, process.stderr];
|
|
58
|
+
|
|
59
|
+
streams.forEach(stream => {
|
|
60
|
+
// submit empty write request and wait for completion
|
|
61
|
+
draining += 1;
|
|
62
|
+
stream.write('', done);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
done();
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Hide the cursor.
|
|
70
|
+
* @ignore
|
|
71
|
+
* @private
|
|
72
|
+
*/
|
|
73
|
+
const hideCursor = () => {
|
|
74
|
+
process.stdout.write('\u001b[?25l');
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Show the cursor.
|
|
79
|
+
* @ignore
|
|
80
|
+
* @private
|
|
81
|
+
*/
|
|
82
|
+
const showCursor = () => {
|
|
83
|
+
process.stdout.write('\u001b[?25h');
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Stop cursor business
|
|
88
|
+
* @private
|
|
89
|
+
*/
|
|
90
|
+
const stop = () => {
|
|
91
|
+
process.stdout.write('\u001b[2K');
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Coerce a comma-delimited string (or array thereof) into a flattened array of
|
|
96
|
+
* strings
|
|
97
|
+
* @param {string|string[]} str - Value to coerce
|
|
98
|
+
* @returns {string[]} Array of strings
|
|
99
|
+
* @private
|
|
100
|
+
*/
|
|
101
|
+
exports.list = str =>
|
|
102
|
+
Array.isArray(str) ? exports.list(str.join(',')) : str.split(/ *, */);
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* `require()` the modules as required by `--require <require>`
|
|
106
|
+
* @param {string[]} requires - Modules to require
|
|
107
|
+
* @private
|
|
108
|
+
*/
|
|
109
|
+
exports.handleRequires = (requires = []) => {
|
|
110
|
+
requires.forEach(mod => {
|
|
111
|
+
let modpath = mod;
|
|
112
|
+
if (fs.existsSync(mod, {cwd}) || fs.existsSync(`${mod}.js`, {cwd})) {
|
|
113
|
+
modpath = path.resolve(mod);
|
|
114
|
+
debug(`resolved ${mod} to ${modpath}`);
|
|
115
|
+
}
|
|
116
|
+
require(modpath);
|
|
117
|
+
debug(`loaded require "${mod}"`);
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Smash together an array of test files in the correct order
|
|
123
|
+
* @param {Object} [opts] - Options
|
|
124
|
+
* @param {string[]} [opts.extension] - File extensions to use
|
|
125
|
+
* @param {string[]} [opts.spec] - Files, dirs, globs to run
|
|
126
|
+
* @param {string[]} [opts.exclude] - Files, dirs, globs to exclude
|
|
127
|
+
* @param {boolean} [opts.recursive=false] - Find files recursively
|
|
128
|
+
* @param {boolean} [opts.sort=false] - Sort test files
|
|
129
|
+
* @returns {string[]} List of files to test
|
|
130
|
+
* @private
|
|
131
|
+
*/
|
|
132
|
+
exports.handleFiles = ({
|
|
133
|
+
exclude = [],
|
|
134
|
+
extension = [],
|
|
135
|
+
file = [],
|
|
136
|
+
recursive = false,
|
|
137
|
+
sort = false,
|
|
138
|
+
spec = []
|
|
139
|
+
} = {}) => {
|
|
140
|
+
let files = [];
|
|
141
|
+
const unmatched = [];
|
|
142
|
+
spec.forEach(arg => {
|
|
143
|
+
let newFiles;
|
|
144
|
+
try {
|
|
145
|
+
newFiles = utils.lookupFiles(arg, extension, recursive);
|
|
146
|
+
} catch (err) {
|
|
147
|
+
if (err.code === 'ERR_MOCHA_NO_FILES_MATCH_PATTERN') {
|
|
148
|
+
unmatched.push({message: err.message, pattern: err.pattern});
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (typeof newFiles !== 'undefined') {
|
|
156
|
+
if (typeof newFiles === 'string') {
|
|
157
|
+
newFiles = [newFiles];
|
|
158
|
+
}
|
|
159
|
+
newFiles = newFiles.filter(fileName =>
|
|
160
|
+
exclude.every(pattern => !minimatch(fileName, pattern))
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
files = files.concat(newFiles);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
if (!files.length) {
|
|
168
|
+
// give full message details when only 1 file is missing
|
|
169
|
+
const noneFoundMsg =
|
|
170
|
+
unmatched.length === 1
|
|
171
|
+
? `Error: No test files found: ${JSON.stringify(unmatched[0].pattern)}` // stringify to print escaped characters raw
|
|
172
|
+
: 'Error: No test files found';
|
|
173
|
+
console.error(ansi.red(noneFoundMsg));
|
|
174
|
+
process.exit(1);
|
|
175
|
+
} else {
|
|
176
|
+
// print messages as an warning
|
|
177
|
+
unmatched.forEach(warning => {
|
|
178
|
+
console.warn(ansi.yellow(`Warning: ${warning.message}`));
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const fileArgs = file.map(filepath => path.resolve(filepath));
|
|
183
|
+
files = files.map(filepath => path.resolve(filepath));
|
|
184
|
+
|
|
185
|
+
// ensure we don't sort the stuff from fileArgs; order is important!
|
|
186
|
+
if (sort) {
|
|
187
|
+
files.sort();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// add files given through --file to be ran first
|
|
191
|
+
files = fileArgs.concat(files);
|
|
192
|
+
debug('files (in order): ', files);
|
|
193
|
+
return files;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Give Mocha files and tell it to run
|
|
198
|
+
* @param {Mocha} mocha - Mocha instance
|
|
199
|
+
* @param {Options} [opts] - Options
|
|
200
|
+
* @param {string[]} [opts.files] - List of test files
|
|
201
|
+
* @param {boolean} [opts.exit] - Whether or not to force-exit after tests are complete
|
|
202
|
+
* @returns {Runner}
|
|
203
|
+
* @private
|
|
204
|
+
*/
|
|
205
|
+
exports.singleRun = (mocha, {files = [], exit = false} = {}) => {
|
|
206
|
+
mocha.files = files;
|
|
207
|
+
return mocha.run(exit ? exitMocha : exitMochaLater);
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Run Mocha in "watch" mode
|
|
212
|
+
* @param {Mocha} mocha - Mocha instance
|
|
213
|
+
* @param {Object} [opts] - Options
|
|
214
|
+
* @param {string[]} [opts.extension] - List of extensions to watch
|
|
215
|
+
* @param {string|RegExp} [opts.grep] - Grep for test titles
|
|
216
|
+
* @param {string} [opts.ui=bdd] - User interface
|
|
217
|
+
* @param {string[]} [files] - Array of test files
|
|
218
|
+
* @private
|
|
219
|
+
*/
|
|
220
|
+
exports.watchRun = (
|
|
221
|
+
mocha,
|
|
222
|
+
{extension = ['js'], grep = '', ui = 'bdd', files = []} = {}
|
|
223
|
+
) => {
|
|
224
|
+
let runner;
|
|
225
|
+
|
|
226
|
+
console.log();
|
|
227
|
+
hideCursor();
|
|
228
|
+
process.on('SIGINT', () => {
|
|
229
|
+
showCursor();
|
|
230
|
+
console.log('\n');
|
|
231
|
+
process.exit(130);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const watchFiles = utils.files(cwd, extension);
|
|
235
|
+
let runAgain = false;
|
|
236
|
+
|
|
237
|
+
const loadAndRun = () => {
|
|
238
|
+
try {
|
|
239
|
+
mocha.files = files;
|
|
240
|
+
runAgain = false;
|
|
241
|
+
runner = mocha.run(() => {
|
|
242
|
+
runner = null;
|
|
243
|
+
if (runAgain) {
|
|
244
|
+
rerun();
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
} catch (e) {
|
|
248
|
+
console.log(e.stack);
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const purge = () => {
|
|
253
|
+
watchFiles.forEach(Mocha.unloadFile);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
loadAndRun();
|
|
257
|
+
|
|
258
|
+
const rerun = () => {
|
|
259
|
+
purge();
|
|
260
|
+
stop();
|
|
261
|
+
if (!grep) {
|
|
262
|
+
mocha.grep(null);
|
|
263
|
+
}
|
|
264
|
+
mocha.suite = mocha.suite.clone();
|
|
265
|
+
mocha.suite.ctx = new Context();
|
|
266
|
+
mocha.ui(ui);
|
|
267
|
+
loadAndRun();
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
utils.watch(watchFiles, () => {
|
|
271
|
+
runAgain = true;
|
|
272
|
+
if (runner) {
|
|
273
|
+
runner.abort();
|
|
274
|
+
} else {
|
|
275
|
+
rerun();
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Actually run tests
|
|
282
|
+
* @param {Mocha} mocha - Mocha instance
|
|
283
|
+
* @param {Object} [opts] - Options
|
|
284
|
+
* @param {boolean} [opts.watch=false] - Enable watch mode
|
|
285
|
+
* @param {string[]} [opts.extension] - List of extensions to watch
|
|
286
|
+
* @param {string|RegExp} [opts.grep] - Grep for test titles
|
|
287
|
+
* @param {string} [opts.ui=bdd] - User interface
|
|
288
|
+
* @param {boolean} [opts.exit=false] - Force-exit Mocha when tests done
|
|
289
|
+
* @param {string[]} [files] - Array of test files
|
|
290
|
+
* @private
|
|
291
|
+
*/
|
|
292
|
+
exports.runMocha = (
|
|
293
|
+
mocha,
|
|
294
|
+
{watch = false, extension = ['js'], grep = '', ui = 'bdd', exit = false} = {},
|
|
295
|
+
files = []
|
|
296
|
+
) => {
|
|
297
|
+
if (watch) {
|
|
298
|
+
exports.watchRun(mocha, {extension, grep, ui, files});
|
|
299
|
+
} else {
|
|
300
|
+
exports.singleRun(mocha, {files, exit});
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Used for `--reporter` and `--ui`. Ensures there's only one, and asserts
|
|
306
|
+
* that it actually exists.
|
|
307
|
+
* @todo XXX This must get run after requires are processed, as it'll prevent
|
|
308
|
+
* interfaces from loading.
|
|
309
|
+
* @param {Object} opts - Options object
|
|
310
|
+
* @param {string} key - Resolvable module name or path
|
|
311
|
+
* @param {Object} [map] - An object perhaps having key `key`
|
|
312
|
+
* @private
|
|
313
|
+
*/
|
|
314
|
+
exports.validatePlugin = (opts, key, map = {}) => {
|
|
315
|
+
if (Array.isArray(opts[key])) {
|
|
316
|
+
throw new TypeError(`"--${key} <${key}>" can only be specified once`);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const unknownError = () => new Error(`Unknown "${key}": ${opts[key]}`);
|
|
320
|
+
|
|
321
|
+
if (!map[opts[key]]) {
|
|
322
|
+
try {
|
|
323
|
+
opts[key] = require(opts[key]);
|
|
324
|
+
} catch (err) {
|
|
325
|
+
if (err.code === 'MODULE_NOT_FOUND') {
|
|
326
|
+
// Try to load reporters from a path (absolute or relative)
|
|
327
|
+
try {
|
|
328
|
+
opts[key] = require(path.resolve(process.cwd(), opts[key]));
|
|
329
|
+
} catch (err) {
|
|
330
|
+
throw unknownError();
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
throw unknownError();
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
};
|