mocha 5.1.0 → 6.0.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +653 -981
  2. package/README.md +2 -1
  3. package/{images → assets/growl}/error.png +0 -0
  4. package/{images → assets/growl}/ok.png +0 -0
  5. package/bin/_mocha +4 -595
  6. package/bin/mocha +84 -58
  7. package/bin/options.js +6 -39
  8. package/browser-entry.js +21 -17
  9. package/lib/browser/growl.js +164 -2
  10. package/lib/browser/progress.js +11 -11
  11. package/lib/{template.html → browser/template.html} +0 -0
  12. package/lib/browser/tty.js +2 -2
  13. package/lib/cli/cli.js +68 -0
  14. package/lib/cli/commands.js +13 -0
  15. package/lib/cli/config.js +79 -0
  16. package/lib/cli/index.js +9 -0
  17. package/lib/cli/init.js +37 -0
  18. package/lib/cli/node-flags.js +48 -0
  19. package/lib/cli/one-and-dones.js +70 -0
  20. package/lib/cli/options.js +299 -0
  21. package/lib/cli/run-helpers.js +328 -0
  22. package/lib/cli/run-option-metadata.js +72 -0
  23. package/lib/cli/run.js +293 -0
  24. package/lib/context.js +14 -14
  25. package/lib/errors.js +139 -0
  26. package/lib/growl.js +135 -0
  27. package/lib/hook.js +5 -16
  28. package/lib/interfaces/bdd.js +14 -13
  29. package/lib/interfaces/common.js +59 -16
  30. package/lib/interfaces/exports.js +4 -7
  31. package/lib/interfaces/qunit.js +8 -10
  32. package/lib/interfaces/tdd.js +10 -11
  33. package/lib/mocha.js +442 -255
  34. package/lib/mocharc.json +10 -0
  35. package/lib/pending.js +1 -5
  36. package/lib/reporters/base.js +92 -117
  37. package/lib/reporters/doc.js +18 -9
  38. package/lib/reporters/dot.js +13 -13
  39. package/lib/reporters/html.js +76 -47
  40. package/lib/reporters/json-stream.js +38 -23
  41. package/lib/reporters/json.js +26 -23
  42. package/lib/reporters/landing.js +9 -8
  43. package/lib/reporters/list.js +11 -10
  44. package/lib/reporters/markdown.js +13 -12
  45. package/lib/reporters/min.js +4 -3
  46. package/lib/reporters/nyan.js +36 -35
  47. package/lib/reporters/progress.js +8 -7
  48. package/lib/reporters/spec.js +14 -11
  49. package/lib/reporters/tap.js +243 -32
  50. package/lib/reporters/xunit.js +52 -33
  51. package/lib/runnable.js +103 -90
  52. package/lib/runner.js +156 -107
  53. package/lib/stats-collector.js +81 -0
  54. package/lib/suite.js +57 -51
  55. package/lib/test.js +13 -13
  56. package/lib/utils.js +192 -103
  57. package/mocha.js +3836 -2046
  58. package/package.json +122 -38
  59. package/bin/.eslintrc.yml +0 -3
  60. package/lib/browser/.eslintrc.yml +0 -4
  61. package/lib/ms.js +0 -94
  62. package/lib/reporters/base.js.orig +0 -498
  63. package/lib/reporters/json.js.orig +0 -128
