mocha 9.0.0 → 9.1.0
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 +38 -0
- package/bin/mocha +18 -27
- package/lib/cli/cli.js +3 -2
- package/lib/cli/config.js +1 -1
- package/lib/cli/node-flags.js +2 -5
- package/lib/cli/run-helpers.js +6 -6
- package/lib/cli/run-option-metadata.js +3 -0
- package/lib/cli/run.js +8 -0
- package/lib/errors.js +2 -2
- package/lib/esm-utils.js +20 -3
- package/lib/mocha.js +33 -16
- package/lib/reporters/base.js +1 -1
- package/lib/reporters/json.js +28 -3
- package/lib/runner.js +5 -2
- package/mocha-es2018.js +19834 -0
- package/mocha.js +2881 -2625
- package/mocha.js.map +1 -1
- package/package.json +7 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,41 @@
|
|
|
1
|
+
# 9.1.0 / 2021-08-20
|
|
2
|
+
|
|
3
|
+
## :tada: Enhancements
|
|
4
|
+
|
|
5
|
+
- [#4716](https://github.com/mochajs/mocha/issues/4716): Add new option `--fail-zero` ([**@juergba**](https://github.com/juergba))
|
|
6
|
+
- [#4691](https://github.com/mochajs/mocha/issues/4691): Add new option `--node-option` ([**@juergba**](https://github.com/juergba))
|
|
7
|
+
- [#4607](https://github.com/mochajs/mocha/issues/4607): Add output option to `JSON` reporter ([**@dorny**](https://github.com/dorny))
|
|
8
|
+
|
|
9
|
+
# 9.0.3 / 2021-07-25
|
|
10
|
+
|
|
11
|
+
## :bug: Fixes
|
|
12
|
+
|
|
13
|
+
- [#4702](https://github.com/mochajs/mocha/issues/4702): Error rethrow from cwd-relative path while loading `.mocharc.js` ([**@kirill-golovan**](https://github.com/kirill-golovan))
|
|
14
|
+
|
|
15
|
+
- [#4688](https://github.com/mochajs/mocha/issues/4688): Usage of custom interface in parallel mode ([**@juergba**](https://github.com/juergba))
|
|
16
|
+
|
|
17
|
+
- [#4687](https://github.com/mochajs/mocha/issues/4687): ESM: don't swallow `MODULE_NOT_FOUND` errors in case of `type:module` ([**@giltayar**](https://github.com/giltayar))
|
|
18
|
+
|
|
19
|
+
# 9.0.2 / 2021-07-03
|
|
20
|
+
|
|
21
|
+
## :bug: Fixes
|
|
22
|
+
|
|
23
|
+
- [#4668](https://github.com/mochajs/mocha/issues/4668): ESM: make `--require <dir>` work with new `import`-first loading ([**@giltayar**](https://github.com/giltayar))
|
|
24
|
+
|
|
25
|
+
## :nut_and_bolt: Other
|
|
26
|
+
|
|
27
|
+
- [#4674](https://github.com/mochajs/mocha/issues/4674): Update production dependencies ([**@juergba**](https://github.com/juergba))
|
|
28
|
+
|
|
29
|
+
# 9.0.1 / 2021-06-18
|
|
30
|
+
|
|
31
|
+
## :nut_and_bolt: Other
|
|
32
|
+
|
|
33
|
+
- [#4657](https://github.com/mochajs/mocha/issues/4657): Browser: add separate bundle for modern browsers ([**@juergba**](https://github.com/juergba))
|
|
34
|
+
|
|
35
|
+
We added a separate browser bundle `mocha-es2018.js` in javascript ES2018, as we skipped the transpilation down to ES5. This is an **experimental step towards freezing Mocha's support of IE11**.
|
|
36
|
+
|
|
37
|
+
- [#4653](https://github.com/mochajs/mocha/issues/4653): ESM: proper version check in `hasStableEsmImplementation` ([**@alexander-fenster**](https://github.com/alexander-fenster))
|
|
38
|
+
|
|
1
39
|
# 9.0.0 / 2021-06-07
|
|
2
40
|
|
|
3
41
|
## :boom: Breaking Changes
|
package/bin/mocha
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
* @private
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
const {deprecate} = require('../lib/utils');
|
|
14
13
|
const {loadOptions} = require('../lib/cli/options');
|
|
15
14
|
const {
|
|
16
15
|
unparseNodeFlags,
|
|
@@ -23,6 +22,7 @@ const {aliases} = require('../lib/cli/run-option-metadata');
|
|
|
23
22
|
|
|
24
23
|
const mochaArgs = {};
|
|
25
24
|
const nodeArgs = {};
|
|
25
|
+
let hasInspect = false;
|
|
26
26
|
|
|
27
27
|
const opts = loadOptions(process.argv.slice(2));
|
|
28
28
|
debug('loaded opts', opts);
|
|
@@ -59,48 +59,39 @@ Object.keys(opts).forEach(opt => {
|
|
|
59
59
|
|
|
60
60
|
// disable 'timeout' for debugFlags
|
|
61
61
|
Object.keys(nodeArgs).forEach(opt => disableTimeouts(opt));
|
|
62
|
+
mochaArgs['node-option'] &&
|
|
63
|
+
mochaArgs['node-option'].forEach(opt => disableTimeouts(opt));
|
|
62
64
|
|
|
63
65
|
// Native debugger handling
|
|
64
66
|
// see https://nodejs.org/api/debugger.html#debugger_debugger
|
|
65
|
-
// look for 'inspect'
|
|
67
|
+
// look for 'inspect' that would launch this debugger,
|
|
66
68
|
// remove it from Mocha's opts and prepend it to Node's opts.
|
|
67
69
|
// A deprecation warning will be printed by node, if applicable.
|
|
68
70
|
// (mochaArgs._ are "positional" arguments, not prefixed with - or --)
|
|
69
71
|
if (mochaArgs._) {
|
|
70
|
-
const i = mochaArgs._.findIndex(val => val === 'inspect'
|
|
72
|
+
const i = mochaArgs._.findIndex(val => val === 'inspect');
|
|
71
73
|
if (i > -1) {
|
|
72
|
-
|
|
74
|
+
mochaArgs._.splice(i, 1);
|
|
73
75
|
disableTimeouts('inspect');
|
|
74
|
-
|
|
76
|
+
hasInspect = true;
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
|
|
79
|
-
if (nodeArgs.gc) {
|
|
80
|
-
deprecate(
|
|
81
|
-
'"-gc" is deprecated and will be removed from a future version of Mocha. Use "--gc-global" instead.'
|
|
82
|
-
);
|
|
83
|
-
nodeArgs['gc-global'] = nodeArgs.gc;
|
|
84
|
-
delete nodeArgs.gc;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// --require/-r is treated as Mocha flag except when 'esm' is preloaded
|
|
88
|
-
if (mochaArgs.require && mochaArgs.require.includes('esm')) {
|
|
89
|
-
nodeArgs.require = ['esm'];
|
|
90
|
-
mochaArgs.require = mochaArgs.require.filter(mod => mod !== 'esm');
|
|
91
|
-
if (!mochaArgs.require.length) {
|
|
92
|
-
delete mochaArgs.require;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (Object.keys(nodeArgs).length) {
|
|
80
|
+
if (mochaArgs['node-option'] || Object.keys(nodeArgs).length || hasInspect) {
|
|
97
81
|
const {spawn} = require('child_process');
|
|
98
82
|
const mochaPath = require.resolve('../lib/cli/cli.js');
|
|
99
83
|
|
|
100
|
-
|
|
84
|
+
const nodeArgv =
|
|
85
|
+
(mochaArgs['node-option'] && mochaArgs['node-option'].map(v => '--' + v)) ||
|
|
86
|
+
unparseNodeFlags(nodeArgs);
|
|
87
|
+
|
|
88
|
+
if (hasInspect) nodeArgv.unshift('inspect');
|
|
89
|
+
delete mochaArgs['node-option'];
|
|
90
|
+
|
|
91
|
+
debug('final node argv', nodeArgv);
|
|
101
92
|
|
|
102
93
|
const args = [].concat(
|
|
103
|
-
|
|
94
|
+
nodeArgv,
|
|
104
95
|
mochaPath,
|
|
105
96
|
unparse(mochaArgs, {alias: aliases})
|
|
106
97
|
);
|
|
@@ -147,5 +138,5 @@ if (Object.keys(nodeArgs).length) {
|
|
|
147
138
|
});
|
|
148
139
|
} else {
|
|
149
140
|
debug('running Mocha in-process');
|
|
150
|
-
require('../lib/cli/cli').main(
|
|
141
|
+
require('../lib/cli/cli').main([], mochaArgs);
|
|
151
142
|
}
|
package/lib/cli/cli.js
CHANGED
|
@@ -33,8 +33,9 @@ const {cwd} = require('../utils');
|
|
|
33
33
|
* @public
|
|
34
34
|
* @summary Mocha's main command-line entry-point.
|
|
35
35
|
* @param {string[]} argv - Array of arguments to parse, or by default the lovely `process.argv.slice(2)`
|
|
36
|
+
* @param {object} [mochaArgs] - Object of already parsed Mocha arguments (by bin/mocha)
|
|
36
37
|
*/
|
|
37
|
-
exports.main = (argv = process.argv.slice(2)) => {
|
|
38
|
+
exports.main = (argv = process.argv.slice(2), mochaArgs) => {
|
|
38
39
|
debug('entered main with raw args', argv);
|
|
39
40
|
// ensure we can require() from current working directory
|
|
40
41
|
if (typeof module.paths !== 'undefined') {
|
|
@@ -43,7 +44,7 @@ exports.main = (argv = process.argv.slice(2)) => {
|
|
|
43
44
|
|
|
44
45
|
Error.stackTraceLimit = Infinity; // configurable via --stack-trace-limit?
|
|
45
46
|
|
|
46
|
-
var args = loadOptions(argv);
|
|
47
|
+
var args = mochaArgs || loadOptions(argv);
|
|
47
48
|
|
|
48
49
|
yargs()
|
|
49
50
|
.scriptName('mocha')
|
package/lib/cli/config.js
CHANGED
package/lib/cli/node-flags.js
CHANGED
|
@@ -49,7 +49,7 @@ exports.isNodeFlag = (flag, bareword = true) => {
|
|
|
49
49
|
// and also any V8 flags with `--v8-` prefix
|
|
50
50
|
(!isMochaFlag(flag) && nodeFlags && nodeFlags.has(flag)) ||
|
|
51
51
|
debugFlags.has(flag) ||
|
|
52
|
-
/(?:preserve-symlinks(?:-main)?|harmony(?:[_-]|$)|(?:trace[_-].+$)|gc
|
|
52
|
+
/(?:preserve-symlinks(?:-main)?|harmony(?:[_-]|$)|(?:trace[_-].+$)|gc[_-]global$|es[_-]staging$|use[_-]strict$|v8[_-](?!options).+?$)/.test(
|
|
53
53
|
flag
|
|
54
54
|
)
|
|
55
55
|
);
|
|
@@ -67,7 +67,6 @@ exports.impliesNoTimeouts = flag => debugFlags.has(flag);
|
|
|
67
67
|
/**
|
|
68
68
|
* All non-strictly-boolean arguments to node--those with values--must specify those values using `=`, e.g., `--inspect=0.0.0.0`.
|
|
69
69
|
* Unparse these arguments using `yargs-unparser` (which would result in `--inspect 0.0.0.0`), then supply `=` where we have values.
|
|
70
|
-
* Apparently --require in Node.js v8 does NOT want `=`.
|
|
71
70
|
* There's probably an easier or more robust way to do this; fixes welcome
|
|
72
71
|
* @param {Object} opts - Arguments object
|
|
73
72
|
* @returns {string[]} Unparsed arguments using `=` to specify values
|
|
@@ -79,9 +78,7 @@ exports.unparseNodeFlags = opts => {
|
|
|
79
78
|
? args
|
|
80
79
|
.join(' ')
|
|
81
80
|
.split(/\b/)
|
|
82
|
-
.map((arg
|
|
83
|
-
arg === ' ' && args[index - 1] !== 'require' ? '=' : arg
|
|
84
|
-
)
|
|
81
|
+
.map(arg => (arg === ' ' ? '=' : arg))
|
|
85
82
|
.join('')
|
|
86
83
|
.split(' ')
|
|
87
84
|
: [];
|
package/lib/cli/run-helpers.js
CHANGED
|
@@ -195,10 +195,10 @@ exports.runMocha = async (mocha, options) => {
|
|
|
195
195
|
* it actually exists. This must be run _after_ requires are processed (see
|
|
196
196
|
* {@link handleRequires}), as it'll prevent interfaces from loading otherwise.
|
|
197
197
|
* @param {Object} opts - Options object
|
|
198
|
-
* @param {"reporter"|"
|
|
199
|
-
* @param {Object} [map] -
|
|
200
|
-
*
|
|
201
|
-
* name
|
|
198
|
+
* @param {"reporter"|"ui"} pluginType - Type of plugin.
|
|
199
|
+
* @param {Object} [map] - Used as a cache of sorts;
|
|
200
|
+
* `Mocha.reporters` where each key corresponds to a reporter name,
|
|
201
|
+
* `Mocha.interfaces` where each key corresponds to an interface name.
|
|
202
202
|
* @private
|
|
203
203
|
*/
|
|
204
204
|
exports.validateLegacyPlugin = (opts, pluginType, map = {}) => {
|
|
@@ -226,12 +226,12 @@ exports.validateLegacyPlugin = (opts, pluginType, map = {}) => {
|
|
|
226
226
|
// if this exists, then it's already loaded, so nothing more to do.
|
|
227
227
|
if (!map[pluginId]) {
|
|
228
228
|
try {
|
|
229
|
-
|
|
229
|
+
map[pluginId] = require(pluginId);
|
|
230
230
|
} catch (err) {
|
|
231
231
|
if (err.code === 'MODULE_NOT_FOUND') {
|
|
232
232
|
// Try to load reporters from a path (absolute or relative)
|
|
233
233
|
try {
|
|
234
|
-
|
|
234
|
+
map[pluginId] = require(path.resolve(pluginId));
|
|
235
235
|
} catch (err) {
|
|
236
236
|
throw createUnknownError(err);
|
|
237
237
|
}
|
|
@@ -18,6 +18,7 @@ const TYPES = (exports.types = {
|
|
|
18
18
|
'file',
|
|
19
19
|
'global',
|
|
20
20
|
'ignore',
|
|
21
|
+
'node-option',
|
|
21
22
|
'reporter-option',
|
|
22
23
|
'require',
|
|
23
24
|
'spec',
|
|
@@ -34,6 +35,7 @@ const TYPES = (exports.types = {
|
|
|
34
35
|
'diff',
|
|
35
36
|
'dry-run',
|
|
36
37
|
'exit',
|
|
38
|
+
'fail-zero',
|
|
37
39
|
'forbid-only',
|
|
38
40
|
'forbid-pending',
|
|
39
41
|
'full-trace',
|
|
@@ -79,6 +81,7 @@ exports.aliases = {
|
|
|
79
81
|
invert: ['i'],
|
|
80
82
|
jobs: ['j'],
|
|
81
83
|
'no-colors': ['C'],
|
|
84
|
+
'node-option': ['n'],
|
|
82
85
|
parallel: ['p'],
|
|
83
86
|
reporter: ['R'],
|
|
84
87
|
'reporter-option': ['reporter-options', 'O'],
|
package/lib/cli/run.js
CHANGED
|
@@ -98,6 +98,10 @@ exports.builder = yargs =>
|
|
|
98
98
|
requiresArg: true,
|
|
99
99
|
coerce: list
|
|
100
100
|
},
|
|
101
|
+
'fail-zero': {
|
|
102
|
+
description: 'Fail test run if no test(s) encountered',
|
|
103
|
+
group: GROUPS.RULES
|
|
104
|
+
},
|
|
101
105
|
fgrep: {
|
|
102
106
|
conflicts: 'grep',
|
|
103
107
|
description: 'Only run tests containing this string',
|
|
@@ -176,6 +180,10 @@ exports.builder = yargs =>
|
|
|
176
180
|
group: GROUPS.OUTPUT,
|
|
177
181
|
hidden: true
|
|
178
182
|
},
|
|
183
|
+
'node-option': {
|
|
184
|
+
description: 'Node or V8 option (no leading "--")',
|
|
185
|
+
group: GROUPS.CONFIG
|
|
186
|
+
},
|
|
179
187
|
package: {
|
|
180
188
|
description: 'Path to package.json for config',
|
|
181
189
|
group: GROUPS.CONFIG,
|
package/lib/errors.js
CHANGED
|
@@ -328,7 +328,7 @@ function createFatalError(message, value) {
|
|
|
328
328
|
/**
|
|
329
329
|
* Dynamically creates a plugin-type-specific error based on plugin type
|
|
330
330
|
* @param {string} message - Error message
|
|
331
|
-
* @param {"reporter"|"
|
|
331
|
+
* @param {"reporter"|"ui"} pluginType - Plugin type. Future: expand as needed
|
|
332
332
|
* @param {string} [pluginId] - Name/path of plugin, if any
|
|
333
333
|
* @throws When `pluginType` is not known
|
|
334
334
|
* @public
|
|
@@ -339,7 +339,7 @@ function createInvalidLegacyPluginError(message, pluginType, pluginId) {
|
|
|
339
339
|
switch (pluginType) {
|
|
340
340
|
case 'reporter':
|
|
341
341
|
return createInvalidReporterError(message, pluginId);
|
|
342
|
-
case '
|
|
342
|
+
case 'ui':
|
|
343
343
|
return createInvalidInterfaceError(message, pluginId);
|
|
344
344
|
default:
|
|
345
345
|
throw new Error('unknown pluginType "' + pluginType + '"');
|
package/lib/esm-utils.js
CHANGED
|
@@ -34,7 +34,9 @@ const hasStableEsmImplementation = (() => {
|
|
|
34
34
|
const [major, minor] = process.version.split('.');
|
|
35
35
|
// ESM is stable from v12.22.0 onward
|
|
36
36
|
// https://nodejs.org/api/esm.html#esm_modules_ecmascript_modules
|
|
37
|
-
|
|
37
|
+
const majorNumber = parseInt(major.slice(1), 10);
|
|
38
|
+
const minorNumber = parseInt(minor, 10);
|
|
39
|
+
return majorNumber > 12 || (majorNumber === 12 && minorNumber >= 22);
|
|
38
40
|
})();
|
|
39
41
|
|
|
40
42
|
exports.requireOrImport = hasStableEsmImplementation
|
|
@@ -47,9 +49,24 @@ exports.requireOrImport = hasStableEsmImplementation
|
|
|
47
49
|
} catch (err) {
|
|
48
50
|
if (
|
|
49
51
|
err.code === 'ERR_MODULE_NOT_FOUND' ||
|
|
50
|
-
err.code === 'ERR_UNKNOWN_FILE_EXTENSION'
|
|
52
|
+
err.code === 'ERR_UNKNOWN_FILE_EXTENSION' ||
|
|
53
|
+
err.code === 'ERR_UNSUPPORTED_DIR_IMPORT'
|
|
51
54
|
) {
|
|
52
|
-
|
|
55
|
+
try {
|
|
56
|
+
return require(file);
|
|
57
|
+
} catch (requireErr) {
|
|
58
|
+
if (requireErr.code === 'ERR_REQUIRE_ESM') {
|
|
59
|
+
// This happens when the test file is a JS file, but via type:module is actually ESM,
|
|
60
|
+
// AND has an import to a file that doesn't exist.
|
|
61
|
+
// This throws an `ERR_MODULE_NOT_FOUND` // error above,
|
|
62
|
+
// and when we try to `require` it here, it throws an `ERR_REQUIRE_ESM`.
|
|
63
|
+
// What we want to do is throw the original error (the `ERR_MODULE_NOT_FOUND`),
|
|
64
|
+
// and not the `ERR_REQUIRE_ESM` error, which is a red herring.
|
|
65
|
+
throw err;
|
|
66
|
+
} else {
|
|
67
|
+
throw requireErr;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
53
70
|
} else {
|
|
54
71
|
throw err;
|
|
55
72
|
}
|
package/lib/mocha.js
CHANGED
|
@@ -164,6 +164,7 @@ exports.run = function(...args) {
|
|
|
164
164
|
* @param {boolean} [options.delay] - Delay root suite execution?
|
|
165
165
|
* @param {boolean} [options.diff] - Show diff on failure?
|
|
166
166
|
* @param {boolean} [options.dryRun] - Report tests without running them?
|
|
167
|
+
* @param {boolean} [options.failZero] - Fail test run if zero tests?
|
|
167
168
|
* @param {string} [options.fgrep] - Test filter given string.
|
|
168
169
|
* @param {boolean} [options.forbidOnly] - Tests marked `only` fail the suite?
|
|
169
170
|
* @param {boolean} [options.forbidPending] - Pending tests fail the suite?
|
|
@@ -223,6 +224,7 @@ function Mocha(options = {}) {
|
|
|
223
224
|
'delay',
|
|
224
225
|
'diff',
|
|
225
226
|
'dryRun',
|
|
227
|
+
'failZero',
|
|
226
228
|
'forbidOnly',
|
|
227
229
|
'forbidPending',
|
|
228
230
|
'fullTrace',
|
|
@@ -581,7 +583,7 @@ Mocha.prototype.fgrep = function(str) {
|
|
|
581
583
|
Mocha.prototype.grep = function(re) {
|
|
582
584
|
if (utils.isString(re)) {
|
|
583
585
|
// extract args if it's regex-like, i.e: [string, pattern, flag]
|
|
584
|
-
var arg = re.match(/^\/(.*)\/(
|
|
586
|
+
var arg = re.match(/^\/(.*)\/([gimy]{0,4})$|.*/);
|
|
585
587
|
this.options.grep = new RegExp(arg[1] || arg[0], arg[2]);
|
|
586
588
|
} else {
|
|
587
589
|
this.options.grep = re;
|
|
@@ -778,20 +780,6 @@ Mocha.prototype.diff = function(diff) {
|
|
|
778
780
|
return this;
|
|
779
781
|
};
|
|
780
782
|
|
|
781
|
-
/**
|
|
782
|
-
* Enables or disables running tests in dry-run mode.
|
|
783
|
-
*
|
|
784
|
-
* @public
|
|
785
|
-
* @see [CLI option](../#-dry-run)
|
|
786
|
-
* @param {boolean} [dryRun=true] - Whether to activate dry-run mode.
|
|
787
|
-
* @return {Mocha} this
|
|
788
|
-
* @chainable
|
|
789
|
-
*/
|
|
790
|
-
Mocha.prototype.dryRun = function(dryRun) {
|
|
791
|
-
this.options.dryRun = dryRun !== false;
|
|
792
|
-
return this;
|
|
793
|
-
};
|
|
794
|
-
|
|
795
783
|
/**
|
|
796
784
|
* @summary
|
|
797
785
|
* Sets timeout threshold value.
|
|
@@ -918,6 +906,34 @@ Mocha.prototype.delay = function delay() {
|
|
|
918
906
|
return this;
|
|
919
907
|
};
|
|
920
908
|
|
|
909
|
+
/**
|
|
910
|
+
* Enables or disables running tests in dry-run mode.
|
|
911
|
+
*
|
|
912
|
+
* @public
|
|
913
|
+
* @see [CLI option](../#-dry-run)
|
|
914
|
+
* @param {boolean} [dryRun=true] - Whether to activate dry-run mode.
|
|
915
|
+
* @return {Mocha} this
|
|
916
|
+
* @chainable
|
|
917
|
+
*/
|
|
918
|
+
Mocha.prototype.dryRun = function(dryRun) {
|
|
919
|
+
this.options.dryRun = dryRun !== false;
|
|
920
|
+
return this;
|
|
921
|
+
};
|
|
922
|
+
|
|
923
|
+
/**
|
|
924
|
+
* Fails test run if no tests encountered with exit-code 1.
|
|
925
|
+
*
|
|
926
|
+
* @public
|
|
927
|
+
* @see [CLI option](../#-fail-zero)
|
|
928
|
+
* @param {boolean} [failZero=true] - Whether to fail test run.
|
|
929
|
+
* @return {Mocha} this
|
|
930
|
+
* @chainable
|
|
931
|
+
*/
|
|
932
|
+
Mocha.prototype.failZero = function(failZero) {
|
|
933
|
+
this.options.failZero = failZero !== false;
|
|
934
|
+
return this;
|
|
935
|
+
};
|
|
936
|
+
|
|
921
937
|
/**
|
|
922
938
|
* Causes tests marked `only` to fail the suite.
|
|
923
939
|
*
|
|
@@ -1023,9 +1039,10 @@ Mocha.prototype.run = function(fn) {
|
|
|
1023
1039
|
var options = this.options;
|
|
1024
1040
|
options.files = this.files;
|
|
1025
1041
|
const runner = new this._runnerClass(suite, {
|
|
1042
|
+
cleanReferencesAfterRun: this._cleanReferencesAfterRun,
|
|
1026
1043
|
delay: options.delay,
|
|
1027
1044
|
dryRun: options.dryRun,
|
|
1028
|
-
|
|
1045
|
+
failZero: options.failZero
|
|
1029
1046
|
});
|
|
1030
1047
|
createStatsCollector(runner);
|
|
1031
1048
|
var reporter = new this._reporter(runner, options);
|
package/lib/reporters/base.js
CHANGED
package/lib/reporters/json.js
CHANGED
|
@@ -7,12 +7,16 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
var Base = require('./base');
|
|
10
|
+
var fs = require('fs');
|
|
11
|
+
var path = require('path');
|
|
12
|
+
const createUnsupportedError = require('../errors').createUnsupportedError;
|
|
13
|
+
const utils = require('../utils');
|
|
10
14
|
var constants = require('../runner').constants;
|
|
11
15
|
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
|
|
16
|
+
var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
|
|
12
17
|
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
|
|
13
18
|
var EVENT_TEST_END = constants.EVENT_TEST_END;
|
|
14
19
|
var EVENT_RUN_END = constants.EVENT_RUN_END;
|
|
15
|
-
var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
|
|
16
20
|
|
|
17
21
|
/**
|
|
18
22
|
* Expose `JSON`.
|
|
@@ -30,7 +34,7 @@ exports = module.exports = JSONReporter;
|
|
|
30
34
|
* @param {Runner} runner - Instance triggers reporter actions.
|
|
31
35
|
* @param {Object} [options] - runner options
|
|
32
36
|
*/
|
|
33
|
-
function JSONReporter(runner, options) {
|
|
37
|
+
function JSONReporter(runner, options = {}) {
|
|
34
38
|
Base.call(this, runner, options);
|
|
35
39
|
|
|
36
40
|
var self = this;
|
|
@@ -38,6 +42,14 @@ function JSONReporter(runner, options) {
|
|
|
38
42
|
var pending = [];
|
|
39
43
|
var failures = [];
|
|
40
44
|
var passes = [];
|
|
45
|
+
var output;
|
|
46
|
+
|
|
47
|
+
if (options.reporterOption && options.reporterOption.output) {
|
|
48
|
+
if (utils.isBrowser()) {
|
|
49
|
+
throw createUnsupportedError('file output not supported in browser');
|
|
50
|
+
}
|
|
51
|
+
output = options.reporterOption.output;
|
|
52
|
+
}
|
|
41
53
|
|
|
42
54
|
runner.on(EVENT_TEST_END, function(test) {
|
|
43
55
|
tests.push(test);
|
|
@@ -66,7 +78,20 @@ function JSONReporter(runner, options) {
|
|
|
66
78
|
|
|
67
79
|
runner.testResults = obj;
|
|
68
80
|
|
|
69
|
-
|
|
81
|
+
var json = JSON.stringify(obj, null, 2);
|
|
82
|
+
if (output) {
|
|
83
|
+
try {
|
|
84
|
+
fs.mkdirSync(path.dirname(output), {recursive: true});
|
|
85
|
+
fs.writeFileSync(output, json);
|
|
86
|
+
} catch (err) {
|
|
87
|
+
console.error(
|
|
88
|
+
`${Base.symbols.err} [mocha] writing output to "${output}" failed: ${err.message}\n`
|
|
89
|
+
);
|
|
90
|
+
process.stdout.write(json);
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
process.stdout.write(json);
|
|
94
|
+
}
|
|
70
95
|
});
|
|
71
96
|
}
|
|
72
97
|
|
package/lib/runner.js
CHANGED
|
@@ -135,10 +135,11 @@ class Runner extends EventEmitter {
|
|
|
135
135
|
* @public
|
|
136
136
|
* @class
|
|
137
137
|
* @param {Suite} suite - Root suite
|
|
138
|
-
* @param {Object|boolean} [opts] - Options. If `boolean` (deprecated), whether
|
|
138
|
+
* @param {Object|boolean} [opts] - Options. If `boolean` (deprecated), whether to delay execution of root suite until ready.
|
|
139
|
+
* @param {boolean} [opts.cleanReferencesAfterRun] - Whether to clean references to test fns and hooks when a suite is done.
|
|
139
140
|
* @param {boolean} [opts.delay] - Whether to delay execution of root suite until ready.
|
|
140
141
|
* @param {boolean} [opts.dryRun] - Whether to report tests without running them.
|
|
141
|
-
* @param {boolean} [
|
|
142
|
+
* @param {boolean} [options.failZero] - Whether to fail test run if zero tests encountered.
|
|
142
143
|
*/
|
|
143
144
|
constructor(suite, opts) {
|
|
144
145
|
super();
|
|
@@ -1044,6 +1045,8 @@ Runner.prototype.run = function(fn, opts = {}) {
|
|
|
1044
1045
|
fn = fn || function() {};
|
|
1045
1046
|
|
|
1046
1047
|
const end = () => {
|
|
1048
|
+
if (!this.total && this._opts.failZero) this.failures = 1;
|
|
1049
|
+
|
|
1047
1050
|
debug('run(): root suite completed; emitting %s', constants.EVENT_RUN_END);
|
|
1048
1051
|
this.emit(constants.EVENT_RUN_END);
|
|
1049
1052
|
};
|