cypress 12.0.2 → 12.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,38 +1,26 @@
1
1
  "use strict";
2
2
 
3
3
  const _ = require('lodash');
4
-
5
4
  const la = require('lazy-ass');
6
-
7
5
  const is = require('check-more-types');
8
-
9
6
  const cp = require('child_process');
10
-
11
7
  const os = require('os');
12
-
13
8
  const yauzl = require('yauzl');
14
-
15
9
  const debug = require('debug')('cypress:cli:unzip');
16
-
17
10
  const extract = require('extract-zip');
18
-
19
11
  const Promise = require('bluebird');
20
-
21
12
  const readline = require('readline');
22
-
23
13
  const {
24
14
  throwFormErrorText,
25
15
  errors
26
16
  } = require('../errors');
27
-
28
17
  const fs = require('../fs');
29
-
30
18
  const util = require('../util');
31
-
32
19
  const unzipTools = {
33
20
  extract
34
- }; // expose this function for simple testing
21
+ };
35
22
 
23
+ // expose this function for simple testing
36
24
  const unzip = ({
37
25
  zipFilePath,
38
26
  installDir,
@@ -40,42 +28,35 @@ const unzip = ({
40
28
  }) => {
41
29
  debug('unzipping from %s', zipFilePath);
42
30
  debug('into', installDir);
43
-
44
31
  if (!zipFilePath) {
45
32
  throw new Error('Missing zip filename');
46
33
  }
47
-
48
34
  const startTime = Date.now();
49
35
  let yauzlDoneTime = 0;
50
36
  return fs.ensureDirAsync(installDir).then(() => {
51
37
  return new Promise((resolve, reject) => {
52
38
  return yauzl.open(zipFilePath, (err, zipFile) => {
53
39
  yauzlDoneTime = Date.now();
54
-
55
40
  if (err) {
56
41
  debug('error using yauzl %s', err.message);
57
42
  return reject(err);
58
43
  }
59
-
60
44
  const total = zipFile.entryCount;
61
45
  debug('zipFile entries count', total);
62
46
  const started = new Date();
63
47
  let percent = 0;
64
48
  let count = 0;
65
-
66
49
  const notify = percent => {
67
50
  const elapsed = +new Date() - +started;
68
51
  const eta = util.calculateEta(percent, elapsed);
69
52
  progress.onProgress(percent, util.secsRemaining(eta));
70
53
  };
71
-
72
54
  const tick = () => {
73
55
  count += 1;
74
56
  percent = count / total * 100;
75
57
  const displayPercent = percent.toFixed(0);
76
58
  return notify(displayPercent);
77
59
  };
78
-
79
60
  const unzipWithNode = () => {
80
61
  debug('unzipping with node.js (slow)');
81
62
  const opts = {
@@ -93,9 +74,7 @@ const unzip = ({
93
74
  }
94
75
  });
95
76
  };
96
-
97
77
  const unzipFallback = _.once(unzipWithNode);
98
-
99
78
  const unzipWithUnzipTool = () => {
100
79
  debug('unzipping via `unzip`');
101
80
  const inflatingRe = /inflating:/;
@@ -106,13 +85,11 @@ const unzip = ({
106
85
  });
107
86
  sp.on('close', code => {
108
87
  debug('unzip tool close with code %d', code);
109
-
110
88
  if (code === 0) {
111
89
  percent = 100;
112
90
  notify(percent);
113
91
  return resolve();
114
92
  }
115
-
116
93
  debug('`unzip` failed %o', {
117
94
  code
118
95
  });
@@ -126,18 +103,19 @@ const unzip = ({
126
103
  sp.stderr.on('data', data => {
127
104
  debug('`unzip` stderr %s', data);
128
105
  });
129
- }; // we attempt to first unzip with the native osx
106
+ };
107
+
108
+ // we attempt to first unzip with the native osx
130
109
  // ditto because its less likely to have problems
131
110
  // with corruption, symlinks, or icons causing failures
132
111
  // and can handle resource forks
133
112
  // http://automatica.com.au/2011/02/unzip-mac-os-x-zip-in-terminal/
134
-
135
-
136
113
  const unzipWithOsx = () => {
137
114
  debug('unzipping via `ditto`');
138
115
  const copyingFileRe = /^copying file/;
139
- const sp = cp.spawn('ditto', ['-xkV', zipFilePath, installDir]); // f-it just unzip with node
116
+ const sp = cp.spawn('ditto', ['-xkV', zipFilePath, installDir]);
140
117
 
118
+ // f-it just unzip with node
141
119
  sp.on('error', err => {
142
120
  debug(err.message);
143
121
  unzipFallback();
@@ -150,7 +128,6 @@ const unzip = ({
150
128
  notify(percent);
151
129
  return resolve();
152
130
  }
153
-
154
131
  debug('`ditto` failed %o', {
155
132
  code
156
133
  });
@@ -164,17 +141,13 @@ const unzip = ({
164
141
  }
165
142
  });
166
143
  };
167
-
168
144
  switch (os.platform()) {
169
145
  case 'darwin':
170
146
  return unzipWithOsx();
171
-
172
147
  case 'linux':
173
148
  return unzipWithUnzipTool();
174
-
175
149
  case 'win32':
176
150
  return unzipWithNode();
177
-
178
151
  default:
179
152
  return;
180
153
  }
@@ -187,18 +160,15 @@ const unzip = ({
187
160
  });
188
161
  });
189
162
  };
190
-
191
163
  function isMaybeWindowsMaxPathLengthError(err) {
192
164
  return os.platform() === 'win32' && err.code === 'ENOENT' && err.syscall === 'realpath';
193
165
  }
194
-
195
166
  const start = async ({
196
167
  zipFilePath,
197
168
  installDir,
198
169
  progress
199
170
  }) => {
200
171
  la(is.unemptyString(installDir), 'missing installDir');
201
-
202
172
  if (!progress) {
203
173
  progress = {
204
174
  onProgress: () => {
@@ -206,15 +176,12 @@ const start = async ({
206
176
  }
207
177
  };
208
178
  }
209
-
210
179
  try {
211
180
  const installDirExists = await fs.pathExists(installDir);
212
-
213
181
  if (installDirExists) {
214
182
  debug('removing existing unzipped binary', installDir);
215
183
  await fs.removeAsync(installDir);
216
184
  }
217
-
218
185
  await unzip({
219
186
  zipFilePath,
220
187
  installDir,
@@ -225,7 +192,6 @@ const start = async ({
225
192
  await throwFormErrorText(errorTemplate)(err);
226
193
  }
227
194
  };
228
-
229
195
  module.exports = {
230
196
  start,
231
197
  utils: {
@@ -1,50 +1,33 @@
1
1
  "use strict";
2
2
 
3
3
  const _ = require('lodash');
4
-
5
4
  const chalk = require('chalk');
6
-
7
5
  const {
8
6
  Listr
9
7
  } = require('listr2');
10
-
11
8
  const debug = require('debug')('cypress:cli');
12
-
13
9
  const {
14
10
  stripIndent
15
11
  } = require('common-tags');
16
-
17
12
  const Promise = require('bluebird');
18
-
19
13
  const logSymbols = require('log-symbols');
20
-
21
14
  const path = require('path');
22
-
23
15
  const os = require('os');
24
-
25
16
  const verbose = require('../VerboseRenderer');
26
-
27
17
  const {
28
18
  throwFormErrorText,
29
19
  errors
30
20
  } = require('../errors');
31
-
32
21
  const util = require('../util');
33
-
34
22
  const logger = require('../logger');
35
-
36
23
  const xvfb = require('../exec/xvfb');
37
-
38
24
  const state = require('./state');
39
-
40
25
  const VERIFY_TEST_RUNNER_TIMEOUT_MS = +util.getEnv('CYPRESS_VERIFY_TIMEOUT') || 30000;
41
-
42
26
  const checkExecutable = binaryDir => {
43
27
  const executable = state.getPathToExecutable(binaryDir);
44
28
  debug('checking if executable exists', executable);
45
29
  return util.isExecutableAsync(executable).then(isExecutable => {
46
30
  debug('Binary is executable? :', isExecutable);
47
-
48
31
  if (!isExecutable) {
49
32
  return throwFormErrorText(errors.binaryNotExecutable(executable))();
50
33
  }
@@ -54,99 +37,79 @@ const checkExecutable = binaryDir => {
54
37
  if (util.isCi()) {
55
38
  return throwFormErrorText(errors.notInstalledCI(executable))();
56
39
  }
57
-
58
40
  return throwFormErrorText(errors.missingApp(binaryDir))(stripIndent`
59
41
  Cypress executable not found at: ${chalk.cyan(executable)}
60
42
  `);
61
43
  });
62
44
  };
63
-
64
45
  const runSmokeTest = (binaryDir, options) => {
65
46
  let executable = state.getPathToExecutable(binaryDir);
66
-
67
47
  const onSmokeTestError = (smokeTestCommand, linuxWithDisplayEnv) => {
68
48
  return err => {
69
49
  debug('Smoke test failed:', err);
70
50
  let errMessage = err.stderr || err.message;
71
51
  debug('error message:', errMessage);
72
-
73
52
  if (err.timedOut) {
74
53
  debug('error timedOut is true');
75
54
  return throwFormErrorText(errors.smokeTestFailure(smokeTestCommand, true))(errMessage);
76
55
  }
77
-
78
56
  if (linuxWithDisplayEnv && util.isBrokenGtkDisplay(errMessage)) {
79
57
  util.logBrokenGtkDisplayWarning();
80
58
  return throwFormErrorText(errors.invalidSmokeTestDisplayError)(errMessage);
81
59
  }
82
-
83
60
  return throwFormErrorText(errors.missingDependency)(errMessage);
84
61
  };
85
62
  };
86
-
87
63
  const needsXvfb = xvfb.isNeeded();
88
64
  debug('needs Xvfb?', needsXvfb);
65
+
89
66
  /**
90
67
  * Spawn Cypress running smoke test to check if all operating system
91
68
  * dependencies are good.
92
69
  */
93
-
94
70
  const spawn = linuxWithDisplayEnv => {
95
71
  const random = _.random(0, 1000);
96
-
97
72
  const args = ['--smoke-test', `--ping=${random}`];
98
-
99
73
  if (needsSandbox()) {
100
74
  // electron requires --no-sandbox to run as root
101
75
  debug('disabling Electron sandbox');
102
76
  args.unshift('--no-sandbox');
103
77
  }
104
-
105
78
  if (options.dev) {
106
79
  executable = 'node';
107
80
  args.unshift(path.resolve(__dirname, '..', '..', '..', 'scripts', 'start.js'));
108
81
  }
109
-
110
82
  const smokeTestCommand = `${executable} ${args.join(' ')}`;
111
83
  debug('running smoke test');
112
84
  debug('using Cypress executable %s', executable);
113
85
  debug('smoke test command:', smokeTestCommand);
114
86
  debug('smoke test timeout %d ms', options.smokeTestTimeout);
115
-
116
87
  const env = _.extend({}, process.env, {
117
88
  ELECTRON_ENABLE_LOGGING: true
118
89
  });
119
-
120
90
  const stdioOptions = _.extend({}, {
121
91
  env,
122
92
  timeout: options.smokeTestTimeout
123
93
  });
124
-
125
94
  return Promise.resolve(util.exec(executable, args, stdioOptions)).catch(onSmokeTestError(smokeTestCommand, linuxWithDisplayEnv)).then(result => {
126
95
  // TODO: when execa > 1.1 is released
127
96
  // change this to `result.all` for both stderr and stdout
128
97
  // use lodash to be robust during tests against null result or missing stdout
129
98
  const smokeTestStdout = _.get(result, 'stdout', '');
130
-
131
99
  debug('smoke test stdout "%s"', smokeTestStdout);
132
-
133
100
  if (!util.stdoutLineMatches(String(random), smokeTestStdout)) {
134
101
  debug('Smoke test failed because could not find %d in:', random, result);
135
-
136
102
  const smokeTestStderr = _.get(result, 'stderr', '');
137
-
138
103
  const errorText = smokeTestStderr || smokeTestStdout;
139
104
  return throwFormErrorText(errors.smokeTestFailure(smokeTestCommand, false))(errorText);
140
105
  }
141
106
  });
142
107
  };
143
-
144
108
  const spawnInXvfb = linuxWithDisplayEnv => {
145
109
  return xvfb.start().then(() => {
146
110
  return spawn(linuxWithDisplayEnv);
147
111
  }).finally(xvfb.stop);
148
112
  };
149
-
150
113
  const userFriendlySpawn = linuxWithDisplayEnv => {
151
114
  debug('spawning, should retry on display problem?', Boolean(linuxWithDisplayEnv));
152
115
  return spawn(linuxWithDisplayEnv).catch({
@@ -155,31 +118,30 @@ const runSmokeTest = (binaryDir, options) => {
155
118
  return spawnInXvfb(linuxWithDisplayEnv);
156
119
  });
157
120
  };
158
-
159
121
  if (needsXvfb) {
160
122
  return spawnInXvfb();
161
- } // if we are on linux and there's already a DISPLAY
123
+ }
124
+
125
+ // if we are on linux and there's already a DISPLAY
162
126
  // set, then we may need to rerun cypress after
163
127
  // spawning our own Xvfb server
164
-
165
-
166
128
  const linuxWithDisplayEnv = util.isPossibleLinuxWithIncorrectDisplay();
167
129
  return userFriendlySpawn(linuxWithDisplayEnv);
168
130
  };
169
-
170
131
  function testBinary(version, binaryDir, options) {
171
- debug('running binary verification check', version); // if running from 'cypress verify', don't print this message
132
+ debug('running binary verification check', version);
172
133
 
134
+ // if running from 'cypress verify', don't print this message
173
135
  if (!options.force) {
174
136
  logger.log(stripIndent`
175
137
  It looks like this is your first time using Cypress: ${chalk.cyan(version)}
176
138
  `);
177
139
  }
140
+ logger.log();
178
141
 
179
- logger.log(); // if we are running in CI then use
142
+ // if we are running in CI then use
180
143
  // the verbose renderer else use
181
144
  // the default
182
-
183
145
  let renderer = util.isCi() ? verbose : 'default';
184
146
  if (logger.logLevel() === 'silent') renderer = 'silent';
185
147
  const rendererOptions = {
@@ -206,17 +168,16 @@ function testBinary(version, binaryDir, options) {
206
168
  });
207
169
  return tasks.run();
208
170
  }
209
-
210
171
  const maybeVerify = (installedVersion, binaryDir, options) => {
211
172
  return state.getBinaryVerifiedAsync(binaryDir).then(isVerified => {
212
173
  debug('is Verified ?', isVerified);
213
- let shouldVerify = !isVerified; // force verify if options.force
174
+ let shouldVerify = !isVerified;
214
175
 
176
+ // force verify if options.force
215
177
  if (options.force) {
216
178
  debug('force verify');
217
179
  shouldVerify = true;
218
180
  }
219
-
220
181
  if (shouldVerify) {
221
182
  return testBinary(installedVersion, binaryDir, options).then(() => {
222
183
  if (options.welcomeMessage) {
@@ -227,23 +188,19 @@ const maybeVerify = (installedVersion, binaryDir, options) => {
227
188
  }
228
189
  });
229
190
  };
230
-
231
191
  const start = (options = {}) => {
232
192
  debug('verifying Cypress app');
233
193
  const packageVersion = util.pkgVersion();
234
194
  let binaryDir = state.getBinaryDir(packageVersion);
235
-
236
195
  _.defaults(options, {
237
196
  dev: false,
238
197
  force: false,
239
198
  welcomeMessage: true,
240
199
  smokeTestTimeout: VERIFY_TEST_RUNNER_TIMEOUT_MS
241
200
  });
242
-
243
201
  if (options.dev) {
244
202
  return runSmokeTest('', options);
245
203
  }
246
-
247
204
  const parseBinaryEnvVar = () => {
248
205
  const envBinaryPath = util.getEnv('CYPRESS_RUN_BINARY');
249
206
  debug('CYPRESS_RUN_BINARY exists, =', envBinaryPath);
@@ -257,7 +214,6 @@ const start = (options = {}) => {
257
214
  logger.log();
258
215
  return util.isExecutableAsync(envBinaryPath).then(isExecutable => {
259
216
  debug('CYPRESS_RUN_BINARY is executable? :', isExecutable);
260
-
261
217
  if (!isExecutable) {
262
218
  return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath))(stripIndent`
263
219
  The supplied binary path is not executable
@@ -269,7 +225,6 @@ const start = (options = {}) => {
269
225
  if (!envBinaryDir) {
270
226
  return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath))();
271
227
  }
272
-
273
228
  debug('CYPRESS_RUN_BINARY has binaryDir:', envBinaryDir);
274
229
  binaryDir = envBinaryDir;
275
230
  }).catch({
@@ -278,10 +233,8 @@ const start = (options = {}) => {
278
233
  return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath))(err.message);
279
234
  });
280
235
  };
281
-
282
236
  return Promise.try(() => {
283
237
  debug('checking environment variables');
284
-
285
238
  if (util.getEnv('CYPRESS_RUN_BINARY')) {
286
239
  return parseBinaryEnvVar();
287
240
  }
@@ -300,9 +253,7 @@ const start = (options = {}) => {
300
253
  Cannot read binary version from: ${chalk.cyan(state.getBinaryPkgPath(binaryDir))}
301
254
  `);
302
255
  }
303
-
304
256
  debug(`Found binary version ${chalk.green(binaryVersion)} installed in: ${chalk.cyan(binaryDir)}`);
305
-
306
257
  if (binaryVersion !== packageVersion) {
307
258
  // warn if we installed with CYPRESS_INSTALL_BINARY or changed version
308
259
  // in the package.json
@@ -317,18 +268,16 @@ const start = (options = {}) => {
317
268
  `);
318
269
  logger.log();
319
270
  }
320
-
321
271
  return maybeVerify(binaryVersion, binaryDir, options);
322
272
  }).catch(err => {
323
273
  if (err.known) {
324
274
  throw err;
325
275
  }
326
-
327
276
  return throwFormErrorText(errors.unexpected)(err.stack);
328
277
  });
329
278
  };
330
-
331
279
  const isLinuxLike = () => os.platform() !== 'win32';
280
+
332
281
  /**
333
282
  * Returns true if running on a system where Electron needs "--no-sandbox" flag.
334
283
  * @see https://crbug.com/638180
@@ -338,10 +287,7 @@ const isLinuxLike = () => os.platform() !== 'win32';
338
287
  * Seems there is a lot of discussion around this issue among Electron users
339
288
  * @see https://github.com/electron/electron/issues/17972
340
289
  */
341
-
342
-
343
290
  const needsSandbox = () => isLinuxLike();
344
-
345
291
  module.exports = {
346
292
  start,
347
293
  VERIFY_TEST_RUNNER_TIMEOUT_MS,