UNPKG

4.01 kBJavaScriptView Raw
1#!/usr/bin/env node
2
3'use strict';
4
5/**
6 * This wrapper executable checks for known node flags and appends them when found,
7 * before invoking the "real" executable (`lib/cli/cli.js`)
8 *
9 * @module bin/mocha
10 * @private
11 */
12
13const {loadOptions} = require('../lib/cli/options');
14const {
15 unparseNodeFlags,
16 isNodeFlag,
17 impliesNoTimeouts
18} = require('../lib/cli/node-flags');
19const unparse = require('yargs-unparser');
20const debug = require('debug')('mocha:cli:mocha');
21const {aliases} = require('../lib/cli/run-option-metadata');
22
23const mochaArgs = {};
24const nodeArgs = {};
25let hasInspect = false;
26
27const opts = loadOptions(process.argv.slice(2));
28debug('loaded opts', opts);
29
30/**
31 * Given option/command `value`, disable timeouts if applicable
32 * @param {string} [value] - Value to check
33 * @ignore
34 */
35const disableTimeouts = value => {
36 if (impliesNoTimeouts(value)) {
37 debug('option %s disabled timeouts', value);
38 mochaArgs.timeout = 0;
39 }
40};
41
42/**
43 * If `value` begins with `v8-` and is not explicitly `v8-options`, remove prefix
44 * @param {string} [value] - Value to check
45 * @returns {string} `value` with prefix (maybe) removed
46 * @ignore
47 */
48const trimV8Option = value =>
49 value !== 'v8-options' && /^v8-/.test(value) ? value.slice(3) : value;
50
51// sort options into "node" and "mocha" buckets
52Object.keys(opts).forEach(opt => {
53 if (isNodeFlag(opt)) {
54 nodeArgs[trimV8Option(opt)] = opts[opt];
55 } else {
56 mochaArgs[opt] = opts[opt];
57 }
58});
59
60// disable 'timeout' for debugFlags
61Object.keys(nodeArgs).forEach(opt => disableTimeouts(opt));
62mochaArgs['node-option'] &&
63 mochaArgs['node-option'].forEach(opt => disableTimeouts(opt));
64
65// Native debugger handling
66// see https://nodejs.org/api/debugger.html#debugger_debugger
67// look for 'inspect' that would launch this debugger,
68// remove it from Mocha's opts and prepend it to Node's opts.
69// A deprecation warning will be printed by node, if applicable.
70// (mochaArgs._ are "positional" arguments, not prefixed with - or --)
71if (mochaArgs._) {
72 const i = mochaArgs._.findIndex(val => val === 'inspect');
73 if (i > -1) {
74 mochaArgs._.splice(i, 1);
75 disableTimeouts('inspect');
76 hasInspect = true;
77 }
78}
79
80if (mochaArgs['node-option'] || Object.keys(nodeArgs).length || hasInspect) {
81 const {spawn} = require('child_process');
82 const mochaPath = require.resolve('../lib/cli/cli.js');
83
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);
92
93 const args = [].concat(
94 nodeArgv,
95 mochaPath,
96 unparse(mochaArgs, {alias: aliases})
97 );
98
99 debug(
100 'forking child process via command: %s %s',
101 process.execPath,
102 args.join(' ')
103 );
104
105 const proc = spawn(process.execPath, args, {
106 stdio: 'inherit'
107 });
108
109 proc.on('exit', (code, signal) => {
110 process.on('exit', () => {
111 if (signal) {
112 process.kill(process.pid, signal);
113 } else {
114 process.exit(code);
115 }
116 });
117 });
118
119 // terminate children.
120 process.on('SIGINT', () => {
121 // XXX: a previous comment said this would abort the runner, but I can't see that it does
122 // anything with the default runner.
123 debug('main process caught SIGINT');
124 proc.kill('SIGINT');
125 // if running in parallel mode, we will have a proper SIGINT handler, so the below won't
126 // be needed.
127 if (!args.parallel || args.jobs < 2) {
128 // win32 does not support SIGTERM, so use next best thing.
129 if (require('os').platform() === 'win32') {
130 proc.kill('SIGKILL');
131 } else {
132 // using SIGKILL won't cleanly close the output streams, which can result
133 // in cut-off text or a befouled terminal.
134 debug('sending SIGTERM to child process');
135 proc.kill('SIGTERM');
136 }
137 }
138 });
139} else {
140 debug('running Mocha in-process');
141 require('../lib/cli/cli').main([], mochaArgs);
142}