cypress 15.1.0 → 15.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cypress +3 -1
- package/index.js +49 -24
- package/lib/VerboseRenderer.js +50 -47
- package/lib/cli.js +455 -351
- package/lib/cypress.js +93 -90
- package/lib/errors.js +181 -194
- package/lib/exec/info.js +85 -74
- package/lib/exec/open.js +77 -73
- package/lib/exec/run.js +144 -154
- package/lib/exec/shared.js +37 -44
- package/lib/exec/spawn.js +270 -232
- package/lib/exec/versions.js +57 -49
- package/lib/exec/xvfb.js +79 -81
- package/lib/fs.js +7 -3
- package/lib/logger.js +37 -32
- package/lib/tasks/cache.js +128 -113
- package/lib/tasks/download.js +247 -258
- package/lib/tasks/get-folder-size.js +33 -22
- package/lib/tasks/install.js +274 -312
- package/lib/tasks/state.js +132 -143
- package/lib/tasks/unzip.js +186 -188
- package/lib/tasks/verify.js +274 -261
- package/lib/util.js +357 -355
- package/package.json +3 -3
package/lib/exec/shared.js
CHANGED
@@ -1,62 +1,55 @@
|
|
1
1
|
"use strict";
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
} = require('../errors');
|
6
|
-
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.checkConfigFile = exports.processTestingType = exports.throwInvalidOptionError = void 0;
|
4
|
+
const errors_1 = require("../errors");
|
7
5
|
/**
|
8
6
|
* Throws an error with "details" property from
|
9
7
|
* "errors" object.
|
10
8
|
* @param {Object} details - Error details
|
11
9
|
*/
|
12
|
-
const throwInvalidOptionError = details => {
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
throw err;
|
10
|
+
const throwInvalidOptionError = (details) => {
|
11
|
+
if (!details) {
|
12
|
+
details = errors_1.errors.unknownError;
|
13
|
+
}
|
14
|
+
// throw this error synchronously, it will be caught later on and
|
15
|
+
// the details will be propagated to the promise chain
|
16
|
+
const err = new Error();
|
17
|
+
err.details = details;
|
18
|
+
throw err;
|
22
19
|
};
|
23
|
-
|
20
|
+
exports.throwInvalidOptionError = throwInvalidOptionError;
|
24
21
|
/**
|
25
22
|
* Selects exec args based on the configured `testingType`
|
26
23
|
* @param {string} testingType The type of tests being executed
|
27
24
|
* @returns {string[]} The array of new exec arguments
|
28
25
|
*/
|
29
|
-
const processTestingType = options => {
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
26
|
+
const processTestingType = (options) => {
|
27
|
+
if (options.e2e && options.component) {
|
28
|
+
return (0, exports.throwInvalidOptionError)(errors_1.errors.incompatibleTestTypeFlags);
|
29
|
+
}
|
30
|
+
if (options.testingType && (options.component || options.e2e)) {
|
31
|
+
return (0, exports.throwInvalidOptionError)(errors_1.errors.incompatibleTestTypeFlags);
|
32
|
+
}
|
33
|
+
if (options.testingType === 'component' || options.component || options.ct) {
|
34
|
+
return ['--testing-type', 'component'];
|
35
|
+
}
|
36
|
+
if (options.testingType === 'e2e' || options.e2e) {
|
37
|
+
return ['--testing-type', 'e2e'];
|
38
|
+
}
|
39
|
+
if (options.testingType) {
|
40
|
+
return (0, exports.throwInvalidOptionError)(errors_1.errors.invalidTestingType);
|
41
|
+
}
|
42
|
+
return [];
|
46
43
|
};
|
47
|
-
|
44
|
+
exports.processTestingType = processTestingType;
|
48
45
|
/**
|
49
46
|
* Throws an error if configFile is string 'false' or boolean false
|
50
47
|
* @param {*} options
|
51
48
|
*/
|
52
|
-
const checkConfigFile = options => {
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
49
|
+
const checkConfigFile = (options) => {
|
50
|
+
// CLI will parse as string, module API can pass in boolean
|
51
|
+
if (options.configFile === 'false' || options.configFile === false) {
|
52
|
+
(0, exports.throwInvalidOptionError)(errors_1.errors.invalidConfigFile);
|
53
|
+
}
|
57
54
|
};
|
58
|
-
|
59
|
-
throwInvalidOptionError,
|
60
|
-
processTestingType,
|
61
|
-
checkConfigFile
|
62
|
-
};
|
55
|
+
exports.checkConfigFile = checkConfigFile;
|
package/lib/exec/spawn.js
CHANGED
@@ -1,247 +1,285 @@
|
|
1
1
|
"use strict";
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
19
|
+
var ownKeys = function(o) {
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
21
|
+
var ar = [];
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
23
|
+
return ar;
|
24
|
+
};
|
25
|
+
return ownKeys(o);
|
26
|
+
};
|
27
|
+
return function (mod) {
|
28
|
+
if (mod && mod.__esModule) return mod;
|
29
|
+
var result = {};
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
31
|
+
__setModuleDefault(result, mod);
|
32
|
+
return result;
|
33
|
+
};
|
34
|
+
})();
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
42
|
+
});
|
43
|
+
};
|
44
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
45
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
46
|
+
};
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
48
|
+
const lodash_1 = __importDefault(require("lodash"));
|
49
|
+
const os_1 = __importDefault(require("os"));
|
50
|
+
const child_process_1 = __importDefault(require("child_process"));
|
51
|
+
const path_1 = __importDefault(require("path"));
|
52
|
+
const bluebird_1 = __importDefault(require("bluebird"));
|
53
|
+
const debug_1 = __importDefault(require("debug"));
|
54
|
+
const util_1 = __importDefault(require("../util"));
|
55
|
+
const state_1 = __importDefault(require("../tasks/state"));
|
56
|
+
const xvfb_1 = __importDefault(require("./xvfb"));
|
57
|
+
const verify_1 = __importDefault(require("../tasks/verify"));
|
58
|
+
const errors_1 = require("../errors");
|
59
|
+
const readline_1 = __importDefault(require("readline"));
|
60
|
+
const debug = (0, debug_1.default)('cypress:cli');
|
15
61
|
function isPlatform(platform) {
|
16
|
-
|
62
|
+
return os_1.default.platform() === platform;
|
17
63
|
}
|
18
64
|
function needsStderrPiped(needsXvfb) {
|
19
|
-
|
65
|
+
return lodash_1.default.some([
|
66
|
+
isPlatform('darwin'),
|
67
|
+
(needsXvfb && isPlatform('linux')),
|
68
|
+
util_1.default.isPossibleLinuxWithIncorrectDisplay(),
|
69
|
+
]);
|
20
70
|
}
|
21
71
|
function needsEverythingPipedDirectly() {
|
22
|
-
|
72
|
+
return isPlatform('win32');
|
23
73
|
}
|
24
74
|
function getStdio(needsXvfb) {
|
25
|
-
|
26
|
-
|
27
|
-
}
|
28
|
-
|
29
|
-
// https://github.com/cypress-io/cypress/issues/921
|
30
|
-
// https://github.com/cypress-io/cypress/issues/1143
|
31
|
-
// https://github.com/cypress-io/cypress/issues/1745
|
32
|
-
if (needsStderrPiped(needsXvfb)) {
|
33
|
-
// returning pipe here so we can massage stderr
|
34
|
-
// and remove garbage from Xlib and libuv
|
35
|
-
// due to starting the Xvfb process on linux
|
36
|
-
return ['inherit', 'inherit', 'pipe'];
|
37
|
-
}
|
38
|
-
return 'inherit';
|
39
|
-
}
|
40
|
-
module.exports = {
|
41
|
-
start(args, options = {}) {
|
42
|
-
const needsXvfb = xvfb.isNeeded();
|
43
|
-
let executable = state.getPathToExecutable(state.getBinaryDir());
|
44
|
-
if (util.getEnv('CYPRESS_RUN_BINARY')) {
|
45
|
-
executable = path.resolve(util.getEnv('CYPRESS_RUN_BINARY'));
|
75
|
+
if (needsEverythingPipedDirectly()) {
|
76
|
+
return 'pipe';
|
46
77
|
}
|
47
|
-
|
48
|
-
|
49
|
-
//
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
78
|
+
// https://github.com/cypress-io/cypress/issues/921
|
79
|
+
// https://github.com/cypress-io/cypress/issues/1143
|
80
|
+
// https://github.com/cypress-io/cypress/issues/1745
|
81
|
+
if (needsStderrPiped(needsXvfb)) {
|
82
|
+
// returning pipe here so we can massage stderr
|
83
|
+
// and remove garbage from Xlib and libuv
|
84
|
+
// due to starting the Xvfb process on linux
|
85
|
+
return ['inherit', 'inherit', 'pipe'];
|
55
86
|
}
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
return new Promise((resolve, reject) => {
|
65
|
-
_.defaults(overrides, {
|
66
|
-
onStderrData: false
|
67
|
-
});
|
68
|
-
const {
|
69
|
-
onStderrData
|
70
|
-
} = overrides;
|
71
|
-
const envOverrides = util.getEnvOverrides(options);
|
72
|
-
const electronArgs = [];
|
73
|
-
const node11WindowsFix = isPlatform('win32');
|
74
|
-
let startScriptPath;
|
75
|
-
if (options.dev) {
|
76
|
-
executable = 'node';
|
77
|
-
// if we're in dev then reset
|
78
|
-
// the launch cmd to be 'npm run dev'
|
79
|
-
startScriptPath = path.resolve(__dirname, '..', '..', '..', 'scripts', 'start.js'), debug('in dev mode the args became %o', args);
|
80
|
-
}
|
81
|
-
if (!options.dev && verify.needsSandbox()) {
|
82
|
-
electronArgs.push('--no-sandbox');
|
83
|
-
}
|
84
|
-
|
85
|
-
// strip dev out of child process options
|
86
|
-
/**
|
87
|
-
* @type {import('child_process').ForkOptions}
|
88
|
-
*/
|
89
|
-
let stdioOptions = _.pick(options, 'env', 'detached', 'stdio');
|
90
|
-
|
91
|
-
// figure out if we're going to be force enabling or disabling colors.
|
92
|
-
// also figure out whether we should force stdout and stderr into thinking
|
93
|
-
// it is a tty as opposed to a pipe.
|
94
|
-
stdioOptions.env = _.extend({}, stdioOptions.env, envOverrides);
|
95
|
-
if (node11WindowsFix) {
|
96
|
-
stdioOptions = _.extend({}, stdioOptions, {
|
97
|
-
windowsHide: false
|
98
|
-
});
|
99
|
-
}
|
100
|
-
if (util.isPossibleLinuxWithIncorrectDisplay()) {
|
101
|
-
// make sure we use the latest DISPLAY variable if any
|
102
|
-
debug('passing DISPLAY', process.env.DISPLAY);
|
103
|
-
stdioOptions.env.DISPLAY = process.env.DISPLAY;
|
104
|
-
}
|
105
|
-
if (stdioOptions.env.ELECTRON_RUN_AS_NODE) {
|
106
|
-
// Since we are running electron as node, we need to add an entry point file.
|
107
|
-
startScriptPath = path.join(state.getBinaryPkgPath(path.dirname(executable)), '..', 'index.js');
|
108
|
-
} else {
|
109
|
-
// Start arguments with "--" so Electron knows these are OUR
|
110
|
-
// arguments and does not try to sanitize them. Otherwise on Windows
|
111
|
-
// an url in one of the arguments crashes it :(
|
112
|
-
// https://github.com/cypress-io/cypress/issues/5466
|
113
|
-
args = [...electronArgs, '--', ...args];
|
114
|
-
}
|
115
|
-
if (startScriptPath) {
|
116
|
-
args.unshift(startScriptPath);
|
117
|
-
}
|
118
|
-
if (process.env.CYPRESS_INTERNAL_DEV_DEBUG) {
|
119
|
-
args.unshift(process.env.CYPRESS_INTERNAL_DEV_DEBUG);
|
120
|
-
}
|
121
|
-
debug('spawn args %o %o', args, _.omit(stdioOptions, 'env'));
|
122
|
-
debug('spawning Cypress with executable: %s', executable);
|
123
|
-
const child = cp.spawn(executable, args, stdioOptions);
|
124
|
-
function resolveOn(event) {
|
125
|
-
return function (code, signal) {
|
126
|
-
debug('child event fired %o', {
|
127
|
-
event,
|
128
|
-
code,
|
129
|
-
signal
|
130
|
-
});
|
131
|
-
if (code === null) {
|
132
|
-
const errorObject = errors.errors.childProcessKilled(event, signal);
|
133
|
-
return errors.getError(errorObject).then(reject);
|
134
|
-
}
|
135
|
-
resolve(code);
|
136
|
-
};
|
137
|
-
}
|
138
|
-
child.on('close', resolveOn('close'));
|
139
|
-
child.on('exit', resolveOn('exit'));
|
140
|
-
child.on('error', reject);
|
141
|
-
if (isPlatform('win32')) {
|
142
|
-
const rl = readline.createInterface({
|
143
|
-
input: process.stdin,
|
144
|
-
output: process.stdout
|
145
|
-
});
|
146
|
-
|
147
|
-
// on windows, SIGINT does not propagate to the child process when ctrl+c is pressed
|
148
|
-
// this makes sure all nested processes are closed(ex: firefox inside the server)
|
149
|
-
rl.on('SIGINT', function () {
|
150
|
-
let kill = require('tree-kill');
|
151
|
-
kill(child.pid, 'SIGINT');
|
152
|
-
});
|
153
|
-
}
|
154
|
-
|
155
|
-
// if stdio options is set to 'pipe', then
|
156
|
-
// we should set up pipes:
|
157
|
-
// process STDIN (read stream) => child STDIN (writeable)
|
158
|
-
// child STDOUT => process STDOUT
|
159
|
-
// child STDERR => process STDERR with additional filtering
|
160
|
-
if (child.stdin) {
|
161
|
-
debug('piping process STDIN into child STDIN');
|
162
|
-
process.stdin.pipe(child.stdin);
|
163
|
-
}
|
164
|
-
if (child.stdout) {
|
165
|
-
debug('piping child STDOUT to process STDOUT');
|
166
|
-
child.stdout.pipe(process.stdout);
|
87
|
+
return 'inherit';
|
88
|
+
}
|
89
|
+
const spawnModule = {
|
90
|
+
start(args, options = {}) {
|
91
|
+
const needsXvfb = xvfb_1.default.isNeeded();
|
92
|
+
let executable = state_1.default.getPathToExecutable(state_1.default.getBinaryDir());
|
93
|
+
if (util_1.default.getEnv('CYPRESS_RUN_BINARY')) {
|
94
|
+
executable = path_1.default.resolve(util_1.default.getEnv('CYPRESS_RUN_BINARY'));
|
167
95
|
}
|
168
|
-
|
169
|
-
//
|
170
|
-
//
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
// if we have a callback and this explicitly returns
|
177
|
-
// false then bail
|
178
|
-
if (onStderrData && onStderrData(str)) {
|
179
|
-
return;
|
180
|
-
}
|
181
|
-
|
182
|
-
// else pass it along!
|
183
|
-
process.stderr.write(data);
|
184
|
-
});
|
96
|
+
debug('needs to start own Xvfb?', needsXvfb);
|
97
|
+
// Always push cwd into the args
|
98
|
+
// which additionally acts as a signal to the
|
99
|
+
// binary that it was invoked through the NPM module
|
100
|
+
args = args || [];
|
101
|
+
if (typeof args === 'string') {
|
102
|
+
args = [args];
|
185
103
|
}
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
// to have any effect. so we're just catching the
|
193
|
-
// error here and not doing anything.
|
194
|
-
process.stdin.on('error', err => {
|
195
|
-
if (['EPIPE', 'ENOTCONN'].includes(err.code)) {
|
196
|
-
return;
|
197
|
-
}
|
198
|
-
throw err;
|
104
|
+
args = [...args, '--cwd', process.cwd(), '--userNodePath', process.execPath, '--userNodeVersion', process.versions.node];
|
105
|
+
lodash_1.default.defaults(options, {
|
106
|
+
dev: false,
|
107
|
+
env: process.env,
|
108
|
+
detached: false,
|
109
|
+
stdio: getStdio(needsXvfb),
|
199
110
|
});
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
111
|
+
const spawn = (overrides = {}) => {
|
112
|
+
return new bluebird_1.default((resolve, reject) => {
|
113
|
+
lodash_1.default.defaults(overrides, {
|
114
|
+
onStderrData: false,
|
115
|
+
});
|
116
|
+
const { onStderrData } = overrides;
|
117
|
+
const envOverrides = util_1.default.getEnvOverrides(options);
|
118
|
+
const electronArgs = [];
|
119
|
+
const node11WindowsFix = isPlatform('win32');
|
120
|
+
let startScriptPath;
|
121
|
+
if (options.dev) {
|
122
|
+
executable = 'node';
|
123
|
+
// if we're in dev then reset
|
124
|
+
// the launch cmd to be 'npm run dev'
|
125
|
+
startScriptPath = path_1.default.resolve(__dirname, '..', '..', '..', 'scripts', 'start.js');
|
126
|
+
debug('in dev mode the args became %o', args);
|
127
|
+
}
|
128
|
+
if (!options.dev && verify_1.default.needsSandbox()) {
|
129
|
+
electronArgs.push('--no-sandbox');
|
130
|
+
}
|
131
|
+
// strip dev out of child process options
|
132
|
+
/**
|
133
|
+
* @type {import('child_process').ForkOptions}
|
134
|
+
*/
|
135
|
+
let stdioOptions = lodash_1.default.pick(options, 'env', 'detached', 'stdio');
|
136
|
+
// figure out if we're going to be force enabling or disabling colors.
|
137
|
+
// also figure out whether we should force stdout and stderr into thinking
|
138
|
+
// it is a tty as opposed to a pipe.
|
139
|
+
stdioOptions.env = lodash_1.default.extend({}, stdioOptions.env, envOverrides);
|
140
|
+
if (node11WindowsFix) {
|
141
|
+
stdioOptions = lodash_1.default.extend({}, stdioOptions, { windowsHide: false });
|
142
|
+
}
|
143
|
+
if (util_1.default.isPossibleLinuxWithIncorrectDisplay()) {
|
144
|
+
// make sure we use the latest DISPLAY variable if any
|
145
|
+
debug('passing DISPLAY', process.env.DISPLAY);
|
146
|
+
stdioOptions.env.DISPLAY = process.env.DISPLAY;
|
147
|
+
}
|
148
|
+
if (stdioOptions.env.ELECTRON_RUN_AS_NODE) {
|
149
|
+
// Since we are running electron as node, we need to add an entry point file.
|
150
|
+
startScriptPath = path_1.default.join(state_1.default.getBinaryPkgPath(path_1.default.dirname(executable)), '..', 'index.js');
|
151
|
+
}
|
152
|
+
else {
|
153
|
+
// Start arguments with "--" so Electron knows these are OUR
|
154
|
+
// arguments and does not try to sanitize them. Otherwise on Windows
|
155
|
+
// an url in one of the arguments crashes it :(
|
156
|
+
// https://github.com/cypress-io/cypress/issues/5466
|
157
|
+
args = [...electronArgs, '--', ...args];
|
158
|
+
}
|
159
|
+
if (startScriptPath) {
|
160
|
+
args.unshift(startScriptPath);
|
161
|
+
}
|
162
|
+
if (process.env.CYPRESS_INTERNAL_DEV_DEBUG) {
|
163
|
+
args.unshift(process.env.CYPRESS_INTERNAL_DEV_DEBUG);
|
164
|
+
}
|
165
|
+
debug('spawn args %o %o', args, lodash_1.default.omit(stdioOptions, 'env'));
|
166
|
+
debug('spawning Cypress with executable: %s', executable);
|
167
|
+
const child = child_process_1.default.spawn(executable, args, stdioOptions);
|
168
|
+
function resolveOn(event) {
|
169
|
+
return function (code, signal) {
|
170
|
+
debug('child event fired %o', { event, code, signal });
|
171
|
+
if (code === null) {
|
172
|
+
const errorObject = errors_1.errors.childProcessKilled(event, signal);
|
173
|
+
return (0, errors_1.getError)(errorObject).then(reject);
|
174
|
+
}
|
175
|
+
resolve(code);
|
176
|
+
};
|
177
|
+
}
|
178
|
+
child.on('close', resolveOn('close'));
|
179
|
+
child.on('exit', resolveOn('exit'));
|
180
|
+
child.on('error', reject);
|
181
|
+
if (isPlatform('win32')) {
|
182
|
+
const rl = readline_1.default.createInterface({
|
183
|
+
input: process.stdin,
|
184
|
+
output: process.stdout,
|
185
|
+
});
|
186
|
+
// on windows, SIGINT does not propagate to the child process when ctrl+c is pressed
|
187
|
+
// this makes sure all nested processes are closed(ex: firefox inside the server)
|
188
|
+
rl.on('SIGINT', function () {
|
189
|
+
return __awaiter(this, void 0, void 0, function* () {
|
190
|
+
const kill = (yield Promise.resolve().then(() => __importStar(require('tree-kill')))).default;
|
191
|
+
kill(child.pid, 'SIGINT');
|
192
|
+
});
|
193
|
+
});
|
194
|
+
}
|
195
|
+
// if stdio options is set to 'pipe', then
|
196
|
+
// we should set up pipes:
|
197
|
+
// process STDIN (read stream) => child STDIN (writeable)
|
198
|
+
// child STDOUT => process STDOUT
|
199
|
+
// child STDERR => process STDERR with additional filtering
|
200
|
+
if (child.stdin) {
|
201
|
+
debug('piping process STDIN into child STDIN');
|
202
|
+
process.stdin.pipe(child.stdin);
|
203
|
+
}
|
204
|
+
if (child.stdout) {
|
205
|
+
debug('piping child STDOUT to process STDOUT');
|
206
|
+
child.stdout.pipe(process.stdout);
|
207
|
+
}
|
208
|
+
// if this is defined then we are manually piping for linux
|
209
|
+
// to filter out the garbage
|
210
|
+
if (child.stderr) {
|
211
|
+
debug('piping child STDERR to process STDERR');
|
212
|
+
child.stderr.on('data', (data) => {
|
213
|
+
const str = data.toString();
|
214
|
+
// if we have a callback and this explicitly returns
|
215
|
+
// false then bail
|
216
|
+
if (onStderrData && onStderrData(str)) {
|
217
|
+
return;
|
218
|
+
}
|
219
|
+
// else pass it along!
|
220
|
+
process.stderr.write(data);
|
221
|
+
});
|
222
|
+
}
|
223
|
+
// https://github.com/cypress-io/cypress/issues/1841
|
224
|
+
// https://github.com/cypress-io/cypress/issues/5241
|
225
|
+
// In some versions of node, it will throw on windows
|
226
|
+
// when you close the parent process after piping
|
227
|
+
// into the child process. unpiping does not seem
|
228
|
+
// to have any effect. so we're just catching the
|
229
|
+
// error here and not doing anything.
|
230
|
+
process.stdin.on('error', (err) => {
|
231
|
+
if (['EPIPE', 'ENOTCONN'].includes(err.code)) {
|
232
|
+
return;
|
233
|
+
}
|
234
|
+
throw err;
|
235
|
+
});
|
236
|
+
if (stdioOptions.detached) {
|
237
|
+
child.unref();
|
238
|
+
}
|
239
|
+
});
|
240
|
+
};
|
241
|
+
const spawnInXvfb = () => {
|
242
|
+
return xvfb_1.default
|
243
|
+
.start()
|
244
|
+
.then(userFriendlySpawn)
|
245
|
+
.finally(xvfb_1.default.stop);
|
246
|
+
};
|
247
|
+
const userFriendlySpawn = (linuxWithDisplayEnv) => {
|
248
|
+
debug('spawning, should retry on display problem?', Boolean(linuxWithDisplayEnv));
|
249
|
+
let brokenGtkDisplay;
|
250
|
+
const overrides = {};
|
251
|
+
if (linuxWithDisplayEnv) {
|
252
|
+
lodash_1.default.extend(overrides, {
|
253
|
+
electronLogging: true,
|
254
|
+
onStderrData(str) {
|
255
|
+
// if we receive a broken pipe anywhere
|
256
|
+
// then we know that's why cypress exited early
|
257
|
+
if (util_1.default.isBrokenGtkDisplay(str)) {
|
258
|
+
brokenGtkDisplay = true;
|
259
|
+
}
|
260
|
+
},
|
261
|
+
});
|
220
262
|
}
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
263
|
+
return spawn(overrides)
|
264
|
+
.then((code) => {
|
265
|
+
if (code !== 0 && brokenGtkDisplay) {
|
266
|
+
util_1.default.logBrokenGtkDisplayWarning();
|
267
|
+
return spawnInXvfb();
|
268
|
+
}
|
269
|
+
return code;
|
270
|
+
})
|
271
|
+
// we can format and handle an error message from the code above
|
272
|
+
// prevent wrapping error again by using "known: undefined" filter
|
273
|
+
.catch({ known: undefined }, (0, errors_1.throwFormErrorText)(errors_1.errors.unexpected));
|
274
|
+
};
|
275
|
+
if (needsXvfb) {
|
276
|
+
return spawnInXvfb();
|
228
277
|
}
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
if (needsXvfb) {
|
238
|
-
return spawnInXvfb();
|
239
|
-
}
|
240
|
-
|
241
|
-
// if we are on linux and there's already a DISPLAY
|
242
|
-
// set, then we may need to rerun cypress after
|
243
|
-
// spawning our own Xvfb server
|
244
|
-
const linuxWithDisplayEnv = util.isPossibleLinuxWithIncorrectDisplay();
|
245
|
-
return userFriendlySpawn(linuxWithDisplayEnv);
|
246
|
-
}
|
247
|
-
};
|
278
|
+
// if we are on linux and there's already a DISPLAY
|
279
|
+
// set, then we may need to rerun cypress after
|
280
|
+
// spawning our own Xvfb server
|
281
|
+
const linuxWithDisplayEnv = util_1.default.isPossibleLinuxWithIncorrectDisplay();
|
282
|
+
return userFriendlySpawn(linuxWithDisplayEnv);
|
283
|
+
},
|
284
|
+
};
|
285
|
+
exports.default = spawnModule;
|