1 | #!/usr/bin/env node
|
2 |
|
3 | 'use strict';
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | const {loadOptions} = require('../lib/cli/options');
|
14 | const {
|
15 | unparseNodeFlags,
|
16 | isNodeFlag,
|
17 | impliesNoTimeouts
|
18 | } = require('../lib/cli/node-flags');
|
19 | const unparse = require('yargs-unparser');
|
20 | const debug = require('debug')('mocha:cli:mocha');
|
21 | const {aliases} = require('../lib/cli/run-option-metadata');
|
22 |
|
23 | const mochaArgs = {};
|
24 | const nodeArgs = {};
|
25 | let hasInspect = false;
|
26 |
|
27 | const opts = loadOptions(process.argv.slice(2));
|
28 | debug('loaded opts', opts);
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | const disableTimeouts = value => {
|
36 | if (impliesNoTimeouts(value)) {
|
37 | debug('option %s disabled timeouts', value);
|
38 | mochaArgs.timeout = 0;
|
39 | }
|
40 | };
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | const trimV8Option = value =>
|
49 | value !== 'v8-options' && /^v8-/.test(value) ? value.slice(3) : value;
|
50 |
|
51 |
|
52 | Object.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 |
|
61 | Object.keys(nodeArgs).forEach(opt => disableTimeouts(opt));
|
62 | mochaArgs['node-option'] &&
|
63 | mochaArgs['node-option'].forEach(opt => disableTimeouts(opt));
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 | if (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 |
|
80 | if (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 |
|
120 | process.on('SIGINT', () => {
|
121 |
|
122 |
|
123 | debug('main process caught SIGINT');
|
124 | proc.kill('SIGINT');
|
125 |
|
126 |
|
127 | if (!args.parallel || args.jobs < 2) {
|
128 |
|
129 | if (require('os').platform() === 'win32') {
|
130 | proc.kill('SIGKILL');
|
131 | } else {
|
132 |
|
133 |
|
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 | }
|