| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- #!/usr/bin/env node
- 'use strict';
- /**
- * This wrapper executable checks for known node flags and appends them when found,
- * before invoking the "real" executable (`lib/cli/cli.js`)
- *
- * @module bin/mocha
- * @private
- */
- const os = require('node:os');
- 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 mochaArgs = {};
- const nodeArgs = {};
- const SIGNAL_OFFSET = 128;
- let hasInspect = false;
- 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 %s disabled timeouts', value);
- mochaArgs.timeout = 0;
- }
- };
- /**
- * 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];
- } else {
- mochaArgs[opt] = opts[opt];
- }
- });
- // disable 'timeout' for debugFlags
- Object.keys(nodeArgs).forEach(opt => disableTimeouts(opt));
- mochaArgs['node-option'] &&
- mochaArgs['node-option'].forEach(opt => disableTimeouts(opt));
- // Native debugger handling
- // see https://nodejs.org/api/debugger.html#debugger_debugger
- // look for 'inspect' that would launch this debugger,
- // remove it from Mocha's opts and prepend it to Node's opts.
- // A deprecation warning will be printed by node, if applicable.
- // (mochaArgs._ are "positional" arguments, not prefixed with - or --)
- if (mochaArgs._) {
- const i = mochaArgs._.findIndex(val => val === 'inspect');
- if (i > -1) {
- mochaArgs._.splice(i, 1);
- disableTimeouts('inspect');
- hasInspect = true;
- }
- }
- if (mochaArgs['node-option'] || Object.keys(nodeArgs).length || hasInspect) {
- const {spawn} = require('node:child_process');
- const mochaPath = require.resolve('../lib/cli/cli.js');
- const nodeArgv =
- (mochaArgs['node-option'] && mochaArgs['node-option'].map(v => '--' + v)) ||
- unparseNodeFlags(nodeArgs);
- if (hasInspect) nodeArgv.unshift('inspect');
- delete mochaArgs['node-option'];
- debug('final node argv', nodeArgv);
- const args = [].concat(
- nodeArgv,
- mochaPath,
- unparse(mochaArgs, {alias: aliases})
- );
- debug(
- 'forking child process via command: %s %s',
- process.execPath,
- args.join(' ')
- );
- const proc = spawn(process.execPath, args, {
- stdio: 'inherit'
- });
- proc.on('exit', (code, signal) => {
- process.on('exit', () => {
- if (signal) {
- signal = typeof signal === 'string' ? os.constants.signals[signal] : signal;
- if (mochaArgs['posix-exit-codes'] === true) {
- process.exitCode = SIGNAL_OFFSET + signal;
- }
- process.kill(process.pid, signal);
- } else {
- process.exit(Math.min(code, mochaArgs['posix-exit-codes'] ? 1 : 255));
- }
- });
- });
- // terminate children.
- process.on('SIGINT', () => {
- // XXX: a previous comment said this would abort the runner, but I can't see that it does
- // anything with the default runner.
- debug('main process caught SIGINT');
- proc.kill('SIGINT');
- // if running in parallel mode, we will have a proper SIGINT handler, so the below won't
- // be needed.
- if (!args.parallel || args.jobs < 2) {
- // win32 does not support SIGTERM, so use next best thing.
- if (os.platform() === 'win32') {
- proc.kill('SIGKILL');
- } else {
- // using SIGKILL won't cleanly close the output streams, which can result
- // in cut-off text or a befouled terminal.
- debug('sending SIGTERM to child process');
- proc.kill('SIGTERM');
- }
- }
- });
- } else {
- debug('running Mocha in-process');
- require('../lib/cli/cli').main([], mochaArgs);
- }
|