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