@@ -0,0 +1,328 @@
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 debug = require('debug')('mocha:cli:run:helpers');
12
+ const Context = require('../context');
13
+ const path = require('path');
14
+ const utils = require('../utils');
15
+ const minimatch = require('minimatch');
16
+ const ansi = require('ansi-colors');
17
+ const symbols = require('log-symbols');
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.exit(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
+ spec.forEach(arg => {
142
+ let newFiles;
143
+ try {
144
+ newFiles = utils.lookupFiles(arg, extension, recursive);
145
+ } catch (err) {
146
+ if (err.code === 'ERR_MOCHA_NO_FILES_MATCH_PATTERN') {
147
+ console.warn('Warning: %s: %O', err.message, err.pattern);
148
+ return;
149
+ }
150
+
151
+ throw err;
152
+ }
153
+
154
+ if (typeof newFiles !== 'undefined') {
155
+ if (typeof newFiles === 'string') {
156
+ newFiles = [newFiles];
157
+ }
158
+ newFiles = newFiles.filter(fileName =>
159
+ exclude.every(pattern => !minimatch(fileName, pattern))
160
+ );
161
+ }
162
+
163
+ files = files.concat(newFiles);
164
+ });
165
+
166
+ if (!files.length) {
167
+ console.error(ansi.red(`${symbols.error} No test files found`));
168
+ process.exit(1);
169
+ }
170
+
171
+ const fileArgs = file.map(filepath => path.resolve(filepath));
172
+ files = files.map(filepath => path.resolve(filepath));
173
+
174
+ // ensure we don't sort the stuff from fileArgs; order is important!
175
+ if (sort) {
176
+ files.sort();
177
+ }
178
+
179
+ // add files given through --file to be ran first
180
+ files = fileArgs.concat(files);
181
+ debug('files (in order): ', files);
182
+ return files;
183
+ };
184
+
185
+ /**
186
+ * Give Mocha files and tell it to run
187
+ * @param {Mocha} mocha - Mocha instance
188
+ * @param {Options} [opts] - Options
189
+ * @param {string[]} [opts.files] - List of test files
190
+ * @param {boolean} [opts.exit] - Whether or not to force-exit after tests are complete
191
+ * @returns {Runner}
192
+ * @private
193
+ */
194
+ exports.singleRun = (mocha, {files = [], exit = false} = {}) => {
195
+ mocha.files = files;
196
+ return mocha.run(exit ? exitMocha : exitMochaLater);
197
+ };
198
+
199
+ /**
200
+ * Run Mocha in "watch" mode
201
+ * @param {Mocha} mocha - Mocha instance
202
+ * @param {Object} [opts] - Options
203
+ * @param {string[]} [opts.extension] - List of extensions to watch
204
+ * @param {string|RegExp} [opts.grep] - Grep for test titles
205
+ * @param {string} [opts.ui=bdd] - User interface
206
+ * @param {string[]} [files] - Array of test files
207
+ * @private
208
+ */
209
+ exports.watchRun = (
210
+ mocha,
211
+ {extension = ['js'], grep = '', ui = 'bdd', files = []} = {}
212
+ ) => {
213
+ let runner;
214
+
215
+ console.log();
216
+ hideCursor();
217
+ process.on('SIGINT', () => {
218
+ showCursor();
219
+ console.log('\n');
220
+ process.exit(130);
221
+ });
222
+
223
+ const watchFiles = utils.files(cwd, extension);
224
+ let runAgain = false;
225
+
226
+ const loadAndRun = () => {
227
+ try {
228
+ mocha.files = files;
229
+ runAgain = false;
230
+ runner = mocha.run(() => {
231
+ runner = null;
232
+ if (runAgain) {
233
+ rerun();
234
+ }
235
+ });
236
+ } catch (e) {
237
+ console.log(e.stack);
238
+ }
239
+ };
240
+
241
+ const purge = () => {
242
+ watchFiles.forEach(file => {
243
+ delete require.cache[file];
244
+ });
245
+ };
246
+
247
+ loadAndRun();
248
+
249
+ const rerun = () => {
250
+ purge();
251
+ stop();
252
+ if (!grep) {
253
+ mocha.grep(null);
254
+ }
255
+ mocha.suite = mocha.suite.clone();
256
+ mocha.suite.ctx = new Context();
257
+ mocha.ui(ui);
258
+ loadAndRun();
259
+ };
260
+
261
+ utils.watch(watchFiles, () => {
262
+ runAgain = true;
263
+ if (runner) {
264
+ runner.abort();
265
+ } else {
266
+ rerun();
267
+ }
268
+ });
269
+ };
270
+
271
+ /**
272
+ * Actually run tests
273
+ * @param {Mocha} mocha - Mocha instance
274
+ * @param {Object} [opts] - Options
275
+ * @param {boolean} [opts.watch=false] - Enable watch mode
276
+ * @param {string[]} [opts.extension] - List of extensions to watch
277
+ * @param {string|RegExp} [opts.grep] - Grep for test titles
278
+ * @param {string} [opts.ui=bdd] - User interface
279
+ * @param {boolean} [opts.exit=false] - Force-exit Mocha when tests done
280
+ * @param {string[]} [files] - Array of test files
281
+ * @private
282
+ */
283
+ exports.runMocha = (
284
+ mocha,
285
+ {watch = false, extension = ['js'], grep = '', ui = 'bdd', exit = false} = {},
286
+ files = []
287
+ ) => {
288
+ if (watch) {
289
+ exports.watchRun(mocha, {extension, grep, ui});
290
+ } else {
291
+ exports.singleRun(mocha, {files, exit});
292
+ }
293
+ };
294
+
295
+ /**
296
+ * Used for `--reporter` and `--ui`. Ensures there's only one, and asserts
297
+ * that it actually exists.
298
+ * @todo XXX This must get run after requires are processed, as it'll prevent
299
+ * interfaces from loading.
300
+ * @param {Object} opts - Options object
301
+ * @param {string} key - Resolvable module name or path
302
+ * @param {Object} [map] - An object perhaps having key `key`
303
+ * @private
304
+ */
305
+ exports.validatePlugin = (opts, key, map = {}) => {
306
+ if (Array.isArray(opts[key])) {
307
+ throw new TypeError(`"--${key} <${key}>" can only be specified once`);
308
+ }
309
+
310
+ const unknownError = () => new Error(`Unknown "${key}": ${opts[key]}`);
311
+
312
+ if (!map[opts[key]]) {
313
+ try {
314
+ opts[key] = require(opts[key]);
315
+ } catch (err) {
316
+ if (err.code === 'MODULE_NOT_FOUND') {
317
+ // Try to load reporters from a path (absolute or relative)
318
+ try {
319
+ opts[key] = require(path.resolve(process.cwd(), opts[key]));
320
+ } catch (err) {
321
+ throw unknownError();
322
+ }
323
+ } else {
324
+ throw unknownError();
325
+ }
326
+ }
327
+ }
328
+ };
@@ -0,0 +1,72 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Metadata about various options of the `run` command
5
+ * @see module:lib/cli/run
6
+ * @module
7
+ * @private
8
+ */
9
+
10
+ /**
11
+ * Dictionary of yargs option types to list of options having said type
12
+ * @type {{string:string[]}}
13
+ * @private
14
+ */
15
+ exports.types = {
16
+ array: [
17
+ 'exclude',
18
+ 'extension',
19
+ 'file',
20
+ 'global',
21
+ 'require',
22
+ 'reporter-option',
23
+ 'spec'
24
+ ],
25
+ boolean: [
26
+ 'allow-uncaught',
27
+ 'async-only',
28
+ 'bail',
29
+ 'check-leaks',
30
+ 'color',
31
+ 'diff',
32
+ 'exit',
33
+ 'forbid-only',
34
+ 'forbid-pending',
35
+ 'full-trace',
36
+ 'growl',
37
+ 'inline-diffs',
38
+ 'invert',
39
+ 'no-colors',
40
+ 'recursive',
41
+ 'watch'
42
+ ],
43
+ number: ['retries', 'slow', 'timeout'],
44
+ string: ['fgrep', 'grep', 'package', 'reporter', 'ui']
45
+ };
46
+
47
+ /**
48
+ * Option aliases keyed by canonical option name.
49
+ * Arrays used to reduce
50
+ * @type {{string:string[]}}
51
+ * @private
52
+ */
53
+ exports.aliases = {
54
+ 'async-only': ['A'],
55
+ bail: ['b'],
56
+ color: ['c', 'colors'],
57
+ extension: ['watch-extensions'],
58
+ fgrep: ['f'],
59
+ global: ['globals'],
60
+ grep: ['g'],
61
+ growl: ['G'],
62
+ invert: ['i'],
63
+ 'no-colors': ['C'],
64
+ reporter: ['R'],
65
+ 'reporter-option': ['reporter-options', 'O'],
66
+ require: ['r'],
67
+ slow: ['s'],
68
+ sort: ['S'],
69
+ timeout: ['t', 'timeouts'],
70
+ ui: ['u'],
71
+ watch: ['w']
72
+ };
package/lib/cli/run.js ADDED
@@ -0,0 +1,293 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Definition for Mocha's default ("run tests") command
5
+ *
6
+ * @module
7
+ * @private
8
+ */
9
+
10
+ const Mocha = require('../mocha');
11
+ const ansi = require('ansi-colors');
12
+ const errors = require('../errors');
13
+ const createInvalidArgumentValueError = errors.createInvalidArgumentValueError;
14
+
15
+ const {
16
+ list,
17
+ handleFiles,
18
+ handleRequires,
19
+ validatePlugin,
20
+ runMocha
21
+ } = require('./run-helpers');
22
+ const {ONE_AND_DONES, ONE_AND_DONE_ARGS} = require('./one-and-dones');
23
+ const debug = require('debug')('mocha:cli:run');
24
+ const defaults = require('../mocharc');
25
+ const {types, aliases} = require('./run-option-metadata');
26
+
27
+ /**
28
+ * Logical option groups
29
+ * @constant
30
+ */
31
+ const GROUPS = {
32
+ FILES: 'File Handling',
33
+ FILTERS: 'Test Filters',
34
+ NODEJS: 'Node.js & V8',
35
+ OUTPUT: 'Reporting & Output',
36
+ RULES: 'Rules & Behavior',
37
+ CONFIG: 'Configuration'
38
+ };
39
+
40
+ exports.command = ['$0 [spec..]', 'debug [spec..]'];
41
+
42
+ exports.describe = 'Run tests with Mocha';
43
+
44
+ exports.builder = yargs =>
45
+ yargs
46
+ .options({
47
+ 'allow-uncaught': {
48
+ description: 'Allow uncaught errors to propagate',
49
+ group: GROUPS.RULES
50
+ },
51
+ 'async-only': {
52
+ description:
53
+ 'Require all tests to use a callback (async) or return a Promise',
54
+ group: GROUPS.RULES
55
+ },
56
+ bail: {
57
+ description: 'Abort ("bail") after first test failure',
58
+ group: GROUPS.RULES
59
+ },
60
+ 'check-leaks': {
61
+ description: 'Check for global variable leaks',
62
+ group: GROUPS.RULES
63
+ },
64
+ color: {
65
+ description: 'Force-enable color output',
66
+ group: GROUPS.OUTPUT
67
+ },
68
+ config: {
69
+ config: true,
70
+ defaultDescription: '(nearest rc file)',
71
+ description: 'Path to config file',
72
+ group: GROUPS.CONFIG
73
+ },
74
+ delay: {
75
+ description: 'Delay initial execution of root suite',
76
+ group: GROUPS.RULES
77
+ },
78
+ diff: {
79
+ default: true,
80
+ description: 'Show diff on failure',
81
+ group: GROUPS.OUTPUT
82
+ },
83
+ exclude: {
84
+ defaultDescription: '(none)',
85
+ description: 'Ignore file(s) or glob pattern(s)',
86
+ group: GROUPS.FILES,
87
+ requiresArg: true
88
+ },
89
+ exit: {
90
+ description: 'Force Mocha to quit after tests complete',
91
+ group: GROUPS.RULES
92
+ },
93
+ extension: {
94
+ default: defaults.extension,
95
+ defaultDescription: 'js',
96
+ description: 'File extension(s) to load and/or watch',
97
+ group: GROUPS.FILES,
98
+ requiresArg: true,
99
+ coerce: list
100
+ },
101
+ fgrep: {
102
+ conflicts: 'grep',
103
+ description: 'Only run tests containing this string',
104
+ group: GROUPS.FILTERS,
105
+ requiresArg: true
106
+ },
107
+ file: {
108
+ defaultDescription: '(none)',
109
+ description:
110
+ 'Specify file(s) to be loaded prior to root suite execution',
111
+ group: GROUPS.FILES,
112
+ normalize: true,
113
+ requiresArg: true
114
+ },
115
+ 'forbid-only': {
116
+ description: 'Fail if exclusive test(s) encountered',
117
+ group: GROUPS.RULES
118
+ },
119
+ 'forbid-pending': {
120
+ description: 'Fail if pending test(s) encountered',
121
+ group: GROUPS.RULES
122
+ },
123
+ 'full-trace': {
124
+ description: 'Display full stack traces',
125
+ group: GROUPS.OUTPUT
126
+ },
127
+ global: {
128
+ coerce: list,
129
+ description: 'List of allowed global variables',
130
+ group: GROUPS.RULES,
131
+ requiresArg: true
132
+ },
133
+ grep: {
134
+ coerce: value => (!value ? null : value),
135
+ conflicts: 'fgrep',
136
+ description: 'Only run tests matching this string or regexp',
137
+ group: GROUPS.FILTERS,
138
+ requiresArg: true
139
+ },
140
+ growl: {
141
+ description: 'Enable Growl notifications',
142
+ group: GROUPS.OUTPUT
143
+ },
144
+ 'inline-diffs': {
145
+ description:
146
+ 'Display actual/expected differences inline within each string',
147
+ group: GROUPS.OUTPUT
148
+ },
149
+ interfaces: {
150
+ conflicts: Array.from(ONE_AND_DONE_ARGS),
151
+ description: 'List built-in user interfaces & exit'
152
+ },
153
+ invert: {
154
+ description: 'Inverts --grep and --fgrep matches',
155
+ group: GROUPS.FILTERS
156
+ },
157
+ 'no-colors': {
158
+ description: 'Force-disable color output',
159
+ group: GROUPS.OUTPUT,
160
+ hidden: true
161
+ },
162
+ opts: {
163
+ default: defaults.opts,
164
+ description: 'Path to `mocha.opts`',
165
+ group: GROUPS.CONFIG,
166
+ normalize: true,
167
+ requiresArg: true
168
+ },
169
+ package: {
170
+ description: 'Path to package.json for config',
171
+ group: GROUPS.CONFIG,
172
+ normalize: true,
173
+ requiresArg: true
174
+ },
175
+ recursive: {
176
+ description: 'Look for tests in subdirectories',
177
+ group: GROUPS.FILES
178
+ },
179
+ reporter: {
180
+ default: defaults.reporter,
181
+ description: 'Specify reporter to use',
182
+ group: GROUPS.OUTPUT,
183
+ requiresArg: true
184
+ },
185
+ reporters: {
186
+ conflicts: Array.from(ONE_AND_DONE_ARGS),
187
+ description: 'List built-in reporters & exit'
188
+ },
189
+ 'reporter-option': {
190
+ coerce: opts =>
191
+ opts.reduce((acc, opt) => {
192
+ const pair = opt.split('=');
193
+
194
+ if (pair.length > 2 || !pair.length) {
195
+ throw createInvalidArgumentValueError(
196
+ `invalid reporter option '${opt}'`,
197
+ '--reporter-option',
198
+ opt,
199
+ 'expected "key=value" format'
200
+ );
201
+ }
202
+
203
+ acc[pair[0]] = pair.length === 2 ? pair[1] : true;
204
+ return acc;
205
+ }, {}),
206
+ description: 'Reporter-specific options (<k=v,[k1=v1,..]>)',
207
+ group: GROUPS.OUTPUT,
208
+ requiresArg: true
209
+ },
210
+ require: {
211
+ defaultDescription: '(none)',
212
+ description: 'Require module',
213
+ group: GROUPS.FILES,
214
+ requiresArg: true
215
+ },
216
+ retries: {
217
+ description: 'Retry failed tests this many times',
218
+ group: GROUPS.RULES
219
+ },
220
+ slow: {
221
+ default: defaults.slow,
222
+ description: 'Specify "slow" test threshold (in milliseconds)',
223
+ group: GROUPS.RULES
224
+ },
225
+ sort: {
226
+ description: 'Sort test files',
227
+ group: GROUPS.FILES
228
+ },
229
+ timeout: {
230
+ default: defaults.timeout,
231
+ description: 'Specify test timeout threshold (in milliseconds)',
232
+ group: GROUPS.RULES
233
+ },
234
+ ui: {
235
+ default: defaults.ui,
236
+ description: 'Specify user interface',
237
+ group: GROUPS.RULES,
238
+ requiresArg: true
239
+ },
240
+ watch: {
241
+ description: 'Watch files in the current working directory for changes',
242
+ group: GROUPS.FILES
243
+ }
244
+ })
245
+ .positional('spec', {
246
+ default: ['test/'],
247
+ description: 'One or more files, directories, or globs to test',
248
+ type: 'array'
249
+ })
250
+ .check(argv => {
251
+ // "one-and-dones"; let yargs handle help and version
252
+ Object.keys(ONE_AND_DONES).forEach(opt => {
253
+ if (argv[opt]) {
254
+ ONE_AND_DONES[opt].call(null, yargs);
255
+ process.exit();
256
+ }
257
+ });
258
+
259
+ // yargs.implies() isn't flexible enough to handle this
260
+ if (argv.invert && !('fgrep' in argv || 'grep' in argv)) {
261
+ throw new Error(
262
+ '"--invert" requires one of "--fgrep <str>" or "--grep <regexp>"'
263
+ );
264
+ }
265
+
266
+ if (argv.compilers) {
267
+ throw new Error(
268
+ `--compilers is DEPRECATED and no longer supported.
269
+ See ${ansi.cyan('https://git.io/vdcSr')} for migration information.`
270
+ );
271
+ }
272
+
273
+ // load requires first, because it can impact "plugin" validation
274
+ handleRequires(argv.require);
275
+ validatePlugin(argv, 'reporter', Mocha.reporters);
276
+ validatePlugin(argv, 'ui', Mocha.interfaces);
277
+
278
+ return true;
279
+ })
280
+ .array(types.array)
281
+ .boolean(types.boolean)
282
+ .string(types.string)
283
+ .number(types.number)
284
+ .alias(aliases);
285
+
286
+ exports.handler = argv => {
287
+ debug('post-yargs config', argv);
288
+ const mocha = new Mocha(argv);
289
+ const files = handleFiles(argv);
290
+
291
+ debug('running tests with files', files);
292
+ runMocha(mocha, argv, files);
293
+ };