Skip to content

Commit 54a5788

Browse files
authoredJul 31, 2021
Add new option "node-option" (#4691)
1 parent e044ef0 commit 54a5788

File tree

11 files changed

+79
-47
lines changed

11 files changed

+79
-47
lines changed
 

‎bin/mocha

+18-27
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
* @private
1111
*/
1212

13-
const {deprecate} = require('../lib/utils');
1413
const {loadOptions} = require('../lib/cli/options');
1514
const {
1615
unparseNodeFlags,
@@ -23,6 +22,7 @@ const {aliases} = require('../lib/cli/run-option-metadata');
2322

2423
const mochaArgs = {};
2524
const nodeArgs = {};
25+
let hasInspect = false;
2626

2727
const opts = loadOptions(process.argv.slice(2));
2828
debug('loaded opts', opts);
@@ -59,48 +59,39 @@ Object.keys(opts).forEach(opt => {
5959

6060
// disable 'timeout' for debugFlags
6161
Object.keys(nodeArgs).forEach(opt => disableTimeouts(opt));
62+
mochaArgs['node-option'] &&
63+
mochaArgs['node-option'].forEach(opt => disableTimeouts(opt));
6264

6365
// Native debugger handling
6466
// see https://nodejs.org/api/debugger.html#debugger_debugger
65-
// look for 'inspect' or 'debug' that would launch this debugger,
67+
// look for 'inspect' that would launch this debugger,
6668
// remove it from Mocha's opts and prepend it to Node's opts.
6769
// A deprecation warning will be printed by node, if applicable.
6870
// (mochaArgs._ are "positional" arguments, not prefixed with - or --)
6971
if (mochaArgs._) {
70-
const i = mochaArgs._.findIndex(val => val === 'inspect' || val === 'debug');
72+
const i = mochaArgs._.findIndex(val => val === 'inspect');
7173
if (i > -1) {
72-
const [command] = mochaArgs._.splice(i, 1);
74+
mochaArgs._.splice(i, 1);
7375
disableTimeouts('inspect');
74-
nodeArgs._ = [command];
76+
hasInspect = true;
7577
}
7678
}
7779

78-
// historical
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) {
9781
const {spawn} = require('child_process');
9882
const mochaPath = require.resolve('../lib/cli/cli.js');
9983

100-
debug('final node args', nodeArgs);
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);
10192

10293
const args = [].concat(
103-
unparseNodeFlags(nodeArgs),
94+
nodeArgv,
10495
mochaPath,
10596
unparse(mochaArgs, {alias: aliases})
10697
);
@@ -147,5 +138,5 @@ if (Object.keys(nodeArgs).length) {
147138
});
148139
} else {
149140
debug('running Mocha in-process');
150-
require('../lib/cli/cli').main(unparse(mochaArgs, {alias: aliases}));
141+
require('../lib/cli/cli').main([], mochaArgs);
151142
}

‎docs/index.md

+14-5
Original file line numberDiff line numberDiff line change
@@ -876,9 +876,7 @@ Use this option to have Mocha check for global variables that are leaked while r
876876
877877
### `--dry-run`
878878

879-
> _New in v9.0.0._
880-
881-
Report tests without executing any of them, neither tests nor hooks.
879+
> _New in v9.0.0._ Report tests without executing any of them, neither tests nor hooks.
882880
883881
### `--exit`
884882

@@ -1015,6 +1013,15 @@ Specify an explicit path to a [configuration file](#configuring-mocha-nodejs).
10151013

10161014
By default, Mocha will search for a config file if `--config` is not specified; use `--no-config` to suppress this behavior.
10171015

1016+
### `--node-option <name>, -n <name>`
1017+
1018+
> _New in v9.1.0._
1019+
1020+
For Node.js and V8 options. Mocha forwards these options to Node.js by spawning a new child-process.<br>
1021+
The options are set without leading dashes `--`, e.g. `-n require=foo -n unhandled-rejections=strict`
1022+
1023+
Can also be specified as a comma-delimited list: `-n require=foo,unhandled-rejections=strict`
1024+
10181025
### `--opts <path>`
10191026

10201027
> _Removed in v8.0.0. Please use [configuration file](#configuring-mocha-nodejs) instead._
@@ -1159,8 +1166,6 @@ Requires either `--grep` or `--fgrep` (but not both).
11591166

11601167
### `--inspect, --inspect-brk, inspect`
11611168

1162-
> _BREAKING CHANGE in v7.0.0; `--debug` / `--debug-brk` are removed and `debug` is deprecated._
1163-
11641169
Enables Node.js' inspector.
11651170

11661171
Use `--inspect` / `--inspect-brk` to launch the V8 inspector for use with Chrome Dev Tools.
@@ -1209,6 +1214,8 @@ These flags vary depending on your version of Node.js.
12091214

12101215
`node` flags can be defined in Mocha's [configuration](#configuring-mocha-nodejs).
12111216

1217+
> _New in v9.1.0._ You can also pass `node` flags to Node.js using [`--node-option`](#-node-option-name-n-name).
1218+
12121219
### `--enable-source-maps`
12131220

12141221
> _New in Node.js v12.12.0_
@@ -1228,6 +1235,8 @@ Prepend `--v8-` to any flag listed in the output of `node --v8-options` (excludi
12281235

12291236
V8 flags can be defined in Mocha's [configuration](#configuring-mocha-nodejs).
12301237

1238+
> _New in v9.1.0._ You can also pass V8 flags (without `--v8-`) to Node.js using [`--node-option`](#-node-option-name-n-name).
1239+
12311240
## Parallel Tests
12321241

12331242
> _New in v.8.0.0._

‎example/config/.mocharc.js

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ module.exports = {
2626
'inline-diffs': false,
2727
// invert: false, // needs to be used with grep or fgrep
2828
jobs: 1,
29+
'node-option': ['unhandled-rejections=strict'], // without leading "--", also V8 flags
2930
package: './package.json',
3031
parallel: false,
3132
recursive: false,

‎example/config/.mocharc.yml

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ inline-diffs: false
2929
# needs to be used with grep or fgrep
3030
# invert: false
3131
jobs: 1
32+
node-option:
33+
- 'unhandled-rejections=strict' # without leading "--", also V8 flags
3234
package: './package.json'
3335
parallel: false
3436
recursive: false

‎lib/cli/cli.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ const {cwd} = require('../utils');
3333
* @public
3434
* @summary Mocha's main command-line entry-point.
3535
* @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)
3637
*/
37-
exports.main = (argv = process.argv.slice(2)) => {
38+
exports.main = (argv = process.argv.slice(2), mochaArgs) => {
3839
debug('entered main with raw args', argv);
3940
// ensure we can require() from current working directory
4041
if (typeof module.paths !== 'undefined') {
@@ -43,7 +44,7 @@ exports.main = (argv = process.argv.slice(2)) => {
4344

4445
Error.stackTraceLimit = Infinity; // configurable via --stack-trace-limit?
4546

46-
var args = loadOptions(argv);
47+
var args = mochaArgs || loadOptions(argv);
4748

4849
yargs()
4950
.scriptName('mocha')

‎lib/cli/node-flags.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ exports.isNodeFlag = (flag, bareword = true) => {
4949
// and also any V8 flags with `--v8-` prefix
5050
(!isMochaFlag(flag) && nodeFlags && nodeFlags.has(flag)) ||
5151
debugFlags.has(flag) ||
52-
/(?:preserve-symlinks(?:-main)?|harmony(?:[_-]|$)|(?:trace[_-].+$)|gc(?:[_-]global)?$|es[_-]staging$|use[_-]strict$|v8[_-](?!options).+?$)/.test(
52+
/(?:preserve-symlinks(?:-main)?|harmony(?:[_-]|$)|(?:trace[_-].+$)|gc[_-]global$|es[_-]staging$|use[_-]strict$|v8[_-](?!options).+?$)/.test(
5353
flag
5454
)
5555
);
@@ -67,7 +67,6 @@ exports.impliesNoTimeouts = flag => debugFlags.has(flag);
6767
/**
6868
* All non-strictly-boolean arguments to node--those with values--must specify those values using `=`, e.g., `--inspect=0.0.0.0`.
6969
* 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 `=`.
7170
* There's probably an easier or more robust way to do this; fixes welcome
7271
* @param {Object} opts - Arguments object
7372
* @returns {string[]} Unparsed arguments using `=` to specify values
@@ -79,9 +78,7 @@ exports.unparseNodeFlags = opts => {
7978
? args
8079
.join(' ')
8180
.split(/\b/)
82-
.map((arg, index, args) =>
83-
arg === ' ' && args[index - 1] !== 'require' ? '=' : arg
84-
)
81+
.map(arg => (arg === ' ' ? '=' : arg))
8582
.join('')
8683
.split(' ')
8784
: [];

‎lib/cli/run-option-metadata.js

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const TYPES = (exports.types = {
1818
'file',
1919
'global',
2020
'ignore',
21+
'node-option',
2122
'reporter-option',
2223
'require',
2324
'spec',
@@ -79,6 +80,7 @@ exports.aliases = {
7980
invert: ['i'],
8081
jobs: ['j'],
8182
'no-colors': ['C'],
83+
'node-option': ['n'],
8284
parallel: ['p'],
8385
reporter: ['R'],
8486
'reporter-option': ['reporter-options', 'O'],

‎lib/cli/run.js

+4
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,10 @@ exports.builder = yargs =>
176176
group: GROUPS.OUTPUT,
177177
hidden: true
178178
},
179+
'node-option': {
180+
description: 'Node or V8 option (no leading "--")',
181+
group: GROUPS.CONFIG
182+
},
179183
package: {
180184
description: 'Path to package.json for config',
181185
group: GROUPS.CONFIG,

‎test/integration/options/node-flags.spec.js

+16
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,19 @@ describe('node flags', function() {
1717
);
1818
});
1919
});
20+
21+
describe('node flags using "--node-option"', function() {
22+
it('should pass fake option to node and fail with node exception', function(done) {
23+
invokeMocha(
24+
['--node-option', 'fake-flag'],
25+
function(err, res) {
26+
if (err) {
27+
return done(err);
28+
}
29+
expect(res, 'to have failed with output', /bad option: --fake-flag/i);
30+
done();
31+
},
32+
'pipe'
33+
);
34+
});
35+
});

‎test/integration/options/timeout.spec.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe('--timeout', function() {
5050
});
5151
});
5252

53-
it('should disable timeout with --inspect', function(done) {
53+
it('should disable timeout with "--inspect"', function(done) {
5454
var fixture = 'options/slow-test';
5555
runMochaJSON(fixture, ['--inspect', '--timeout', '200'], function(
5656
err,
@@ -64,4 +64,19 @@ describe('--timeout', function() {
6464
done();
6565
});
6666
});
67+
68+
it('should disable timeout with "-n inspect"', function(done) {
69+
var fixture = 'options/slow-test';
70+
runMochaJSON(fixture, ['-n', 'inspect', '--timeout', '200'], function(
71+
err,
72+
res
73+
) {
74+
if (err) {
75+
done(err);
76+
return;
77+
}
78+
expect(res, 'to have passed').and('to have passed test count', 2);
79+
done();
80+
});
81+
});
6782
});

‎test/node-unit/cli/node-flags.spec.js

+1-7
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,7 @@ describe('node-flags', function() {
4242
it('should return true for flags starting with "preserve-symlinks"', function() {
4343
expect(isNodeFlag('preserve-symlinks'), 'to be true');
4444
expect(isNodeFlag('preserve-symlinks-main'), 'to be true');
45-
// Node >= v12 both flags exist in process.allowedNodeEnvironmentFlags
46-
const nodeVersion = parseInt(process.version.match(/^v(\d+)\./)[1], 10);
47-
expect(
48-
isNodeFlag('preserve_symlinks'),
49-
nodeVersion >= 12 ? 'to be true' : 'to be false'
50-
);
45+
expect(isNodeFlag('preserve_symlinks'), 'to be true');
5146
});
5247

5348
it('should return true for flags starting with "harmony-" or "harmony_"', function() {
@@ -69,7 +64,6 @@ describe('node-flags', function() {
6964
it('should return true for "gc-global"', function() {
7065
expect(isNodeFlag('gc-global'), 'to be true');
7166
expect(isNodeFlag('gc_global'), 'to be true');
72-
expect(isNodeFlag('gc'), 'to be true');
7367
});
7468

7569
it('should return true for "es-staging"', function() {

0 commit comments

Comments
 (0)
Please sign in to comment.