cypress 12.1.0 → 12.3.0
Sign up to get free protection for your applications and to get access to all the features.
- package/angular/dist/index.js +1 -1
- package/index.js +2 -11
- package/lib/VerboseRenderer.js +2 -16
- package/lib/cli.js +25 -83
- package/lib/cypress.js +1 -14
- package/lib/errors.js +13 -38
- package/lib/exec/info.js +10 -31
- package/lib/exec/open.js +1 -24
- package/lib/exec/run.js +15 -52
- package/lib/exec/shared.js +6 -15
- package/lib/exec/spawn.js +45 -88
- package/lib/exec/versions.js +0 -9
- package/lib/exec/xvfb.js +5 -18
- package/lib/fs.js +0 -1
- package/lib/logger.js +3 -10
- package/lib/tasks/cache.js +5 -29
- package/lib/tasks/download.js +21 -57
- package/lib/tasks/get-folder-size.js +1 -9
- package/lib/tasks/install.js +20 -66
- package/lib/tasks/state.js +5 -51
- package/lib/tasks/unzip.js +7 -41
- package/lib/tasks/verify.js +11 -65
- package/lib/util.js +41 -128
- package/mount-utils/package.json +2 -2
- package/package.json +3 -3
- package/react/dist/cypress-react.cjs.js +8 -15
- package/react/dist/cypress-react.esm-bundler.js +1 -1
- package/react/package.json +1 -1
- package/react18/dist/cypress-react.cjs.js +7 -13
- package/react18/dist/cypress-react.esm-bundler.js +1 -1
- package/react18/package.json +1 -1
- package/svelte/dist/cypress-svelte.cjs.js +2 -4
- package/svelte/dist/cypress-svelte.esm-bundler.js +2 -2
- package/types/cypress.d.ts +11 -6
- package/types/net-stubbing.d.ts +11 -0
- package/vue/dist/cypress-vue.cjs.js +4 -7
- package/vue/dist/cypress-vue.esm-bundler.js +1 -1
- package/vue/package.json +1 -1
- package/vue2/dist/cypress-vue2.cjs.js +19 -28
- package/vue2/dist/cypress-vue2.esm-bundler.js +1 -4
package/lib/tasks/cache.js
CHANGED
@@ -1,49 +1,35 @@
|
|
1
1
|
"use strict";
|
2
2
|
|
3
3
|
const state = require('./state');
|
4
|
-
|
5
4
|
const logger = require('../logger');
|
6
|
-
|
7
5
|
const fs = require('../fs');
|
8
|
-
|
9
6
|
const util = require('../util');
|
10
|
-
|
11
7
|
const {
|
12
8
|
join
|
13
9
|
} = require('path');
|
14
|
-
|
15
10
|
const Table = require('cli-table3');
|
16
|
-
|
17
11
|
const dayjs = require('dayjs');
|
18
|
-
|
19
12
|
const relativeTime = require('dayjs/plugin/relativeTime');
|
20
|
-
|
21
13
|
const chalk = require('chalk');
|
22
|
-
|
23
14
|
const _ = require('lodash');
|
24
|
-
|
25
15
|
const getFolderSize = require('./get-folder-size');
|
26
|
-
|
27
16
|
const Bluebird = require('bluebird');
|
17
|
+
dayjs.extend(relativeTime);
|
28
18
|
|
29
|
-
|
30
|
-
|
19
|
+
// output colors for the table
|
31
20
|
const colors = {
|
32
21
|
titles: chalk.white,
|
33
22
|
dates: chalk.cyan,
|
34
23
|
values: chalk.green,
|
35
24
|
size: chalk.gray
|
36
25
|
};
|
37
|
-
|
38
26
|
const logCachePath = () => {
|
39
27
|
logger.always(state.getCacheDir());
|
40
28
|
return undefined;
|
41
29
|
};
|
42
|
-
|
43
30
|
const clear = () => {
|
44
31
|
return fs.removeAsync(state.getCacheDir());
|
45
32
|
};
|
46
|
-
|
47
33
|
const prune = () => {
|
48
34
|
const cacheDir = state.getCacheDir();
|
49
35
|
const currentVersion = util.pkgVersion();
|
@@ -68,24 +54,20 @@ const prune = () => {
|
|
68
54
|
logger.always(`No Cypress cache was found at ${cacheDir}. Nothing to prune.`);
|
69
55
|
});
|
70
56
|
};
|
71
|
-
|
72
57
|
const fileSizeInMB = size => {
|
73
58
|
return `${(size / 1024 / 1024).toFixed(1)}MB`;
|
74
59
|
};
|
60
|
+
|
75
61
|
/**
|
76
62
|
* Collects all cached versions, finds when each was used
|
77
63
|
* and prints a table with results to the terminal
|
78
64
|
*/
|
79
|
-
|
80
|
-
|
81
65
|
const list = showSize => {
|
82
66
|
return getCachedVersions(showSize).then(binaries => {
|
83
67
|
const head = [colors.titles('version'), colors.titles('last used')];
|
84
|
-
|
85
68
|
if (showSize) {
|
86
69
|
head.push(colors.titles('size'));
|
87
70
|
}
|
88
|
-
|
89
71
|
const table = new Table({
|
90
72
|
head
|
91
73
|
});
|
@@ -93,18 +75,15 @@ const list = showSize => {
|
|
93
75
|
const versionString = colors.values(binary.version);
|
94
76
|
const lastUsed = binary.accessed ? colors.dates(binary.accessed) : 'unknown';
|
95
77
|
const row = [versionString, lastUsed];
|
96
|
-
|
97
78
|
if (showSize) {
|
98
79
|
const size = colors.size(fileSizeInMB(binary.size));
|
99
80
|
row.push(size);
|
100
81
|
}
|
101
|
-
|
102
82
|
return table.push(row);
|
103
83
|
});
|
104
84
|
logger.always(table.toString());
|
105
85
|
});
|
106
86
|
};
|
107
|
-
|
108
87
|
const getCachedVersions = showSize => {
|
109
88
|
const cacheDir = state.getCacheDir();
|
110
89
|
return fs.readdirAsync(cacheDir).filter(util.isSemver).map(version => {
|
@@ -119,13 +98,11 @@ const getCachedVersions = showSize => {
|
|
119
98
|
const executable = state.getPathToExecutable(binaryDir);
|
120
99
|
return fs.statAsync(executable).then(stat => {
|
121
100
|
const lastAccessedTime = _.get(stat, 'atime');
|
122
|
-
|
123
101
|
if (!lastAccessedTime) {
|
124
102
|
// the test runner has never been opened
|
125
103
|
// or could be a test simulating missing timestamp
|
126
104
|
return binary;
|
127
105
|
}
|
128
|
-
|
129
106
|
const accessed = dayjs(lastAccessedTime).fromNow();
|
130
107
|
binary.accessed = accessed;
|
131
108
|
return binary;
|
@@ -137,16 +114,15 @@ const getCachedVersions = showSize => {
|
|
137
114
|
if (showSize) {
|
138
115
|
const binaryDir = state.getBinaryDir(binary.version);
|
139
116
|
return getFolderSize(binaryDir).then(size => {
|
140
|
-
return {
|
117
|
+
return {
|
118
|
+
...binary,
|
141
119
|
size
|
142
120
|
};
|
143
121
|
});
|
144
122
|
}
|
145
|
-
|
146
123
|
return binary;
|
147
124
|
});
|
148
125
|
};
|
149
|
-
|
150
126
|
module.exports = {
|
151
127
|
path: logCachePath,
|
152
128
|
clear,
|
package/lib/tasks/download.js
CHANGED
@@ -1,59 +1,39 @@
|
|
1
1
|
"use strict";
|
2
2
|
|
3
3
|
const la = require('lazy-ass');
|
4
|
-
|
5
4
|
const is = require('check-more-types');
|
6
|
-
|
7
5
|
const os = require('os');
|
8
|
-
|
9
6
|
const url = require('url');
|
10
|
-
|
11
7
|
const path = require('path');
|
12
|
-
|
13
8
|
const debug = require('debug')('cypress:cli');
|
14
|
-
|
15
9
|
const request = require('@cypress/request');
|
16
|
-
|
17
10
|
const Promise = require('bluebird');
|
18
|
-
|
19
11
|
const requestProgress = require('request-progress');
|
20
|
-
|
21
12
|
const {
|
22
13
|
stripIndent
|
23
14
|
} = require('common-tags');
|
24
|
-
|
25
15
|
const getProxyForUrl = require('proxy-from-env').getProxyForUrl;
|
26
|
-
|
27
16
|
const {
|
28
17
|
throwFormErrorText,
|
29
18
|
errors
|
30
19
|
} = require('../errors');
|
31
|
-
|
32
20
|
const fs = require('../fs');
|
33
|
-
|
34
21
|
const util = require('../util');
|
35
|
-
|
36
22
|
const defaultBaseUrl = 'https://download.cypress.io/';
|
37
23
|
const defaultMaxRedirects = 10;
|
38
|
-
|
39
24
|
const getProxyForUrlWithNpmConfig = url => {
|
40
25
|
return getProxyForUrl(url) || process.env.npm_config_https_proxy || process.env.npm_config_proxy || null;
|
41
26
|
};
|
42
|
-
|
43
27
|
const getBaseUrl = () => {
|
44
28
|
if (util.getEnv('CYPRESS_DOWNLOAD_MIRROR')) {
|
45
29
|
let baseUrl = util.getEnv('CYPRESS_DOWNLOAD_MIRROR');
|
46
|
-
|
47
30
|
if (!baseUrl.endsWith('/')) {
|
48
31
|
baseUrl += '/';
|
49
32
|
}
|
50
|
-
|
51
33
|
return baseUrl;
|
52
34
|
}
|
53
|
-
|
54
35
|
return defaultBaseUrl;
|
55
36
|
};
|
56
|
-
|
57
37
|
const getCA = () => {
|
58
38
|
return new Promise(resolve => {
|
59
39
|
if (process.env.npm_config_cafile) {
|
@@ -69,28 +49,23 @@ const getCA = () => {
|
|
69
49
|
}
|
70
50
|
});
|
71
51
|
};
|
72
|
-
|
73
52
|
const prepend = (arch, urlPath, version) => {
|
74
53
|
const endpoint = url.resolve(getBaseUrl(), urlPath);
|
75
54
|
const platform = os.platform();
|
76
55
|
const pathTemplate = util.getEnv('CYPRESS_DOWNLOAD_PATH_TEMPLATE', true);
|
77
56
|
return pathTemplate ? pathTemplate.replace(/\\?\$\{endpoint\}/, endpoint).replace(/\\?\$\{platform\}/, platform).replace(/\\?\$\{arch\}/, arch).replace(/\\?\$\{version\}/, version) : `${endpoint}?platform=${platform}&arch=${arch}`;
|
78
57
|
};
|
79
|
-
|
80
58
|
const getUrl = (arch, version) => {
|
81
59
|
if (is.url(version)) {
|
82
60
|
debug('version is already an url', version);
|
83
61
|
return version;
|
84
62
|
}
|
85
|
-
|
86
63
|
const urlPath = version ? `desktop/${version}` : 'desktop';
|
87
64
|
return prepend(arch, urlPath, version);
|
88
65
|
};
|
89
|
-
|
90
66
|
const statusMessage = err => {
|
91
67
|
return err.statusCode ? [err.statusCode, err.statusMessage].join(' - ') : err.toString();
|
92
68
|
};
|
93
|
-
|
94
69
|
const prettyDownloadErr = (err, url) => {
|
95
70
|
const msg = stripIndent`
|
96
71
|
URL: ${url}
|
@@ -99,12 +74,11 @@ const prettyDownloadErr = (err, url) => {
|
|
99
74
|
debug(msg);
|
100
75
|
return throwFormErrorText(errors.failedDownload)(msg);
|
101
76
|
};
|
77
|
+
|
102
78
|
/**
|
103
79
|
* Checks checksum and file size for the given file. Allows both
|
104
80
|
* values or just one of them to be checked.
|
105
81
|
*/
|
106
|
-
|
107
|
-
|
108
82
|
const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => {
|
109
83
|
if (expectedSize && expectedChecksum) {
|
110
84
|
debug('verifying checksum and file size');
|
@@ -113,7 +87,6 @@ const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => {
|
|
113
87
|
debug('downloaded file has the expected checksum and size ✅');
|
114
88
|
return;
|
115
89
|
}
|
116
|
-
|
117
90
|
debug('raising error: checksum or file size mismatch');
|
118
91
|
const text = stripIndent`
|
119
92
|
Corrupted download
|
@@ -128,7 +101,6 @@ const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => {
|
|
128
101
|
throw new Error(text);
|
129
102
|
});
|
130
103
|
}
|
131
|
-
|
132
104
|
if (expectedChecksum) {
|
133
105
|
debug('only checking expected file checksum %d', expectedChecksum);
|
134
106
|
return util.getFileChecksum(filename).then(checksum => {
|
@@ -136,7 +108,6 @@ const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => {
|
|
136
108
|
debug('downloaded file has the expected checksum ✅');
|
137
109
|
return;
|
138
110
|
}
|
139
|
-
|
140
111
|
debug('raising error: file checksum mismatch');
|
141
112
|
const text = stripIndent`
|
142
113
|
Corrupted download
|
@@ -147,7 +118,6 @@ const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => {
|
|
147
118
|
throw new Error(text);
|
148
119
|
});
|
149
120
|
}
|
150
|
-
|
151
121
|
if (expectedSize) {
|
152
122
|
// maybe we don't have a checksum, but at least CDN returns content length
|
153
123
|
// which we can check against the file size
|
@@ -157,7 +127,6 @@ const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => {
|
|
157
127
|
debug('downloaded file has the expected size ✅');
|
158
128
|
return;
|
159
129
|
}
|
160
|
-
|
161
130
|
debug('raising error: file size mismatch');
|
162
131
|
const text = stripIndent`
|
163
132
|
Corrupted download
|
@@ -168,14 +137,13 @@ const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => {
|
|
168
137
|
throw new Error(text);
|
169
138
|
});
|
170
139
|
}
|
171
|
-
|
172
140
|
debug('downloaded file lacks checksum or size to verify');
|
173
141
|
return Promise.resolve();
|
174
|
-
};
|
142
|
+
};
|
143
|
+
|
144
|
+
// downloads from given url
|
175
145
|
// return an object with
|
176
146
|
// {filename: ..., downloaded: true}
|
177
|
-
|
178
|
-
|
179
147
|
const downloadFromUrl = ({
|
180
148
|
url,
|
181
149
|
downloadDestination,
|
@@ -191,7 +159,6 @@ const downloadFromUrl = ({
|
|
191
159
|
Maybe you got stuck in a redirect loop?
|
192
160
|
`));
|
193
161
|
}
|
194
|
-
|
195
162
|
return new Promise((resolve, reject) => {
|
196
163
|
const proxy = getProxyForUrlWithNpmConfig(url);
|
197
164
|
debug('Downloading package', {
|
@@ -199,11 +166,9 @@ const downloadFromUrl = ({
|
|
199
166
|
proxy,
|
200
167
|
downloadDestination
|
201
168
|
});
|
202
|
-
|
203
169
|
if (ca) {
|
204
170
|
debug('using custom CA details from npm config');
|
205
171
|
}
|
206
|
-
|
207
172
|
const reqOptions = {
|
208
173
|
uri: url,
|
209
174
|
...(proxy ? {
|
@@ -217,8 +182,9 @@ const downloadFromUrl = ({
|
|
217
182
|
method: 'GET',
|
218
183
|
followRedirect: false
|
219
184
|
};
|
220
|
-
const req = request(reqOptions);
|
185
|
+
const req = request(reqOptions);
|
221
186
|
|
187
|
+
// closure
|
222
188
|
let started = null;
|
223
189
|
let expectedSize;
|
224
190
|
let expectedChecksum;
|
@@ -231,21 +197,18 @@ const downloadFromUrl = ({
|
|
231
197
|
// see https://github.com/cypress-io/cypress/pull/4092
|
232
198
|
expectedSize = response.headers['x-amz-meta-size'] || response.headers['content-length'];
|
233
199
|
expectedChecksum = response.headers['x-amz-meta-checksum'];
|
234
|
-
|
235
200
|
if (expectedChecksum) {
|
236
201
|
debug('expected checksum %s', expectedChecksum);
|
237
202
|
}
|
238
|
-
|
239
203
|
if (expectedSize) {
|
240
204
|
// convert from string (all Amazon custom headers are strings)
|
241
205
|
expectedSize = Number(expectedSize);
|
242
206
|
debug('expected file size %d', expectedSize);
|
243
|
-
}
|
244
|
-
// response headers
|
245
|
-
|
207
|
+
}
|
246
208
|
|
209
|
+
// start counting now once we've gotten
|
210
|
+
// response headers
|
247
211
|
started = new Date();
|
248
|
-
|
249
212
|
if (/^3/.test(response.statusCode)) {
|
250
213
|
const redirectVersion = response.headers['x-version'];
|
251
214
|
const redirectUrl = response.headers.location;
|
@@ -258,7 +221,9 @@ const downloadFromUrl = ({
|
|
258
221
|
downloadDestination,
|
259
222
|
version: redirectVersion,
|
260
223
|
redirectTTL: redirectTTL - 1
|
261
|
-
}).then(resolve).catch(reject);
|
224
|
+
}).then(resolve).catch(reject);
|
225
|
+
|
226
|
+
// if our status code does not start with 200
|
262
227
|
} else if (!/^2/.test(response.statusCode)) {
|
263
228
|
debug('response code %d', response.statusCode);
|
264
229
|
const err = new Error(stripIndent`
|
@@ -266,7 +231,8 @@ const downloadFromUrl = ({
|
|
266
231
|
Response code: ${response.statusCode}
|
267
232
|
Response message: ${response.statusMessage}
|
268
233
|
`);
|
269
|
-
reject(err);
|
234
|
+
reject(err);
|
235
|
+
// status codes here are all 2xx
|
270
236
|
} else {
|
271
237
|
// We only enable this pipe connection when we know we've got a successful return
|
272
238
|
// and handle the completion with verify and resolve
|
@@ -286,22 +252,23 @@ const downloadFromUrl = ({
|
|
286
252
|
}).on('progress', state => {
|
287
253
|
// total time we've elapsed
|
288
254
|
// starting on our first progress notification
|
289
|
-
const elapsed = new Date() - started;
|
255
|
+
const elapsed = new Date() - started;
|
290
256
|
|
257
|
+
// request-progress sends a value between 0 and 1
|
291
258
|
const percentage = util.convertPercentToPercentage(state.percent);
|
292
|
-
const eta = util.calculateEta(percentage, elapsed);
|
259
|
+
const eta = util.calculateEta(percentage, elapsed);
|
293
260
|
|
261
|
+
// send up our percent and seconds remaining
|
294
262
|
progress.onProgress(percentage, util.secsRemaining(eta));
|
295
263
|
});
|
296
264
|
});
|
297
265
|
};
|
266
|
+
|
298
267
|
/**
|
299
268
|
* Download Cypress.zip from external versionUrl to local file.
|
300
269
|
* @param [string] version Could be "3.3.0" or full URL
|
301
270
|
* @param [string] downloadDestination Local filename to save as
|
302
271
|
*/
|
303
|
-
|
304
|
-
|
305
272
|
const start = async opts => {
|
306
273
|
let {
|
307
274
|
version,
|
@@ -309,11 +276,9 @@ const start = async opts => {
|
|
309
276
|
progress,
|
310
277
|
redirectTTL
|
311
278
|
} = opts;
|
312
|
-
|
313
279
|
if (!downloadDestination) {
|
314
280
|
la(is.unemptyString(downloadDestination), 'missing download dir', opts);
|
315
281
|
}
|
316
|
-
|
317
282
|
if (!progress) {
|
318
283
|
progress = {
|
319
284
|
onProgress: () => {
|
@@ -321,14 +286,14 @@ const start = async opts => {
|
|
321
286
|
}
|
322
287
|
};
|
323
288
|
}
|
324
|
-
|
325
289
|
const arch = await util.getRealArch();
|
326
290
|
const versionUrl = getUrl(arch, version);
|
327
291
|
progress.throttle = 100;
|
328
292
|
debug('needed Cypress version: %s', version);
|
329
293
|
debug('source url %s', versionUrl);
|
330
|
-
debug(`downloading cypress.zip to "${downloadDestination}"`);
|
294
|
+
debug(`downloading cypress.zip to "${downloadDestination}"`);
|
331
295
|
|
296
|
+
// ensure download dir exists
|
332
297
|
return fs.ensureDirAsync(path.dirname(downloadDestination)).then(() => {
|
333
298
|
return getCA();
|
334
299
|
}).then(ca => {
|
@@ -346,7 +311,6 @@ const start = async opts => {
|
|
346
311
|
return prettyDownloadErr(err, versionUrl);
|
347
312
|
});
|
348
313
|
};
|
349
|
-
|
350
314
|
module.exports = {
|
351
315
|
start,
|
352
316
|
getUrl,
|
@@ -1,12 +1,11 @@
|
|
1
1
|
"use strict";
|
2
2
|
|
3
3
|
const fs = require('../fs');
|
4
|
-
|
5
4
|
const {
|
6
5
|
join
|
7
6
|
} = require('path');
|
8
|
-
|
9
7
|
const Bluebird = require('bluebird');
|
8
|
+
|
10
9
|
/**
|
11
10
|
* Get the size of a folder or a file.
|
12
11
|
*
|
@@ -16,26 +15,19 @@ const Bluebird = require('bluebird');
|
|
16
15
|
*
|
17
16
|
* @param {string} path path to the file or the folder.
|
18
17
|
*/
|
19
|
-
|
20
|
-
|
21
18
|
async function getSize(path) {
|
22
19
|
const stat = await fs.lstat(path);
|
23
|
-
|
24
20
|
if (stat.isDirectory()) {
|
25
21
|
const list = await fs.readdir(path);
|
26
22
|
return Bluebird.resolve(list).reduce(async (prev, curr) => {
|
27
23
|
const currPath = join(path, curr);
|
28
24
|
const s = await fs.lstat(currPath);
|
29
|
-
|
30
25
|
if (s.isDirectory()) {
|
31
26
|
return prev + (await getSize(currPath));
|
32
27
|
}
|
33
|
-
|
34
28
|
return prev + s.size;
|
35
29
|
}, 0);
|
36
30
|
}
|
37
|
-
|
38
31
|
return stat.size;
|
39
32
|
}
|
40
|
-
|
41
33
|
module.exports = getSize;
|