1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | const Mocha = require('../mocha');
|
11 | const {
|
12 | createUnsupportedError,
|
13 | createInvalidArgumentValueError,
|
14 | createMissingArgumentError
|
15 | } = require('../errors');
|
16 |
|
17 | const {
|
18 | list,
|
19 | handleRequires,
|
20 | validatePlugin,
|
21 | runMocha
|
22 | } = require('./run-helpers');
|
23 | const {ONE_AND_DONES, ONE_AND_DONE_ARGS} = require('./one-and-dones');
|
24 | const debug = require('debug')('mocha:cli:run');
|
25 | const defaults = require('../mocharc');
|
26 | const {types, aliases} = require('./run-option-metadata');
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 | const GROUPS = {
|
33 | FILES: 'File Handling',
|
34 | FILTERS: 'Test Filters',
|
35 | NODEJS: 'Node.js & V8',
|
36 | OUTPUT: 'Reporting & Output',
|
37 | RULES: 'Rules & Behavior',
|
38 | CONFIG: 'Configuration'
|
39 | };
|
40 |
|
41 | exports.command = ['$0 [spec..]', 'inspect'];
|
42 |
|
43 | exports.describe = 'Run tests with Mocha';
|
44 |
|
45 | exports.builder = yargs =>
|
46 | yargs
|
47 | .options({
|
48 | 'allow-uncaught': {
|
49 | description: 'Allow uncaught errors to propagate',
|
50 | group: GROUPS.RULES
|
51 | },
|
52 | 'async-only': {
|
53 | description:
|
54 | 'Require all tests to use a callback (async) or return a Promise',
|
55 | group: GROUPS.RULES
|
56 | },
|
57 | bail: {
|
58 | description: 'Abort ("bail") after first test failure',
|
59 | group: GROUPS.RULES
|
60 | },
|
61 | 'check-leaks': {
|
62 | description: 'Check for global variable leaks',
|
63 | group: GROUPS.RULES
|
64 | },
|
65 | color: {
|
66 | description: 'Force-enable color output',
|
67 | group: GROUPS.OUTPUT
|
68 | },
|
69 | config: {
|
70 | config: true,
|
71 | defaultDescription: '(nearest rc file)',
|
72 | description: 'Path to config file',
|
73 | group: GROUPS.CONFIG
|
74 | },
|
75 | delay: {
|
76 | description: 'Delay initial execution of root suite',
|
77 | group: GROUPS.RULES
|
78 | },
|
79 | diff: {
|
80 | default: true,
|
81 | description: 'Show diff on failure',
|
82 | group: GROUPS.OUTPUT
|
83 | },
|
84 | exit: {
|
85 | description: 'Force Mocha to quit after tests complete',
|
86 | group: GROUPS.RULES
|
87 | },
|
88 | extension: {
|
89 | default: defaults.extension,
|
90 | defaultDescription: 'js',
|
91 | description: 'File extension(s) to load',
|
92 | group: GROUPS.FILES,
|
93 | requiresArg: true,
|
94 | coerce: list
|
95 | },
|
96 | fgrep: {
|
97 | conflicts: 'grep',
|
98 | description: 'Only run tests containing this string',
|
99 | group: GROUPS.FILTERS,
|
100 | requiresArg: true
|
101 | },
|
102 | file: {
|
103 | defaultDescription: '(none)',
|
104 | description:
|
105 | 'Specify file(s) to be loaded prior to root suite execution',
|
106 | group: GROUPS.FILES,
|
107 | normalize: true,
|
108 | requiresArg: true
|
109 | },
|
110 | 'forbid-only': {
|
111 | description: 'Fail if exclusive test(s) encountered',
|
112 | group: GROUPS.RULES
|
113 | },
|
114 | 'forbid-pending': {
|
115 | description: 'Fail if pending test(s) encountered',
|
116 | group: GROUPS.RULES
|
117 | },
|
118 | 'full-trace': {
|
119 | description: 'Display full stack traces',
|
120 | group: GROUPS.OUTPUT
|
121 | },
|
122 | global: {
|
123 | coerce: list,
|
124 | description: 'List of allowed global variables',
|
125 | group: GROUPS.RULES,
|
126 | requiresArg: true
|
127 | },
|
128 | grep: {
|
129 | coerce: value => (!value ? null : value),
|
130 | conflicts: 'fgrep',
|
131 | description: 'Only run tests matching this string or regexp',
|
132 | group: GROUPS.FILTERS,
|
133 | requiresArg: true
|
134 | },
|
135 | growl: {
|
136 | description: 'Enable Growl notifications',
|
137 | group: GROUPS.OUTPUT
|
138 | },
|
139 | ignore: {
|
140 | defaultDescription: '(none)',
|
141 | description: 'Ignore file(s) or glob pattern(s)',
|
142 | group: GROUPS.FILES,
|
143 | requiresArg: true
|
144 | },
|
145 | 'inline-diffs': {
|
146 | description:
|
147 | 'Display actual/expected differences inline within each string',
|
148 | group: GROUPS.OUTPUT
|
149 | },
|
150 | invert: {
|
151 | description: 'Inverts --grep and --fgrep matches',
|
152 | group: GROUPS.FILTERS
|
153 | },
|
154 | 'list-interfaces': {
|
155 | conflicts: Array.from(ONE_AND_DONE_ARGS),
|
156 | description: 'List built-in user interfaces & exit'
|
157 | },
|
158 | 'list-reporters': {
|
159 | conflicts: Array.from(ONE_AND_DONE_ARGS),
|
160 | description: 'List built-in reporters & exit'
|
161 | },
|
162 | 'no-colors': {
|
163 | description: 'Force-disable color output',
|
164 | group: GROUPS.OUTPUT,
|
165 | hidden: true
|
166 | },
|
167 | opts: {
|
168 | default: defaults.opts,
|
169 | description: 'Path to `mocha.opts` (DEPRECATED)',
|
170 | group: GROUPS.CONFIG,
|
171 | normalize: true,
|
172 | requiresArg: true
|
173 | },
|
174 | package: {
|
175 | description: 'Path to package.json for config',
|
176 | group: GROUPS.CONFIG,
|
177 | normalize: true,
|
178 | requiresArg: true
|
179 | },
|
180 | recursive: {
|
181 | description: 'Look for tests in subdirectories',
|
182 | group: GROUPS.FILES
|
183 | },
|
184 | reporter: {
|
185 | default: defaults.reporter,
|
186 | description: 'Specify reporter to use',
|
187 | group: GROUPS.OUTPUT,
|
188 | requiresArg: true
|
189 | },
|
190 | 'reporter-option': {
|
191 | coerce: opts =>
|
192 | list(opts).reduce((acc, opt) => {
|
193 | const pair = opt.split('=');
|
194 |
|
195 | if (pair.length > 2 || !pair.length) {
|
196 | throw createInvalidArgumentValueError(
|
197 | `invalid reporter option '${opt}'`,
|
198 | '--reporter-option',
|
199 | opt,
|
200 | 'expected "key=value" format'
|
201 | );
|
202 | }
|
203 |
|
204 | acc[pair[0]] = pair.length === 2 ? pair[1] : true;
|
205 | return acc;
|
206 | }, {}),
|
207 | description: 'Reporter-specific options (<k=v,[k1=v1,..]>)',
|
208 | group: GROUPS.OUTPUT,
|
209 | requiresArg: true
|
210 | },
|
211 | require: {
|
212 | defaultDescription: '(none)',
|
213 | description: 'Require module',
|
214 | group: GROUPS.FILES,
|
215 | requiresArg: true
|
216 | },
|
217 | retries: {
|
218 | description: 'Retry failed tests this many times',
|
219 | group: GROUPS.RULES
|
220 | },
|
221 | slow: {
|
222 | default: defaults.slow,
|
223 | description: 'Specify "slow" test threshold (in milliseconds)',
|
224 | group: GROUPS.RULES
|
225 | },
|
226 | sort: {
|
227 | description: 'Sort test files',
|
228 | group: GROUPS.FILES
|
229 | },
|
230 | timeout: {
|
231 | default: defaults.timeout,
|
232 | description: 'Specify test timeout threshold (in milliseconds)',
|
233 | group: GROUPS.RULES
|
234 | },
|
235 | ui: {
|
236 | default: defaults.ui,
|
237 | description: 'Specify user interface',
|
238 | group: GROUPS.RULES,
|
239 | requiresArg: true
|
240 | },
|
241 | watch: {
|
242 | description: 'Watch files in the current working directory for changes',
|
243 | group: GROUPS.FILES
|
244 | },
|
245 | 'watch-files': {
|
246 | description: 'List of paths or globs to watch',
|
247 | group: GROUPS.FILES,
|
248 | requiresArg: true,
|
249 | coerce: list
|
250 | },
|
251 | 'watch-ignore': {
|
252 | description: 'List of paths or globs to exclude from watching',
|
253 | group: GROUPS.FILES,
|
254 | requiresArg: true,
|
255 | coerce: list,
|
256 | default: defaults['watch-ignore']
|
257 | }
|
258 | })
|
259 | .positional('spec', {
|
260 | default: ['test'],
|
261 | description: 'One or more files, directories, or globs to test',
|
262 | type: 'array'
|
263 | })
|
264 | .check(argv => {
|
265 |
|
266 | Object.keys(ONE_AND_DONES).forEach(opt => {
|
267 | if (argv[opt]) {
|
268 | ONE_AND_DONES[opt].call(null, yargs);
|
269 | process.exit();
|
270 | }
|
271 | });
|
272 |
|
273 |
|
274 | if (argv.invert && !('fgrep' in argv || 'grep' in argv)) {
|
275 | throw createMissingArgumentError(
|
276 | '"--invert" requires one of "--fgrep <str>" or "--grep <regexp>"',
|
277 | '--fgrep|--grep',
|
278 | 'string|regexp'
|
279 | );
|
280 | }
|
281 |
|
282 | if (argv.compilers) {
|
283 | throw createUnsupportedError(
|
284 | `--compilers is DEPRECATED and no longer supported.
|
285 | See https://git.io/vdcSr for migration information.`
|
286 | );
|
287 | }
|
288 |
|
289 |
|
290 | handleRequires(argv.require);
|
291 | validatePlugin(argv, 'reporter', Mocha.reporters);
|
292 | validatePlugin(argv, 'ui', Mocha.interfaces);
|
293 |
|
294 | return true;
|
295 | })
|
296 | .array(types.array)
|
297 | .boolean(types.boolean)
|
298 | .string(types.string)
|
299 | .number(types.number)
|
300 | .alias(aliases);
|
301 |
|
302 | exports.handler = async function(argv) {
|
303 | debug('post-yargs config', argv);
|
304 | const mocha = new Mocha(argv);
|
305 |
|
306 | try {
|
307 | await runMocha(mocha, argv);
|
308 | } catch (err) {
|
309 | console.error(err.stack || `Error: ${err.message || err}`);
|
310 | process.exit(1);
|
311 | }
|
312 | };
|