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.
Files changed (61) hide show
  1. package/CHANGELOG.md +1776 -1751
  2. package/LICENSE +22 -22
  3. package/README.md +105 -105
  4. package/bin/_mocha +10 -10
  5. package/bin/mocha +149 -149
  6. package/bin/options.js +10 -10
  7. package/browser-entry.js +191 -191
  8. package/index.js +3 -3
  9. package/lib/browser/growl.js +168 -168
  10. package/lib/browser/progress.js +119 -119
  11. package/lib/browser/template.html +18 -18
  12. package/lib/browser/tty.js +13 -13
  13. package/lib/cli/cli.js +69 -69
  14. package/lib/cli/commands.js +13 -13
  15. package/lib/cli/config.js +101 -101
  16. package/lib/cli/index.js +9 -9
  17. package/lib/cli/init.js +37 -37
  18. package/lib/cli/node-flags.js +86 -86
  19. package/lib/cli/one-and-dones.js +70 -70
  20. package/lib/cli/options.js +347 -347
  21. package/lib/cli/run-helpers.js +337 -337
  22. package/lib/cli/run-option-metadata.js +76 -76
  23. package/lib/cli/run.js +297 -297
  24. package/lib/context.js +101 -101
  25. package/lib/errors.js +141 -141
  26. package/lib/growl.js +136 -136
  27. package/lib/hook.js +46 -46
  28. package/lib/interfaces/bdd.js +118 -118
  29. package/lib/interfaces/common.js +191 -191
  30. package/lib/interfaces/exports.js +60 -60
  31. package/lib/interfaces/index.js +6 -6
  32. package/lib/interfaces/qunit.js +99 -99
  33. package/lib/interfaces/tdd.js +107 -107
  34. package/lib/mocha.js +843 -843
  35. package/lib/mocharc.json +10 -10
  36. package/lib/pending.js +12 -12
  37. package/lib/reporters/base.js +491 -491
  38. package/lib/reporters/doc.js +85 -85
  39. package/lib/reporters/dot.js +81 -81
  40. package/lib/reporters/html.js +390 -390
  41. package/lib/reporters/index.js +19 -19
  42. package/lib/reporters/json-stream.js +90 -90
  43. package/lib/reporters/json.js +135 -135
  44. package/lib/reporters/landing.js +108 -108
  45. package/lib/reporters/list.js +78 -78
  46. package/lib/reporters/markdown.js +112 -112
  47. package/lib/reporters/min.js +52 -52
  48. package/lib/reporters/nyan.js +276 -276
  49. package/lib/reporters/progress.js +104 -104
  50. package/lib/reporters/spec.js +99 -99
  51. package/lib/reporters/tap.js +294 -294
  52. package/lib/reporters/xunit.js +216 -216
  53. package/lib/runnable.js +496 -496
  54. package/lib/runner.js +1049 -1049
  55. package/lib/stats-collector.js +83 -83
  56. package/lib/suite.js +642 -642
  57. package/lib/test.js +51 -51
  58. package/lib/utils.js +897 -897
  59. package/mocha.css +326 -326
  60. package/mocha.js +8170 -8476
  61. package/package.json +630 -628
@@ -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
+ };