cypress 12.1.0 → 12.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,58 +1,39 @@
1
1
  "use strict";
2
2
 
3
3
  const _ = require('lodash');
4
-
5
4
  const os = require('os');
6
-
7
5
  const path = require('path');
8
-
9
6
  const chalk = require('chalk');
10
-
11
7
  const debug = require('debug')('cypress:cli');
12
-
13
8
  const {
14
9
  Listr
15
10
  } = require('listr2');
16
-
17
11
  const Promise = require('bluebird');
18
-
19
12
  const logSymbols = require('log-symbols');
20
-
21
13
  const {
22
14
  stripIndent
23
15
  } = require('common-tags');
24
-
25
16
  const fs = require('../fs');
26
-
27
17
  const download = require('./download');
28
-
29
18
  const util = require('../util');
30
-
31
19
  const state = require('./state');
32
-
33
20
  const unzip = require('./unzip');
34
-
35
21
  const logger = require('../logger');
36
-
37
22
  const {
38
23
  throwFormErrorText,
39
24
  errors
40
25
  } = require('../errors');
41
-
42
26
  const verbose = require('../VerboseRenderer');
43
-
44
27
  const {
45
28
  buildInfo,
46
29
  version
47
30
  } = require('../../package.json');
48
-
49
31
  function _getBinaryUrlFromBuildInfo(arch, {
50
32
  commitSha,
51
33
  commitBranch
52
34
  }) {
53
35
  return `https://cdn.cypress.io/beta/binary/${version}/${os.platform()}-${arch}/${commitBranch}-${commitSha}/cypress.zip`;
54
36
  }
55
-
56
37
  const alreadyInstalledMsg = () => {
57
38
  if (!util.isPostInstall()) {
58
39
  logger.log(stripIndent`
@@ -62,7 +43,6 @@ const alreadyInstalledMsg = () => {
62
43
  `);
63
44
  }
64
45
  };
