123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- #!/usr/bin/env node
- 'use strict';
- /**
- * This wrapper executable checks for known node flags and appends them when found, before invoking the "real" _mocha(1) executable.
- *
- * @module bin/mocha
- * @private
- */
- const {deprecate, warn} = require('../lib/utils');
- const {spawn} = require('child_process');
- const {loadOptions} = require('../lib/cli/options');
- const {
- unparseNodeFlags,
- isNodeFlag,
- impliesNoTimeouts
- } = require('../lib/cli/node-flags');
- const unparse = require('yargs-unparser');
- const debug = require('debug')('mocha:cli:mocha');
- const {aliases} = require('../lib/cli/run-option-metadata');
- const nodeEnv = require('node-environment-flags');
- const mochaPath = require.resolve('./_mocha');
- const mochaArgs = {};
- const nodeArgs = {};
- const opts = loadOptions(process.argv.slice(2));
- debug('loaded opts', opts);
- /**
- * Given option/command `value`, disable timeouts if applicable
- * @param {string} [value] - Value to check
- * @ignore
- */
- const disableTimeouts = value => {
- if (impliesNoTimeouts(value)) {
- debug(`option "${value}" disabled timeouts`);
- mochaArgs.timeout = 0;
- delete mochaArgs.timeouts;
- delete mochaArgs.t;
- }
- };
- /**
- * If `value` begins with `v8-` and is not explicitly `v8-options`, remove prefix
- * @param {string} [value] - Value to check
- * @returns {string} `value` with prefix (maybe) removed
- * @ignore
- */
- const trimV8Option = value =>
- value !== 'v8-options' && /^v8-/.test(value) ? value.slice(3) : value;
- // sort options into "node" and "mocha" buckets
- Object.keys(opts).forEach(opt => {
- if (isNodeFlag(opt)) {
- nodeArgs[trimV8Option(opt)] = opts[opt];
- disableTimeouts(opt);
- } else {
- mochaArgs[opt] = opts[opt];
- }
- });
- // Native debugger handling
- // see https://nodejs.org/api/debugger.html#debugger_debugger
- // look for 'debug' or 'inspect' that would launch this debugger,
- // remove it from Mocha's opts and prepend it to Node's opts.
- // also coerce depending on Node.js version.
- // A deprecation warning will be printed by node, if applicable.
- // (mochaArgs._ are "positional" arguments, not prefixed with - or --)
- if (/^(debug|inspect)$/.test(mochaArgs._[0])) {
- const command = mochaArgs._.shift();
- disableTimeouts(command);
- // don't conflict with inspector
- ['debug', 'inspect', 'debug-brk', 'inspect-brk']
- .filter(opt => opt in nodeArgs || opt in mochaArgs)
- .forEach(opt => {
- warn(`command "${command}" provided; --${opt} ignored`);
- delete nodeArgs[opt];
- delete mochaArgs[opt];
- });
- nodeArgs._ = [
- parseInt(
- process.version
- .slice(1)
- .split('.')
- .shift(),
- 10
- ) >= 8
- ? 'inspect'
- : 'debug'
- ];
- }
- // allow --debug to invoke --inspect on Node.js v8 or newer.
- ['debug', 'debug-brk']
- .filter(opt => opt in nodeArgs && !nodeEnv.has(opt))
- .forEach(opt => {
- const newOpt = opt === 'debug' ? 'inspect' : 'inspect-brk';
- warn(
- `"--${opt}" is not available in Node.js ${
- process.version
- }; use "--${newOpt}" instead.`
- );
- nodeArgs[newOpt] = nodeArgs[opt];
- mochaArgs.timeout = false;
- debug(`--${opt} -> ${newOpt}`);
- delete nodeArgs[opt];
- });
- // historical
- if (nodeArgs.gc) {
- deprecate(
- '"-gc" is deprecated and will be removed from a future version of Mocha. Use "--gc-global" instead.'
- );
- nodeArgs['gc-global'] = nodeArgs.gc;
- delete nodeArgs.gc;
- }
- debug('final node args', nodeArgs);
- const args = [].concat(
- unparseNodeFlags(nodeArgs),
- mochaPath,
- unparse(mochaArgs, {alias: aliases})
- );
- debug(`exec ${process.execPath} w/ args:`, args);
- const proc = spawn(process.execPath, args, {
- stdio: 'inherit'
- });
- proc.on('exit', (code, signal) => {
- process.on('exit', () => {
- if (signal) {
- process.kill(process.pid, signal);
- } else {
- process.exit(code);
- }
- });
- });
- // terminate children.
- process.on('SIGINT', () => {
- proc.kill('SIGINT'); // calls runner.abort()
- proc.kill('SIGTERM'); // if that didn't work, we're probably in an infinite loop, so make it die.
- });
|