cypress 9.2.0 → 9.4.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +25 -25
- package/bin/cypress +3 -3
- package/lib/cli.js +14 -14
- package/lib/cypress.js +27 -27
- package/lib/errors.js +25 -25
- package/lib/exec/run.js +13 -13
- package/lib/exec/shared.js +8 -8
- package/lib/tasks/cache.js +3 -3
- package/lib/tasks/download.js +77 -49
- package/lib/tasks/get-folder-size.js +8 -8
- package/lib/tasks/state.js +17 -17
- package/lib/tasks/verify.js +12 -12
- package/lib/util.js +69 -53
- package/package.json +6 -5
- package/types/chai/index.d.ts +5 -5
- package/types/cy-blob-util.d.ts +13 -13
- package/types/cy-bluebird.d.ts +12 -12
- package/types/cy-chai.d.ts +10 -10
- package/types/cy-http.d.ts +13 -13
- package/types/cy-minimatch.d.ts +96 -96
- package/types/cypress-eventemitter.d.ts +33 -29
- package/types/cypress-expect.d.ts +3 -3
- package/types/cypress-global-vars.d.ts +22 -22
- package/types/cypress-npm-api.d.ts +404 -404
- package/types/cypress-type-helpers.d.ts +2 -2
- package/types/cypress.d.ts +5861 -5815
- package/types/index.d.ts +33 -33
- package/types/jquery/JQuery.d.ts +12939 -12939
- package/types/jquery/legacy.d.ts +200 -200
- package/types/jquery/misc.d.ts +6661 -6661
- package/types/minimatch/index.d.ts +0 -0
- package/types/mocha/index.d.ts +2801 -2801
- package/types/net-stubbing.ts +553 -553
- package/types/sinon/index.d.ts +227 -217
- package/types/sinon/ts3.1/index.d.ts +0 -1789
package/README.md
CHANGED
@@ -1,25 +1,25 @@
|
|
1
|
-
# Cypress
|
2
|
-
|
3
|
-
Fast, easy and reliable testing for anything that runs in a browser.
|
4
|
-
|
5
|
-
## What is this?
|
6
|
-
|
7
|
-
[Cypress](https://www.cypress.io/) comes packaged as an `npm` module, which is all you need to get started testing.
|
8
|
-
|
9
|
-
After installing you'll be able to:
|
10
|
-
|
11
|
-
- Open Cypress from the CLI
|
12
|
-
- Run Cypress from the CLI
|
13
|
-
- `require` Cypress as a module
|
14
|
-
|
15
|
-
## Install
|
16
|
-
|
17
|
-
Please check our [system requirements](https://on.cypress.io/installing-cypress).
|
18
|
-
|
19
|
-
```sh
|
20
|
-
npm install --save-dev cypress
|
21
|
-
```
|
22
|
-
|
23
|
-
## Documentation
|
24
|
-
|
25
|
-
Please [visit our documentation](https://on.cypress.io/cli) for a full list of commands and examples.
|
1
|
+
# Cypress
|
2
|
+
|
3
|
+
Fast, easy and reliable testing for anything that runs in a browser.
|
4
|
+
|
5
|
+
## What is this?
|
6
|
+
|
7
|
+
[Cypress](https://www.cypress.io/) comes packaged as an `npm` module, which is all you need to get started testing.
|
8
|
+
|
9
|
+
After installing you'll be able to:
|
10
|
+
|
11
|
+
- Open Cypress from the CLI
|
12
|
+
- Run Cypress from the CLI
|
13
|
+
- `require` Cypress as a module
|
14
|
+
|
15
|
+
## Install
|
16
|
+
|
17
|
+
Please check our [system requirements](https://on.cypress.io/installing-cypress).
|
18
|
+
|
19
|
+
```sh
|
20
|
+
npm install --save-dev cypress
|
21
|
+
```
|
22
|
+
|
23
|
+
## Documentation
|
24
|
+
|
25
|
+
Please [visit our documentation](https://on.cypress.io/cli) for a full list of commands and examples.
|
package/bin/cypress
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
#!/usr/bin/env node
|
2
|
-
|
3
|
-
require('../lib/cli').init()
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
require('../lib/cli').init()
|
package/lib/cli.js
CHANGED
@@ -223,12 +223,12 @@ const createProgram = () => {
|
|
223
223
|
const addCypressRunCommand = program => {
|
224
224
|
return program.command('run').usage('[options]').description('Runs Cypress tests from the CLI without the GUI').option('-b, --browser <browser-name-or-path>', text('browserRunMode')).option('--ci-build-id <id>', text('ciBuildId')).option('-c, --config <config>', text('config')).option('-C, --config-file <config-file>', text('configFile')).option('-e, --env <env>', text('env')).option('--group <name>', text('group')).option('-k, --key <record-key>', text('key')).option('--headed', text('headed')).option('--headless', text('headless')).option('--no-exit', text('exit')).option('--parallel', text('parallel')).option('-p, --port <port>', text('port')).option('-P, --project <project-path>', text('project')).option('-q, --quiet', text('quiet')).option('--record [bool]', text('record'), coerceFalse).option('-r, --reporter <reporter>', text('reporter')).option('-o, --reporter-options <reporter-options>', text('reporterOptions')).option('-s, --spec <spec>', text('spec')).option('-t, --tag <tag>', text('tag')).option('--dev', text('dev'), coerceFalse);
|
225
225
|
};
|
226
|
-
/**
|
227
|
-
* Casts known command line options for "cypress run" to their intended type.
|
228
|
-
* For example if the user passes "--port 5005" the ".port" property should be
|
229
|
-
* a number 5005 and not a string "5005".
|
230
|
-
*
|
231
|
-
* Returns a clone of the original object.
|
226
|
+
/**
|
227
|
+
* Casts known command line options for "cypress run" to their intended type.
|
228
|
+
* For example if the user passes "--port 5005" the ".port" property should be
|
229
|
+
* a number 5005 and not a string "5005".
|
230
|
+
*
|
231
|
+
* Returns a clone of the original object.
|
232
232
|
*/
|
233
233
|
|
234
234
|
|
@@ -251,12 +251,12 @@ const castCypressRunOptions = opts => {
|
|
251
251
|
};
|
252
252
|
|
253
253
|
module.exports = {
|
254
|
-
/**
|
255
|
-
* Parses `cypress run` command line option array into an object
|
256
|
-
* with options that you can feed into a `cypress.run()` module API call.
|
257
|
-
* @example
|
258
|
-
* const options = parseRunCommand(['cypress', 'run', '--browser', 'chrome'])
|
259
|
-
* // options is {browser: 'chrome'}
|
254
|
+
/**
|
255
|
+
* Parses `cypress run` command line option array into an object
|
256
|
+
* with options that you can feed into a `cypress.run()` module API call.
|
257
|
+
* @example
|
258
|
+
* const options = parseRunCommand(['cypress', 'run', '--browser', 'chrome'])
|
259
|
+
* // options is {browser: 'chrome'}
|
260
260
|
*/
|
261
261
|
parseRunCommand(args) {
|
262
262
|
return new Promise((resolve, reject) => {
|
@@ -284,8 +284,8 @@ module.exports = {
|
|
284
284
|
});
|
285
285
|
},
|
286
286
|
|
287
|
-
/**
|
288
|
-
* Parses the command line and kicks off Cypress process.
|
287
|
+
/**
|
288
|
+
* Parses the command line and kicks off Cypress process.
|
289
289
|
*/
|
290
290
|
init(args) {
|
291
291
|
if (!args) {
|
package/lib/cypress.js
CHANGED
@@ -16,18 +16,18 @@ const util = require('./util');
|
|
16
16
|
const cli = require('./cli');
|
17
17
|
|
18
18
|
const cypressModuleApi = {
|
19
|
-
/**
|
20
|
-
* Opens Cypress GUI
|
21
|
-
* @see https://on.cypress.io/module-api#cypress-open
|
19
|
+
/**
|
20
|
+
* Opens Cypress GUI
|
21
|
+
* @see https://on.cypress.io/module-api#cypress-open
|
22
22
|
*/
|
23
23
|
open(options = {}) {
|
24
24
|
options = util.normalizeModuleOptions(options);
|
25
25
|
return open.start(options);
|
26
26
|
},
|
27
27
|
|
28
|
-
/**
|
29
|
-
* Runs Cypress tests in the current project
|
30
|
-
* @see https://on.cypress.io/module-api#cypress-run
|
28
|
+
/**
|
29
|
+
* Runs Cypress tests in the current project
|
30
|
+
* @see https://on.cypress.io/module-api#cypress-run
|
31
31
|
*/
|
32
32
|
run(options = {}) {
|
33
33
|
if (!run.isValidProject(options.project)) {
|
@@ -56,15 +56,15 @@ const cypressModuleApi = {
|
|
56
56
|
},
|
57
57
|
|
58
58
|
cli: {
|
59
|
-
/**
|
60
|
-
* Parses CLI arguments into an object that you can pass to "cypress.run"
|
61
|
-
* @example
|
62
|
-
* const cypress = require('cypress')
|
63
|
-
* const cli = ['cypress', 'run', '--browser', 'firefox']
|
64
|
-
* const options = await cypress.cli.parseRunArguments(cli)
|
65
|
-
* // options is {browser: 'firefox'}
|
66
|
-
* await cypress.run(options)
|
67
|
-
* @see https://on.cypress.io/module-api
|
59
|
+
/**
|
60
|
+
* Parses CLI arguments into an object that you can pass to "cypress.run"
|
61
|
+
* @example
|
62
|
+
* const cypress = require('cypress')
|
63
|
+
* const cli = ['cypress', 'run', '--browser', 'firefox']
|
64
|
+
* const options = await cypress.cli.parseRunArguments(cli)
|
65
|
+
* // options is {browser: 'firefox'}
|
66
|
+
* await cypress.run(options)
|
67
|
+
* @see https://on.cypress.io/module-api
|
68
68
|
*/
|
69
69
|
parseRunArguments(args) {
|
70
70
|
return cli.parseRunCommand(args);
|
@@ -72,18 +72,18 @@ const cypressModuleApi = {
|
|
72
72
|
|
73
73
|
},
|
74
74
|
|
75
|
-
/**
|
76
|
-
* Provides automatic code completion for configuration in many popular code editors.
|
77
|
-
* While it's not strictly necessary for Cypress to parse your configuration, we
|
78
|
-
* recommend wrapping your config object with `defineConfig()`
|
79
|
-
* @example
|
80
|
-
* module.exports = defineConfig({
|
81
|
-
* viewportWith: 400
|
82
|
-
* })
|
83
|
-
*
|
84
|
-
* @see ../types/cypress-npm-api.d.ts
|
85
|
-
* @param {Cypress.ConfigOptions} config
|
86
|
-
* @returns {Cypress.ConfigOptions} the configuration passed in parameter
|
75
|
+
/**
|
76
|
+
* Provides automatic code completion for configuration in many popular code editors.
|
77
|
+
* While it's not strictly necessary for Cypress to parse your configuration, we
|
78
|
+
* recommend wrapping your config object with `defineConfig()`
|
79
|
+
* @example
|
80
|
+
* module.exports = defineConfig({
|
81
|
+
* viewportWith: 400
|
82
|
+
* })
|
83
|
+
*
|
84
|
+
* @see ../types/cypress-npm-api.d.ts
|
85
|
+
* @param {Cypress.ConfigOptions} config
|
86
|
+
* @returns {Cypress.ConfigOptions} the configuration passed in parameter
|
87
87
|
*/
|
88
88
|
defineConfig(config) {
|
89
89
|
return config;
|
package/lib/errors.js
CHANGED
@@ -208,12 +208,12 @@ const invalidTestingType = {
|
|
208
208
|
description: 'Invalid testingType',
|
209
209
|
solution: `Please provide a valid testingType. Valid test types are ${chalk.cyan('\'e2e\'')} and ${chalk.cyan('\'component\'')}.`
|
210
210
|
};
|
211
|
-
/**
|
212
|
-
* This error happens when CLI detects that the child Test Runner process
|
213
|
-
* was killed with a signal, like SIGBUS
|
214
|
-
* @see https://github.com/cypress-io/cypress/issues/5808
|
215
|
-
* @param {'close'|'event'} eventName Child close event name
|
216
|
-
* @param {string} signal Signal that closed the child process, like "SIGBUS"
|
211
|
+
/**
|
212
|
+
* This error happens when CLI detects that the child Test Runner process
|
213
|
+
* was killed with a signal, like SIGBUS
|
214
|
+
* @see https://github.com/cypress-io/cypress/issues/5808
|
215
|
+
* @param {'close'|'event'} eventName Child close event name
|
216
|
+
* @param {string} signal Signal that closed the child process, like "SIGBUS"
|
217
217
|
*/
|
218
218
|
|
219
219
|
const childProcessKilled = (eventName, signal) => {
|
@@ -240,17 +240,17 @@ function addPlatformInformation(info) {
|
|
240
240
|
};
|
241
241
|
});
|
242
242
|
}
|
243
|
-
/**
|
244
|
-
* Given an error object (see the errors above), forms error message text with details,
|
245
|
-
* then resolves with Error instance you can throw or reject with.
|
246
|
-
* @param {object} errorObject
|
247
|
-
* @returns {Promise<Error>} resolves with an Error
|
248
|
-
* @example
|
249
|
-
```js
|
250
|
-
// inside a Promise with "resolve" and "reject"
|
251
|
-
const errorObject = childProcessKilled('exit', 'SIGKILL')
|
252
|
-
return getError(errorObject).then(reject)
|
253
|
-
```
|
243
|
+
/**
|
244
|
+
* Given an error object (see the errors above), forms error message text with details,
|
245
|
+
* then resolves with Error instance you can throw or reject with.
|
246
|
+
* @param {object} errorObject
|
247
|
+
* @returns {Promise<Error>} resolves with an Error
|
248
|
+
* @example
|
249
|
+
```js
|
250
|
+
// inside a Promise with "resolve" and "reject"
|
251
|
+
const errorObject = childProcessKilled('exit', 'SIGKILL')
|
252
|
+
return getError(errorObject).then(reject)
|
253
|
+
```
|
254
254
|
*/
|
255
255
|
|
256
256
|
|
@@ -261,9 +261,9 @@ function getError(errorObject) {
|
|
261
261
|
return err;
|
262
262
|
});
|
263
263
|
}
|
264
|
-
/**
|
265
|
-
* Forms nice error message with error and platform information,
|
266
|
-
* and if possible a way to solve it. Resolves with a string.
|
264
|
+
/**
|
265
|
+
* Forms nice error message with error and platform information,
|
266
|
+
* and if possible a way to solve it. Resolves with a string.
|
267
267
|
*/
|
268
268
|
|
269
269
|
|
@@ -343,11 +343,11 @@ const throwFormErrorText = info => {
|
|
343
343
|
return formErrorText(info, msg, prevMessage).then(raise(info));
|
344
344
|
};
|
345
345
|
};
|
346
|
-
/**
|
347
|
-
* Forms full error message with error and OS details, prints to the error output
|
348
|
-
* and then exits the process.
|
349
|
-
* @param {ErrorInformation} info Error information {description, solution}
|
350
|
-
* @example return exitWithError(errors.invalidCypressEnv)('foo')
|
346
|
+
/**
|
347
|
+
* Forms full error message with error and OS details, prints to the error output
|
348
|
+
* and then exits the process.
|
349
|
+
* @param {ErrorInformation} info Error information {description, solution}
|
350
|
+
* @example return exitWithError(errors.invalidCypressEnv)('foo')
|
351
351
|
*/
|
352
352
|
|
353
353
|
|
package/lib/exec/run.js
CHANGED
@@ -19,11 +19,11 @@ const {
|
|
19
19
|
processTestingType,
|
20
20
|
throwInvalidOptionError
|
21
21
|
} = require('./shared');
|
22
|
-
/**
|
23
|
-
* Typically a user passes a string path to the project.
|
24
|
-
* But "cypress open" allows using `false` to open in global mode,
|
25
|
-
* and the user can accidentally execute `cypress run --project false`
|
26
|
-
* which should be invalid.
|
22
|
+
/**
|
23
|
+
* Typically a user passes a string path to the project.
|
24
|
+
* But "cypress open" allows using `false` to open in global mode,
|
25
|
+
* and the user can accidentally execute `cypress run --project false`
|
26
|
+
* which should be invalid.
|
27
27
|
*/
|
28
28
|
|
29
29
|
|
@@ -38,14 +38,14 @@ const isValidProject = v => {
|
|
38
38
|
|
39
39
|
return true;
|
40
40
|
};
|
41
|
-
/**
|
42
|
-
* Maps options collected by the CLI
|
43
|
-
* and forms list of CLI arguments to the server.
|
44
|
-
*
|
45
|
-
* Note: there is lightweight validation, with errors
|
46
|
-
* thrown synchronously.
|
47
|
-
*
|
48
|
-
* @returns {string[]} list of CLI arguments
|
41
|
+
/**
|
42
|
+
* Maps options collected by the CLI
|
43
|
+
* and forms list of CLI arguments to the server.
|
44
|
+
*
|
45
|
+
* Note: there is lightweight validation, with errors
|
46
|
+
* thrown synchronously.
|
47
|
+
*
|
48
|
+
* @returns {string[]} list of CLI arguments
|
49
49
|
*/
|
50
50
|
|
51
51
|
|
package/lib/exec/shared.js
CHANGED
@@ -3,10 +3,10 @@
|
|
3
3
|
const {
|
4
4
|
errors
|
5
5
|
} = require('../errors');
|
6
|
-
/**
|
7
|
-
* Throws an error with "details" property from
|
8
|
-
* "errors" object.
|
9
|
-
* @param {Object} details - Error details
|
6
|
+
/**
|
7
|
+
* Throws an error with "details" property from
|
8
|
+
* "errors" object.
|
9
|
+
* @param {Object} details - Error details
|
10
10
|
*/
|
11
11
|
|
12
12
|
|
@@ -21,10 +21,10 @@ const throwInvalidOptionError = details => {
|
|
21
21
|
err.details = details;
|
22
22
|
throw err;
|
23
23
|
};
|
24
|
-
/**
|
25
|
-
* Selects exec args based on the configured `testingType`
|
26
|
-
* @param {string} testingType The type of tests being executed
|
27
|
-
* @returns {string[]} The array of new exec arguments
|
24
|
+
/**
|
25
|
+
* Selects exec args based on the configured `testingType`
|
26
|
+
* @param {string} testingType The type of tests being executed
|
27
|
+
* @returns {string[]} The array of new exec arguments
|
28
28
|
*/
|
29
29
|
|
30
30
|
|
package/lib/tasks/cache.js
CHANGED
@@ -72,9 +72,9 @@ const prune = () => {
|
|
72
72
|
const fileSizeInMB = size => {
|
73
73
|
return `${(size / 1024 / 1024).toFixed(1)}MB`;
|
74
74
|
};
|
75
|
-
/**
|
76
|
-
* Collects all cached versions, finds when each was used
|
77
|
-
* and prints a table with results to the terminal
|
75
|
+
/**
|
76
|
+
* Collects all cached versions, finds when each was used
|
77
|
+
* and prints a table with results to the terminal
|
78
78
|
*/
|
79
79
|
|
80
80
|
|
package/lib/tasks/download.js
CHANGED
@@ -36,6 +36,7 @@ const fs = require('../fs');
|
|
36
36
|
const util = require('../util');
|
37
37
|
|
38
38
|
const defaultBaseUrl = 'https://download.cypress.io/';
|
39
|
+
const defaultMaxRedirects = 10;
|
39
40
|
|
40
41
|
const getProxyForUrlWithNpmConfig = url => {
|
41
42
|
return getProxyForUrl(url) || process.env.npm_config_https_proxy || process.env.npm_config_proxy || null;
|
@@ -78,7 +79,8 @@ const getCA = () => {
|
|
78
79
|
const prepend = urlPath => {
|
79
80
|
const endpoint = url.resolve(getBaseUrl(), urlPath);
|
80
81
|
const platform = os.platform();
|
81
|
-
|
82
|
+
const pathTemplate = util.getEnv('CYPRESS_DOWNLOAD_PATH_TEMPLATE');
|
83
|
+
return pathTemplate ? pathTemplate.replace('${endpoint}', endpoint).replace('${platform}', platform).replace('${arch}', arch()) : `${endpoint}?platform=${platform}&arch=${arch()}`;
|
82
84
|
};
|
83
85
|
|
84
86
|
const getUrl = version => {
|
@@ -102,9 +104,9 @@ const prettyDownloadErr = (err, version) => {
|
|
102
104
|
debug(msg);
|
103
105
|
return throwFormErrorText(errors.failedDownload)(msg);
|
104
106
|
};
|
105
|
-
/**
|
106
|
-
* Checks checksum and file size for the given file. Allows both
|
107
|
-
* values or just one of them to be checked.
|
107
|
+
/**
|
108
|
+
* Checks checksum and file size for the given file. Allows both
|
109
|
+
* values or just one of them to be checked.
|
108
110
|
*/
|
109
111
|
|
110
112
|
|
@@ -183,8 +185,18 @@ const downloadFromUrl = ({
|
|
183
185
|
url,
|
184
186
|
downloadDestination,
|
185
187
|
progress,
|
186
|
-
ca
|
188
|
+
ca,
|
189
|
+
version,
|
190
|
+
redirectTTL = defaultMaxRedirects
|
187
191
|
}) => {
|
192
|
+
if (redirectTTL <= 0) {
|
193
|
+
return Promise.reject(new Error(stripIndent`
|
194
|
+
Failed downloading the Cypress binary.
|
195
|
+
There were too many redirects. The default allowance is ${defaultMaxRedirects}.
|
196
|
+
Maybe you got stuck in a redirect loop?
|
197
|
+
`));
|
198
|
+
}
|
199
|
+
|
188
200
|
return new Promise((resolve, reject) => {
|
189
201
|
const proxy = getProxyForUrlWithNpmConfig(url);
|
190
202
|
debug('Downloading package', {
|
@@ -192,35 +204,24 @@ const downloadFromUrl = ({
|
|
192
204
|
proxy,
|
193
205
|
downloadDestination
|
194
206
|
});
|
195
|
-
let redirectVersion;
|
196
|
-
const reqOptions = {
|
197
|
-
url,
|
198
|
-
proxy,
|
199
|
-
|
200
|
-
followRedirect(response) {
|
201
|
-
const version = response.headers['x-version'];
|
202
|
-
debug('redirect version:', version);
|
203
|
-
|
204
|
-
if (version) {
|
205
|
-
// set the version in options if we have one.
|
206
|
-
// this insulates us from potential redirect
|
207
|
-
// problems where version would be set to undefined.
|
208
|
-
redirectVersion = version;
|
209
|
-
} // yes redirect
|
210
|
-
|
211
|
-
|
212
|
-
return true;
|
213
|
-
}
|
214
|
-
|
215
|
-
};
|
216
207
|
|
217
208
|
if (ca) {
|
218
209
|
debug('using custom CA details from npm config');
|
219
|
-
reqOptions.agentOptions = {
|
220
|
-
ca
|
221
|
-
};
|
222
210
|
}
|
223
211
|
|
212
|
+
const reqOptions = {
|
213
|
+
uri: url,
|
214
|
+
...(proxy ? {
|
215
|
+
proxy
|
216
|
+
} : {}),
|
217
|
+
...(ca ? {
|
218
|
+
agentOptions: {
|
219
|
+
ca
|
220
|
+
}
|
221
|
+
} : {}),
|
222
|
+
method: 'GET',
|
223
|
+
followRedirect: false
|
224
|
+
};
|
224
225
|
const req = request(reqOptions); // closure
|
225
226
|
|
226
227
|
let started = null;
|
@@ -248,18 +249,46 @@ const downloadFromUrl = ({
|
|
248
249
|
// response headers
|
249
250
|
|
250
251
|
|
251
|
-
started = new Date();
|
252
|
-
|
253
|
-
if (
|
252
|
+
started = new Date();
|
253
|
+
|
254
|
+
if (/^3/.test(response.statusCode)) {
|
255
|
+
const redirectVersion = response.headers['x-version'];
|
256
|
+
const redirectUrl = response.headers.location;
|
257
|
+
debug('redirect version:', redirectVersion);
|
258
|
+
debug('redirect url:', redirectUrl);
|
259
|
+
downloadFromUrl({
|
260
|
+
url: redirectUrl,
|
261
|
+
progress,
|
262
|
+
ca,
|
263
|
+
downloadDestination,
|
264
|
+
version: redirectVersion,
|
265
|
+
redirectTTL: redirectTTL - 1
|
266
|
+
}).then(resolve).catch(reject); // if our status code does not start with 200
|
267
|
+
} else if (!/^2/.test(response.statusCode)) {
|
254
268
|
debug('response code %d', response.statusCode);
|
255
269
|
const err = new Error(stripIndent`
|
256
270
|
Failed downloading the Cypress binary.
|
257
271
|
Response code: ${response.statusCode}
|
258
272
|
Response message: ${response.statusMessage}
|
259
273
|
`);
|
260
|
-
reject(err);
|
274
|
+
reject(err); // status codes here are all 2xx
|
275
|
+
} else {
|
276
|
+
// We only enable this pipe connection when we know we've got a successful return
|
277
|
+
// and handle the completion with verify and resolve
|
278
|
+
// there was a possible race condition between end of request and close of writeStream
|
279
|
+
// that is made ordered with this Promise.all
|
280
|
+
Promise.all([new Promise(r => {
|
281
|
+
return response.pipe(fs.createWriteStream(downloadDestination).on('close', r));
|
282
|
+
}), new Promise(r => response.on('end', r))]).then(() => {
|
283
|
+
debug('downloading finished');
|
284
|
+
verifyDownloadedFile(downloadDestination, expectedSize, expectedChecksum).then(() => debug('verified')).then(() => resolve(version)).catch(reject);
|
285
|
+
});
|
261
286
|
}
|
262
|
-
}).on('error',
|
287
|
+
}).on('error', e => {
|
288
|
+
if (e.code === 'ECONNRESET') return; // sometimes proxies give ECONNRESET but we don't care
|
289
|
+
|
290
|
+
reject(e);
|
291
|
+
}).on('progress', state => {
|
263
292
|
// total time we've elapsed
|
264
293
|
// starting on our first progress notification
|
265
294
|
const elapsed = new Date() - started; // request-progress sends a value between 0 and 1
|
@@ -268,19 +297,13 @@ const downloadFromUrl = ({
|
|
268
297
|
const eta = util.calculateEta(percentage, elapsed); // send up our percent and seconds remaining
|
269
298
|
|
270
299
|
progress.onProgress(percentage, util.secsRemaining(eta));
|
271
|
-
}) // save this download here
|
272
|
-
.pipe(fs.createWriteStream(downloadDestination)).on('finish', () => {
|
273
|
-
debug('downloading finished');
|
274
|
-
verifyDownloadedFile(downloadDestination, expectedSize, expectedChecksum).then(() => {
|
275
|
-
return resolve(redirectVersion);
|
276
|
-
}, reject);
|
277
300
|
});
|
278
301
|
});
|
279
302
|
};
|
280
|
-
/**
|
281
|
-
* Download Cypress.zip from external
|
282
|
-
* @param [string] version Could be "3.3.0" or full URL
|
283
|
-
* @param [string] downloadDestination Local filename to save as
|
303
|
+
/**
|
304
|
+
* Download Cypress.zip from external versionUrl to local file.
|
305
|
+
* @param [string] version Could be "3.3.0" or full URL
|
306
|
+
* @param [string] downloadDestination Local filename to save as
|
284
307
|
*/
|
285
308
|
|
286
309
|
|
@@ -288,7 +311,8 @@ const start = opts => {
|
|
288
311
|
let {
|
289
312
|
version,
|
290
313
|
downloadDestination,
|
291
|
-
progress
|
314
|
+
progress,
|
315
|
+
redirectTTL
|
292
316
|
} = opts;
|
293
317
|
|
294
318
|
if (!downloadDestination) {
|
@@ -303,20 +327,24 @@ const start = opts => {
|
|
303
327
|
};
|
304
328
|
}
|
305
329
|
|
306
|
-
const
|
330
|
+
const versionUrl = getUrl(version);
|
307
331
|
progress.throttle = 100;
|
308
332
|
debug('needed Cypress version: %s', version);
|
309
|
-
debug('source url %s',
|
333
|
+
debug('source url %s', versionUrl);
|
310
334
|
debug(`downloading cypress.zip to "${downloadDestination}"`); // ensure download dir exists
|
311
335
|
|
312
336
|
return fs.ensureDirAsync(path.dirname(downloadDestination)).then(() => {
|
313
337
|
return getCA();
|
314
338
|
}).then(ca => {
|
315
339
|
return downloadFromUrl({
|
316
|
-
url,
|
340
|
+
url: versionUrl,
|
317
341
|
downloadDestination,
|
318
342
|
progress,
|
319
|
-
ca
|
343
|
+
ca,
|
344
|
+
version,
|
345
|
+
...(redirectTTL ? {
|
346
|
+
redirectTTL
|
347
|
+
} : {})
|
320
348
|
});
|
321
349
|
}).catch(err => {
|
322
350
|
return prettyDownloadErr(err, version);
|
@@ -7,14 +7,14 @@ const {
|
|
7
7
|
} = require('path');
|
8
8
|
|
9
9
|
const Bluebird = require('bluebird');
|
10
|
-
/**
|
11
|
-
* Get the size of a folder or a file.
|
12
|
-
*
|
13
|
-
* This function returns the actual file size of the folder (size), not the allocated space on disk (size on disk).
|
14
|
-
* For more details between the difference, check this link:
|
15
|
-
* https://www.howtogeek.com/180369/why-is-there-a-big-difference-between-size-and-size-on-disk/
|
16
|
-
*
|
17
|
-
* @param {string} path path to the file or the folder.
|
10
|
+
/**
|
11
|
+
* Get the size of a folder or a file.
|
12
|
+
*
|
13
|
+
* This function returns the actual file size of the folder (size), not the allocated space on disk (size on disk).
|
14
|
+
* For more details between the difference, check this link:
|
15
|
+
* https://www.howtogeek.com/180369/why-is-there-a-big-difference-between-size-and-size-on-disk/
|
16
|
+
*
|
17
|
+
* @param {string} path path to the file or the folder.
|
18
18
|
*/
|
19
19
|
|
20
20
|
|
package/lib/tasks/state.js
CHANGED
@@ -70,8 +70,8 @@ const getBinaryPkgPath = binaryDir => {
|
|
70
70
|
throw new Error(`Platform: "${platform}" is not supported.`);
|
71
71
|
}
|
72
72
|
};
|
73
|
-
/**
|
74
|
-
* Get path to binary directory
|
73
|
+
/**
|
74
|
+
* Get path to binary directory
|
75
75
|
*/
|
76
76
|
|
77
77
|
|
@@ -82,9 +82,9 @@ const getBinaryDir = (version = util.pkgVersion()) => {
|
|
82
82
|
const getVersionDir = (version = util.pkgVersion()) => {
|
83
83
|
return path.join(getCacheDir(), version);
|
84
84
|
};
|
85
|
-
/**
|
86
|
-
* When executing "npm postinstall" hook, the working directory is set to
|
87
|
-
* "<current folder>/node_modules/cypress", which can be surprising when using relative paths.
|
85
|
+
/**
|
86
|
+
* When executing "npm postinstall" hook, the working directory is set to
|
87
|
+
* "<current folder>/node_modules/cypress", which can be surprising when using relative paths.
|
88
88
|
*/
|
89
89
|
|
90
90
|
|
@@ -134,10 +134,10 @@ const parseRealPlatformBinaryFolderAsync = binaryPath => {
|
|
134
134
|
const getDistDir = () => {
|
135
135
|
return path.join(__dirname, '..', '..', 'dist');
|
136
136
|
};
|
137
|
-
/**
|
138
|
-
* Returns full filename to the file that keeps the Test Runner verification state as JSON text.
|
139
|
-
* Note: the binary state file will be stored one level up from the given binary folder.
|
140
|
-
* @param {string} binaryDir - full path to the folder holding the binary.
|
137
|
+
/**
|
138
|
+
* Returns full filename to the file that keeps the Test Runner verification state as JSON text.
|
139
|
+
* Note: the binary state file will be stored one level up from the given binary folder.
|
140
|
+
* @param {string} binaryDir - full path to the folder holding the binary.
|
141
141
|
*/
|
142
142
|
|
143
143
|
|
@@ -162,11 +162,11 @@ const getBinaryVerifiedAsync = binaryDir => {
|
|
162
162
|
const clearBinaryStateAsync = binaryDir => {
|
163
163
|
return fs.removeAsync(getBinaryStatePath(binaryDir));
|
164
164
|
};
|
165
|
-
/**
|
166
|
-
* Writes the new binary status.
|
167
|
-
* @param {boolean} verified The new test runner state after smoke test
|
168
|
-
* @param {string} binaryDir Folder holding the binary
|
169
|
-
* @returns {Promise<void>} returns a promise
|
165
|
+
/**
|
166
|
+
* Writes the new binary status.
|
167
|
+
* @param {boolean} verified The new test runner state after smoke test
|
168
|
+
* @param {string} binaryDir Folder holding the binary
|
169
|
+
* @returns {Promise<void>} returns a promise
|
170
170
|
*/
|
171
171
|
|
172
172
|
|
@@ -183,9 +183,9 @@ const writeBinaryVerifiedAsync = (verified, binaryDir) => {
|
|
183
183
|
const getPathToExecutable = binaryDir => {
|
184
184
|
return path.join(binaryDir, getPlatformExecutable());
|
185
185
|
};
|
186
|
-
/**
|
187
|
-
* Resolves with an object read from the binary app package.json file.
|
188
|
-
* If the file does not exist resolves with null
|
186
|
+
/**
|
187
|
+
* Resolves with an object read from the binary app package.json file.
|
188
|
+
* If the file does not exist resolves with null
|
189
189
|
*/
|
190
190
|
|
191
191
|
|