65
-
66
46
  const displayCompletionMsg = () => {
67
47
  // check here to see if we are globally installed
68
48
  if (util.isInstalledGlobally()) {
@@ -82,14 +62,12 @@ const displayCompletionMsg = () => {
82
62
  `);
83
63
  return;
84
64
  }
85
-
86
65
  logger.log();
87
66
  logger.log('You can now open Cypress by running:', chalk.cyan(path.join('node_modules', '.bin', 'cypress'), 'open'));
88
67
  logger.log();
89
68
  logger.log(chalk.grey('https://on.cypress.io/installing-cypress'));
90
69
  logger.log();
91
70
  };
92
-
93
71
  const downloadAndUnzip = ({
94
72
  version,
95
73
  installDir,
@@ -100,8 +78,9 @@ const downloadAndUnzip = ({
100
78
  onProgress: null
101
79
  };
102
80
  const downloadDestination = path.join(downloadDir, `cypress-${process.pid}.zip`);
103
- const rendererOptions = getRendererOptions(); // let the user know what version of cypress we're downloading!
81
+ const rendererOptions = getRendererOptions();
104
82
 
83
+ // let the user know what version of cypress we're downloading!
105
84
  logger.log(`Installing Cypress ${chalk.gray(`(version: ${version})`)}`);
106
85
  logger.log();
107
86
  const tasks = new Listr([{
@@ -137,7 +116,6 @@ const downloadAndUnzip = ({
137
116
  debug('removing zip file %s', downloadDestination);
138
117
  return fs.removeAsync(downloadDestination);
139
118
  };
140
-
141
119
  return cleanup().then(() => {
142
120
  debug('finished installation in', installDir);
143
121
  util.setTaskTitle(task, util.titleize(chalk.green('Finished Installation'), chalk.gray(installDir)), rendererOptions.renderer);
@@ -145,22 +123,21 @@ const downloadAndUnzip = ({
145
123
  }
146
124
  }], {
147
125
  rendererOptions
148
- }); // start the tasks!
126
+ });
149
127
 
128
+ // start the tasks!
150
129
  return Promise.resolve(tasks.run());
151
130
  };
152
-
153
131
  const validateOS = () => {
154
132
  return util.getPlatformInfo().then(platformInfo => {
155
133
  return platformInfo.match(/(win32-x64|linux-x64|linux-arm64|darwin-x64|darwin-arm64)/);
156
134
  });
157
135
  };
136
+
158
137
  /**
159
138
  * Returns the version to install - either a string like `1.2.3` to be fetched
160
139
  * from the download server or a file path or HTTP URL.
161
140
  */
162
-
163
-
164
141
  function getVersionOverride({
165
142
  arch,
166
143
  envVarVersion,
@@ -170,7 +147,6 @@ function getVersionOverride({
170
147
  if (envVarVersion) {
171
148
  return envVarVersion;
172
149
  }
173
-
174
150
  if (buildInfo && !buildInfo.stable) {
175
151
  logger.log(chalk.yellow(stripIndent`
176
152
  ${logSymbols.warning} Warning: You are installing a pre-release build of Cypress.
@@ -186,21 +162,19 @@ function getVersionOverride({
186
162
  return _getBinaryUrlFromBuildInfo(arch, buildInfo);
187
163
  }
188
164
  }
189
-
190
165
  function getEnvVarVersion() {
191
- if (!util.getEnv('CYPRESS_INSTALL_BINARY')) return; // because passed file paths are often double quoted
192
- // and might have extra whitespace around, be robust and trim the string
166
+ if (!util.getEnv('CYPRESS_INSTALL_BINARY')) return;
193
167
 
168
+ // because passed file paths are often double quoted
169
+ // and might have extra whitespace around, be robust and trim the string
194
170
  const trimAndRemoveDoubleQuotes = true;
195
171
  const envVarVersion = util.getEnv('CYPRESS_INSTALL_BINARY', trimAndRemoveDoubleQuotes);
196
172
  debug('using environment variable CYPRESS_INSTALL_BINARY "%s"', envVarVersion);
197
173
  return envVarVersion;
198
174
  }
199
-
200
175
  const start = async (options = {}) => {
201
176
  debug('installing with options %j', options);
202
177
  const envVarVersion = getEnvVarVersion();
203
-
204
178
  if (envVarVersion === '0') {
205
179
  debug('environment variable CYPRESS_INSTALL_BINARY = 0, skipping install');
206
180
  logger.log(stripIndent`
@@ -208,12 +182,10 @@ const start = async (options = {}) => {
208
182
  logger.log();
209
183
  return;
210
184
  }
211
-
212
185
  _.defaults(options, {
213
186
  force: false,
214
187
  buildInfo
215
188
  });
216
-
217
189
  if (util.getEnv('CYPRESS_CACHE_FOLDER')) {
218
190
  const envCache = util.getEnv('CYPRESS_CACHE_FOLDER');
219
191
  logger.log(stripIndent`
@@ -223,7 +195,6 @@ const start = async (options = {}) => {
223
195
  `);
224
196
  logger.log();
225
197
  }
226
-
227
198
  const pkgVersion = util.pkgVersion();
228
199
  const arch = await util.getRealArch();
229
200
  const versionOverride = getVersionOverride({
@@ -236,11 +207,9 @@ const start = async (options = {}) => {
236
207
  const installDir = state.getVersionDir(pkgVersion, options.buildInfo);
237
208
  const cacheDir = state.getCacheDir();
238
209
  const binaryDir = state.getBinaryDir(pkgVersion);
239
-
240
210
  if (!(await validateOS())) {
241
211
  return throwFormErrorText(errors.invalidOS)();
242
212
  }
243
-
244
213
  await fs.ensureDirAsync(cacheDir).catch({
245
214
  code: 'EACCES'
246
215
  }, err => {
@@ -252,38 +221,32 @@ const start = async (options = {}) => {
252
221
  });
253
222
  const binaryPkg = await state.getBinaryPkgAsync(binaryDir);
254
223
  const binaryVersion = await state.getBinaryPkgVersion(binaryPkg);
255
-
256
224
  const shouldInstall = () => {
257
225
  if (!binaryVersion) {
258
226
  debug('no binary installed under cli version');
259
227
  return true;
260
228
  }
261
-
262
229
  logger.log();
263
230
  logger.log(stripIndent`
264
231
  Cypress ${chalk.green(binaryVersion)} is installed in ${chalk.cyan(installDir)}
265
232
  `);
266
233
  logger.log();
267
-
268
234
  if (options.force) {
269
235
  debug('performing force install over existing binary');
270
236
  return true;
271
237
  }
272
-
273
238
  if (binaryVersion === versionToInstall || !util.isSemver(versionToInstall)) {
274
239
  // our version matches, tell the user this is a noop
275
240
  alreadyInstalledMsg();
276
241
  return false;
277
242
  }
278
-
279
243
  return true;
280
- }; // noop if we've been told not to download
281
-
244
+ };
282
245
 
246
+ // noop if we've been told not to download
283
247
  if (!shouldInstall()) {
284
248
  return debug('Not downloading or installing binary');
285
249
  }
286
-
287
250
  if (envVarVersion) {
288
251
  logger.log(chalk.yellow(stripIndent`
289
252
  ${logSymbols.warning} Warning: Forcing a binary version different than the default.
@@ -296,26 +259,22 @@ const start = async (options = {}) => {
296
259
  `));
297
260
  logger.log();
298
261
  }
299
-
300
262
  const getLocalFilePath = async () => {
301
263
  // see if version supplied is a path to a binary
302
264
  if (await fs.pathExistsAsync(versionToInstall)) {
303
265
  return path.extname(versionToInstall) === '.zip' ? versionToInstall : false;
304
266
  }
305
-
306
267
  const possibleFile = util.formAbsolutePath(versionToInstall);
307
- debug('checking local file', possibleFile, 'cwd', process.cwd()); // if this exists return the path to it
308
- // else false
268
+ debug('checking local file', possibleFile, 'cwd', process.cwd());
309
269
 
270
+ // if this exists return the path to it
271
+ // else false
310
272
  if ((await fs.pathExistsAsync(possibleFile)) && path.extname(possibleFile) === '.zip') {
311
273
  return possibleFile;
312
274
  }
313
-
314
275
  return false;
315
276
  };
316
-
317
277
  const pathToLocalFile = await getLocalFilePath();
318
-
319
278
  if (pathToLocalFile) {
320
279
  const absolutePath = path.resolve(versionToInstall);
321
280
  debug('found local file at', absolutePath);
@@ -333,29 +292,26 @@ const start = async (options = {}) => {
333
292
  rendererOptions
334
293
  }).run();
335
294
  }
336
-
337
295
  if (options.force) {
338
296
  debug('Cypress already installed at', installDir);
339
297
  debug('but the installation was forced');
340
298
  }
341
-
342
299
  debug('preparing to download and unzip version ', versionToInstall, 'to path', installDir);
343
300
  const downloadDir = os.tmpdir();
344
301
  await downloadAndUnzip({
345
302
  version: versionToInstall,
346
303
  installDir,
347
304
  downloadDir
348
- }); // delay 1 sec for UX, unless we are testing
305
+ });
349
306
 
307
+ // delay 1 sec for UX, unless we are testing
350
308
  await Promise.delay(1000);
351
309
  displayCompletionMsg();
352
310
  };
353
-
354
311
  module.exports = {
355
312
  start,
356
313
  _getBinaryUrlFromBuildInfo
357
314
  };
358
-
359
315
  const unzipTask = ({
360
316
  zipFilePath,
361
317
  installDir,
@@ -379,27 +335,25 @@ const unzipTask = ({
379
335
  }
380
336
  };
381
337
  };
382
-
383
338
  const progessify = (task, title) => {
384
339
  // return higher order function
385
340
  return (percentComplete, remaining) => {
386
- percentComplete = chalk.white(` ${percentComplete}%`); // pluralize seconds remaining
341
+ percentComplete = chalk.white(` ${percentComplete}%`);
387
342
 
343
+ // pluralize seconds remaining
388
344
  remaining = chalk.gray(`${remaining}s`);
389
345
  util.setTaskTitle(task, util.titleize(title, percentComplete, remaining), getRendererOptions().renderer);
390
346
  };
391
- }; // if we are running in CI then use
347
+ };
348
+
349
+ // if we are running in CI then use
392
350
  // the verbose renderer else use
393
351
  // the default
394
-
395
-
396
352
  const getRendererOptions = () => {
397
353
  let renderer = util.isCi() ? verbose : 'default';
398
-
399
354
  if (logger.logLevel() === 'silent') {
400
355
  renderer = 'silent';
401
356
  }
402
-
403
357
  return {
404
358
  renderer
405
359
  };
@@ -1,111 +1,83 @@
1
1
  "use strict";
2
2
 
3
3
  const _ = require('lodash');
4
-
5
4
  const os = require('os');
6
-
7
5
  const path = require('path');
8
-
9
6
  const untildify = require('untildify');
10
-
11
7
  const debug = require('debug')('cypress:cli');
12
-
13
8
  const fs = require('../fs');
14
-
15
9
  const util = require('../util');
16
-
17
10
  const getPlatformExecutable = () => {
18
11
  const platform = os.platform();
19
-
20
12
  switch (platform) {
21
13
  case 'darwin':
22
14
  return 'Contents/MacOS/Cypress';
23
-
24
15
  case 'linux':
25
16
  return 'Cypress';
26
-
27
17
  case 'win32':
28
18
  return 'Cypress.exe';
29
19
  // TODO handle this error using our standard
30
-
31
20
  default:
32
21
  throw new Error(`Platform: "${platform}" is not supported.`);
33
22
  }
34
23
  };
35
-
36
24
  const getPlatFormBinaryFolder = () => {
37
25
  const platform = os.platform();
38
-
39
26
  switch (platform) {
40
27
  case 'darwin':
41
28
  return 'Cypress.app';
42
-
43
29
  case 'linux':
44
30
  return 'Cypress';
45
-
46
31
  case 'win32':
47
32
  return 'Cypress';
48
33
  // TODO handle this error using our standard
49
-
50
34
  default:
51
35
  throw new Error(`Platform: "${platform}" is not supported.`);
52
36
  }
53
37
  };
54
-
55
38
  const getBinaryPkgPath = binaryDir => {
56
39
  const platform = os.platform();
57
-
58
40
  switch (platform) {
59
41
  case 'darwin':
60
42
  return path.join(binaryDir, 'Contents', 'Resources', 'app', 'package.json');
61
-
62
43
  case 'linux':
63
44
  return path.join(binaryDir, 'resources', 'app', 'package.json');
64
-
65
45
  case 'win32':
66
46
  return path.join(binaryDir, 'resources', 'app', 'package.json');
67
47
  // TODO handle this error using our standard
68
-
69
48
  default:
70
49
  throw new Error(`Platform: "${platform}" is not supported.`);
71
50
  }
72
51
  };
52
+
73
53
  /**
74
54
  * Get path to binary directory
75
55
  */
76
-
77
-
78
56
  const getBinaryDir = (version = util.pkgVersion()) => {
79
57
  return path.join(getVersionDir(version), getPlatFormBinaryFolder());
80
58
  };
81
-
82
59
  const getVersionDir = (version = util.pkgVersion(), buildInfo = util.pkgBuildInfo()) => {
83
60
  if (buildInfo && !buildInfo.stable) {
84
61
  version = ['beta', version, buildInfo.commitBranch, buildInfo.commitSha.slice(0, 8)].join('-');
85
62
  }
86
-
87
63
  return path.join(getCacheDir(), version);
88
64
  };
65
+
89
66
  /**
90
67
  * When executing "npm postinstall" hook, the working directory is set to
91
68
  * "<current folder>/node_modules/cypress", which can be surprising when using relative paths.
92
69
  */
93
-
94
-
95
70
  const isInstallingFromPostinstallHook = () => {
96
71
  // individual folders
97
72
  const cwdFolders = process.cwd().split(path.sep);
98
73
  const length = cwdFolders.length;
99
74
  return cwdFolders[length - 2] === 'node_modules' && cwdFolders[length - 1] === 'cypress';
100
75
  };
101
-
102
76
  const getCacheDir = () => {
103
77
  let cache_directory = util.getCacheDir();
104
-
105
78
  if (util.getEnv('CYPRESS_CACHE_FOLDER')) {
106
79
  const envVarCacheDir = untildify(util.getEnv('CYPRESS_CACHE_FOLDER'));
107
80
  debug('using environment variable CYPRESS_CACHE_FOLDER %s', envVarCacheDir);
108
-
109
81
  if (!path.isAbsolute(envVarCacheDir) && isInstallingFromPostinstallHook()) {
110
82
  const packageRootFolder = path.join('..', '..', envVarCacheDir);
111
83
  cache_directory = path.resolve(packageRootFolder);
@@ -115,40 +87,32 @@ const getCacheDir = () => {
115
87
  cache_directory = path.resolve(envVarCacheDir);
116
88
  }
117
89
  }
118
-
119
90
  return cache_directory;
120
91
  };
121
-
122
92
  const parseRealPlatformBinaryFolderAsync = binaryPath => {
123
93
  return fs.realpathAsync(binaryPath).then(realPath => {
124
94
  debug('CYPRESS_RUN_BINARY has realpath:', realPath);
125
-
126
95
  if (!realPath.toString().endsWith(getPlatformExecutable())) {
127
96
  return false;
128
97
  }
129
-
130
98
  if (os.platform() === 'darwin') {
131
99
  return path.resolve(realPath, '..', '..', '..');
132
100
  }
133
-
134
101
  return path.resolve(realPath, '..');
135
102
  });
136
103
  };
137
-
138
104
  const getDistDir = () => {
139
105
  return path.join(__dirname, '..', '..', 'dist');
140
106
  };
107
+
141
108
  /**
142
109
  * Returns full filename to the file that keeps the Test Runner verification state as JSON text.
143
110
  * Note: the binary state file will be stored one level up from the given binary folder.
144
111
  * @param {string} binaryDir - full path to the folder holding the binary.
145
112
  */
146
-
147
-
148
113
  const getBinaryStatePath = binaryDir => {
149
114
  return path.join(binaryDir, '..', 'binary_state.json');
150
115
  };
151
-
152
116
  const getBinaryStateContentsAsync = binaryDir => {
153
117
  const fullPath = getBinaryStatePath(binaryDir);
154
118
  return fs.readJsonAsync(fullPath).catch({
@@ -158,22 +122,19 @@ const getBinaryStateContentsAsync = binaryDir => {
158
122
  return {};
159
123
  });
160
124
  };
161
-
162
125
  const getBinaryVerifiedAsync = binaryDir => {
163
126
  return getBinaryStateContentsAsync(binaryDir).tap(debug).get('verified');
164
127
  };
165
-
166
128
  const clearBinaryStateAsync = binaryDir => {
167
129
  return fs.removeAsync(getBinaryStatePath(binaryDir));
168
130
  };
131
+
169
132
  /**
170
133
  * Writes the new binary status.
171
134
  * @param {boolean} verified The new test runner state after smoke test
172
135
  * @param {string} binaryDir Folder holding the binary
173
136
  * @returns {Promise<void>} returns a promise
174
137
  */
175
-
176
-
177
138
  const writeBinaryVerifiedAsync = (verified, binaryDir) => {
178
139
  return getBinaryStateContentsAsync(binaryDir).then(contents => {
179
140
  return fs.outputJsonAsync(getBinaryStatePath(binaryDir), _.extend(contents, {
@@ -183,16 +144,14 @@ const writeBinaryVerifiedAsync = (verified, binaryDir) => {
183
144
  });
184
145
  });
185
146
  };
186
-
187
147
  const getPathToExecutable = binaryDir => {
188
148
  return path.join(binaryDir, getPlatformExecutable());
189
149
  };
150
+
190
151
  /**
191
152
  * Resolves with an object read from the binary app package.json file.
192
153
  * If the file does not exist resolves with null
193
154
  */
194
-
195
-
196
155
  const getBinaryPkgAsync = binaryDir => {
197
156
  const pathToPackageJson = getBinaryPkgPath(binaryDir);
198
157
  debug('Reading binary package.json from:', pathToPackageJson);
@@ -200,17 +159,12 @@ const getBinaryPkgAsync = binaryDir => {
200
159
  if (!exists) {
201
160
  return null;
202
161
  }
203
-
204
162
  return fs.readJsonAsync(pathToPackageJson);
205
163
  });
206
164
  };
207
-
208
165
  const getBinaryPkgVersion = o => _.get(o, 'version', null);
209
-
210
166
  const getBinaryElectronVersion = o => _.get(o, 'electronVersion', null);
211
-
212
167
  const getBinaryElectronNodeVersion = o => _.get(o, 'electronNodeVersion', null);
213
-
214
168
  module.exports = {
215
169
  getPathToExecutable,
216
170
  getPlatformExecutable,