cypress 15.1.0 → 15.3.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.
Files changed (49) hide show
  1. package/bin/cypress +3 -1
  2. package/dist/VerboseRenderer.js +61 -0
  3. package/dist/cli.js +544 -0
  4. package/dist/cypress.js +104 -0
  5. package/dist/errors.js +391 -0
  6. package/dist/exec/info.js +103 -0
  7. package/dist/exec/open.js +103 -0
  8. package/dist/exec/run.js +177 -0
  9. package/dist/exec/shared.js +55 -0
  10. package/dist/exec/spawn.js +301 -0
  11. package/dist/exec/versions.js +67 -0
  12. package/dist/exec/xvfb.js +118 -0
  13. package/dist/index.js +52 -0
  14. package/dist/index.mjs +9 -0
  15. package/dist/logger.js +55 -0
  16. package/dist/tasks/cache.js +144 -0
  17. package/dist/tasks/download.js +304 -0
  18. package/dist/tasks/get-folder-size.js +44 -0
  19. package/dist/tasks/install.js +326 -0
  20. package/dist/tasks/state.js +184 -0
  21. package/dist/tasks/unzip.js +192 -0
  22. package/dist/tasks/verify.js +303 -0
  23. package/dist/util.js +452 -0
  24. package/package.json +10 -13
  25. package/types/cypress-automation.d.ts +2 -1
  26. package/types/cypress.d.ts +1 -0
  27. package/index.js +0 -27
  28. package/index.mjs +0 -17
  29. package/lib/VerboseRenderer.js +0 -58
  30. package/lib/cli.js +0 -411
  31. package/lib/cypress.js +0 -98
  32. package/lib/errors.js +0 -392
  33. package/lib/exec/info.js +0 -92
  34. package/lib/exec/open.js +0 -90
  35. package/lib/exec/run.js +0 -176
  36. package/lib/exec/shared.js +0 -62
  37. package/lib/exec/spawn.js +0 -247
  38. package/lib/exec/versions.js +0 -53
  39. package/lib/exec/xvfb.js +0 -93
  40. package/lib/fs.js +0 -4
  41. package/lib/logger.js +0 -50
  42. package/lib/tasks/cache.js +0 -132
  43. package/lib/tasks/download.js +0 -324
  44. package/lib/tasks/get-folder-size.js +0 -33
  45. package/lib/tasks/install.js +0 -368
  46. package/lib/tasks/state.js +0 -185
  47. package/lib/tasks/unzip.js +0 -200
  48. package/lib/tasks/verify.js +0 -300
  49. package/lib/util.js +0 -448
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.start = exports.processOpenOptions = void 0;
16
+ const debug_1 = __importDefault(require("debug"));
17
+ const util_1 = __importDefault(require("../util"));
18
+ const spawn_1 = __importDefault(require("./spawn"));
19
+ const verify_1 = require("../tasks/verify");
20
+ const shared_1 = require("./shared");
21
+ const errors_1 = require("../errors");
22
+ const debug = (0, debug_1.default)('cypress:cli');
23
+ /**
24
+ * Maps options collected by the CLI
25
+ * and forms list of CLI arguments to the server.
26
+ *
27
+ * Note: there is lightweight validation, with errors
28
+ * thrown synchronously.
29
+ *
30
+ * @returns {string[]} list of CLI arguments
31
+ */
32
+ const processOpenOptions = (options = {}) => {
33
+ // In addition to setting the project directory, setting the project option
34
+ // here ultimately decides whether cypress is run in global mode or not.
35
+ // It's first based off whether it's installed globally by npm/yarn (-g).
36
+ // A global install can be overridden by the --project flag, putting Cypress
37
+ // in project mode. A non-global install can be overridden by the --global
38
+ // flag, putting it in global mode.
39
+ if (!util_1.default.isInstalledGlobally() && !options.global && !options.project) {
40
+ options.project = process.cwd();
41
+ }
42
+ const args = [];
43
+ if (options.config) {
44
+ args.push('--config', options.config);
45
+ }
46
+ if (options.configFile !== undefined) {
47
+ (0, shared_1.checkConfigFile)(options);
48
+ args.push('--config-file', options.configFile);
49
+ }
50
+ if (options.browser) {
51
+ args.push('--browser', options.browser);
52
+ }
53
+ if (options.env) {
54
+ args.push('--env', options.env);
55
+ }
56
+ if (options.port) {
57
+ args.push('--port', options.port);
58
+ }
59
+ if (options.project) {
60
+ args.push('--project', options.project);
61
+ }
62
+ if (options.global) {
63
+ args.push('--global', options.global);
64
+ }
65
+ if (options.inspect) {
66
+ args.push('--inspect');
67
+ }
68
+ if (options.inspectBrk) {
69
+ args.push('--inspectBrk');
70
+ }
71
+ args.push(...(0, shared_1.processTestingType)(options));
72
+ debug('opening from options %j', options);
73
+ debug('command line arguments %j', args);
74
+ return args;
75
+ };
76
+ exports.processOpenOptions = processOpenOptions;
77
+ const start = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (options = {}) {
78
+ function open() {
79
+ try {
80
+ const args = (0, exports.processOpenOptions)(options);
81
+ return spawn_1.default.start(args, {
82
+ dev: options.dev,
83
+ detached: Boolean(options.detached),
84
+ });
85
+ }
86
+ catch (err) {
87
+ if (err.details) {
88
+ return (0, errors_1.exitWithError)(err.details)();
89
+ }
90
+ throw err;
91
+ }
92
+ }
93
+ if (options.dev) {
94
+ return open();
95
+ }
96
+ yield (0, verify_1.start)();
97
+ return open();
98
+ });
99
+ exports.start = start;
100
+ exports.default = {
101
+ start: exports.start,
102
+ processOpenOptions: exports.processOpenOptions,
103
+ };
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const lodash_1 = __importDefault(require("lodash"));
16
+ const debug_1 = __importDefault(require("debug"));
17
+ const util_1 = __importDefault(require("../util"));
18
+ const spawn_1 = __importDefault(require("./spawn"));
19
+ const verify_1 = require("../tasks/verify");
20
+ const errors_1 = require("../errors");
21
+ const shared_1 = require("./shared");
22
+ const debug = (0, debug_1.default)('cypress:cli:run');
23
+ /**
24
+ * Typically a user passes a string path to the project.
25
+ * But "cypress open" allows using `false` to open in global mode,
26
+ * and the user can accidentally execute `cypress run --project false`
27
+ * which should be invalid.
28
+ */
29
+ const isValidProject = (v) => {
30
+ if (typeof v === 'boolean') {
31
+ return false;
32
+ }
33
+ if (v === '' || v === 'false' || v === 'true') {
34
+ return false;
35
+ }
36
+ return true;
37
+ };
38
+ /**
39
+ * Maps options collected by the CLI
40
+ * and forms list of CLI arguments to the server.
41
+ *
42
+ * Note: there is lightweight validation, with errors
43
+ * thrown synchronously.
44
+ *
45
+ * @returns {string[]} list of CLI arguments
46
+ */
47
+ const processRunOptions = (options = {}) => {
48
+ debug('processing run options %o', options);
49
+ if (!isValidProject(options.project)) {
50
+ debug('invalid project option %o', { project: options.project });
51
+ return (0, shared_1.throwInvalidOptionError)(errors_1.errors.invalidRunProjectPath);
52
+ }
53
+ const args = ['--run-project', options.project];
54
+ if (options.autoCancelAfterFailures || options.autoCancelAfterFailures === 0 || options.autoCancelAfterFailures === false) {
55
+ args.push('--auto-cancel-after-failures', options.autoCancelAfterFailures);
56
+ }
57
+ if (options.browser) {
58
+ args.push('--browser', options.browser);
59
+ }
60
+ if (options.ciBuildId) {
61
+ args.push('--ci-build-id', options.ciBuildId);
62
+ }
63
+ if (options.config) {
64
+ args.push('--config', options.config);
65
+ }
66
+ if (options.configFile !== undefined) {
67
+ (0, shared_1.checkConfigFile)(options);
68
+ args.push('--config-file', options.configFile);
69
+ }
70
+ if (options.env) {
71
+ args.push('--env', options.env);
72
+ }
73
+ if (options.exit === false) {
74
+ args.push('--no-exit');
75
+ }
76
+ if (options.group) {
77
+ args.push('--group', options.group);
78
+ }
79
+ if (options.headed) {
80
+ args.push('--headed', options.headed);
81
+ }
82
+ if (options.headless) {
83
+ if (options.headed) {
84
+ return (0, shared_1.throwInvalidOptionError)(errors_1.errors.incompatibleHeadlessFlags);
85
+ }
86
+ args.push('--headed', String(!options.headless));
87
+ }
88
+ // if key is set use that - else attempt to find it by environment variable
89
+ if (options.key == null) {
90
+ debug('--key is not set, looking up environment variable CYPRESS_RECORD_KEY');
91
+ options.key = util_1.default.getEnv('CYPRESS_RECORD_KEY');
92
+ }
93
+ // if we have a key assume we're in record mode
94
+ if (options.key) {
95
+ args.push('--key', options.key);
96
+ }
97
+ if (options.outputPath) {
98
+ args.push('--output-path', options.outputPath);
99
+ }
100
+ if (options.parallel) {
101
+ args.push('--parallel');
102
+ }
103
+ if (options.port) {
104
+ args.push('--port', options.port);
105
+ }
106
+ if (options.quiet) {
107
+ args.push('--quiet');
108
+ }
109
+ // if record is defined and we're not
110
+ // already in ci mode, then send it up
111
+ if (options.record != null) {
112
+ args.push('--record', options.record);
113
+ }
114
+ // if we have a specific reporter push that into the args
115
+ if (options.reporter) {
116
+ args.push('--reporter', options.reporter);
117
+ }
118
+ // if we have a specific reporter push that into the args
119
+ if (options.reporterOptions) {
120
+ args.push('--reporter-options', options.reporterOptions);
121
+ }
122
+ if (options.runnerUi != null) {
123
+ args.push('--runner-ui', options.runnerUi);
124
+ }
125
+ // if we have specific spec(s) push that into the args
126
+ if (options.spec) {
127
+ args.push('--spec', options.spec);
128
+ }
129
+ if (options.tag) {
130
+ args.push('--tag', options.tag);
131
+ }
132
+ if (options.inspect) {
133
+ args.push('--inspect');
134
+ }
135
+ if (options.inspectBrk) {
136
+ args.push('--inspectBrk');
137
+ }
138
+ args.push(...(0, shared_1.processTestingType)(options));
139
+ return args;
140
+ };
141
+ const runModule = {
142
+ processRunOptions,
143
+ isValidProject,
144
+ // resolves with the number of failed tests
145
+ start() {
146
+ return __awaiter(this, arguments, void 0, function* (options = {}) {
147
+ lodash_1.default.defaults(options, {
148
+ key: null,
149
+ spec: null,
150
+ reporter: null,
151
+ reporterOptions: null,
152
+ project: process.cwd(),
153
+ });
154
+ function run() {
155
+ try {
156
+ const args = processRunOptions(options);
157
+ debug('run to spawn.start args %j', args);
158
+ return spawn_1.default.start(args, {
159
+ dev: options.dev,
160
+ });
161
+ }
162
+ catch (err) {
163
+ if (err.details) {
164
+ return (0, errors_1.exitWithError)(err.details)();
165
+ }
166
+ throw err;
167
+ }
168
+ }
169
+ if (options.dev) {
170
+ return run();
171
+ }
172
+ yield (0, verify_1.start)();
173
+ return run();
174
+ });
175
+ },
176
+ };
177
+ exports.default = runModule;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkConfigFile = exports.processTestingType = exports.throwInvalidOptionError = void 0;
4
+ const errors_1 = require("../errors");
5
+ /**
6
+ * Throws an error with "details" property from
7
+ * "errors" object.
8
+ * @param {Object} details - Error details
9
+ */
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;
19
+ };
20
+ exports.throwInvalidOptionError = throwInvalidOptionError;
21
+ /**
22
+ * Selects exec args based on the configured `testingType`
23
+ * @param {string} testingType The type of tests being executed
24
+ * @returns {string[]} The array of new exec arguments
25
+ */
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 [];
43
+ };
44
+ exports.processTestingType = processTestingType;
45
+ /**
46
+ * Throws an error if configFile is string 'false' or boolean false
47
+ * @param {*} options
48
+ */
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
+ }
54
+ };
55
+ exports.checkConfigFile = checkConfigFile;
@@ -0,0 +1,301 @@
1
+ "use strict";
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 = require("../tasks/verify");
58
+ const errors_1 = require("../errors");
59
+ const readline_1 = __importDefault(require("readline"));
60
+ const process_1 = require("process");
61
+ const debug = (0, debug_1.default)('cypress:cli');
62
+ function isPlatform(platform) {
63
+ return os_1.default.platform() === platform;
64
+ }
65
+ function needsStderrPiped(needsXvfb) {
66
+ return lodash_1.default.some([
67
+ isPlatform('darwin'),
68
+ (needsXvfb && isPlatform('linux')),
69
+ util_1.default.isPossibleLinuxWithIncorrectDisplay(),
70
+ ]);
71
+ }
72
+ function needsEverythingPipedDirectly() {
73
+ return isPlatform('win32');
74
+ }
75
+ function getStdio(needsXvfb) {
76
+ if (needsEverythingPipedDirectly()) {
77
+ return 'pipe';
78
+ }
79
+ // https://github.com/cypress-io/cypress/issues/921
80
+ // https://github.com/cypress-io/cypress/issues/1143
81
+ // https://github.com/cypress-io/cypress/issues/1745
82
+ if (needsStderrPiped(needsXvfb)) {
83
+ // returning pipe here so we can massage stderr
84
+ // and remove garbage from Xlib and libuv
85
+ // due to starting the Xvfb process on linux
86
+ return ['inherit', 'inherit', 'pipe'];
87
+ }
88
+ return 'inherit';
89
+ }
90
+ const spawnModule = {
91
+ start(args_1) {
92
+ return __awaiter(this, arguments, void 0, function* (args, options = {}) {
93
+ const needsXvfb = xvfb_1.default.isNeeded();
94
+ let executable = state_1.default.getPathToExecutable(state_1.default.getBinaryDir());
95
+ if (util_1.default.getEnv('CYPRESS_RUN_BINARY')) {
96
+ executable = path_1.default.resolve(util_1.default.getEnv('CYPRESS_RUN_BINARY'));
97
+ }
98
+ debug('needs to start own Xvfb?', needsXvfb);
99
+ // Always push cwd into the args
100
+ // which additionally acts as a signal to the
101
+ // binary that it was invoked through the NPM module
102
+ args = args || [];
103
+ if (typeof args === 'string') {
104
+ args = [args];
105
+ }
106
+ args = [...args, '--cwd', process.cwd(), '--userNodePath', process.execPath, '--userNodeVersion', process.versions.node];
107
+ lodash_1.default.defaults(options, {
108
+ dev: false,
109
+ env: process.env,
110
+ detached: false,
111
+ stdio: getStdio(needsXvfb),
112
+ });
113
+ const spawn = (overrides = {}) => {
114
+ return new bluebird_1.default((resolve, reject) => {
115
+ lodash_1.default.defaults(overrides, {
116
+ onStderrData: false,
117
+ });
118
+ const { onStderrData } = overrides;
119
+ const envOverrides = util_1.default.getEnvOverrides(options);
120
+ const electronArgs = [];
121
+ const node11WindowsFix = isPlatform('win32');
122
+ let startScriptPath;
123
+ if (options.dev) {
124
+ executable = 'node';
125
+ // if we're in dev then reset
126
+ // the launch cmd to be 'npm run dev'
127
+ startScriptPath = path_1.default.resolve(__dirname, '..', '..', '..', 'scripts', 'start.js');
128
+ debug('in dev mode the args became %o', args);
129
+ }
130
+ if (!options.dev && (0, verify_1.needsSandbox)()) {
131
+ electronArgs.push('--no-sandbox');
132
+ }
133
+ // strip dev out of child process options
134
+ /**
135
+ * @type {import('child_process').ForkOptions}
136
+ */
137
+ let stdioOptions = lodash_1.default.pick(options, 'env', 'detached', 'stdio');
138
+ // figure out if we're going to be force enabling or disabling colors.
139
+ // also figure out whether we should force stdout and stderr into thinking
140
+ // it is a tty as opposed to a pipe.
141
+ stdioOptions.env = lodash_1.default.extend({}, stdioOptions.env, envOverrides);
142
+ if (node11WindowsFix) {
143
+ stdioOptions = lodash_1.default.extend({}, stdioOptions, { windowsHide: false });
144
+ }
145
+ if (util_1.default.isPossibleLinuxWithIncorrectDisplay()) {
146
+ // make sure we use the latest DISPLAY variable if any
147
+ debug('passing DISPLAY', process.env.DISPLAY);
148
+ stdioOptions.env.DISPLAY = process.env.DISPLAY;
149
+ }
150
+ if (stdioOptions.env.ELECTRON_RUN_AS_NODE) {
151
+ // Since we are running electron as node, we need to add an entry point file.
152
+ startScriptPath = path_1.default.join(state_1.default.getBinaryPkgPath(path_1.default.dirname(executable)), '..', 'index.js');
153
+ }
154
+ else {
155
+ // Start arguments with "--" so Electron knows these are OUR
156
+ // arguments and does not try to sanitize them. Otherwise on Windows
157
+ // an url in one of the arguments crashes it :(
158
+ // https://github.com/cypress-io/cypress/issues/5466
159
+ args = [...electronArgs, '--', ...args];
160
+ }
161
+ if (startScriptPath) {
162
+ args.unshift(startScriptPath);
163
+ }
164
+ if (process.env.CYPRESS_INTERNAL_DEV_DEBUG) {
165
+ args.unshift(process.env.CYPRESS_INTERNAL_DEV_DEBUG);
166
+ }
167
+ debug('spawn args %o %o', args, lodash_1.default.omit(stdioOptions, 'env'));
168
+ debug('spawning Cypress with executable: %s', executable);
169
+ const child = child_process_1.default.spawn(executable, args, stdioOptions);
170
+ function resolveOn(event) {
171
+ return function (code, signal) {
172
+ return __awaiter(this, void 0, void 0, function* () {
173
+ debug('child event fired %o', { event, code, signal });
174
+ if (code === null) {
175
+ const errorObject = errors_1.errors.childProcessKilled(event, signal);
176
+ const err = yield (0, errors_1.getError)(errorObject);
177
+ return reject(err);
178
+ }
179
+ resolve(code);
180
+ });
181
+ };
182
+ }
183
+ child.on('close', resolveOn('close'));
184
+ child.on('exit', resolveOn('exit'));
185
+ child.on('error', reject);
186
+ if (isPlatform('win32')) {
187
+ const rl = readline_1.default.createInterface({
188
+ input: process_1.stdin,
189
+ output: process_1.stdout,
190
+ });
191
+ // on windows, SIGINT does not propagate to the child process when ctrl+c is pressed
192
+ // this makes sure all nested processes are closed(ex: firefox inside the server)
193
+ rl.on('SIGINT', function () {
194
+ return __awaiter(this, void 0, void 0, function* () {
195
+ const kill = (yield Promise.resolve().then(() => __importStar(require('tree-kill')))).default;
196
+ kill(child.pid, 'SIGINT');
197
+ });
198
+ });
199
+ }
200
+ // if stdio options is set to 'pipe', then
201
+ // we should set up pipes:
202
+ // process STDIN (read stream) => child STDIN (writeable)
203
+ // child STDOUT => process STDOUT
204
+ // child STDERR => process STDERR with additional filtering
205
+ if (child.stdin) {
206
+ debug('piping process STDIN into child STDIN');
207
+ process_1.stdin.pipe(child.stdin);
208
+ }
209
+ if (child.stdout) {
210
+ debug('piping child STDOUT to process STDOUT');
211
+ child.stdout.pipe(process_1.stdout);
212
+ }
213
+ // if this is defined then we are manually piping for linux
214
+ // to filter out the garbage
215
+ if (child.stderr) {
216
+ debug('piping child STDERR to process STDERR');
217
+ child.stderr.on('data', (data) => {
218
+ const str = data.toString();
219
+ // if we have a callback and this explicitly returns
220
+ // false then bail
221
+ if (onStderrData && onStderrData(str)) {
222
+ return;
223
+ }
224
+ // else pass it along!
225
+ process_1.stderr.write(data);
226
+ });
227
+ }
228
+ // https://github.com/cypress-io/cypress/issues/1841
229
+ // https://github.com/cypress-io/cypress/issues/5241
230
+ // In some versions of node, it will throw on windows
231
+ // when you close the parent process after piping
232
+ // into the child process. unpiping does not seem
233
+ // to have any effect. so we're just catching the
234
+ // error here and not doing anything.
235
+ process_1.stdin.on('error', (err) => {
236
+ if (['EPIPE', 'ENOTCONN'].includes(err.code)) {
237
+ return;
238
+ }
239
+ throw err;
240
+ });
241
+ if (stdioOptions.detached) {
242
+ child.unref();
243
+ }
244
+ });
245
+ };
246
+ const spawnInXvfb = () => __awaiter(this, void 0, void 0, function* () {
247
+ try {
248
+ yield xvfb_1.default.start();
249
+ const code = yield userFriendlySpawn();
250
+ return code;
251
+ }
252
+ finally {
253
+ yield xvfb_1.default.stop();
254
+ }
255
+ });
256
+ const userFriendlySpawn = (linuxWithDisplayEnv) => __awaiter(this, void 0, void 0, function* () {
257
+ debug('spawning, should retry on display problem?', Boolean(linuxWithDisplayEnv));
258
+ let brokenGtkDisplay = false;
259
+ const overrides = {};
260
+ if (linuxWithDisplayEnv) {
261
+ lodash_1.default.extend(overrides, {
262
+ electronLogging: true,
263
+ onStderrData(str) {
264
+ // if we receive a broken pipe anywhere
265
+ // then we know that's why cypress exited early
266
+ if (util_1.default.isBrokenGtkDisplay(str)) {
267
+ brokenGtkDisplay = true;
268
+ }
269
+ },
270
+ });
271
+ }
272
+ try {
273
+ const code = yield spawn(overrides);
274
+ if (code !== 0 && brokenGtkDisplay) {
275
+ util_1.default.logBrokenGtkDisplayWarning();
276
+ return spawnInXvfb();
277
+ }
278
+ return code;
279
+ }
280
+ catch (error) {
281
+ // we can format and handle an error message from the code above
282
+ // prevent wrapping error again by using "known: undefined" filter
283
+ if (error.known === undefined) {
284
+ const raiseErrorFn = (0, errors_1.throwFormErrorText)(errors_1.errors.unexpected);
285
+ yield raiseErrorFn(error.message);
286
+ }
287
+ throw error;
288
+ }
289
+ });
290
+ if (needsXvfb) {
291
+ return spawnInXvfb();
292
+ }
293
+ // if we are on linux and there's already a DISPLAY
294
+ // set, then we may need to rerun cypress after
295
+ // spawning our own Xvfb server
296
+ const linuxWithDisplayEnv = util_1.default.isPossibleLinuxWithIncorrectDisplay();
297
+ return userFriendlySpawn(linuxWithDisplayEnv);
298
+ });
299
+ },
300
+ };
301
+ exports.default = spawnModule;