cypress 12.1.0 → 12.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.
@@ -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,