mirror of
https://github.com/cypress-io/cypress.git
synced 2025-12-21 06:11:11 -06:00
chore: refactor cypress/cli to TypeScript (#32063)
* migrate cli scripts to TypeScript * convert all javascript source files in the CLI to TypeScript rebase into first * chore: refactor all tests to TypeScript rebase into second * add npmignore for cli for typescript files * update build process * fix publically available exports * Fix cy-in-cy tests * add ts-expect-error to failing files * fix projectConfigIpc failures as there are now multiple installs of tsx * fix after-pack hook * fix binary script * chore: update publish binary to account for CLI being an ESModule compiled down to CommonJS * does this work? * fix the verify spec by making the listr2 renderer silent as it behaves differently since the refactor and is printing non deterministic outputs into our tests that do not have a large impact on the area we are testing and mostly served to actually test the renders of the listr2 framework itself * empty commit * additional refactor to code to remove strange any typing and exporting * bump cache and build binaries * fix CLI exports to keep backwards compatibility * fix unit-tests * turn on mac jobs * fix group name rename in CLI * remove babel deps from cli and explicitly install typescript * address feedback from code review * dont just falsy check results and instead explicitly check for null or undefined * add ts-expect-error * additional pass on cleaning up dynamic require / import from global lib references * annotate ts-expect-errors with reason for why error is expected * add rest of ts-expect-error comments * removing hardcoded branch to publish binary chore/migrate_cli_to_typescript
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
# Bump this version to force CI to re-create the cache from scratch.
|
||||
8-28-2025-dtslint
|
||||
9-2-2025-cli2
|
||||
|
||||
@@ -38,7 +38,7 @@ mainBuildFilters: &mainBuildFilters
|
||||
- /^release\/\d+\.\d+\.\d+$/
|
||||
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
|
||||
- 'update-v8-snapshot-cache-on-develop'
|
||||
- 'fix/set_fixed_gtk_version'
|
||||
- 'chore/refactor_cli_to_ts'
|
||||
|
||||
# usually we don't build Mac app - it takes a long time
|
||||
# but sometimes we want to really confirm we are doing the right thing
|
||||
@@ -49,7 +49,7 @@ macWorkflowFilters: &darwin-workflow-filters
|
||||
- equal: [ develop, << pipeline.git.branch >> ]
|
||||
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
|
||||
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
|
||||
- equal: [ 'fix/set_fixed_gtk_version', << pipeline.git.branch >> ]
|
||||
- equal: [ 'chore/refactor_cli_to_ts', << pipeline.git.branch >> ]
|
||||
- matches:
|
||||
pattern: /^release\/\d+\.\d+\.\d+$/
|
||||
value: << pipeline.git.branch >>
|
||||
@@ -60,7 +60,7 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters
|
||||
- equal: [ develop, << pipeline.git.branch >> ]
|
||||
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
|
||||
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
|
||||
- equal: [ 'fix/set_fixed_gtk_version', << pipeline.git.branch >> ]
|
||||
- equal: [ 'chore/refactor_cli_to_ts', << pipeline.git.branch >> ]
|
||||
- matches:
|
||||
pattern: /^release\/\d+\.\d+\.\d+$/
|
||||
value: << pipeline.git.branch >>
|
||||
@@ -83,7 +83,7 @@ windowsWorkflowFilters: &windows-workflow-filters
|
||||
- equal: [ develop, << pipeline.git.branch >> ]
|
||||
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
|
||||
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
|
||||
- equal: [ 'bugfix/tsx_loader_path', << pipeline.git.branch >> ]
|
||||
- equal: [ 'chore/refactor_cli_to_ts', << pipeline.git.branch >> ]
|
||||
- matches:
|
||||
pattern: /^release\/\d+\.\d+\.\d+$/
|
||||
value: << pipeline.git.branch >>
|
||||
@@ -157,7 +157,7 @@ commands:
|
||||
name: Set environment variable to determine whether or not to persist artifacts
|
||||
command: |
|
||||
echo "Setting SHOULD_PERSIST_ARTIFACTS variable"
|
||||
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "bugfix/tsx_loader_path" ]]; then
|
||||
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "chore/refactor_cli_to_ts" ]]; then
|
||||
export SHOULD_PERSIST_ARTIFACTS=true
|
||||
fi' >> "$BASH_ENV"
|
||||
# You must run `setup_should_persist_artifacts` command and be using bash before running this command
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"presets": [["@babel/preset-env", { "targets": { "node": 10 }}]]
|
||||
}
|
||||
2
cli/.gitignore
vendored
2
cli/.gitignore
vendored
@@ -20,3 +20,5 @@ react*
|
||||
mount-utils
|
||||
angular
|
||||
svelte
|
||||
index.js
|
||||
lib/**/*.js
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
spec: 'test/**/*_spec.js',
|
||||
spec: 'test/**/*_spec.ts',
|
||||
timeout: 10000,
|
||||
reporter: 'spec',
|
||||
recursive: true
|
||||
|
||||
2
cli/.npmignore
Normal file
2
cli/.npmignore
Normal file
@@ -0,0 +1,2 @@
|
||||
# ignore all ts files in the library directory as they should be compiled to js
|
||||
lib/**/*.ts
|
||||
@@ -1,3 +1,7 @@
|
||||
exports['lib/tasks/cache .path lists path to cache 1'] = `
|
||||
/.cache/Cypress
|
||||
`
|
||||
|
||||
exports['lib/tasks/cache .clear deletes cache folder and everything inside it 1'] = `
|
||||
[no output]
|
||||
`
|
||||
@@ -24,8 +28,24 @@ exports['lib/tasks/cache .list lists all versions of cached binary 1'] = `
|
||||
└─────────┴───────────┘
|
||||
`
|
||||
|
||||
exports['lib/tasks/cache .path lists path to cache 1'] = `
|
||||
/.cache/Cypress
|
||||
exports['cache list with silent log level'] = `
|
||||
┌─────────┬───────────┐
|
||||
│ version │ last used │
|
||||
├─────────┼───────────┤
|
||||
│ 1.2.3 │ unknown │
|
||||
├─────────┼───────────┤
|
||||
│ 2.3.4 │ unknown │
|
||||
└─────────┴───────────┘
|
||||
`
|
||||
|
||||
exports['cache list with warn log level'] = `
|
||||
┌─────────┬───────────┐
|
||||
│ version │ last used │
|
||||
├─────────┼───────────┤
|
||||
│ 1.2.3 │ unknown │
|
||||
├─────────┼───────────┤
|
||||
│ 2.3.4 │ unknown │
|
||||
└─────────┴───────────┘
|
||||
`
|
||||
|
||||
exports['lib/tasks/cache .list lists all versions of cached binary with last access 1'] = `
|
||||
@@ -48,26 +68,6 @@ exports['lib/tasks/cache .list some versions have never been opened 1'] = `
|
||||
└─────────┴──────────────┘
|
||||
`
|
||||
|
||||
exports['cache list with silent log level'] = `
|
||||
┌─────────┬───────────┐
|
||||
│ version │ last used │
|
||||
├─────────┼───────────┤
|
||||
│ 1.2.3 │ unknown │
|
||||
├─────────┼───────────┤
|
||||
│ 2.3.4 │ unknown │
|
||||
└─────────┴───────────┘
|
||||
`
|
||||
|
||||
exports['cache list with warn log level'] = `
|
||||
┌─────────┬───────────┐
|
||||
│ version │ last used │
|
||||
├─────────┼───────────┤
|
||||
│ 1.2.3 │ unknown │
|
||||
├─────────┼───────────┤
|
||||
│ 2.3.4 │ unknown │
|
||||
└─────────┴───────────┘
|
||||
`
|
||||
|
||||
exports['lib/tasks/cache .list shows sizes 1'] = `
|
||||
┌─────────┬──────────────┬───────┐
|
||||
│ version │ last used │ size │
|
||||
@@ -346,6 +346,41 @@ exports['cli unknown command shows usage and exits 1'] = `
|
||||
|
||||
`
|
||||
|
||||
exports['cli CYPRESS_INTERNAL_ENV allows and warns when staging environment 1'] = `
|
||||
code: 0
|
||||
stdout:
|
||||
-------
|
||||
⚠ Warning: It looks like you're passing CYPRESS_INTERNAL_ENV=staging
|
||||
|
||||
The environment variable "CYPRESS_INTERNAL_ENV" is reserved and should only be used internally.
|
||||
|
||||
Unset the "CYPRESS_INTERNAL_ENV" environment variable and run Cypress again.
|
||||
|
||||
Usage: cypress <command> [options]
|
||||
|
||||
Options:
|
||||
-v, --version prints Cypress version
|
||||
-h, --help display help for command
|
||||
|
||||
Commands:
|
||||
help Shows CLI help and exits
|
||||
version [options] prints Cypress version
|
||||
open [options] Opens Cypress in the interactive GUI.
|
||||
run [options] Runs Cypress tests from the CLI without the GUI
|
||||
install [options] Installs the Cypress executable matching this package's
|
||||
version
|
||||
verify [options] Verifies that Cypress is installed correctly and
|
||||
executable
|
||||
cache [options] Manages the Cypress binary cache
|
||||
info [options] Prints Cypress and system information
|
||||
-------
|
||||
stderr:
|
||||
-------
|
||||
|
||||
-------
|
||||
|
||||
`
|
||||
|
||||
exports['cli CYPRESS_INTERNAL_ENV catches environment "foo" 1'] = `
|
||||
code: 11
|
||||
stderr:
|
||||
@@ -387,6 +422,20 @@ Electron version: 10.10.88
|
||||
Bundled Node version: 11.10.3
|
||||
`
|
||||
|
||||
exports['cli version and binary version with npm log silent'] = `
|
||||
Cypress package version: 1.2.3
|
||||
Cypress binary version: X.Y.Z
|
||||
Electron version: not found
|
||||
Bundled Node version: not found
|
||||
`
|
||||
|
||||
exports['cli version and binary version with npm log warn'] = `
|
||||
Cypress package version: 1.2.3
|
||||
Cypress binary version: X.Y.Z
|
||||
Electron version: not found
|
||||
Bundled Node version: not found
|
||||
`
|
||||
|
||||
exports['cli version no binary version 1'] = `
|
||||
Cypress package version: 1.2.3
|
||||
Cypress binary version: not installed
|
||||
@@ -420,55 +469,6 @@ If you are trying to pass multiple arguments, separate them with commas instead:
|
||||
cypress run --tag arg1,arg2,arg3
|
||||
`
|
||||
|
||||
exports['cli CYPRESS_INTERNAL_ENV allows and warns when staging environment 1'] = `
|
||||
code: 0
|
||||
stdout:
|
||||
-------
|
||||
⚠ Warning: It looks like you're passing CYPRESS_INTERNAL_ENV=staging
|
||||
|
||||
The environment variable "CYPRESS_INTERNAL_ENV" is reserved and should only be used internally.
|
||||
|
||||
Unset the "CYPRESS_INTERNAL_ENV" environment variable and run Cypress again.
|
||||
|
||||
Usage: cypress <command> [options]
|
||||
|
||||
Options:
|
||||
-v, --version prints Cypress version
|
||||
-h, --help display help for command
|
||||
|
||||
Commands:
|
||||
help Shows CLI help and exits
|
||||
version [options] prints Cypress version
|
||||
open [options] Opens Cypress in the interactive GUI.
|
||||
run [options] Runs Cypress tests from the CLI without the GUI
|
||||
install [options] Installs the Cypress executable matching this package's
|
||||
version
|
||||
verify [options] Verifies that Cypress is installed correctly and
|
||||
executable
|
||||
cache [options] Manages the Cypress binary cache
|
||||
info [options] Prints Cypress and system information
|
||||
-------
|
||||
stderr:
|
||||
-------
|
||||
|
||||
-------
|
||||
|
||||
`
|
||||
|
||||
exports['cli version and binary version with npm log silent'] = `
|
||||
Cypress package version: 1.2.3
|
||||
Cypress binary version: X.Y.Z
|
||||
Electron version: not found
|
||||
Bundled Node version: not found
|
||||
`
|
||||
|
||||
exports['cli version and binary version with npm log warn'] = `
|
||||
Cypress package version: 1.2.3
|
||||
Cypress binary version: X.Y.Z
|
||||
Electron version: not found
|
||||
Bundled Node version: not found
|
||||
`
|
||||
|
||||
exports['prints explanation when no cache'] = `
|
||||
No cached binary versions were found.
|
||||
`
|
||||
@@ -1,19 +1,3 @@
|
||||
exports['base url from CYPRESS_DOWNLOAD_MIRROR 1'] = `
|
||||
https://cypress.example.com/desktop/0.20.2?platform=OS&arch=ARCH
|
||||
`
|
||||
|
||||
exports['base url from CYPRESS_DOWNLOAD_MIRROR with subdirectory 1'] = `
|
||||
https://cypress.example.com/example/desktop/0.20.2?platform=OS&arch=ARCH
|
||||
`
|
||||
|
||||
exports['base url from CYPRESS_DOWNLOAD_MIRROR with subdirectory and trailing slash 1'] = `
|
||||
https://cypress.example.com/example/desktop/0.20.2?platform=OS&arch=ARCH
|
||||
`
|
||||
|
||||
exports['base url from CYPRESS_DOWNLOAD_MIRROR with trailing slash 1'] = `
|
||||
https://cypress.example.com/desktop/0.20.2?platform=OS&arch=ARCH
|
||||
`
|
||||
|
||||
exports['download status errors 1'] = `
|
||||
Error: The Cypress App could not be downloaded.
|
||||
|
||||
@@ -49,6 +33,10 @@ exports['desktop url from template with version'] = `
|
||||
https://mycompany/0.20.2/OS-ARCH/cypress.zip
|
||||
`
|
||||
|
||||
exports['desktop url from template with multiple replacements'] = `
|
||||
https://download.cypress.io/desktop/0.20.2/OS/ARCH/cypress-0.20.2-OS-ARCH.zip?referrer=https://download.cypress.io/desktop/0.20.2&version=0.20.2
|
||||
`
|
||||
|
||||
exports['desktop url from template with escaped dollar sign'] = `
|
||||
https://download.cypress.io/desktop/0.20.2/OS-ARCH/cypress.zip
|
||||
`
|
||||
@@ -61,6 +49,18 @@ exports['desktop url from template with escaped dollar sign wrapped in quote'] =
|
||||
https://download.cypress.io/desktop/0.20.2/OS-ARCH/cypress.zip
|
||||
`
|
||||
|
||||
exports['desktop url from template with multiple replacements'] = `
|
||||
https://download.cypress.io/desktop/0.20.2/OS/ARCH/cypress-0.20.2-OS-ARCH.zip?referrer=https://download.cypress.io/desktop/0.20.2&version=0.20.2
|
||||
exports['base url from CYPRESS_DOWNLOAD_MIRROR 1'] = `
|
||||
https://cypress.example.com/desktop/0.20.2?platform=OS&arch=ARCH
|
||||
`
|
||||
|
||||
exports['base url from CYPRESS_DOWNLOAD_MIRROR with trailing slash 1'] = `
|
||||
https://cypress.example.com/desktop/0.20.2?platform=OS&arch=ARCH
|
||||
`
|
||||
|
||||
exports['base url from CYPRESS_DOWNLOAD_MIRROR with subdirectory 1'] = `
|
||||
https://cypress.example.com/example/desktop/0.20.2?platform=OS&arch=ARCH
|
||||
`
|
||||
|
||||
exports['base url from CYPRESS_DOWNLOAD_MIRROR with subdirectory and trailing slash 1'] = `
|
||||
https://cypress.example.com/example/desktop/0.20.2?platform=OS&arch=ARCH
|
||||
`
|
||||
@@ -1,7 +1,48 @@
|
||||
exports['errors .errors.formErrorText calls solution if a function 1'] = `
|
||||
description
|
||||
exports['errors individual has the following errors 1'] = [
|
||||
'CYPRESS_RUN_BINARY',
|
||||
'binaryNotExecutable',
|
||||
'childProcessKilled',
|
||||
'failedDownload',
|
||||
'failedUnzip',
|
||||
'failedUnzipWindowsMaxPathLength',
|
||||
'incompatibleHeadlessFlags',
|
||||
'incompatibleTestTypeFlags',
|
||||
'incompatibleTestingTypeAndFlag',
|
||||
'invalidCacheDirectory',
|
||||
'invalidConfigFile',
|
||||
'invalidCypressEnv',
|
||||
'invalidOS',
|
||||
'invalidRunProjectPath',
|
||||
'invalidSmokeTestDisplayError',
|
||||
'invalidTestingType',
|
||||
'missingApp',
|
||||
'missingDependency',
|
||||
'missingXvfb',
|
||||
'nonZeroExitCodeXvfb',
|
||||
'notInstalledCI',
|
||||
'smokeTestFailure',
|
||||
'unexpected',
|
||||
'unknownError',
|
||||
'versionMismatch',
|
||||
]
|
||||
|
||||
a solution
|
||||
exports['child kill error object'] = {
|
||||
'description': 'The Test Runner unexpectedly exited via a [36mexit[39m event with signal [36mSIGKILL[39m',
|
||||
'solution': 'Please search Cypress documentation for possible solutions:\n\n [34mhttps://on.cypress.io[39m\n\nCheck if there is a GitHub issue describing this crash:\n\n [34mhttps://github.com/cypress-io/cypress/issues[39m\n\nConsider opening a new issue.',
|
||||
}
|
||||
|
||||
exports['Error message'] = `
|
||||
The Test Runner unexpectedly exited via a [36mexit[39m event with signal [36mSIGKILL[39m
|
||||
|
||||
Please search Cypress documentation for possible solutions:
|
||||
|
||||
[34mhttps://on.cypress.io[39m
|
||||
|
||||
Check if there is a GitHub issue describing this crash:
|
||||
|
||||
[34mhttps://github.com/cypress-io/cypress/issues[39m
|
||||
|
||||
Consider opening a new issue.
|
||||
|
||||
----------
|
||||
|
||||
@@ -26,6 +67,17 @@ Platform: test platform-x64 (Foo-OsVersion)
|
||||
Cypress Version: 1.2.3
|
||||
`
|
||||
|
||||
exports['errors .errors.formErrorText calls solution if a function 1'] = `
|
||||
description
|
||||
|
||||
a solution
|
||||
|
||||
----------
|
||||
|
||||
Platform: test platform-x64 (Foo-OsVersion)
|
||||
Cypress Version: 1.2.3
|
||||
`
|
||||
|
||||
exports['invalid display error'] = `
|
||||
Cypress verification failed.
|
||||
|
||||
@@ -48,55 +100,3 @@ Please refer to the error above for more detail.
|
||||
Platform: test platform-x64 (Foo-OsVersion)
|
||||
Cypress Version: 1.2.3
|
||||
`
|
||||
|
||||
exports['child kill error object'] = {
|
||||
'description': 'The Test Runner unexpectedly exited via a [36mexit[39m event with signal [36mSIGKILL[39m',
|
||||
'solution': 'Please search Cypress documentation for possible solutions:\n\n [34mhttps://on.cypress.io[39m\n\nCheck if there is a GitHub issue describing this crash:\n\n [34mhttps://github.com/cypress-io/cypress/issues[39m\n\nConsider opening a new issue.',
|
||||
}
|
||||
|
||||
exports['Error message'] = `
|
||||
The Test Runner unexpectedly exited via a [36mexit[39m event with signal [36mSIGKILL[39m
|
||||
|
||||
Please search Cypress documentation for possible solutions:
|
||||
|
||||
[34mhttps://on.cypress.io[39m
|
||||
|
||||
Check if there is a GitHub issue describing this crash:
|
||||
|
||||
[34mhttps://github.com/cypress-io/cypress/issues[39m
|
||||
|
||||
Consider opening a new issue.
|
||||
|
||||
----------
|
||||
|
||||
Platform: test platform-x64 (Foo-OsVersion)
|
||||
Cypress Version: 1.2.3
|
||||
`
|
||||
|
||||
exports['errors individual has the following errors 1'] = [
|
||||
'CYPRESS_RUN_BINARY',
|
||||
'binaryNotExecutable',
|
||||
'childProcessKilled',
|
||||
'failedDownload',
|
||||
'failedUnzip',
|
||||
'failedUnzipWindowsMaxPathLength',
|
||||
'incompatibleHeadlessFlags',
|
||||
'incompatibleTestTypeFlags',
|
||||
'incompatibleTestingTypeAndFlag',
|
||||
'invalidCacheDirectory',
|
||||
'invalidConfigFile',
|
||||
'invalidCypressEnv',
|
||||
'invalidOS',
|
||||
'invalidRunProjectPath',
|
||||
'invalidSmokeTestDisplayError',
|
||||
'invalidTestingType',
|
||||
'missingApp',
|
||||
'missingDependency',
|
||||
'missingXvfb',
|
||||
'nonZeroExitCodeXvfb',
|
||||
'notInstalledCI',
|
||||
'smokeTestFailure',
|
||||
'unexpected',
|
||||
'unknownError',
|
||||
'versionMismatch',
|
||||
]
|
||||
@@ -1,3 +1,122 @@
|
||||
exports['silent install 1'] = `
|
||||
[no output]
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['error when installing on unsupported os'] = `
|
||||
Error: The Cypress App could not be installed. Your machine does not meet the operating system requirements.
|
||||
|
||||
https://on.cypress.io/app/get-started/install-cypress#System-requirements
|
||||
|
||||
----------
|
||||
|
||||
Platform: win32-ia32
|
||||
|
||||
`
|
||||
|
||||
exports['skip installation 1'] = `
|
||||
Note: Skipping binary installation: Environment variable CYPRESS_INSTALL_BINARY = 0.
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['/lib/tasks/install .start non-stable builds logs a warning about installing a pre-release 1'] = `
|
||||
⚠ Warning: You are installing a pre-release build of Cypress.
|
||||
|
||||
Bugs may be present which do not exist in production builds.
|
||||
|
||||
This build was created from:
|
||||
* Commit SHA: 3b7f0b5c59def1e9b5f385bd585c9b2836706c29
|
||||
* Commit Branch: aBranchName
|
||||
* Commit Timestamp: 1996-11-27Txx:xx:xx.000Z
|
||||
|
||||
Installing Cypress (version: https://cdn.cypress.io/beta/binary/0.0.0-development/darwin-x64/aBranchName-3b7f0b5c59def1e9b5f385bd585c9b2836706c29/cypress.zip)
|
||||
|
||||
|
||||
⠋ Downloaded Cypress
|
||||
✔ Downloaded Cypress
|
||||
✔ Downloaded Cypress
|
||||
⠋ Unzipped Cypress
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
⠋ Finished Installation /cache/Cypress/1.2.3
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
✔ Finished Installation /cache/Cypress/1.2.3
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
✔ Finished Installation /cache/Cypress/1.2.3
|
||||
|
||||
You can now open Cypress by running one of the following, depending on your package manager:
|
||||
|
||||
- npx cypress open
|
||||
- yarn cypress open
|
||||
- pnpm cypress open
|
||||
|
||||
https://on.cypress.io/opening-the-app
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['specify version in env vars 1'] = `
|
||||
⚠ Warning: Forcing a binary version different than the default.
|
||||
|
||||
The CLI expected to install version: 1.2.3
|
||||
|
||||
Instead we will install version: 0.12.1
|
||||
|
||||
These versions may not work properly together.
|
||||
|
||||
Installing Cypress (version: 0.12.1)
|
||||
|
||||
|
||||
⠋ Downloaded Cypress
|
||||
✔ Downloaded Cypress
|
||||
✔ Downloaded Cypress
|
||||
⠋ Unzipped Cypress
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
⠋ Finished Installation /cache/Cypress/1.2.3
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
✔ Finished Installation /cache/Cypress/1.2.3
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
✔ Finished Installation /cache/Cypress/1.2.3
|
||||
|
||||
You can now open Cypress by running one of the following, depending on your package manager:
|
||||
|
||||
- npx cypress open
|
||||
- yarn cypress open
|
||||
- pnpm cypress open
|
||||
|
||||
https://on.cypress.io/opening-the-app
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['version already installed - cypress install 1'] = `
|
||||
|
||||
Cypress 1.2.3 is installed in /cache/Cypress/1.2.3
|
||||
|
||||
Skipping installation:
|
||||
|
||||
Pass the --force option if you'd like to reinstall anyway.
|
||||
|
||||
`
|
||||
|
||||
exports['version already installed - postInstall 1'] = `
|
||||
|
||||
Cypress 1.2.3 is installed in /cache/Cypress/1.2.3
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['continues installing on failure 1'] = `
|
||||
Installing Cypress (version: 1.2.3)
|
||||
|
||||
@@ -29,10 +148,7 @@ https://on.cypress.io/opening-the-app
|
||||
|
||||
`
|
||||
|
||||
exports['forcing true always installs 1'] = `
|
||||
|
||||
Cypress 1.2.3 is installed in /cache/Cypress/1.2.3
|
||||
|
||||
exports['installs without existing installation 1'] = `
|
||||
Installing Cypress (version: 1.2.3)
|
||||
|
||||
|
||||
@@ -97,30 +213,13 @@ https://on.cypress.io/opening-the-app
|
||||
|
||||
`
|
||||
|
||||
exports['installing in ci 1'] = `
|
||||
exports['forcing true always installs 1'] = `
|
||||
|
||||
Cypress x.x.x is installed in /cache/Cypress/1.2.3
|
||||
Cypress 1.2.3 is installed in /cache/Cypress/1.2.3
|
||||
|
||||
Installing Cypress (version: 1.2.3)
|
||||
|
||||
|
||||
|
||||
|
||||
You can now open Cypress by running one of the following, depending on your package manager:
|
||||
|
||||
- npx cypress open
|
||||
- yarn cypress open
|
||||
- pnpm cypress open
|
||||
|
||||
https://on.cypress.io/opening-the-app
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['installs without existing installation 1'] = `
|
||||
Installing Cypress (version: 1.2.3)
|
||||
|
||||
|
||||
⠋ Downloaded Cypress
|
||||
✔ Downloaded Cypress
|
||||
✔ Downloaded Cypress
|
||||
@@ -146,93 +245,6 @@ You can now open Cypress by running one of the following, depending on your pack
|
||||
https://on.cypress.io/opening-the-app
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['invalid cache directory 1'] = `
|
||||
Error: Cypress cannot write to the cache directory due to file permissions
|
||||
|
||||
See discussion and possible solutions at
|
||||
https://github.com/cypress-io/cypress/issues/1281
|
||||
|
||||
----------
|
||||
|
||||
Failed to access /invalid/cache/dir:
|
||||
|
||||
EACCES: permission denied, mkdir '/invalid'
|
||||
|
||||
----------
|
||||
|
||||
Platform: darwin-x64 (Foo-OsVersion)
|
||||
Cypress Version: 1.2.3
|
||||
|
||||
`
|
||||
|
||||
exports['silent install 1'] = `
|
||||
[no output]
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['skip installation 1'] = `
|
||||
Note: Skipping binary installation: Environment variable CYPRESS_INSTALL_BINARY = 0.
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['specify version in env vars 1'] = `
|
||||
⚠ Warning: Forcing a binary version different than the default.
|
||||
|
||||
The CLI expected to install version: 1.2.3
|
||||
|
||||
Instead we will install version: 0.12.1
|
||||
|
||||
These versions may not work properly together.
|
||||
|
||||
Installing Cypress (version: 0.12.1)
|
||||
|
||||
|
||||
⠋ Downloaded Cypress
|
||||
✔ Downloaded Cypress
|
||||
✔ Downloaded Cypress
|
||||
⠋ Unzipped Cypress
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
⠋ Finished Installation /cache/Cypress/1.2.3
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
✔ Finished Installation /cache/Cypress/1.2.3
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
✔ Finished Installation /cache/Cypress/1.2.3
|
||||
|
||||
You can now open Cypress by running one of the following, depending on your package manager:
|
||||
|
||||
- npx cypress open
|
||||
- yarn cypress open
|
||||
- pnpm cypress open
|
||||
|
||||
https://on.cypress.io/opening-the-app
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['version already installed - cypress install 1'] = `
|
||||
|
||||
Cypress 1.2.3 is installed in /cache/Cypress/1.2.3
|
||||
|
||||
Skipping installation:
|
||||
|
||||
Pass the --force option if you'd like to reinstall anyway.
|
||||
|
||||
`
|
||||
|
||||
exports['version already installed - postInstall 1'] = `
|
||||
|
||||
Cypress 1.2.3 is installed in /cache/Cypress/1.2.3
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['warning installing as global 1'] = `
|
||||
@@ -269,45 +281,14 @@ Installing Cypress (version: 1.2.3)
|
||||
|
||||
`
|
||||
|
||||
exports['error when installing on unsupported os'] = `
|
||||
Error: The Cypress App could not be installed. Your machine does not meet the operating system requirements.
|
||||
exports['installing in ci 1'] = `
|
||||
|
||||
https://on.cypress.io/app/get-started/install-cypress#System-requirements
|
||||
Cypress x.x.x is installed in /cache/Cypress/1.2.3
|
||||
|
||||
Installing Cypress (version: 1.2.3)
|
||||
|
||||
----------
|
||||
|
||||
Platform: win32-ia32
|
||||
|
||||
`
|
||||
|
||||
exports['/lib/tasks/install .start non-stable builds logs a warning about installing a pre-release 1'] = `
|
||||
⚠ Warning: You are installing a pre-release build of Cypress.
|
||||
|
||||
Bugs may be present which do not exist in production builds.
|
||||
|
||||
This build was created from:
|
||||
* Commit SHA: 3b7f0b5c59def1e9b5f385bd585c9b2836706c29
|
||||
* Commit Branch: aBranchName
|
||||
* Commit Timestamp: 1996-11-27Txx:xx:xx.000Z
|
||||
|
||||
Installing Cypress (version: https://cdn.cypress.io/beta/binary/0.0.0-development/darwin-x64/aBranchName-3b7f0b5c59def1e9b5f385bd585c9b2836706c29/cypress.zip)
|
||||
|
||||
|
||||
⠋ Downloaded Cypress
|
||||
✔ Downloaded Cypress
|
||||
✔ Downloaded Cypress
|
||||
⠋ Unzipped Cypress
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
⠋ Finished Installation /cache/Cypress/1.2.3
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
✔ Finished Installation /cache/Cypress/1.2.3
|
||||
✔ Downloaded Cypress
|
||||
✔ Unzipped Cypress
|
||||
✔ Finished Installation /cache/Cypress/1.2.3
|
||||
|
||||
You can now open Cypress by running one of the following, depending on your package manager:
|
||||
|
||||
@@ -318,4 +299,23 @@ You can now open Cypress by running one of the following, depending on your pack
|
||||
https://on.cypress.io/opening-the-app
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['invalid cache directory 1'] = `
|
||||
Error: Cypress cannot write to the cache directory due to file permissions
|
||||
|
||||
See discussion and possible solutions at
|
||||
https://github.com/cypress-io/cypress/issues/1281
|
||||
|
||||
----------
|
||||
|
||||
Failed to access /invalid/cache/dir:
|
||||
|
||||
EACCES: permission denied, mkdir '/invalid'
|
||||
|
||||
----------
|
||||
|
||||
Platform: darwin-x64 (Foo-OsVersion)
|
||||
Cypress Version: 1.2.3
|
||||
|
||||
`
|
||||
@@ -1,12 +1,3 @@
|
||||
exports['exec run .processRunOptions does not remove --record option when using --browser 1'] = [
|
||||
'--run-project',
|
||||
null,
|
||||
'--browser',
|
||||
'test browser',
|
||||
'--record',
|
||||
'foo',
|
||||
]
|
||||
|
||||
exports['exec run .processRunOptions passes --browser option 1'] = [
|
||||
'--run-project',
|
||||
null,
|
||||
@@ -21,6 +12,15 @@ exports['exec run .processRunOptions passes --record option 1'] = [
|
||||
'my record id',
|
||||
]
|
||||
|
||||
exports['exec run .processRunOptions does not remove --record option when using --browser 1'] = [
|
||||
'--run-project',
|
||||
null,
|
||||
'--browser',
|
||||
'test browser',
|
||||
'--record',
|
||||
'foo',
|
||||
]
|
||||
|
||||
exports['exec run .processRunOptions defaults to e2e testingType 1'] = [
|
||||
'--run-project',
|
||||
null,
|
||||
@@ -1,17 +1,17 @@
|
||||
exports['config_as_object 1'] = {
|
||||
'config': '{"baseUrl":"http://localhost:2000","watchForFileChanges":false}',
|
||||
}
|
||||
|
||||
exports['env_as_object 1'] = {
|
||||
'env': '{"foo":"bar","magicNumber":1234,"host":"kevin.dev.local"}',
|
||||
exports['others_unchanged 1'] = {
|
||||
'foo': 'bar',
|
||||
}
|
||||
|
||||
exports['env_as_string 1'] = {
|
||||
'env': 'foo=bar',
|
||||
}
|
||||
|
||||
exports['others_unchanged 1'] = {
|
||||
'foo': 'bar',
|
||||
exports['env_as_object 1'] = {
|
||||
'env': '{"foo":"bar","magicNumber":1234,"host":"kevin.dev.local"}',
|
||||
}
|
||||
|
||||
exports['config_as_object 1'] = {
|
||||
'config': '{"baseUrl":"http://localhost:2000","watchForFileChanges":false}',
|
||||
}
|
||||
|
||||
exports['reporter_options_as_object 1'] = {
|
||||
@@ -23,10 +23,6 @@ exports['current version has not been verified 1'] = `
|
||||
It looks like this is your first time using Cypress: 1.2.3
|
||||
|
||||
|
||||
⠋ Verified Cypress! /cache/Cypress/1.2.3/Cypress.app
|
||||
✔ Verified Cypress! /cache/Cypress/1.2.3/Cypress.app
|
||||
✔ Verified Cypress! /cache/Cypress/1.2.3/Cypress.app
|
||||
|
||||
Opening Cypress...
|
||||
|
||||
`
|
||||
@@ -63,10 +59,6 @@ Found binary version 7.8.9 installed in: /cache/Cypress/1.2.3/Cypress.app
|
||||
It looks like this is your first time using Cypress: 7.8.9
|
||||
|
||||
|
||||
⠋ Verified Cypress! /cache/Cypress/1.2.3/Cypress.app
|
||||
✔ Verified Cypress! /cache/Cypress/1.2.3/Cypress.app
|
||||
✔ Verified Cypress! /cache/Cypress/1.2.3/Cypress.app
|
||||
|
||||
Opening Cypress...
|
||||
|
||||
`
|
||||
@@ -111,8 +103,6 @@ Cypress Version: 1.2.3
|
||||
`
|
||||
|
||||
exports['fails verifying Cypress 1'] = `
|
||||
STRIPPED
|
||||
|
||||
|
||||
Error: Cypress failed to start.
|
||||
|
||||
@@ -150,9 +140,7 @@ Cypress Version: 1.2.3
|
||||
`
|
||||
|
||||
exports['lib/tasks/verify logs error when child process hangs 1'] = `
|
||||
STRIPPED
|
||||
|
||||
|
||||
It looks like this is your first time using Cypress: 1.2.3
|
||||
|
||||
Error: Cypress verification timed out.
|
||||
|
||||
@@ -172,9 +160,7 @@ Cypress Version: 1.2.3
|
||||
`
|
||||
|
||||
exports['lib/tasks/verify logs error when child process returns incorrect stdout (stderr when exists) 1'] = `
|
||||
STRIPPED
|
||||
|
||||
|
||||
It looks like this is your first time using Cypress: 1.2.3
|
||||
|
||||
Error: Cypress verification failed.
|
||||
|
||||
@@ -194,9 +180,7 @@ Cypress Version: 1.2.3
|
||||
`
|
||||
|
||||
exports['lib/tasks/verify logs error when child process returns incorrect stdout (stdout when no stderr) 1'] = `
|
||||
STRIPPED
|
||||
|
||||
|
||||
It looks like this is your first time using Cypress: 1.2.3
|
||||
|
||||
Error: Cypress verification failed.
|
||||
|
||||
@@ -281,8 +265,6 @@ Found binary version 7.8.9 installed in: /cache/Cypress/1.2.3/Cypress.app
|
||||
|
||||
exports['silent verify 1'] = `
|
||||
[no output]
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['valid CYPRESS_RUN_BINARY 1'] = `
|
||||
@@ -295,10 +277,6 @@ This overrides the default Cypress binary path used.
|
||||
It looks like this is your first time using Cypress: 1.2.3
|
||||
|
||||
|
||||
⠋ Verified Cypress! /real/custom
|
||||
✔ Verified Cypress! /real/custom
|
||||
✔ Verified Cypress! /real/custom
|
||||
|
||||
Opening Cypress...
|
||||
|
||||
`
|
||||
@@ -307,10 +285,6 @@ exports['verbose stdout output 1'] = `
|
||||
It looks like this is your first time using Cypress: 1.2.3
|
||||
|
||||
|
||||
⠋ Verified Cypress! /cache/Cypress/1.2.3/Cypress.app
|
||||
✔ Verified Cypress! /cache/Cypress/1.2.3/Cypress.app
|
||||
✔ Verified Cypress! /cache/Cypress/1.2.3/Cypress.app
|
||||
|
||||
Opening Cypress...
|
||||
|
||||
`
|
||||
@@ -318,10 +292,6 @@ Opening Cypress...
|
||||
exports['verification with executable 1'] = `
|
||||
|
||||
|
||||
⠋ Verified Cypress! /cache/Cypress/1.2.3/Cypress.app
|
||||
✔ Verified Cypress! /cache/Cypress/1.2.3/Cypress.app
|
||||
✔ Verified Cypress! /cache/Cypress/1.2.3/Cypress.app
|
||||
|
||||
Opening Cypress...
|
||||
|
||||
`
|
||||
@@ -330,8 +300,6 @@ exports['verifying in ci 1'] = `
|
||||
It looks like this is your first time using Cypress: 1.2.3
|
||||
|
||||
|
||||
|
||||
|
||||
Opening Cypress...
|
||||
|
||||
`
|
||||
@@ -369,9 +337,7 @@ Cypress Version: 1.2.3
|
||||
`
|
||||
|
||||
exports['xvfb fails 1'] = `
|
||||
STRIPPED
|
||||
|
||||
|
||||
It looks like this is your first time using Cypress: 1.2.3
|
||||
|
||||
Error: Xvfb exited with a non zero exit code.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require('../lib/cli').init()
|
||||
const CLI = require('../lib/cli').default
|
||||
|
||||
CLI.init()
|
||||
|
||||
28
cli/index.js
28
cli/index.js
@@ -1,28 +0,0 @@
|
||||
const minimist = require('minimist')
|
||||
const debug = require('debug')('cypress:cli')
|
||||
const args = minimist(process.argv.slice(2))
|
||||
const util = require('./lib/util')
|
||||
|
||||
// we're being used from the command line
|
||||
switch (args.exec) {
|
||||
case 'install':
|
||||
debug('installing Cypress from NPM')
|
||||
|
||||
require('./lib/tasks/install')
|
||||
.start({ force: args.force })
|
||||
.catch(util.logErrorExit1)
|
||||
|
||||
break
|
||||
case 'verify':
|
||||
// for simple testing in the monorepo
|
||||
debug('verifying Cypress')
|
||||
|
||||
require('./lib/tasks/verify')
|
||||
.start({ force: true }) // always force verification
|
||||
.catch(util.logErrorExit1)
|
||||
|
||||
break
|
||||
default:
|
||||
debug('exporting Cypress module interface')
|
||||
module.exports = require('./lib/cypress')
|
||||
}
|
||||
46
cli/index.ts
Normal file
46
cli/index.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import minimist from 'minimist'
|
||||
import debug from 'debug'
|
||||
import util from './lib/util'
|
||||
import CLI from './lib/cypress'
|
||||
import installModule from './lib/tasks/install'
|
||||
import verifyModule from './lib/tasks/verify'
|
||||
|
||||
const debugCli = debug('cypress:cli')
|
||||
const args: any = minimist(process.argv.slice(2))
|
||||
|
||||
// we're being used from the command line
|
||||
async function handleExec (): Promise<void> {
|
||||
switch (args.exec) {
|
||||
case 'install': {
|
||||
debugCli('installing Cypress from NPM')
|
||||
|
||||
installModule.start({ force: args.force })
|
||||
.catch(util.logErrorExit1)
|
||||
|
||||
break
|
||||
}
|
||||
case 'verify': {
|
||||
// for simple testing in the monorepo
|
||||
debugCli('verifying Cypress')
|
||||
|
||||
verifyModule.start({ force: true }) // always force verification
|
||||
.catch(util.logErrorExit1)
|
||||
|
||||
break
|
||||
}
|
||||
default: {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the async function
|
||||
if (args.exec) {
|
||||
handleExec().catch(util.logErrorExit1)
|
||||
} else {
|
||||
debugCli('exporting Cypress module interface')
|
||||
}
|
||||
|
||||
// this is how the module needs to be exported to avoid a breaking change
|
||||
// default exports WILL BREAK in a CJS context through a require('cypress') call
|
||||
export = CLI
|
||||
@@ -1,17 +1,17 @@
|
||||
// Vendored from @cypress/listr-verbose-renderer
|
||||
const figures = require('figures')
|
||||
const cliCursor = require('cli-cursor')
|
||||
const chalk = require('chalk')
|
||||
const dayjs = require('dayjs')
|
||||
import figures from 'figures'
|
||||
import cliCursor from 'cli-cursor'
|
||||
import chalk from 'chalk'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
const formattedLog = (options, output) => {
|
||||
const formattedLog = (options: any, output: string): void => {
|
||||
const timestamp = dayjs().format(options.dateFormat)
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`${chalk.dim(`[${timestamp}]`) } ${output}`)
|
||||
console.log(`${chalk.dim(`[${timestamp}]`)} ${output}`)
|
||||
}
|
||||
|
||||
const renderHelper = (task, event, options) => {
|
||||
const renderHelper = (task: any, event: any, options: any): void => {
|
||||
const log = formattedLog.bind(undefined, options)
|
||||
|
||||
if (event.type === 'STATE') {
|
||||
@@ -27,10 +27,10 @@ const renderHelper = (task, event, options) => {
|
||||
}
|
||||
}
|
||||
|
||||
const render = (tasks, options) => {
|
||||
const render = (tasks: any[], options: any): void => {
|
||||
for (const task of tasks) {
|
||||
task.subscribe(
|
||||
(event) => {
|
||||
(event: any) => {
|
||||
if (event.type === 'SUBTASKS') {
|
||||
render(task.subtasks, options)
|
||||
|
||||
@@ -39,7 +39,7 @@ const render = (tasks, options) => {
|
||||
|
||||
renderHelper(task, event, options)
|
||||
},
|
||||
(err) => {
|
||||
(err: any) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(err)
|
||||
},
|
||||
@@ -48,25 +48,28 @@ const render = (tasks, options) => {
|
||||
}
|
||||
|
||||
class VerboseRenderer {
|
||||
constructor (tasks, options) {
|
||||
private _tasks: any[]
|
||||
private _options: any
|
||||
|
||||
constructor (tasks: any[], options: any) {
|
||||
this._tasks = tasks
|
||||
this._options = Object.assign({
|
||||
dateFormat: 'HH:mm:ss',
|
||||
}, options)
|
||||
}
|
||||
|
||||
static get nonTTY () {
|
||||
static get nonTTY (): boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
render () {
|
||||
render (): void {
|
||||
cliCursor.hide()
|
||||
render(this._tasks, this._options)
|
||||
}
|
||||
|
||||
end () {
|
||||
end (): void {
|
||||
cliCursor.show()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = VerboseRenderer
|
||||
export default VerboseRenderer
|
||||
@@ -1,17 +1,26 @@
|
||||
// @ts-check
|
||||
const _ = require('lodash')
|
||||
const commander = require('commander')
|
||||
const { stripIndent } = require('common-tags')
|
||||
const logSymbols = require('log-symbols')
|
||||
const debug = require('debug')('cypress:cli:cli')
|
||||
const util = require('./util')
|
||||
const logger = require('./logger')
|
||||
const errors = require('./errors')
|
||||
const cache = require('./tasks/cache')
|
||||
import _ from 'lodash'
|
||||
import commander from 'commander'
|
||||
import { stripIndent } from 'common-tags'
|
||||
import logSymbols from 'log-symbols'
|
||||
import Debug from 'debug'
|
||||
import util from './util'
|
||||
import logger from './logger'
|
||||
import { exitWithError, errors } from './errors'
|
||||
import cache from './tasks/cache'
|
||||
|
||||
import openModule from './exec/open'
|
||||
import runModule from './exec/run'
|
||||
import verifyModule from './tasks/verify'
|
||||
import installModule from './tasks/install'
|
||||
import versionModule from './exec/versions'
|
||||
import infoModule from './exec/info'
|
||||
|
||||
const debug = Debug('cypress:cli:cli')
|
||||
|
||||
// patch "commander" method called when a user passed an unknown option
|
||||
// we want to print help for the current command and exit with an error
|
||||
function unknownOption (flag, type = 'option') {
|
||||
function unknownOption (this: any, flag: string, type: string = 'option'): void {
|
||||
if (this._allowUnknownOption) return
|
||||
|
||||
logger.error()
|
||||
@@ -22,15 +31,15 @@ function unknownOption (flag, type = 'option') {
|
||||
}
|
||||
commander.Command.prototype.unknownOption = unknownOption
|
||||
|
||||
const coerceFalse = (arg) => {
|
||||
const coerceFalse = (arg: string): boolean => {
|
||||
return arg !== 'false'
|
||||
}
|
||||
|
||||
const coerceAnyStringToInt = (arg) => {
|
||||
const coerceAnyStringToInt = (arg: any): number => {
|
||||
return typeof arg === 'string' ? parseInt(arg) : arg
|
||||
}
|
||||
|
||||
const spaceDelimitedArgsMsg = (flag, args) => {
|
||||
const spaceDelimitedArgsMsg = (flag: string, args: string[]): void => {
|
||||
let msg = `
|
||||
${logSymbols.warning} Warning: It looks like you're passing --${flag} a space-separated list of arguments:
|
||||
|
||||
@@ -55,7 +64,7 @@ const spaceDelimitedArgsMsg = (flag, args) => {
|
||||
logger.log()
|
||||
}
|
||||
|
||||
const parseVariableOpts = (fnArgs, args) => {
|
||||
const parseVariableOpts = (fnArgs: any[], args: string[]): any => {
|
||||
const [opts, unknownArgs] = fnArgs
|
||||
|
||||
if ((unknownArgs && unknownArgs.length) && (opts.spec || opts.tag)) {
|
||||
@@ -69,9 +78,9 @@ const parseVariableOpts = (fnArgs, args) => {
|
||||
opts.tag ? 'tag' : opts.tag,
|
||||
])
|
||||
|
||||
_.forEach(multiArgFlags, (flag) => {
|
||||
_.forEach(multiArgFlags, (flag: string) => {
|
||||
const argIndex = _.indexOf(args, `--${flag}`) + 2
|
||||
const nextOptOffset = _.findIndex(_.slice(args, argIndex), (arg) => {
|
||||
const nextOptOffset = _.findIndex(_.slice(args, argIndex), (arg: string) => {
|
||||
return _.startsWith(arg, '--')
|
||||
})
|
||||
const endIndex = nextOptOffset !== -1 ? argIndex + nextOptOffset : args.length
|
||||
@@ -92,7 +101,7 @@ const parseVariableOpts = (fnArgs, args) => {
|
||||
return util.parseOpts(opts)
|
||||
}
|
||||
|
||||
const descriptions = {
|
||||
const descriptions: any = {
|
||||
autoCancelAfterFailures: 'overrides the project-level Cloud configuration to set the failed test threshold for auto cancellation or to disable auto cancellation when recording to the Cloud',
|
||||
browser: 'runs Cypress in the browser with the given name. if a filesystem path is supplied, Cypress will attempt to use the browser at that path.',
|
||||
cacheClear: 'delete all cached binaries',
|
||||
@@ -144,7 +153,7 @@ const knownCommands = [
|
||||
'info',
|
||||
]
|
||||
|
||||
const text = (description) => {
|
||||
const text = (description: string): string => {
|
||||
if (!descriptions[description]) {
|
||||
throw new Error(`Could not find description for: ${description}`)
|
||||
}
|
||||
@@ -152,28 +161,28 @@ const text = (description) => {
|
||||
return descriptions[description]
|
||||
}
|
||||
|
||||
function includesVersion (args) {
|
||||
function includesVersion (args: string[]): boolean {
|
||||
return (
|
||||
_.includes(args, '--version') ||
|
||||
_.includes(args, '-v')
|
||||
)
|
||||
}
|
||||
|
||||
function showVersions (opts) {
|
||||
function showVersions (opts: any): any {
|
||||
debug('printing Cypress version')
|
||||
debug('additional arguments %o', opts)
|
||||
|
||||
debug('parsed version arguments %o', opts)
|
||||
|
||||
const reportAllVersions = (versions) => {
|
||||
const reportAllVersions = (versions: any): void => {
|
||||
logger.always('Cypress package version:', versions.package)
|
||||
logger.always('Cypress binary version:', versions.binary)
|
||||
logger.always('Electron version:', versions.electronVersion)
|
||||
logger.always('Bundled Node version:', versions.electronNodeVersion)
|
||||
}
|
||||
|
||||
const reportComponentVersion = (componentName, versions) => {
|
||||
const names = {
|
||||
const reportComponentVersion = (componentName: string, versions: any): void => {
|
||||
const names: any = {
|
||||
package: 'package',
|
||||
binary: 'binary',
|
||||
electron: 'electronVersion',
|
||||
@@ -202,9 +211,9 @@ function showVersions (opts) {
|
||||
electronNodeVersion: undefined,
|
||||
}
|
||||
|
||||
return require('./exec/versions')
|
||||
return versionModule
|
||||
.getVersions()
|
||||
.then((versions = defaultVersions) => {
|
||||
.then((versions: any = defaultVersions) => {
|
||||
if (opts?.component) {
|
||||
reportComponentVersion(opts.component, versions)
|
||||
} else {
|
||||
@@ -216,7 +225,7 @@ function showVersions (opts) {
|
||||
.catch(util.logErrorExit1)
|
||||
}
|
||||
|
||||
const createProgram = () => {
|
||||
const createProgram = (): any => {
|
||||
const program = new commander.Command()
|
||||
|
||||
// bug in commander not printing name
|
||||
@@ -228,7 +237,7 @@ const createProgram = () => {
|
||||
return program
|
||||
}
|
||||
|
||||
const addCypressRunCommand = (program) => {
|
||||
const addCypressRunCommand = (program: any): any => {
|
||||
return program
|
||||
.command('run')
|
||||
.usage('[options]')
|
||||
@@ -260,7 +269,7 @@ const addCypressRunCommand = (program) => {
|
||||
.option('--dev', text('dev'), coerceFalse)
|
||||
}
|
||||
|
||||
const addCypressOpenCommand = (program) => {
|
||||
const addCypressOpenCommand = (program: any): any => {
|
||||
return program
|
||||
.command('open')
|
||||
.usage('[options]')
|
||||
@@ -278,7 +287,7 @@ const addCypressOpenCommand = (program) => {
|
||||
.option('--dev', text('dev'), coerceFalse)
|
||||
}
|
||||
|
||||
const maybeAddInspectFlags = (program) => {
|
||||
const maybeAddInspectFlags = (program: any): any => {
|
||||
if (process.argv.includes('--dev')) {
|
||||
return program
|
||||
.option('--inspect', 'Node option')
|
||||
@@ -295,7 +304,7 @@ const maybeAddInspectFlags = (program) => {
|
||||
*
|
||||
* Returns a clone of the original object.
|
||||
*/
|
||||
const castCypressOptions = (opts) => {
|
||||
const castCypressOptions = (opts: any): any => {
|
||||
// only properties that have type "string | false" in our TS definition
|
||||
// require special handling, because CLI parsing takes care of purely
|
||||
// boolean arguments
|
||||
@@ -308,7 +317,7 @@ const castCypressOptions = (opts) => {
|
||||
return castOpts
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
const cliModule = {
|
||||
/**
|
||||
* Parses `cypress run` command line option array into an object
|
||||
* with options that you can feed into a `cypress.run()` module API call.
|
||||
@@ -316,7 +325,7 @@ module.exports = {
|
||||
* const options = parseRunCommand(['cypress', 'run', '--browser', 'chrome'])
|
||||
* // options is {browser: 'chrome'}
|
||||
*/
|
||||
parseRunCommand (args) {
|
||||
parseRunCommand (args: string[]): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!Array.isArray(args)) {
|
||||
return reject(new Error('Expected array of arguments'))
|
||||
@@ -327,13 +336,13 @@ module.exports = {
|
||||
// also remove "cypress" keyword at the start if present
|
||||
const cliArgs = args[0] === 'cypress' ? [...args.slice(1)] : [...args]
|
||||
|
||||
cliArgs.unshift(null, null)
|
||||
cliArgs.unshift(null as any, null as any)
|
||||
|
||||
debug('creating program parser')
|
||||
const program = createProgram()
|
||||
|
||||
maybeAddInspectFlags(addCypressRunCommand(program))
|
||||
.action((...fnArgs) => {
|
||||
.action((...fnArgs: any[]) => {
|
||||
debug('parsed Cypress run %o', fnArgs)
|
||||
const options = parseVariableOpts(fnArgs, cliArgs)
|
||||
|
||||
@@ -357,7 +366,7 @@ module.exports = {
|
||||
* const options = parseOpenCommand(['cypress', 'open', '--browser', 'chrome'])
|
||||
* // options is {browser: 'chrome'}
|
||||
*/
|
||||
parseOpenCommand (args) {
|
||||
parseOpenCommand (args: string[]): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!Array.isArray(args)) {
|
||||
return reject(new Error('Expected array of arguments'))
|
||||
@@ -368,13 +377,13 @@ module.exports = {
|
||||
// also remove "cypress" keyword at the start if present
|
||||
const cliArgs = args[0] === 'cypress' ? [...args.slice(1)] : [...args]
|
||||
|
||||
cliArgs.unshift(null, null)
|
||||
cliArgs.unshift(null as any, null as any)
|
||||
|
||||
debug('creating program parser')
|
||||
const program = createProgram()
|
||||
|
||||
maybeAddInspectFlags(addCypressOpenCommand(program))
|
||||
.action((...fnArgs) => {
|
||||
.action((...fnArgs: any[]) => {
|
||||
debug('parsed Cypress open %o', fnArgs)
|
||||
const options = parseVariableOpts(fnArgs, cliArgs)
|
||||
|
||||
@@ -394,7 +403,7 @@ module.exports = {
|
||||
/**
|
||||
* Parses the command line and kicks off Cypress process.
|
||||
*/
|
||||
init (args) {
|
||||
init (args?: string[]): any {
|
||||
if (!args) {
|
||||
args = process.argv
|
||||
}
|
||||
@@ -418,7 +427,7 @@ module.exports = {
|
||||
if (!util.isValidCypressInternalEnvValue(CYPRESS_INTERNAL_ENV)) {
|
||||
debug('invalid CYPRESS_INTERNAL_ENV value', CYPRESS_INTERNAL_ENV)
|
||||
|
||||
return errors.exitWithError(errors.errors.invalidCypressEnv)(
|
||||
return exitWithError(errors.invalidCypressEnv)(
|
||||
`CYPRESS_INTERNAL_ENV=${CYPRESS_INTERNAL_ENV}`,
|
||||
)
|
||||
}
|
||||
@@ -448,10 +457,10 @@ module.exports = {
|
||||
program.help()
|
||||
})
|
||||
|
||||
const handleVersion = (cmd) => {
|
||||
const handleVersion = (cmd: any): any => {
|
||||
return cmd
|
||||
.option('--component <package|binary|electron|node>', 'component to report version for')
|
||||
.action((opts, ...other) => {
|
||||
.action((opts: any, ...other: any[]) => {
|
||||
showVersions(util.parseOpts(opts))
|
||||
})
|
||||
}
|
||||
@@ -463,19 +472,19 @@ module.exports = {
|
||||
.description(text('version')))
|
||||
|
||||
maybeAddInspectFlags(addCypressOpenCommand(program))
|
||||
.action((opts) => {
|
||||
.action((opts: any) => {
|
||||
debug('opening Cypress')
|
||||
require('./exec/open')
|
||||
.start(util.parseOpts(opts))
|
||||
|
||||
openModule.start(util.parseOpts(opts))
|
||||
.then(util.exit)
|
||||
.catch(util.logErrorExit1)
|
||||
})
|
||||
|
||||
maybeAddInspectFlags(addCypressRunCommand(program))
|
||||
.action((...fnArgs) => {
|
||||
.action((...fnArgs: any[]) => {
|
||||
debug('running Cypress with args %o', fnArgs)
|
||||
require('./exec/run')
|
||||
.start(parseVariableOpts(fnArgs, args))
|
||||
|
||||
runModule.start(parseVariableOpts(fnArgs, args as string[]))
|
||||
.then(util.exit)
|
||||
.catch(util.logErrorExit1)
|
||||
})
|
||||
@@ -487,8 +496,8 @@ module.exports = {
|
||||
'Installs the Cypress executable matching this package\'s version',
|
||||
)
|
||||
.option('-f, --force', text('forceInstall'))
|
||||
.action((opts) => {
|
||||
require('./tasks/install')
|
||||
.action((opts: any) => {
|
||||
installModule
|
||||
.start(util.parseOpts(opts))
|
||||
.catch(util.logErrorExit1)
|
||||
})
|
||||
@@ -500,12 +509,12 @@ module.exports = {
|
||||
'Verifies that Cypress is installed correctly and executable',
|
||||
)
|
||||
.option('--dev', text('dev'), coerceFalse)
|
||||
.action((opts) => {
|
||||
.action((opts: any) => {
|
||||
const defaultOpts = { force: true, welcomeMessage: false }
|
||||
const parsedOpts = util.parseOpts(opts)
|
||||
const options = _.extend(parsedOpts, defaultOpts)
|
||||
|
||||
require('./tasks/verify')
|
||||
verifyModule
|
||||
.start(options)
|
||||
.catch(util.logErrorExit1)
|
||||
})
|
||||
@@ -519,7 +528,7 @@ module.exports = {
|
||||
.option('clear', text('cacheClear'))
|
||||
.option('prune', text('cachePrune'))
|
||||
.option('--size', text('cacheSize'))
|
||||
.action(function (opts, args) {
|
||||
.action(function (this: any, opts: any, args: string[]) {
|
||||
if (!args || !args.length) {
|
||||
this.outputHelp()
|
||||
util.exit(1)
|
||||
@@ -542,7 +551,7 @@ module.exports = {
|
||||
logger.always('No cached binary versions were found.')
|
||||
process.exit(0)
|
||||
})
|
||||
.catch((e) => {
|
||||
.catch((e: Error) => {
|
||||
debug('cache list command failed with "%s"', e.message)
|
||||
|
||||
util.logErrorExit1(e)
|
||||
@@ -557,8 +566,8 @@ module.exports = {
|
||||
.usage('[command]')
|
||||
.description('Prints Cypress and system information')
|
||||
.option('--dev', text('dev'), coerceFalse)
|
||||
.action((opts) => {
|
||||
require('./exec/info')
|
||||
.action((opts: any) => {
|
||||
infoModule
|
||||
.start(opts)
|
||||
.then(util.exit)
|
||||
.catch(util.logErrorExit1)
|
||||
@@ -598,6 +607,8 @@ module.exports = {
|
||||
},
|
||||
}
|
||||
|
||||
export default cliModule
|
||||
|
||||
// @ts-ignore
|
||||
if (!module.parent) {
|
||||
logger.error('This CLI module should be required from another Node module')
|
||||
@@ -1,32 +1,33 @@
|
||||
// https://github.com/cypress-io/cypress/issues/316
|
||||
|
||||
const Promise = require('bluebird')
|
||||
const tmp = Promise.promisifyAll(require('tmp'))
|
||||
import Bluebird from 'bluebird'
|
||||
import tmpModule from 'tmp'
|
||||
import fs from './fs'
|
||||
import openModule from './exec/open'
|
||||
import runModule from './exec/run'
|
||||
import util from './util'
|
||||
import cli from './cli'
|
||||
|
||||
const fs = require('./fs')
|
||||
const open = require('./exec/open')
|
||||
const run = require('./exec/run')
|
||||
const util = require('./util')
|
||||
const cli = require('./cli')
|
||||
const tmp = Bluebird.promisifyAll(tmpModule) as any
|
||||
|
||||
const cypressModuleApi = {
|
||||
/**
|
||||
* Opens Cypress GUI
|
||||
* @see https://on.cypress.io/module-api#cypress-open
|
||||
*/
|
||||
open (options = {}) {
|
||||
open (options: any = {}): any {
|
||||
options = util.normalizeModuleOptions(options)
|
||||
|
||||
return open.start(options)
|
||||
return openModule.start(options)
|
||||
},
|
||||
|
||||
/**
|
||||
* Runs Cypress tests in the current project
|
||||
* @see https://on.cypress.io/module-api#cypress-run
|
||||
*/
|
||||
run (options = {}) {
|
||||
if (!run.isValidProject(options.project)) {
|
||||
return Promise.reject(new Error(`Invalid project path parameter: ${options.project}`))
|
||||
run (options: any = {}): any {
|
||||
if (!runModule.isValidProject(options.project)) {
|
||||
return Bluebird.reject(new Error(`Invalid project path parameter: ${options.project}`))
|
||||
}
|
||||
|
||||
options = util.normalizeModuleOptions(options)
|
||||
@@ -34,13 +35,13 @@ const cypressModuleApi = {
|
||||
tmp.setGracefulCleanup()
|
||||
|
||||
return tmp.fileAsync()
|
||||
.then((outputPath) => {
|
||||
.then((outputPath: string) => {
|
||||
options.outputPath = outputPath
|
||||
|
||||
return run.start(options)
|
||||
.then((failedTests) => {
|
||||
return runModule.start(options)
|
||||
.then((failedTests: any) => {
|
||||
return fs.readJsonAsync(outputPath, { throws: false })
|
||||
.then((output) => {
|
||||
.then((output: any) => {
|
||||
if (!output) {
|
||||
return {
|
||||
status: 'failed',
|
||||
@@ -66,7 +67,7 @@ const cypressModuleApi = {
|
||||
* await cypress.run(options)
|
||||
* @see https://on.cypress.io/module-api
|
||||
*/
|
||||
parseRunArguments (args) {
|
||||
parseRunArguments (args: string[]): any {
|
||||
return cli.parseRunCommand(args)
|
||||
},
|
||||
},
|
||||
@@ -84,7 +85,7 @@ const cypressModuleApi = {
|
||||
* @param {Cypress.ConfigOptions} config
|
||||
* @returns {Cypress.ConfigOptions} the configuration passed in parameter
|
||||
*/
|
||||
defineConfig (config) {
|
||||
defineConfig (config: any): any {
|
||||
return config
|
||||
},
|
||||
|
||||
@@ -102,9 +103,9 @@ const cypressModuleApi = {
|
||||
* @param {Cypress.ThirdPartyComponentFrameworkDefinition} config
|
||||
* @returns {Cypress.ThirdPartyComponentFrameworkDefinition} the configuration passed in parameter
|
||||
*/
|
||||
defineComponentFramework (config) {
|
||||
defineComponentFramework (config: any): any {
|
||||
return config
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = cypressModuleApi
|
||||
export = cypressModuleApi
|
||||
@@ -1,10 +1,9 @@
|
||||
const chalk = require('chalk')
|
||||
const { stripIndent, stripIndents } = require('common-tags')
|
||||
const la = require('lazy-ass')
|
||||
const is = require('check-more-types')
|
||||
|
||||
const util = require('./util')
|
||||
const state = require('./tasks/state')
|
||||
import chalk from 'chalk'
|
||||
import { stripIndent, stripIndents } from 'common-tags'
|
||||
import la from 'lazy-ass'
|
||||
import is from 'check-more-types'
|
||||
import util from './util'
|
||||
import state from './tasks/state'
|
||||
|
||||
const docsUrl = 'https://on.cypress.io'
|
||||
const requiredDependenciesUrl = `${docsUrl}/required-dependencies`
|
||||
@@ -13,7 +12,7 @@ const runDocumentationUrl = `${docsUrl}/cypress-run`
|
||||
// TODO it would be nice if all error objects could be enforced via types
|
||||
// to only have description + solution properties
|
||||
|
||||
const hr = '----------'
|
||||
export const hr = '----------'
|
||||
|
||||
const genericErrorSolution = stripIndent`
|
||||
Search for an existing issue or open a GitHub issue at
|
||||
@@ -65,7 +64,7 @@ const failedUnzipWindowsMaxPathLength = {
|
||||
Read here for solutions to this problem: https://on.cypress.io/win-max-path-length-error`,
|
||||
}
|
||||
|
||||
const missingApp = (binaryDir) => {
|
||||
const missingApp = (binaryDir: string): any => {
|
||||
return {
|
||||
description: `No version of Cypress is installed in: ${chalk.cyan(
|
||||
binaryDir,
|
||||
@@ -76,7 +75,7 @@ const missingApp = (binaryDir) => {
|
||||
}
|
||||
}
|
||||
|
||||
const binaryNotExecutable = (executable) => {
|
||||
const binaryNotExecutable = (executable: string): any => {
|
||||
return {
|
||||
description: `Cypress cannot run because this binary file does not have executable permissions here:\n\n${executable}`,
|
||||
solution: stripIndent`\n
|
||||
@@ -92,7 +91,7 @@ const binaryNotExecutable = (executable) => {
|
||||
}
|
||||
}
|
||||
|
||||
const notInstalledCI = (executable) => {
|
||||
const notInstalledCI = (executable: string): any => {
|
||||
return {
|
||||
description:
|
||||
'The cypress npm package is installed, but the Cypress binary is missing.',
|
||||
@@ -135,7 +134,7 @@ const missingXvfb = {
|
||||
`,
|
||||
}
|
||||
|
||||
const smokeTestFailure = (smokeTestCommand, timedOut) => {
|
||||
const smokeTestFailure = (smokeTestCommand: string, timedOut: boolean): any => {
|
||||
return {
|
||||
description: `Cypress verification ${timedOut ? 'timed out' : 'failed'}.`,
|
||||
solution: stripIndent`
|
||||
@@ -150,7 +149,7 @@ const smokeTestFailure = (smokeTestCommand, timedOut) => {
|
||||
const invalidSmokeTestDisplayError = {
|
||||
code: 'INVALID_SMOKE_TEST_DISPLAY_ERROR',
|
||||
description: 'Cypress verification failed.',
|
||||
solution (msg) {
|
||||
solution (msg: string): string {
|
||||
return stripIndent`
|
||||
Cypress failed to start after spawning a new Xvfb server.
|
||||
|
||||
@@ -249,7 +248,7 @@ const invalidConfigFile = {
|
||||
* @param {'close'|'event'} eventName Child close event name
|
||||
* @param {string} signal Signal that closed the child process, like "SIGBUS"
|
||||
*/
|
||||
const childProcessKilled = (eventName, signal) => {
|
||||
const childProcessKilled = (eventName: string, signal: string): any => {
|
||||
return {
|
||||
description: `The Test Runner unexpectedly exited via a ${chalk.cyan(eventName)} event with signal ${chalk.cyan(signal)}`,
|
||||
solution: solutionUnknown,
|
||||
@@ -257,7 +256,7 @@ const childProcessKilled = (eventName, signal) => {
|
||||
}
|
||||
|
||||
const CYPRESS_RUN_BINARY = {
|
||||
notValid: (value) => {
|
||||
notValid: (value: string): any => {
|
||||
const properFormat = `**/${state.getPlatformExecutable()}`
|
||||
|
||||
return {
|
||||
@@ -267,8 +266,8 @@ const CYPRESS_RUN_BINARY = {
|
||||
},
|
||||
}
|
||||
|
||||
function addPlatformInformation (info) {
|
||||
return util.getPlatformInfo().then((platform) => {
|
||||
function addPlatformInformation (info: any): any {
|
||||
return util.getPlatformInfo().then((platform: string) => {
|
||||
return { ...info, platform }
|
||||
})
|
||||
}
|
||||
@@ -285,9 +284,9 @@ function addPlatformInformation (info) {
|
||||
return getError(errorObject).then(reject)
|
||||
```
|
||||
*/
|
||||
function getError (errorObject) {
|
||||
return formErrorText(errorObject).then((errorMessage) => {
|
||||
const err = new Error(errorMessage)
|
||||
export function getError (errorObject: any): Promise<Error> {
|
||||
return formErrorText(errorObject).then((errorMessage: string) => {
|
||||
const err: any = new Error(errorMessage)
|
||||
|
||||
err.known = true
|
||||
|
||||
@@ -299,11 +298,11 @@ function getError (errorObject) {
|
||||
* Forms nice error message with error and platform information,
|
||||
* and if possible a way to solve it. Resolves with a string.
|
||||
*/
|
||||
function formErrorText (info, msg, prevMessage) {
|
||||
return addPlatformInformation(info).then((obj) => {
|
||||
const formatted = []
|
||||
export function formErrorText (info: any, msg?: string, prevMessage?: string): any {
|
||||
return addPlatformInformation(info).then((obj: any) => {
|
||||
const formatted: string[] = []
|
||||
|
||||
function add (msg) {
|
||||
function add (msg: string): void {
|
||||
formatted.push(stripIndents(msg))
|
||||
}
|
||||
|
||||
@@ -369,9 +368,9 @@ function formErrorText (info, msg, prevMessage) {
|
||||
})
|
||||
}
|
||||
|
||||
const raise = (info) => {
|
||||
return (text) => {
|
||||
const err = new Error(text)
|
||||
export const raise = (info: any) => {
|
||||
return (text: string) => {
|
||||
const err: any = new Error(text)
|
||||
|
||||
if (info.code) {
|
||||
err.code = info.code
|
||||
@@ -382,8 +381,8 @@ const raise = (info) => {
|
||||
}
|
||||
}
|
||||
|
||||
const throwFormErrorText = (info) => {
|
||||
return (msg, prevMessage) => {
|
||||
export const throwFormErrorText = (info: any) => {
|
||||
return (msg?: string, prevMessage?: string) => {
|
||||
return formErrorText(info, msg, prevMessage).then(raise(info))
|
||||
}
|
||||
}
|
||||
@@ -394,9 +393,9 @@ const throwFormErrorText = (info) => {
|
||||
* @param {ErrorInformation} info Error information {description, solution}
|
||||
* @example return exitWithError(errors.invalidCypressEnv)('foo')
|
||||
*/
|
||||
const exitWithError = (info) => {
|
||||
return (msg) => {
|
||||
return formErrorText(info, msg).then((text) => {
|
||||
export const exitWithError = (info: any) => {
|
||||
return (msg?: string) => {
|
||||
return formErrorText(info, msg).then((text: string) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(text)
|
||||
process.exit(info.exitCode || 1)
|
||||
@@ -404,39 +403,30 @@ const exitWithError = (info) => {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
raise,
|
||||
exitWithError,
|
||||
// formError,
|
||||
formErrorText,
|
||||
throwFormErrorText,
|
||||
getError,
|
||||
hr,
|
||||
errors: {
|
||||
unknownError,
|
||||
nonZeroExitCodeXvfb,
|
||||
missingXvfb,
|
||||
missingApp,
|
||||
notInstalledCI,
|
||||
missingDependency,
|
||||
invalidOS,
|
||||
invalidSmokeTestDisplayError,
|
||||
versionMismatch,
|
||||
binaryNotExecutable,
|
||||
unexpected,
|
||||
failedDownload,
|
||||
failedUnzip,
|
||||
failedUnzipWindowsMaxPathLength,
|
||||
invalidCypressEnv,
|
||||
invalidCacheDirectory,
|
||||
CYPRESS_RUN_BINARY,
|
||||
smokeTestFailure,
|
||||
childProcessKilled,
|
||||
incompatibleHeadlessFlags,
|
||||
invalidRunProjectPath,
|
||||
invalidTestingType,
|
||||
incompatibleTestTypeFlags,
|
||||
incompatibleTestingTypeAndFlag,
|
||||
invalidConfigFile,
|
||||
},
|
||||
export const errors = {
|
||||
unknownError,
|
||||
nonZeroExitCodeXvfb,
|
||||
missingXvfb,
|
||||
missingApp,
|
||||
notInstalledCI,
|
||||
missingDependency,
|
||||
invalidOS,
|
||||
invalidSmokeTestDisplayError,
|
||||
versionMismatch,
|
||||
binaryNotExecutable,
|
||||
unexpected,
|
||||
failedDownload,
|
||||
failedUnzip,
|
||||
failedUnzipWindowsMaxPathLength,
|
||||
invalidCypressEnv,
|
||||
invalidCacheDirectory,
|
||||
CYPRESS_RUN_BINARY,
|
||||
smokeTestFailure,
|
||||
childProcessKilled,
|
||||
incompatibleHeadlessFlags,
|
||||
invalidRunProjectPath,
|
||||
invalidTestingType,
|
||||
incompatibleTestTypeFlags,
|
||||
incompatibleTestingTypeAndFlag,
|
||||
invalidConfigFile,
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
/* eslint-disable no-console */
|
||||
const spawn = require('./spawn')
|
||||
const util = require('../util')
|
||||
const state = require('../tasks/state')
|
||||
const os = require('os')
|
||||
const chalk = require('chalk')
|
||||
const prettyBytes = require('pretty-bytes')
|
||||
const _ = require('lodash')
|
||||
import spawn from './spawn'
|
||||
import util from '../util'
|
||||
import state from '../tasks/state'
|
||||
import os from 'os'
|
||||
import chalk from 'chalk'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import _ from 'lodash'
|
||||
|
||||
// color for numbers and show values
|
||||
const g = chalk.green
|
||||
@@ -16,13 +16,13 @@ const red = chalk.red
|
||||
const link = chalk.blue.underline
|
||||
|
||||
// to be exported
|
||||
const methods = {}
|
||||
const methods: any = {}
|
||||
|
||||
methods.findProxyEnvironmentVariables = () => {
|
||||
methods.findProxyEnvironmentVariables = (): any => {
|
||||
return _.pick(process.env, ['HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY'])
|
||||
}
|
||||
|
||||
const maskSensitiveVariables = (obj) => {
|
||||
const maskSensitiveVariables = (obj: any): any => {
|
||||
const masked = { ...obj }
|
||||
|
||||
if (masked.CYPRESS_RECORD_KEY) {
|
||||
@@ -32,19 +32,19 @@ const maskSensitiveVariables = (obj) => {
|
||||
return masked
|
||||
}
|
||||
|
||||
methods.findCypressEnvironmentVariables = () => {
|
||||
const isCyVariable = (val, key) => key.startsWith('CYPRESS_')
|
||||
methods.findCypressEnvironmentVariables = (): any => {
|
||||
const isCyVariable = (val: any, key: string): boolean => key.startsWith('CYPRESS_')
|
||||
|
||||
return _.pickBy(process.env, isCyVariable)
|
||||
}
|
||||
|
||||
const formatCypressVariables = () => {
|
||||
const formatCypressVariables = (): any => {
|
||||
const vars = methods.findCypressEnvironmentVariables()
|
||||
|
||||
return maskSensitiveVariables(vars)
|
||||
}
|
||||
|
||||
methods.start = async (options = {}) => {
|
||||
methods.start = async (options: any = {}): Promise<void> => {
|
||||
const args = ['--mode=info']
|
||||
|
||||
await spawn.start(args, {
|
||||
@@ -58,7 +58,7 @@ methods.start = async (options = {}) => {
|
||||
console.log('Proxy Settings: none detected')
|
||||
} else {
|
||||
console.log('Proxy Settings:')
|
||||
_.forEach(proxyVars, (value, key) => {
|
||||
_.forEach(proxyVars, (value: any, key: string) => {
|
||||
console.log('%s: %s', key, g(value))
|
||||
})
|
||||
|
||||
@@ -73,7 +73,7 @@ methods.start = async (options = {}) => {
|
||||
console.log('Environment Variables: none detected')
|
||||
} else {
|
||||
console.log('Environment Variables:')
|
||||
_.forEach(cyVars, (value, key) => {
|
||||
_.forEach(cyVars, (value: any, key: string) => {
|
||||
console.log('%s: %s', key, g(value))
|
||||
})
|
||||
}
|
||||
@@ -106,4 +106,4 @@ methods.start = async (options = {}) => {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = methods
|
||||
export default methods
|
||||
@@ -1,9 +1,11 @@
|
||||
const debug = require('debug')('cypress:cli')
|
||||
const util = require('../util')
|
||||
const spawn = require('./spawn')
|
||||
const verify = require('../tasks/verify')
|
||||
const { processTestingType, checkConfigFile } = require('./shared')
|
||||
const { exitWithError } = require('../errors')
|
||||
import Debug from 'debug'
|
||||
import util from '../util'
|
||||
import spawn from './spawn'
|
||||
import verifyModule from '../tasks/verify'
|
||||
import { processTestingType, checkConfigFile } from './shared'
|
||||
import { exitWithError } from '../errors'
|
||||
|
||||
const debug = Debug('cypress:cli')
|
||||
|
||||
/**
|
||||
* Maps options collected by the CLI
|
||||
@@ -14,7 +16,7 @@ const { exitWithError } = require('../errors')
|
||||
*
|
||||
* @returns {string[]} list of CLI arguments
|
||||
*/
|
||||
const processOpenOptions = (options = {}) => {
|
||||
export const processOpenOptions = (options: any = {}): string[] => {
|
||||
// In addition to setting the project directory, setting the project option
|
||||
// here ultimately decides whether cypress is run in global mode or not.
|
||||
// It's first based off whether it's installed globally by npm/yarn (-g).
|
||||
@@ -25,7 +27,7 @@ const processOpenOptions = (options = {}) => {
|
||||
options.project = process.cwd()
|
||||
}
|
||||
|
||||
const args = []
|
||||
const args: string[] = []
|
||||
|
||||
if (options.config) {
|
||||
args.push('--config', options.config)
|
||||
@@ -72,31 +74,33 @@ const processOpenOptions = (options = {}) => {
|
||||
return args
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
processOpenOptions,
|
||||
start (options = {}) {
|
||||
function open () {
|
||||
try {
|
||||
const args = processOpenOptions(options)
|
||||
export const start = (options: any = {}): any => {
|
||||
function open (): any {
|
||||
try {
|
||||
const args = processOpenOptions(options)
|
||||
|
||||
return spawn.start(args, {
|
||||
dev: options.dev,
|
||||
detached: Boolean(options.detached),
|
||||
})
|
||||
} catch (err) {
|
||||
if (err.details) {
|
||||
return exitWithError(err.details)()
|
||||
}
|
||||
|
||||
throw err
|
||||
return spawn.start(args, {
|
||||
dev: options.dev,
|
||||
detached: Boolean(options.detached),
|
||||
})
|
||||
} catch (err: any) {
|
||||
if (err.details) {
|
||||
return exitWithError(err.details)()
|
||||
}
|
||||
}
|
||||
|
||||
if (options.dev) {
|
||||
return open()
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
return verify.start()
|
||||
.then(open)
|
||||
},
|
||||
if (options.dev) {
|
||||
return open()
|
||||
}
|
||||
|
||||
return verifyModule.start()
|
||||
.then(open)
|
||||
}
|
||||
|
||||
export default {
|
||||
start,
|
||||
processOpenOptions,
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
const _ = require('lodash')
|
||||
const debug = require('debug')('cypress:cli:run')
|
||||
import _ from 'lodash'
|
||||
import Debug from 'debug'
|
||||
import util from '../util'
|
||||
import spawn from './spawn'
|
||||
import verifyModule from '../tasks/verify'
|
||||
import { exitWithError, errors } from '../errors'
|
||||
import { processTestingType, throwInvalidOptionError, checkConfigFile } from './shared'
|
||||
|
||||
const util = require('../util')
|
||||
const spawn = require('./spawn')
|
||||
const verify = require('../tasks/verify')
|
||||
const { exitWithError, errors } = require('../errors')
|
||||
const { processTestingType, throwInvalidOptionError, checkConfigFile } = require('./shared')
|
||||
const debug = Debug('cypress:cli:run')
|
||||
|
||||
/**
|
||||
* Typically a user passes a string path to the project.
|
||||
@@ -13,7 +14,7 @@ const { processTestingType, throwInvalidOptionError, checkConfigFile } = require
|
||||
* and the user can accidentally execute `cypress run --project false`
|
||||
* which should be invalid.
|
||||
*/
|
||||
const isValidProject = (v) => {
|
||||
const isValidProject = (v: any): boolean => {
|
||||
if (typeof v === 'boolean') {
|
||||
return false
|
||||
}
|
||||
@@ -34,7 +35,7 @@ const isValidProject = (v) => {
|
||||
*
|
||||
* @returns {string[]} list of CLI arguments
|
||||
*/
|
||||
const processRunOptions = (options = {}) => {
|
||||
const processRunOptions = (options: any = {}): string[] => {
|
||||
debug('processing run options %o', options)
|
||||
|
||||
if (!isValidProject(options.project)) {
|
||||
@@ -43,7 +44,7 @@ const processRunOptions = (options = {}) => {
|
||||
return throwInvalidOptionError(errors.invalidRunProjectPath)
|
||||
}
|
||||
|
||||
const args = ['--run-project', options.project]
|
||||
const args: string[] = ['--run-project', options.project]
|
||||
|
||||
if (options.autoCancelAfterFailures || options.autoCancelAfterFailures === 0 || options.autoCancelAfterFailures === false) {
|
||||
args.push('--auto-cancel-after-failures', options.autoCancelAfterFailures)
|
||||
@@ -87,7 +88,7 @@ const processRunOptions = (options = {}) => {
|
||||
return throwInvalidOptionError(errors.incompatibleHeadlessFlags)
|
||||
}
|
||||
|
||||
args.push('--headed', !options.headless)
|
||||
args.push('--headed', String(!options.headless))
|
||||
}
|
||||
|
||||
// if key is set use that - else attempt to find it by environment variable
|
||||
@@ -159,11 +160,11 @@ const processRunOptions = (options = {}) => {
|
||||
return args
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
const runModule = {
|
||||
processRunOptions,
|
||||
isValidProject,
|
||||
// resolves with the number of failed tests
|
||||
start (options = {}) {
|
||||
start (options: any = {}): any {
|
||||
_.defaults(options, {
|
||||
key: null,
|
||||
spec: null,
|
||||
@@ -172,7 +173,7 @@ module.exports = {
|
||||
project: process.cwd(),
|
||||
})
|
||||
|
||||
function run () {
|
||||
function run (): any {
|
||||
try {
|
||||
const args = processRunOptions(options)
|
||||
|
||||
@@ -181,7 +182,7 @@ module.exports = {
|
||||
return spawn.start(args, {
|
||||
dev: options.dev,
|
||||
})
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
if (err.details) {
|
||||
return exitWithError(err.details)()
|
||||
}
|
||||
@@ -194,7 +195,9 @@ module.exports = {
|
||||
return run()
|
||||
}
|
||||
|
||||
return verify.start()
|
||||
return verifyModule.start()
|
||||
.then(run)
|
||||
},
|
||||
}
|
||||
|
||||
export default runModule
|
||||
@@ -1,18 +1,18 @@
|
||||
const { errors } = require('../errors')
|
||||
import { errors } from '../errors'
|
||||
|
||||
/**
|
||||
* Throws an error with "details" property from
|
||||
* "errors" object.
|
||||
* @param {Object} details - Error details
|
||||
*/
|
||||
const throwInvalidOptionError = (details) => {
|
||||
export const throwInvalidOptionError = (details?: any): never => {
|
||||
if (!details) {
|
||||
details = errors.unknownError
|
||||
}
|
||||
|
||||
// throw this error synchronously, it will be caught later on and
|
||||
// the details will be propagated to the promise chain
|
||||
const err = new Error()
|
||||
const err: any = new Error()
|
||||
|
||||
err.details = details
|
||||
throw err
|
||||
@@ -23,7 +23,7 @@ const throwInvalidOptionError = (details) => {
|
||||
* @param {string} testingType The type of tests being executed
|
||||
* @returns {string[]} The array of new exec arguments
|
||||
*/
|
||||
const processTestingType = (options) => {
|
||||
export const processTestingType = (options: any): string[] => {
|
||||
if (options.e2e && options.component) {
|
||||
return throwInvalidOptionError(errors.incompatibleTestTypeFlags)
|
||||
}
|
||||
@@ -51,15 +51,9 @@ const processTestingType = (options) => {
|
||||
* Throws an error if configFile is string 'false' or boolean false
|
||||
* @param {*} options
|
||||
*/
|
||||
const checkConfigFile = (options) => {
|
||||
export const checkConfigFile = (options: any): void => {
|
||||
// CLI will parse as string, module API can pass in boolean
|
||||
if (options.configFile === 'false' || options.configFile === false) {
|
||||
throwInvalidOptionError(errors.invalidConfigFile)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
throwInvalidOptionError,
|
||||
processTestingType,
|
||||
checkConfigFile,
|
||||
}
|
||||
@@ -1,21 +1,23 @@
|
||||
const _ = require('lodash')
|
||||
const os = require('os')
|
||||
const cp = require('child_process')
|
||||
const path = require('path')
|
||||
const Promise = require('bluebird')
|
||||
const debug = require('debug')('cypress:cli')
|
||||
const util = require('../util')
|
||||
const state = require('../tasks/state')
|
||||
const xvfb = require('./xvfb')
|
||||
const verify = require('../tasks/verify')
|
||||
const errors = require('../errors')
|
||||
const readline = require('readline')
|
||||
import _ from 'lodash'
|
||||
import os from 'os'
|
||||
import cp from 'child_process'
|
||||
import path from 'path'
|
||||
import Bluebird from 'bluebird'
|
||||
import Debug from 'debug'
|
||||
import util from '../util'
|
||||
import state from '../tasks/state'
|
||||
import xvfb from './xvfb'
|
||||
import verifyModule from '../tasks/verify'
|
||||
import { throwFormErrorText, getError, errors } from '../errors'
|
||||
import readline from 'readline'
|
||||
|
||||
function isPlatform (platform) {
|
||||
const debug = Debug('cypress:cli')
|
||||
|
||||
function isPlatform (platform: string): boolean {
|
||||
return os.platform() === platform
|
||||
}
|
||||
|
||||
function needsStderrPiped (needsXvfb) {
|
||||
function needsStderrPiped (needsXvfb: boolean): boolean {
|
||||
return _.some([
|
||||
isPlatform('darwin'),
|
||||
|
||||
@@ -25,11 +27,11 @@ function needsStderrPiped (needsXvfb) {
|
||||
])
|
||||
}
|
||||
|
||||
function needsEverythingPipedDirectly () {
|
||||
function needsEverythingPipedDirectly (): boolean {
|
||||
return isPlatform('win32')
|
||||
}
|
||||
|
||||
function getStdio (needsXvfb) {
|
||||
function getStdio (needsXvfb: boolean): any {
|
||||
if (needsEverythingPipedDirectly()) {
|
||||
return 'pipe'
|
||||
}
|
||||
@@ -47,13 +49,13 @@ function getStdio (needsXvfb) {
|
||||
return 'inherit'
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
start (args, options = {}) {
|
||||
const spawnModule = {
|
||||
start (args: any, options: any = {}): any {
|
||||
const needsXvfb = xvfb.isNeeded()
|
||||
let executable = state.getPathToExecutable(state.getBinaryDir())
|
||||
|
||||
if (util.getEnv('CYPRESS_RUN_BINARY')) {
|
||||
executable = path.resolve(util.getEnv('CYPRESS_RUN_BINARY'))
|
||||
executable = path.resolve(util.getEnv('CYPRESS_RUN_BINARY') as string)
|
||||
}
|
||||
|
||||
debug('needs to start own Xvfb?', needsXvfb)
|
||||
@@ -75,29 +77,29 @@ module.exports = {
|
||||
stdio: getStdio(needsXvfb),
|
||||
})
|
||||
|
||||
const spawn = (overrides = {}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const spawn = (overrides: any = {}): any => {
|
||||
return new Bluebird((resolve: any, reject: any) => {
|
||||
_.defaults(overrides, {
|
||||
onStderrData: false,
|
||||
})
|
||||
|
||||
const { onStderrData } = overrides
|
||||
const envOverrides = util.getEnvOverrides(options)
|
||||
const electronArgs = []
|
||||
const electronArgs: string[] = []
|
||||
const node11WindowsFix = isPlatform('win32')
|
||||
|
||||
let startScriptPath
|
||||
let startScriptPath: string | undefined
|
||||
|
||||
if (options.dev) {
|
||||
executable = 'node'
|
||||
// if we're in dev then reset
|
||||
// the launch cmd to be 'npm run dev'
|
||||
startScriptPath = path.resolve(__dirname, '..', '..', '..', 'scripts', 'start.js'),
|
||||
startScriptPath = path.resolve(__dirname, '..', '..', '..', 'scripts', 'start.js')
|
||||
|
||||
debug('in dev mode the args became %o', args)
|
||||
}
|
||||
|
||||
if (!options.dev && verify.needsSandbox()) {
|
||||
if (!options.dev && verifyModule.needsSandbox()) {
|
||||
electronArgs.push('--no-sandbox')
|
||||
}
|
||||
|
||||
@@ -105,7 +107,7 @@ module.exports = {
|
||||
/**
|
||||
* @type {import('child_process').ForkOptions}
|
||||
*/
|
||||
let stdioOptions = _.pick(options, 'env', 'detached', 'stdio')
|
||||
let stdioOptions: any = _.pick(options, 'env', 'detached', 'stdio')
|
||||
|
||||
// figure out if we're going to be force enabling or disabling colors.
|
||||
// also figure out whether we should force stdout and stderr into thinking
|
||||
@@ -146,14 +148,14 @@ module.exports = {
|
||||
|
||||
const child = cp.spawn(executable, args, stdioOptions)
|
||||
|
||||
function resolveOn (event) {
|
||||
return function (code, signal) {
|
||||
function resolveOn (event: any): any {
|
||||
return function (code: any, signal: any): any {
|
||||
debug('child event fired %o', { event, code, signal })
|
||||
|
||||
if (code === null) {
|
||||
const errorObject = errors.errors.childProcessKilled(event, signal)
|
||||
const errorObject = errors.childProcessKilled(event, signal)
|
||||
|
||||
return errors.getError(errorObject).then(reject)
|
||||
return getError(errorObject).then(reject)
|
||||
}
|
||||
|
||||
resolve(code)
|
||||
@@ -172,10 +174,10 @@ module.exports = {
|
||||
|
||||
// on windows, SIGINT does not propagate to the child process when ctrl+c is pressed
|
||||
// this makes sure all nested processes are closed(ex: firefox inside the server)
|
||||
rl.on('SIGINT', function () {
|
||||
let kill = require('tree-kill')
|
||||
rl.on('SIGINT', async function () {
|
||||
const kill = (await import('tree-kill')).default
|
||||
|
||||
kill(child.pid, 'SIGINT')
|
||||
kill(child.pid as number, 'SIGINT')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -198,7 +200,7 @@ module.exports = {
|
||||
// to filter out the garbage
|
||||
if (child.stderr) {
|
||||
debug('piping child STDERR to process STDERR')
|
||||
child.stderr.on('data', (data) => {
|
||||
child.stderr.on('data', (data: any) => {
|
||||
const str = data.toString()
|
||||
|
||||
// if we have a callback and this explicitly returns
|
||||
@@ -219,7 +221,7 @@ module.exports = {
|
||||
// into the child process. unpiping does not seem
|
||||
// to have any effect. so we're just catching the
|
||||
// error here and not doing anything.
|
||||
process.stdin.on('error', (err) => {
|
||||
process.stdin.on('error', (err: any) => {
|
||||
if (['EPIPE', 'ENOTCONN'].includes(err.code)) {
|
||||
return
|
||||
}
|
||||
@@ -233,24 +235,24 @@ module.exports = {
|
||||
})
|
||||
}
|
||||
|
||||
const spawnInXvfb = () => {
|
||||
const spawnInXvfb = (): any => {
|
||||
return xvfb
|
||||
.start()
|
||||
.then(userFriendlySpawn)
|
||||
.finally(xvfb.stop)
|
||||
}
|
||||
|
||||
const userFriendlySpawn = (linuxWithDisplayEnv) => {
|
||||
const userFriendlySpawn = (linuxWithDisplayEnv: any): any => {
|
||||
debug('spawning, should retry on display problem?', Boolean(linuxWithDisplayEnv))
|
||||
|
||||
let brokenGtkDisplay
|
||||
let brokenGtkDisplay: boolean
|
||||
|
||||
const overrides = {}
|
||||
const overrides: any = {}
|
||||
|
||||
if (linuxWithDisplayEnv) {
|
||||
_.extend(overrides, {
|
||||
electronLogging: true,
|
||||
onStderrData (str) {
|
||||
onStderrData (str: string): any {
|
||||
// if we receive a broken pipe anywhere
|
||||
// then we know that's why cypress exited early
|
||||
if (util.isBrokenGtkDisplay(str)) {
|
||||
@@ -261,7 +263,7 @@ module.exports = {
|
||||
}
|
||||
|
||||
return spawn(overrides)
|
||||
.then((code) => {
|
||||
.then((code: any) => {
|
||||
if (code !== 0 && brokenGtkDisplay) {
|
||||
util.logBrokenGtkDisplayWarning()
|
||||
|
||||
@@ -272,7 +274,7 @@ module.exports = {
|
||||
})
|
||||
// we can format and handle an error message from the code above
|
||||
// prevent wrapping error again by using "known: undefined" filter
|
||||
.catch({ known: undefined }, errors.throwFormErrorText(errors.errors.unexpected))
|
||||
.catch({ known: undefined }, throwFormErrorText(errors.unexpected))
|
||||
}
|
||||
|
||||
if (needsXvfb) {
|
||||
@@ -287,3 +289,5 @@ module.exports = {
|
||||
return userFriendlySpawn(linuxWithDisplayEnv)
|
||||
},
|
||||
}
|
||||
|
||||
export default spawnModule
|
||||
@@ -1,18 +1,19 @@
|
||||
const Promise = require('bluebird')
|
||||
const debug = require('debug')('cypress:cli')
|
||||
const path = require('path')
|
||||
import Bluebird from 'bluebird'
|
||||
import Debug from 'debug'
|
||||
import path from 'path'
|
||||
import util from '../util'
|
||||
import state from '../tasks/state'
|
||||
import { throwFormErrorText, errors } from '../errors'
|
||||
|
||||
const util = require('../util')
|
||||
const state = require('../tasks/state')
|
||||
const { throwFormErrorText, errors } = require('../errors')
|
||||
const debug = Debug('cypress:cli')
|
||||
|
||||
const getVersions = () => {
|
||||
return Promise.try(() => {
|
||||
const getVersions = (): any => {
|
||||
return Bluebird.try(() => {
|
||||
if (util.getEnv('CYPRESS_RUN_BINARY')) {
|
||||
let envBinaryPath = path.resolve(util.getEnv('CYPRESS_RUN_BINARY'))
|
||||
let envBinaryPath = path.resolve(util.getEnv('CYPRESS_RUN_BINARY') as string)
|
||||
|
||||
return state.parseRealPlatformBinaryFolderAsync(envBinaryPath)
|
||||
.then((envBinaryDir) => {
|
||||
.then((envBinaryDir: any) => {
|
||||
if (!envBinaryDir) {
|
||||
return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath))()
|
||||
}
|
||||
@@ -21,7 +22,7 @@ const getVersions = () => {
|
||||
|
||||
return envBinaryDir
|
||||
})
|
||||
.catch({ code: 'ENOENT' }, (err) => {
|
||||
.catch({ code: 'ENOENT' }, (err: any) => {
|
||||
return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath))(err.message)
|
||||
})
|
||||
}
|
||||
@@ -29,7 +30,7 @@ const getVersions = () => {
|
||||
return state.getBinaryDir()
|
||||
})
|
||||
.then(state.getBinaryPkgAsync)
|
||||
.then((pkg) => {
|
||||
.then((pkg: any) => {
|
||||
const versions = {
|
||||
binary: state.getBinaryPkgVersion(pkg),
|
||||
electronVersion: state.getBinaryElectronVersion(pkg),
|
||||
@@ -40,7 +41,7 @@ const getVersions = () => {
|
||||
|
||||
return versions
|
||||
})
|
||||
.then((binaryVersions) => {
|
||||
.then((binaryVersions: any) => {
|
||||
const buildInfo = util.pkgBuildInfo()
|
||||
|
||||
let packageVersion = util.pkgVersion()
|
||||
@@ -61,6 +62,8 @@ const getVersions = () => {
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
const versionsModule = {
|
||||
getVersions,
|
||||
}
|
||||
|
||||
export default versionsModule
|
||||
@@ -1,45 +1,45 @@
|
||||
const os = require('os')
|
||||
const Promise = require('bluebird')
|
||||
const Xvfb = require('@cypress/xvfb')
|
||||
const { stripIndent } = require('common-tags')
|
||||
const Debug = require('debug')
|
||||
const { throwFormErrorText, errors } = require('../errors')
|
||||
const util = require('../util')
|
||||
import os from 'os'
|
||||
import Bluebird from 'bluebird'
|
||||
import Xvfb from '@cypress/xvfb'
|
||||
import { stripIndent } from 'common-tags'
|
||||
import Debug from 'debug'
|
||||
import { throwFormErrorText, errors } from '../errors'
|
||||
import util from '../util'
|
||||
|
||||
const debug = Debug('cypress:cli')
|
||||
const debugXvfb = Debug('cypress:xvfb')
|
||||
const debug: any = Debug('cypress:cli')
|
||||
const debugXvfb: any = Debug('cypress:xvfb')
|
||||
|
||||
debug.Debug = debugXvfb.Debug = Debug
|
||||
|
||||
const xvfbOptions = {
|
||||
const xvfbOptions: any = {
|
||||
displayNum: process.env.XVFB_DISPLAY_NUM,
|
||||
timeout: 30000, // milliseconds
|
||||
// need to explicitly define screen otherwise electron will crash
|
||||
// https://github.com/cypress-io/cypress/issues/6184
|
||||
xvfb_args: ['-screen', '0', '1280x1024x24'],
|
||||
onStderrData (data) {
|
||||
onStderrData (data: any): void {
|
||||
if (debugXvfb.enabled) {
|
||||
debugXvfb(data.toString())
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const xvfb = Promise.promisifyAll(new Xvfb(xvfbOptions))
|
||||
const xvfb: any = Bluebird.promisifyAll(new Xvfb(xvfbOptions))
|
||||
|
||||
module.exports = {
|
||||
const xvfbModule = {
|
||||
_debugXvfb: debugXvfb, // expose for testing
|
||||
|
||||
_xvfb: xvfb, // expose for testing
|
||||
|
||||
_xvfbOptions: xvfbOptions, // expose for testing
|
||||
|
||||
start () {
|
||||
start (): any {
|
||||
debug('Starting Xvfb')
|
||||
|
||||
return xvfb.startAsync()
|
||||
.return(null)
|
||||
.catch({ nonZeroExitCode: true }, throwFormErrorText(errors.nonZeroExitCodeXvfb))
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
if (err.known) {
|
||||
throw err
|
||||
}
|
||||
@@ -48,7 +48,7 @@ module.exports = {
|
||||
})
|
||||
},
|
||||
|
||||
stop () {
|
||||
stop (): any {
|
||||
debug('Stopping Xvfb')
|
||||
|
||||
return xvfb.stopAsync()
|
||||
@@ -58,7 +58,7 @@ module.exports = {
|
||||
})
|
||||
},
|
||||
|
||||
isNeeded () {
|
||||
isNeeded (): boolean {
|
||||
if (process.env.ELECTRON_RUN_AS_NODE) {
|
||||
debug('Environment variable ELECTRON_RUN_AS_NODE detected, xvfb is not needed')
|
||||
|
||||
@@ -95,10 +95,10 @@ module.exports = {
|
||||
},
|
||||
|
||||
// async method, resolved with Boolean
|
||||
verify () {
|
||||
verify (): any {
|
||||
return xvfb.startAsync()
|
||||
.return(true)
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
debug('Could not verify xvfb: %s', err.message)
|
||||
|
||||
return false
|
||||
@@ -106,3 +106,5 @@ module.exports = {
|
||||
.finally(xvfb.stopAsync)
|
||||
},
|
||||
}
|
||||
|
||||
export default xvfbModule
|
||||
@@ -1,3 +0,0 @@
|
||||
const Promise = require('bluebird')
|
||||
|
||||
module.exports = Promise.promisifyAll(require('fs-extra'))
|
||||
4
cli/lib/fs.ts
Normal file
4
cli/lib/fs.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import Bluebird from 'bluebird'
|
||||
import fsExtra from 'fs-extra'
|
||||
|
||||
export default Bluebird.promisifyAll(fsExtra) as any
|
||||
@@ -1,38 +1,38 @@
|
||||
const chalk = require('chalk')
|
||||
import chalk from 'chalk'
|
||||
|
||||
let logs = []
|
||||
let logs: string[] = []
|
||||
|
||||
const logLevel = () => {
|
||||
const logLevel = (): string => {
|
||||
return (process.env.npm_config_loglevel || 'notice')
|
||||
}
|
||||
|
||||
const error = (...messages) => {
|
||||
const error = (...messages: any[]): void => {
|
||||
logs.push(messages.join(' '))
|
||||
console.log(chalk.red(...messages)) // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
const warn = (...messages) => {
|
||||
const warn = (...messages: any[]): void => {
|
||||
if (logLevel() === 'silent') return
|
||||
|
||||
logs.push(messages.join(' '))
|
||||
console.log(chalk.yellow(...messages)) // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
const log = (...messages) => {
|
||||
const log = (...messages: any[]): void => {
|
||||
if (logLevel() === 'silent' || logLevel() === 'warn') return
|
||||
|
||||
logs.push(messages.join(' '))
|
||||
console.log(...messages) // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
const always = (...messages) => {
|
||||
const always = (...messages: any[]): void => {
|
||||
logs.push(messages.join(' '))
|
||||
console.log(...messages) // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
// splits long text into lines and calls log()
|
||||
// on each one to allow easy unit testing for specific message
|
||||
const logLines = (text) => {
|
||||
const logLines = (text: string): void => {
|
||||
const lines = text.split('\n')
|
||||
|
||||
for (const line of lines) {
|
||||
@@ -40,15 +40,15 @@ const logLines = (text) => {
|
||||
}
|
||||
}
|
||||
|
||||
const print = () => {
|
||||
const print = (): string => {
|
||||
return logs.join('\n')
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
const reset = (): void => {
|
||||
logs = []
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
const loggerModule = {
|
||||
log,
|
||||
warn,
|
||||
error,
|
||||
@@ -58,3 +58,5 @@ module.exports = {
|
||||
reset,
|
||||
logLevel,
|
||||
}
|
||||
|
||||
export default loggerModule
|
||||
@@ -1,15 +1,15 @@
|
||||
const state = require('./state')
|
||||
const logger = require('../logger')
|
||||
const fs = require('../fs')
|
||||
const util = require('../util')
|
||||
const { join } = require('path')
|
||||
const Table = require('cli-table3')
|
||||
const dayjs = require('dayjs')
|
||||
const relativeTime = require('dayjs/plugin/relativeTime')
|
||||
const chalk = require('chalk')
|
||||
const _ = require('lodash')
|
||||
const getFolderSize = require('./get-folder-size')
|
||||
const Bluebird = require('bluebird')
|
||||
import state from './state'
|
||||
import logger from '../logger'
|
||||
import fs from '../fs'
|
||||
import util from '../util'
|
||||
|
||||
import { join } from 'path'
|
||||
import Table from 'cli-table3'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import chalk from 'chalk'
|
||||
import _ from 'lodash'
|
||||
import getFolderSize from './get-folder-size'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
@@ -21,47 +21,52 @@ const colors = {
|
||||
size: chalk.gray,
|
||||
}
|
||||
|
||||
const logCachePath = () => {
|
||||
const logCachePath = (): undefined => {
|
||||
logger.always(state.getCacheDir())
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
const clear = (): Promise<void> => {
|
||||
return fs.removeAsync(state.getCacheDir())
|
||||
}
|
||||
|
||||
const prune = () => {
|
||||
const prune = async (): Promise<void> => {
|
||||
const cacheDir = state.getCacheDir()
|
||||
const checkedInBinaryVersion = util.pkgVersion()
|
||||
|
||||
let deletedBinary = false
|
||||
|
||||
return fs.readdirAsync(cacheDir)
|
||||
.then((versions) => {
|
||||
return Bluebird.all(versions.map((version) => {
|
||||
try {
|
||||
const versions = await fs.readdirAsync(cacheDir)
|
||||
|
||||
for (const version of versions) {
|
||||
if (version !== checkedInBinaryVersion) {
|
||||
deletedBinary = true
|
||||
|
||||
const versionDir = join(cacheDir, version)
|
||||
|
||||
return fs.removeAsync(versionDir)
|
||||
await fs.removeAsync(versionDir)
|
||||
}
|
||||
}))
|
||||
})
|
||||
.then(() => {
|
||||
}
|
||||
|
||||
if (deletedBinary) {
|
||||
logger.always(`Deleted all binary caches except for the ${checkedInBinaryVersion} binary cache.`)
|
||||
} else {
|
||||
logger.always(`No binary caches found to prune.`)
|
||||
}
|
||||
})
|
||||
.catch({ code: 'ENOENT' }, () => {
|
||||
logger.always(`No Cypress cache was found at ${cacheDir}. Nothing to prune.`)
|
||||
})
|
||||
} catch (e: any) {
|
||||
if (e.code === 'ENOENT') {
|
||||
logger.always(`No Cypress cache was found at ${cacheDir}. Nothing to prune.`)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
const fileSizeInMB = (size) => {
|
||||
const fileSizeInMB = (size: number): string => {
|
||||
return `${(size / 1024 / 1024).toFixed(1)}MB`
|
||||
}
|
||||
|
||||
@@ -69,9 +74,9 @@ const fileSizeInMB = (size) => {
|
||||
* Collects all cached versions, finds when each was used
|
||||
* and prints a table with results to the terminal
|
||||
*/
|
||||
const list = (showSize) => {
|
||||
const list = (showSize: boolean = false): any => {
|
||||
return getCachedVersions(showSize)
|
||||
.then((binaries) => {
|
||||
.then((binaries: any) => {
|
||||
const head = [colors.titles('version'), colors.titles('last used')]
|
||||
|
||||
if (showSize) {
|
||||
@@ -82,7 +87,7 @@ const list = (showSize) => {
|
||||
head,
|
||||
})
|
||||
|
||||
binaries.forEach((binary) => {
|
||||
binaries.forEach((binary: any) => {
|
||||
const versionString = colors.values(binary.version)
|
||||
const lastUsed = binary.accessed ? colors.dates(binary.accessed) : 'unknown'
|
||||
const row = [versionString, lastUsed]
|
||||
@@ -100,25 +105,25 @@ const list = (showSize) => {
|
||||
})
|
||||
}
|
||||
|
||||
const getCachedVersions = (showSize) => {
|
||||
const getCachedVersions = (showSize: boolean): Promise<any> => {
|
||||
const cacheDir = state.getCacheDir()
|
||||
|
||||
return fs
|
||||
.readdirAsync(cacheDir)
|
||||
.filter(util.isSemver)
|
||||
.map((version) => {
|
||||
.map((version: any) => {
|
||||
return {
|
||||
version,
|
||||
folderPath: join(cacheDir, version),
|
||||
}
|
||||
})
|
||||
.mapSeries((binary) => {
|
||||
.mapSeries((binary: any) => {
|
||||
// last access time on the folder is different from last access time
|
||||
// on the Cypress binary
|
||||
const binaryDir = state.getBinaryDir(binary.version)
|
||||
const executable = state.getPathToExecutable(binaryDir)
|
||||
|
||||
return fs.statAsync(executable).then((stat) => {
|
||||
return fs.statAsync(executable).then((stat: any) => {
|
||||
const lastAccessedTime = _.get(stat, 'atime')
|
||||
|
||||
if (!lastAccessedTime) {
|
||||
@@ -132,16 +137,16 @@ const getCachedVersions = (showSize) => {
|
||||
binary.accessed = accessed
|
||||
|
||||
return binary
|
||||
}, (e) => {
|
||||
}, (e: any) => {
|
||||
// could not find the binary or gets its stats
|
||||
return binary
|
||||
})
|
||||
})
|
||||
.mapSeries((binary) => {
|
||||
.mapSeries((binary: any) => {
|
||||
if (showSize) {
|
||||
const binaryDir = state.getBinaryDir(binary.version)
|
||||
|
||||
return getFolderSize(binaryDir).then((size) => {
|
||||
return getFolderSize(binaryDir).then((size: number) => {
|
||||
return {
|
||||
...binary,
|
||||
size,
|
||||
@@ -153,10 +158,12 @@ const getCachedVersions = (showSize) => {
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
const cacheModule = {
|
||||
path: logCachePath,
|
||||
clear,
|
||||
prune,
|
||||
list,
|
||||
getCachedVersions,
|
||||
}
|
||||
|
||||
export default cacheModule
|
||||
@@ -1,48 +1,49 @@
|
||||
const la = require('lazy-ass')
|
||||
const is = require('check-more-types')
|
||||
const os = require('os')
|
||||
const url = require('url')
|
||||
const path = require('path')
|
||||
const debug = require('debug')('cypress:cli')
|
||||
const request = require('@cypress/request')
|
||||
const Promise = require('bluebird')
|
||||
const requestProgress = require('request-progress')
|
||||
const { stripIndent } = require('common-tags')
|
||||
const getProxyForUrl = require('proxy-from-env').getProxyForUrl
|
||||
import la from 'lazy-ass'
|
||||
import is from 'check-more-types'
|
||||
import os from 'os'
|
||||
import url from 'url'
|
||||
import path from 'path'
|
||||
import Debug from 'debug'
|
||||
import request from '@cypress/request'
|
||||
import Bluebird from 'bluebird'
|
||||
import requestProgress from 'request-progress'
|
||||
import { stripIndent } from 'common-tags'
|
||||
import { getProxyForUrl } from 'proxy-from-env'
|
||||
import { throwFormErrorText, errors } from '../errors'
|
||||
import fs from '../fs'
|
||||
import util from '../util'
|
||||
|
||||
const { throwFormErrorText, errors } = require('../errors')
|
||||
const fs = require('../fs')
|
||||
const util = require('../util')
|
||||
const debug = Debug('cypress:cli')
|
||||
|
||||
const defaultBaseUrl = 'https://download.cypress.io/'
|
||||
const defaultMaxRedirects = 10
|
||||
|
||||
const getProxyForUrlWithNpmConfig = (url) => {
|
||||
const getProxyForUrlWithNpmConfig = (url: string): string | null => {
|
||||
return getProxyForUrl(url) ||
|
||||
process.env.npm_config_https_proxy ||
|
||||
process.env.npm_config_proxy ||
|
||||
null
|
||||
}
|
||||
|
||||
const getBaseUrl = () => {
|
||||
const getBaseUrl = (): string => {
|
||||
if (util.getEnv('CYPRESS_DOWNLOAD_MIRROR')) {
|
||||
let baseUrl = util.getEnv('CYPRESS_DOWNLOAD_MIRROR')
|
||||
|
||||
if (!baseUrl.endsWith('/')) {
|
||||
if (!baseUrl?.endsWith('/')) {
|
||||
baseUrl += '/'
|
||||
}
|
||||
|
||||
return baseUrl
|
||||
return baseUrl || defaultBaseUrl
|
||||
}
|
||||
|
||||
return defaultBaseUrl
|
||||
}
|
||||
|
||||
const getCA = () => {
|
||||
return new Promise((resolve) => {
|
||||
const getCA = (): any => {
|
||||
return new Bluebird((resolve: any) => {
|
||||
if (process.env.npm_config_cafile) {
|
||||
fs.readFile(process.env.npm_config_cafile, 'utf8')
|
||||
.then((cafileContent) => {
|
||||
.then((cafileContent: string) => {
|
||||
resolve(cafileContent)
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -56,7 +57,7 @@ const getCA = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const prepend = (arch, urlPath, version) => {
|
||||
const prepend = (arch: string, urlPath: string, version: string): string => {
|
||||
const endpoint = url.resolve(getBaseUrl(), urlPath)
|
||||
const platform = os.platform()
|
||||
const pathTemplate = util.getEnv('CYPRESS_DOWNLOAD_PATH_TEMPLATE', true)
|
||||
@@ -78,8 +79,8 @@ const prepend = (arch, urlPath, version) => {
|
||||
: `${endpoint}?platform=${platform}&arch=${arch}`
|
||||
}
|
||||
|
||||
const getUrl = (arch, version) => {
|
||||
if (is.url(version)) {
|
||||
const getUrl = (arch: string, version: string): string => {
|
||||
if (is.webUrl(version)) {
|
||||
debug('version is already an url', version)
|
||||
|
||||
return version
|
||||
@@ -90,13 +91,13 @@ const getUrl = (arch, version) => {
|
||||
return prepend(arch, urlPath, version)
|
||||
}
|
||||
|
||||
const statusMessage = (err) => {
|
||||
const statusMessage = (err: any): string => {
|
||||
return (err.statusCode
|
||||
? [err.statusCode, err.statusMessage].join(' - ')
|
||||
: err.toString())
|
||||
}
|
||||
|
||||
const prettyDownloadErr = (err, url) => {
|
||||
const prettyDownloadErr = (err: any, url: string): any => {
|
||||
const msg = stripIndent`
|
||||
URL: ${url}
|
||||
${statusMessage(err)}
|
||||
@@ -111,14 +112,14 @@ const prettyDownloadErr = (err, url) => {
|
||||
* Checks checksum and file size for the given file. Allows both
|
||||
* values or just one of them to be checked.
|
||||
*/
|
||||
const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => {
|
||||
const verifyDownloadedFile = (filename: string, expectedSize?: number, expectedChecksum?: string): any => {
|
||||
if (expectedSize && expectedChecksum) {
|
||||
debug('verifying checksum and file size')
|
||||
|
||||
return Promise.join(
|
||||
return Bluebird.join(
|
||||
util.getFileChecksum(filename),
|
||||
util.getFileSize(filename),
|
||||
(checksum, filesize) => {
|
||||
(checksum: string, filesize: number) => {
|
||||
if (checksum === expectedChecksum && filesize === expectedSize) {
|
||||
debug('downloaded file has the expected checksum and size ✅')
|
||||
|
||||
@@ -147,7 +148,7 @@ const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => {
|
||||
debug('only checking expected file checksum %d', expectedChecksum)
|
||||
|
||||
return util.getFileChecksum(filename)
|
||||
.then((checksum) => {
|
||||
.then((checksum: string) => {
|
||||
if (checksum === expectedChecksum) {
|
||||
debug('downloaded file has the expected checksum ✅')
|
||||
|
||||
@@ -172,7 +173,7 @@ const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => {
|
||||
debug('only checking expected file size %d', expectedSize)
|
||||
|
||||
return util.getFileSize(filename)
|
||||
.then((filesize) => {
|
||||
.then((filesize: number) => {
|
||||
if (filesize === expectedSize) {
|
||||
debug('downloaded file has the expected size ✅')
|
||||
|
||||
@@ -193,15 +194,15 @@ const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => {
|
||||
|
||||
debug('downloaded file lacks checksum or size to verify')
|
||||
|
||||
return Promise.resolve()
|
||||
return Bluebird.resolve()
|
||||
}
|
||||
|
||||
// downloads from given url
|
||||
// return an object with
|
||||
// {filename: ..., downloaded: true}
|
||||
const downloadFromUrl = ({ url, downloadDestination, progress, ca, version, redirectTTL = defaultMaxRedirects }) => {
|
||||
const downloadFromUrl = ({ url, downloadDestination, progress, ca, version, redirectTTL = defaultMaxRedirects }: any): any => {
|
||||
if (redirectTTL <= 0) {
|
||||
return Promise.reject(new Error(
|
||||
return Bluebird.reject(new Error(
|
||||
stripIndent`
|
||||
Failed downloading the Cypress binary.
|
||||
There were too many redirects. The default allowance is ${defaultMaxRedirects}.
|
||||
@@ -210,7 +211,7 @@ const downloadFromUrl = ({ url, downloadDestination, progress, ca, version, redi
|
||||
))
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Bluebird((resolve: any, reject: any) => {
|
||||
const proxy = getProxyForUrlWithNpmConfig(url)
|
||||
|
||||
debug('Downloading package', {
|
||||
@@ -233,14 +234,14 @@ const downloadFromUrl = ({ url, downloadDestination, progress, ca, version, redi
|
||||
const req = request(reqOptions)
|
||||
|
||||
// closure
|
||||
let started = null
|
||||
let expectedSize
|
||||
let expectedChecksum
|
||||
let started: Date | null = null
|
||||
let expectedSize: number | undefined
|
||||
let expectedChecksum: string | undefined
|
||||
|
||||
requestProgress(req, {
|
||||
throttle: progress.throttle,
|
||||
})
|
||||
.on('response', (response) => {
|
||||
.on('response', (response: any) => {
|
||||
// we have computed checksum and filesize during test runner binary build
|
||||
// and have set it on the S3 object as user meta data, available via
|
||||
// these custom headers "x-amz-meta-..."
|
||||
@@ -292,9 +293,9 @@ const downloadFromUrl = ({ url, downloadDestination, progress, ca, version, redi
|
||||
// and handle the completion with verify and resolve
|
||||
// there was a possible race condition between end of request and close of writeStream
|
||||
// that is made ordered with this Promise.all
|
||||
Promise.all([new Promise((r) => {
|
||||
Bluebird.all([new Bluebird((r: any) => {
|
||||
return response.pipe(fs.createWriteStream(downloadDestination).on('close', r))
|
||||
}), new Promise((r) => response.on('end', r))])
|
||||
}), new Bluebird((r: any) => response.on('end', r))])
|
||||
.then(() => {
|
||||
debug('downloading finished')
|
||||
verifyDownloadedFile(downloadDestination, expectedSize,
|
||||
@@ -305,15 +306,15 @@ const downloadFromUrl = ({ url, downloadDestination, progress, ca, version, redi
|
||||
})
|
||||
}
|
||||
})
|
||||
.on('error', (e) => {
|
||||
.on('error', (e: any) => {
|
||||
if (e.code === 'ECONNRESET') return // sometimes proxies give ECONNRESET but we don't care
|
||||
|
||||
reject(e)
|
||||
})
|
||||
.on('progress', (state) => {
|
||||
.on('progress', (state: any) => {
|
||||
// total time we've elapsed
|
||||
// starting on our first progress notification
|
||||
const elapsed = new Date() - started
|
||||
const elapsed = +new Date() - +(started as Date)
|
||||
|
||||
// request-progress sends a value between 0 and 1
|
||||
const percentage = util.convertPercentToPercentage(state.percent)
|
||||
@@ -331,7 +332,7 @@ const downloadFromUrl = ({ url, downloadDestination, progress, ca, version, redi
|
||||
* @param [string] version Could be "3.3.0" or full URL
|
||||
* @param [string] downloadDestination Local filename to save as
|
||||
*/
|
||||
const start = async (opts) => {
|
||||
const start = async (opts: any): Promise<any> => {
|
||||
let { version, downloadDestination, progress, redirectTTL } = opts
|
||||
|
||||
if (!downloadDestination) {
|
||||
@@ -358,18 +359,20 @@ const start = async (opts) => {
|
||||
.then(() => {
|
||||
return getCA()
|
||||
})
|
||||
.then((ca) => {
|
||||
.then((ca: any) => {
|
||||
return downloadFromUrl({ url: versionUrl, downloadDestination, progress, ca, version,
|
||||
...(redirectTTL ? { redirectTTL } : {}) })
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
return prettyDownloadErr(err, versionUrl)
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
const downloadModule = {
|
||||
start,
|
||||
getUrl,
|
||||
getProxyForUrlWithNpmConfig,
|
||||
getCA,
|
||||
}
|
||||
|
||||
export default downloadModule
|
||||
@@ -1,6 +1,6 @@
|
||||
const fs = require('../fs')
|
||||
const { join } = require('path')
|
||||
const Bluebird = require('bluebird')
|
||||
import fs from '../fs'
|
||||
import { join } from 'path'
|
||||
import Bluebird from 'bluebird'
|
||||
|
||||
/**
|
||||
* Get the size of a folder or a file.
|
||||
@@ -11,13 +11,13 @@ const Bluebird = require('bluebird')
|
||||
*
|
||||
* @param {string} path path to the file or the folder.
|
||||
*/
|
||||
async function getSize (path) {
|
||||
async function getSize (path: string): Promise<number> {
|
||||
const stat = await fs.lstat(path)
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
const list = await fs.readdir(path)
|
||||
|
||||
return Bluebird.resolve(list).reduce(async (prev, curr) => {
|
||||
return Bluebird.resolve(list).reduce(async (prev: number, curr: string) => {
|
||||
const currPath = join(path, curr)
|
||||
|
||||
const s = await fs.lstat(currPath)
|
||||
@@ -33,4 +33,4 @@ async function getSize (path) {
|
||||
return stat.size
|
||||
}
|
||||
|
||||
module.exports = getSize
|
||||
export default getSize
|
||||
@@ -1,24 +1,27 @@
|
||||
const _ = require('lodash')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const chalk = require('chalk')
|
||||
const debug = require('debug')('cypress:cli')
|
||||
const { Listr } = require('listr2')
|
||||
const Promise = require('bluebird')
|
||||
const logSymbols = require('log-symbols')
|
||||
const { stripIndent } = require('common-tags')
|
||||
const fs = require('../fs')
|
||||
const download = require('./download')
|
||||
const util = require('../util')
|
||||
const state = require('./state')
|
||||
const unzip = require('./unzip')
|
||||
const logger = require('../logger')
|
||||
const { throwFormErrorText, errors } = require('../errors')
|
||||
const verbose = require('../VerboseRenderer')
|
||||
import _ from 'lodash'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import chalk from 'chalk'
|
||||
import Debug from 'debug'
|
||||
import { Listr } from 'listr2'
|
||||
import Bluebird from 'bluebird'
|
||||
import logSymbols from 'log-symbols'
|
||||
import { stripIndent } from 'common-tags'
|
||||
import fs from '../fs'
|
||||
import download from './download'
|
||||
import util from '../util'
|
||||
import state from './state'
|
||||
import unzip from './unzip'
|
||||
import logger from '../logger'
|
||||
import { throwFormErrorText, errors } from '../errors'
|
||||
import verbose from '../VerboseRenderer'
|
||||
|
||||
const debug = Debug('cypress:cli')
|
||||
|
||||
// Import package.json dynamically to avoid TypeScript JSON import issues
|
||||
const { buildInfo, version } = require('../../package.json')
|
||||
|
||||
function _getBinaryUrlFromBuildInfo (arch, { commitSha, commitBranch }) {
|
||||
function _getBinaryUrlFromBuildInfo (arch: string, { commitSha, commitBranch }: any): string {
|
||||
const platform = os.platform()
|
||||
|
||||
if ((platform === 'win32') && (arch === 'arm64')) {
|
||||
@@ -30,7 +33,7 @@ function _getBinaryUrlFromBuildInfo (arch, { commitSha, commitBranch }) {
|
||||
return `https://cdn.cypress.io/beta/binary/${version}/${platform}-${arch}/${commitBranch}-${commitSha}/cypress.zip`
|
||||
}
|
||||
|
||||
const alreadyInstalledMsg = () => {
|
||||
const alreadyInstalledMsg = (): void => {
|
||||
if (!util.isPostInstall()) {
|
||||
logger.log(stripIndent`
|
||||
Skipping installation:
|
||||
@@ -40,7 +43,7 @@ const alreadyInstalledMsg = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const displayCompletionMsg = () => {
|
||||
const displayCompletionMsg = (): void => {
|
||||
// check here to see if we are globally installed
|
||||
if (util.isInstalledGlobally()) {
|
||||
// if we are display a warning
|
||||
@@ -74,7 +77,7 @@ const displayCompletionMsg = () => {
|
||||
logger.log()
|
||||
}
|
||||
|
||||
const downloadAndUnzip = ({ version, installDir, downloadDir }) => {
|
||||
const downloadAndUnzip = ({ version, installDir, downloadDir }: any): any => {
|
||||
const progress = {
|
||||
throttle: 100,
|
||||
onProgress: null,
|
||||
@@ -89,12 +92,12 @@ const downloadAndUnzip = ({ version, installDir, downloadDir }) => {
|
||||
const tasks = new Listr([
|
||||
{
|
||||
options: { title: util.titleize('Downloading Cypress') },
|
||||
task: (ctx, task) => {
|
||||
task: (ctx: any, task: any) => {
|
||||
// as our download progresses indicate the status
|
||||
progress.onProgress = progessify(task, 'Downloading Cypress')
|
||||
|
||||
return download.start({ version, downloadDestination, progress })
|
||||
.then((redirectVersion) => {
|
||||
.then((redirectVersion: any) => {
|
||||
if (redirectVersion) version = redirectVersion
|
||||
|
||||
debug(`finished downloading file: ${downloadDestination}`)
|
||||
@@ -117,7 +120,7 @@ const downloadAndUnzip = ({ version, installDir, downloadDir }) => {
|
||||
}),
|
||||
{
|
||||
options: { title: util.titleize('Finishing Installation') },
|
||||
task: (ctx, task) => {
|
||||
task: (ctx: any, task: any) => {
|
||||
const cleanup = () => {
|
||||
debug('removing zip file %s', downloadDestination)
|
||||
|
||||
@@ -139,11 +142,11 @@ const downloadAndUnzip = ({ version, installDir, downloadDir }) => {
|
||||
], { rendererOptions })
|
||||
|
||||
// start the tasks!
|
||||
return Promise.resolve(tasks.run())
|
||||
return Bluebird.resolve(tasks.run())
|
||||
}
|
||||
|
||||
const validateOS = () => {
|
||||
return util.getPlatformInfo().then((platformInfo) => {
|
||||
const validateOS = (): any => {
|
||||
return util.getPlatformInfo().then((platformInfo: string) => {
|
||||
return platformInfo.match(/(win32-x64|win32-arm64|linux-x64|linux-arm64|darwin-x64|darwin-arm64)/)
|
||||
})
|
||||
}
|
||||
@@ -152,7 +155,7 @@ const validateOS = () => {
|
||||
* Returns the version to install - either a string like `1.2.3` to be fetched
|
||||
* from the download server or a file path or HTTP URL.
|
||||
*/
|
||||
function getVersionOverride ({ arch, envVarVersion, buildInfo }) {
|
||||
function getVersionOverride ({ arch, envVarVersion, buildInfo }: any): string | undefined {
|
||||
// let this environment variable reset the binary version we need
|
||||
if (envVarVersion) {
|
||||
return envVarVersion
|
||||
@@ -178,7 +181,7 @@ function getVersionOverride ({ arch, envVarVersion, buildInfo }) {
|
||||
}
|
||||
}
|
||||
|
||||
function getEnvVarVersion () {
|
||||
function getEnvVarVersion (): string | undefined {
|
||||
if (!util.getEnv('CYPRESS_INSTALL_BINARY')) return
|
||||
|
||||
// because passed file paths are often double quoted
|
||||
@@ -191,7 +194,7 @@ function getEnvVarVersion () {
|
||||
return envVarVersion
|
||||
}
|
||||
|
||||
const start = async (options = {}) => {
|
||||
const start = async (options: any = {}): Promise<any> => {
|
||||
debug('installing with options %j', options)
|
||||
|
||||
const envVarVersion = getEnvVarVersion()
|
||||
@@ -243,7 +246,7 @@ const start = async (options = {}) => {
|
||||
}
|
||||
|
||||
await fs.ensureDirAsync(cacheDir)
|
||||
.catch({ code: 'EACCES' }, (err) => {
|
||||
.catch({ code: 'EACCES' }, (err: any) => {
|
||||
return throwFormErrorText(errors.invalidCacheDirectory)(stripIndent`
|
||||
Failed to access ${chalk.cyan(cacheDir)}:
|
||||
|
||||
@@ -254,7 +257,7 @@ const start = async (options = {}) => {
|
||||
const binaryPkg = await state.getBinaryPkgAsync(binaryDir)
|
||||
const binaryVersion = await state.getBinaryPkgVersion(binaryPkg)
|
||||
|
||||
const shouldInstall = () => {
|
||||
const shouldInstall = (): boolean => {
|
||||
if (!binaryVersion) {
|
||||
debug('no binary installed under cli version')
|
||||
|
||||
@@ -305,7 +308,7 @@ const start = async (options = {}) => {
|
||||
logger.log()
|
||||
}
|
||||
|
||||
const getLocalFilePath = async () => {
|
||||
const getLocalFilePath = async (): Promise<string | false> => {
|
||||
// see if version supplied is a path to a binary
|
||||
if (await fs.pathExistsAsync(versionToInstall)) {
|
||||
return path.extname(versionToInstall) === '.zip' ? versionToInstall : false
|
||||
@@ -357,20 +360,15 @@ const start = async (options = {}) => {
|
||||
await downloadAndUnzip({ version: versionToInstall, installDir, downloadDir })
|
||||
|
||||
// delay 1 sec for UX, unless we are testing
|
||||
await Promise.delay(1000)
|
||||
await Bluebird.delay(1000)
|
||||
|
||||
displayCompletionMsg()
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
start,
|
||||
_getBinaryUrlFromBuildInfo,
|
||||
}
|
||||
|
||||
const unzipTask = ({ zipFilePath, installDir, progress, rendererOptions }) => {
|
||||
const unzipTask = ({ zipFilePath, installDir, progress, rendererOptions }: any): any => {
|
||||
return {
|
||||
options: { title: util.titleize('Unzipping Cypress') },
|
||||
task: (ctx, task) => {
|
||||
task: (ctx: any, task: any) => {
|
||||
// as our unzip progresses indicate the status
|
||||
progress.onProgress = progessify(task, 'Unzipping Cypress')
|
||||
|
||||
@@ -386,17 +384,17 @@ const unzipTask = ({ zipFilePath, installDir, progress, rendererOptions }) => {
|
||||
}
|
||||
}
|
||||
|
||||
const progessify = (task, title) => {
|
||||
const progessify = (task: any, title: string): any => {
|
||||
// return higher order function
|
||||
return (percentComplete, remaining) => {
|
||||
percentComplete = chalk.white(` ${percentComplete}%`)
|
||||
return (percentComplete: number, remaining: number) => {
|
||||
const percentCompleteStr = chalk.white(` ${percentComplete}%`)
|
||||
|
||||
// pluralize seconds remaining
|
||||
remaining = chalk.gray(`${remaining}s`)
|
||||
const remainingStr = chalk.gray(`${remaining}s`)
|
||||
|
||||
util.setTaskTitle(
|
||||
task,
|
||||
util.titleize(title, percentComplete, remaining),
|
||||
util.titleize(title, percentCompleteStr, remainingStr),
|
||||
getRendererOptions().renderer,
|
||||
)
|
||||
}
|
||||
@@ -405,7 +403,7 @@ const progessify = (task, title) => {
|
||||
// if we are running in CI then use
|
||||
// the verbose renderer else use
|
||||
// the default
|
||||
const getRendererOptions = () => {
|
||||
const getRendererOptions = (): any => {
|
||||
let renderer = util.isCi() ? verbose : 'default'
|
||||
|
||||
if (logger.logLevel() === 'silent') {
|
||||
@@ -416,3 +414,8 @@ const getRendererOptions = () => {
|
||||
renderer,
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
start,
|
||||
_getBinaryUrlFromBuildInfo,
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
const _ = require('lodash')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const untildify = require('untildify')
|
||||
const debug = require('debug')('cypress:cli')
|
||||
import _ from 'lodash'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import untildify from 'untildify'
|
||||
import Debug from 'debug'
|
||||
import fs from '../fs'
|
||||
import util from '../util'
|
||||
|
||||
const fs = require('../fs')
|
||||
const util = require('../util')
|
||||
const debug = Debug('cypress:cli')
|
||||
|
||||
const getPlatformExecutable = () => {
|
||||
const getPlatformExecutable = (): string => {
|
||||
const platform = os.platform()
|
||||
|
||||
switch (platform) {
|
||||
@@ -19,7 +20,7 @@ const getPlatformExecutable = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const getPlatFormBinaryFolder = () => {
|
||||
const getPlatFormBinaryFolder = (): string => {
|
||||
const platform = os.platform()
|
||||
|
||||
switch (platform) {
|
||||
@@ -31,7 +32,7 @@ const getPlatFormBinaryFolder = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const getBinaryPkgPath = (binaryDir) => {
|
||||
const getBinaryPkgPath = (binaryDir: string): string => {
|
||||
const platform = os.platform()
|
||||
|
||||
switch (platform) {
|
||||
@@ -46,11 +47,11 @@ const getBinaryPkgPath = (binaryDir) => {
|
||||
/**
|
||||
* Get path to binary directory
|
||||
*/
|
||||
const getBinaryDir = (version = util.pkgVersion()) => {
|
||||
const getBinaryDir = (version: string = util.pkgVersion()): string => {
|
||||
return path.join(getVersionDir(version), getPlatFormBinaryFolder())
|
||||
}
|
||||
|
||||
const getVersionDir = (version = util.pkgVersion(), buildInfo = util.pkgBuildInfo()) => {
|
||||
const getVersionDir = (version: string = util.pkgVersion(), buildInfo: any = util.pkgBuildInfo()): string => {
|
||||
if (buildInfo && !buildInfo.stable) {
|
||||
version = ['beta', version, buildInfo.commitBranch, buildInfo.commitSha.slice(0, 8)].join('-')
|
||||
}
|
||||
@@ -62,7 +63,7 @@ const getVersionDir = (version = util.pkgVersion(), buildInfo = util.pkgBuildInf
|
||||
* When executing "npm postinstall" hook, the working directory is set to
|
||||
* "<current folder>/node_modules/cypress", which can be surprising when using relative paths.
|
||||
*/
|
||||
const isInstallingFromPostinstallHook = () => {
|
||||
const isInstallingFromPostinstallHook = (): boolean => {
|
||||
// individual folders
|
||||
const cwdFolders = process.cwd().split(path.sep)
|
||||
const length = cwdFolders.length
|
||||
@@ -70,11 +71,11 @@ const isInstallingFromPostinstallHook = () => {
|
||||
return cwdFolders[length - 2] === 'node_modules' && cwdFolders[length - 1] === 'cypress'
|
||||
}
|
||||
|
||||
const getCacheDir = () => {
|
||||
const getCacheDir = (): string => {
|
||||
let cache_directory = util.getCacheDir()
|
||||
|
||||
if (util.getEnv('CYPRESS_CACHE_FOLDER')) {
|
||||
const envVarCacheDir = untildify(util.getEnv('CYPRESS_CACHE_FOLDER'))
|
||||
const envVarCacheDir = untildify(util.getEnv('CYPRESS_CACHE_FOLDER') as string)
|
||||
|
||||
debug('using environment variable CYPRESS_CACHE_FOLDER %s', envVarCacheDir)
|
||||
|
||||
@@ -92,9 +93,9 @@ const getCacheDir = () => {
|
||||
return cache_directory
|
||||
}
|
||||
|
||||
const parseRealPlatformBinaryFolderAsync = (binaryPath) => {
|
||||
const parseRealPlatformBinaryFolderAsync = (binaryPath: string): any => {
|
||||
return fs.realpathAsync(binaryPath)
|
||||
.then((realPath) => {
|
||||
.then((realPath: any) => {
|
||||
debug('CYPRESS_RUN_BINARY has realpath:', realPath)
|
||||
if (!realPath.toString().endsWith(getPlatformExecutable())) {
|
||||
return false
|
||||
@@ -108,7 +109,7 @@ const parseRealPlatformBinaryFolderAsync = (binaryPath) => {
|
||||
})
|
||||
}
|
||||
|
||||
const getDistDir = () => {
|
||||
const getDistDir = (): string => {
|
||||
return path.join(__dirname, '..', '..', 'dist')
|
||||
}
|
||||
|
||||
@@ -117,11 +118,11 @@ const getDistDir = () => {
|
||||
* Note: the binary state file will be stored one level up from the given binary folder.
|
||||
* @param {string} binaryDir - full path to the folder holding the binary.
|
||||
*/
|
||||
const getBinaryStatePath = (binaryDir) => {
|
||||
const getBinaryStatePath = (binaryDir: string): string => {
|
||||
return path.join(binaryDir, '..', 'binary_state.json')
|
||||
}
|
||||
|
||||
const getBinaryStateContentsAsync = (binaryDir) => {
|
||||
const getBinaryStateContentsAsync = (binaryDir: string): any => {
|
||||
const fullPath = getBinaryStatePath(binaryDir)
|
||||
|
||||
return fs.readJsonAsync(fullPath)
|
||||
@@ -132,13 +133,13 @@ const getBinaryStateContentsAsync = (binaryDir) => {
|
||||
})
|
||||
}
|
||||
|
||||
const getBinaryVerifiedAsync = (binaryDir) => {
|
||||
const getBinaryVerifiedAsync = (binaryDir: string): any => {
|
||||
return getBinaryStateContentsAsync(binaryDir)
|
||||
.tap(debug)
|
||||
.get('verified')
|
||||
}
|
||||
|
||||
const clearBinaryStateAsync = (binaryDir) => {
|
||||
const clearBinaryStateAsync = (binaryDir: string): any => {
|
||||
return fs.removeAsync(getBinaryStatePath(binaryDir))
|
||||
}
|
||||
|
||||
@@ -148,9 +149,9 @@ const clearBinaryStateAsync = (binaryDir) => {
|
||||
* @param {string} binaryDir Folder holding the binary
|
||||
* @returns {Promise<void>} returns a promise
|
||||
*/
|
||||
const writeBinaryVerifiedAsync = (verified, binaryDir) => {
|
||||
const writeBinaryVerifiedAsync = (verified: boolean, binaryDir: string): any => {
|
||||
return getBinaryStateContentsAsync(binaryDir)
|
||||
.then((contents) => {
|
||||
.then((contents: any) => {
|
||||
return fs.outputJsonAsync(
|
||||
getBinaryStatePath(binaryDir),
|
||||
_.extend(contents, { verified }),
|
||||
@@ -159,7 +160,7 @@ const writeBinaryVerifiedAsync = (verified, binaryDir) => {
|
||||
})
|
||||
}
|
||||
|
||||
const getPathToExecutable = (binaryDir) => {
|
||||
const getPathToExecutable = (binaryDir: string): string => {
|
||||
return path.join(binaryDir, getPlatformExecutable())
|
||||
}
|
||||
|
||||
@@ -167,13 +168,13 @@ const getPathToExecutable = (binaryDir) => {
|
||||
* Resolves with an object read from the binary app package.json file.
|
||||
* If the file does not exist resolves with null
|
||||
*/
|
||||
const getBinaryPkgAsync = (binaryDir) => {
|
||||
const getBinaryPkgAsync = (binaryDir: string): any => {
|
||||
const pathToPackageJson = getBinaryPkgPath(binaryDir)
|
||||
|
||||
debug('Reading binary package.json from:', pathToPackageJson)
|
||||
|
||||
return fs.pathExistsAsync(pathToPackageJson)
|
||||
.then((exists) => {
|
||||
.then((exists: boolean) => {
|
||||
if (!exists) {
|
||||
return null
|
||||
}
|
||||
@@ -182,11 +183,11 @@ const getBinaryPkgAsync = (binaryDir) => {
|
||||
})
|
||||
}
|
||||
|
||||
const getBinaryPkgVersion = (o) => _.get(o, 'version', null)
|
||||
const getBinaryElectronVersion = (o) => _.get(o, 'electronVersion', null)
|
||||
const getBinaryElectronNodeVersion = (o) => _.get(o, 'electronNodeVersion', null)
|
||||
const getBinaryPkgVersion = (o: any): any => _.get(o, 'version', null)
|
||||
const getBinaryElectronVersion = (o: any): any => _.get(o, 'electronVersion', null)
|
||||
const getBinaryElectronNodeVersion = (o: any): any => _.get(o, 'electronNodeVersion', null)
|
||||
|
||||
module.exports = {
|
||||
const stateModule = {
|
||||
getPathToExecutable,
|
||||
getPlatformExecutable,
|
||||
// those names start to sound like Java
|
||||
@@ -204,3 +205,5 @@ module.exports = {
|
||||
getDistDir,
|
||||
getVersionDir,
|
||||
}
|
||||
|
||||
export default stateModule
|
||||
@@ -1,24 +1,25 @@
|
||||
const _ = require('lodash')
|
||||
const la = require('lazy-ass')
|
||||
const is = require('check-more-types')
|
||||
const cp = require('child_process')
|
||||
const os = require('os')
|
||||
const yauzl = require('yauzl')
|
||||
const debug = require('debug')('cypress:cli:unzip')
|
||||
const extract = require('extract-zip')
|
||||
const Promise = require('bluebird')
|
||||
const readline = require('readline')
|
||||
import _ from 'lodash'
|
||||
import la from 'lazy-ass'
|
||||
import is from 'check-more-types'
|
||||
import cp from 'child_process'
|
||||
import os from 'os'
|
||||
import yauzl from 'yauzl'
|
||||
import Debug from 'debug'
|
||||
import extract from 'extract-zip'
|
||||
import Bluebird from 'bluebird'
|
||||
import readline from 'readline'
|
||||
import { throwFormErrorText, errors } from '../errors'
|
||||
import fs from '../fs'
|
||||
import util from '../util'
|
||||
|
||||
const { throwFormErrorText, errors } = require('../errors')
|
||||
const fs = require('../fs')
|
||||
const util = require('../util')
|
||||
const debug = Debug('cypress:cli:unzip')
|
||||
|
||||
const unzipTools = {
|
||||
extract,
|
||||
}
|
||||
|
||||
// expose this function for simple testing
|
||||
const unzip = ({ zipFilePath, installDir, progress }) => {
|
||||
const unzip = ({ zipFilePath, installDir, progress }: any): any => {
|
||||
debug('unzipping from %s', zipFilePath)
|
||||
debug('into', installDir)
|
||||
|
||||
@@ -31,8 +32,8 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
|
||||
|
||||
return fs.ensureDirAsync(installDir)
|
||||
.then(() => {
|
||||
return new Promise((resolve, reject) => {
|
||||
return yauzl.open(zipFilePath, (err, zipFile) => {
|
||||
return new Bluebird((resolve: any, reject: any) => {
|
||||
return yauzl.open(zipFilePath, (err: any, zipFile: any) => {
|
||||
yauzlDoneTime = Date.now()
|
||||
|
||||
if (err) {
|
||||
@@ -50,7 +51,7 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
|
||||
let percent = 0
|
||||
let count = 0
|
||||
|
||||
const notify = (percent) => {
|
||||
const notify = (percent: number): void => {
|
||||
const elapsed = +new Date() - +started
|
||||
|
||||
const eta = util.calculateEta(percent, elapsed)
|
||||
@@ -58,16 +59,16 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
|
||||
progress.onProgress(percent, util.secsRemaining(eta))
|
||||
}
|
||||
|
||||
const tick = () => {
|
||||
const tick = (): any => {
|
||||
count += 1
|
||||
|
||||
percent = ((count / total) * 100)
|
||||
const displayPercent = percent.toFixed(0)
|
||||
|
||||
return notify(displayPercent)
|
||||
return notify(Number(displayPercent))
|
||||
}
|
||||
|
||||
const unzipWithNode = () => {
|
||||
const unzipWithNode = (): any => {
|
||||
debug('unzipping with node.js (slow)')
|
||||
|
||||
const opts = {
|
||||
@@ -83,7 +84,7 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
|
||||
|
||||
return resolve()
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
const error = err || new Error('Unknown error with Node extract tool')
|
||||
|
||||
debug('error %s', error.message)
|
||||
@@ -94,19 +95,19 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
|
||||
|
||||
const unzipFallback = _.once(unzipWithNode)
|
||||
|
||||
const unzipWithUnzipTool = () => {
|
||||
const unzipWithUnzipTool = (): any => {
|
||||
debug('unzipping via `unzip`')
|
||||
|
||||
const inflatingRe = /inflating:/
|
||||
|
||||
const sp = cp.spawn('unzip', ['-o', zipFilePath, '-d', installDir])
|
||||
|
||||
sp.on('error', (err) => {
|
||||
sp.on('error', (err: any) => {
|
||||
debug('unzip tool error: %s', err.message)
|
||||
unzipFallback()
|
||||
})
|
||||
|
||||
sp.on('close', (code) => {
|
||||
sp.on('close', (code: number) => {
|
||||
debug('unzip tool close with code %d', code)
|
||||
if (code === 0) {
|
||||
percent = 100
|
||||
@@ -120,13 +121,13 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
|
||||
return unzipFallback()
|
||||
})
|
||||
|
||||
sp.stdout.on('data', (data) => {
|
||||
sp.stdout.on('data', (data: any) => {
|
||||
if (inflatingRe.test(data)) {
|
||||
return tick()
|
||||
}
|
||||
})
|
||||
|
||||
sp.stderr.on('data', (data) => {
|
||||
sp.stderr.on('data', (data: any) => {
|
||||
debug('`unzip` stderr %s', data)
|
||||
})
|
||||
}
|
||||
@@ -136,7 +137,7 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
|
||||
// with corruption, symlinks, or icons causing failures
|
||||
// and can handle resource forks
|
||||
// http://automatica.com.au/2011/02/unzip-mac-os-x-zip-in-terminal/
|
||||
const unzipWithOsx = () => {
|
||||
const unzipWithOsx = (): any => {
|
||||
debug('unzipping via `ditto`')
|
||||
|
||||
const copyingFileRe = /^copying file/
|
||||
@@ -144,12 +145,12 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
|
||||
const sp = cp.spawn('ditto', ['-xkV', zipFilePath, installDir])
|
||||
|
||||
// f-it just unzip with node
|
||||
sp.on('error', (err) => {
|
||||
sp.on('error', (err: any) => {
|
||||
debug(err.message)
|
||||
unzipFallback()
|
||||
})
|
||||
|
||||
sp.on('close', (code) => {
|
||||
sp.on('close', (code: number) => {
|
||||
if (code === 0) {
|
||||
// make sure we get to 100% on the progress bar
|
||||
// because reading in lines is not really accurate
|
||||
@@ -167,7 +168,7 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
|
||||
return readline.createInterface({
|
||||
input: sp.stderr,
|
||||
})
|
||||
.on('line', (line) => {
|
||||
.on('line', (line: string) => {
|
||||
if (copyingFileRe.test(line)) {
|
||||
return tick()
|
||||
}
|
||||
@@ -195,11 +196,11 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
|
||||
})
|
||||
}
|
||||
|
||||
function isMaybeWindowsMaxPathLengthError (err) {
|
||||
function isMaybeWindowsMaxPathLengthError (err: any): boolean {
|
||||
return os.platform() === 'win32' && err.code === 'ENOENT' && err.syscall === 'realpath'
|
||||
}
|
||||
|
||||
const start = async ({ zipFilePath, installDir, progress }) => {
|
||||
const start = async ({ zipFilePath, installDir, progress }: any): Promise<void> => {
|
||||
la(is.unemptyString(installDir), 'missing installDir')
|
||||
if (!progress) {
|
||||
progress = { onProgress: () => {
|
||||
@@ -222,14 +223,16 @@ const start = async ({ zipFilePath, installDir, progress }) => {
|
||||
errors.failedUnzipWindowsMaxPathLength
|
||||
: errors.failedUnzip
|
||||
|
||||
await throwFormErrorText(errorTemplate)(err)
|
||||
await throwFormErrorText(errorTemplate)(err as string)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
const unzipModule = {
|
||||
start,
|
||||
utils: {
|
||||
unzip,
|
||||
unzipTools,
|
||||
},
|
||||
}
|
||||
|
||||
export default unzipModule
|
||||
@@ -1,29 +1,38 @@
|
||||
const _ = require('lodash')
|
||||
const chalk = require('chalk')
|
||||
const { Listr } = require('listr2')
|
||||
const debug = require('debug')('cypress:cli')
|
||||
const { stripIndent } = require('common-tags')
|
||||
const Promise = require('bluebird')
|
||||
const logSymbols = require('log-symbols')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
import _ from 'lodash'
|
||||
import chalk from 'chalk'
|
||||
import { Listr } from 'listr2'
|
||||
import Debug from 'debug'
|
||||
import { stripIndent } from 'common-tags'
|
||||
import Bluebird from 'bluebird'
|
||||
import logSymbols from 'log-symbols'
|
||||
import path from 'path'
|
||||
import os from 'os'
|
||||
import verbose from '../VerboseRenderer'
|
||||
import { throwFormErrorText, errors } from '../errors'
|
||||
import util from '../util'
|
||||
import logger from '../logger'
|
||||
import xvfb from '../exec/xvfb'
|
||||
import state from './state'
|
||||
|
||||
const verbose = require('../VerboseRenderer')
|
||||
const { throwFormErrorText, errors } = require('../errors')
|
||||
const util = require('../util')
|
||||
const logger = require('../logger')
|
||||
const xvfb = require('../exec/xvfb')
|
||||
const state = require('./state')
|
||||
const debug = Debug('cypress:cli')
|
||||
|
||||
const VERIFY_TEST_RUNNER_TIMEOUT_MS = +util.getEnv('CYPRESS_VERIFY_TIMEOUT') || 30000
|
||||
const VERIFY_TEST_RUNNER_TIMEOUT_MS = (() => {
|
||||
const verifyTimeout = +(util?.getEnv('CYPRESS_VERIFY_TIMEOUT') || 'NaN')
|
||||
|
||||
const checkExecutable = (binaryDir) => {
|
||||
if (_.isNumber(verifyTimeout) && !_.isNaN(verifyTimeout)) {
|
||||
return verifyTimeout
|
||||
}
|
||||
|
||||
return 30000
|
||||
})()
|
||||
|
||||
const checkExecutable = (binaryDir: string): any => {
|
||||
const executable = state.getPathToExecutable(binaryDir)
|
||||
|
||||
debug('checking if executable exists', executable)
|
||||
|
||||
return util.isExecutableAsync(executable)
|
||||
.then((isExecutable) => {
|
||||
.then((isExecutable: boolean) => {
|
||||
debug('Binary is executable? :', isExecutable)
|
||||
if (!isExecutable) {
|
||||
return throwFormErrorText(errors.binaryNotExecutable(executable))()
|
||||
@@ -40,11 +49,11 @@ const checkExecutable = (binaryDir) => {
|
||||
})
|
||||
}
|
||||
|
||||
const runSmokeTest = (binaryDir, options) => {
|
||||
const runSmokeTest = (binaryDir: string, options: any): any => {
|
||||
let executable = state.getPathToExecutable(binaryDir)
|
||||
|
||||
const onSmokeTestError = (smokeTestCommand, linuxWithDisplayEnv) => {
|
||||
return (err) => {
|
||||
const onSmokeTestError = (smokeTestCommand: string, linuxWithDisplayEnv: boolean) => {
|
||||
return (err: any) => {
|
||||
debug('Smoke test failed:', err)
|
||||
|
||||
let errMessage = err.stderr || err.message
|
||||
@@ -77,7 +86,7 @@ const runSmokeTest = (binaryDir, options) => {
|
||||
* Spawn Cypress running smoke test to check if all operating system
|
||||
* dependencies are good.
|
||||
*/
|
||||
const spawn = (linuxWithDisplayEnv) => {
|
||||
const spawn = (linuxWithDisplayEnv: boolean): any => {
|
||||
const random = _.random(0, 1000)
|
||||
const args = ['--smoke-test', `--ping=${random}`]
|
||||
|
||||
@@ -104,18 +113,18 @@ const runSmokeTest = (binaryDir, options) => {
|
||||
const stdioOptions = _.extend({}, {
|
||||
env: {
|
||||
...process.env,
|
||||
FORCE_COLOR: 0,
|
||||
FORCE_COLOR: '0',
|
||||
},
|
||||
timeout: options.smokeTestTimeout,
|
||||
})
|
||||
|
||||
return Promise.resolve(util.exec(
|
||||
return Bluebird.resolve(util.exec(
|
||||
executable,
|
||||
args,
|
||||
stdioOptions,
|
||||
))
|
||||
.catch(onSmokeTestError(smokeTestCommand, linuxWithDisplayEnv))
|
||||
.then((result) => {
|
||||
.then((result: any) => {
|
||||
// TODO: when execa > 1.1 is released
|
||||
// change this to `result.all` for both stderr and stdout
|
||||
// use lodash to be robust during tests against null result or missing stdout
|
||||
@@ -134,16 +143,16 @@ const runSmokeTest = (binaryDir, options) => {
|
||||
})
|
||||
}
|
||||
|
||||
const spawnInXvfb = (linuxWithDisplayEnv) => {
|
||||
const spawnInXvfb = (linuxWithDisplayEnv?: boolean): any => {
|
||||
return xvfb
|
||||
.start()
|
||||
.then(() => {
|
||||
return spawn(linuxWithDisplayEnv)
|
||||
return spawn(linuxWithDisplayEnv || false)
|
||||
})
|
||||
.finally(xvfb.stop)
|
||||
}
|
||||
|
||||
const userFriendlySpawn = (linuxWithDisplayEnv) => {
|
||||
const userFriendlySpawn = (linuxWithDisplayEnv: boolean): any => {
|
||||
debug('spawning, should retry on display problem?', Boolean(linuxWithDisplayEnv))
|
||||
|
||||
return spawn(linuxWithDisplayEnv)
|
||||
@@ -164,7 +173,7 @@ const runSmokeTest = (binaryDir, options) => {
|
||||
return userFriendlySpawn(linuxWithDisplayEnv)
|
||||
}
|
||||
|
||||
function testBinary (version, binaryDir, options) {
|
||||
function testBinary (version: string, binaryDir: string, options: any): any {
|
||||
debug('running binary verification check', version)
|
||||
|
||||
// if running from 'cypress verify', don't print this message
|
||||
@@ -181,7 +190,8 @@ function testBinary (version, binaryDir, options) {
|
||||
// the default
|
||||
let renderer = util.isCi() ? verbose : 'default'
|
||||
|
||||
if (logger.logLevel() === 'silent') renderer = 'silent'
|
||||
// NOTE: under test we set the listr renderer to 'silent' in order to get deterministic snapshots
|
||||
if (logger.logLevel() === 'silent' || options.listrRenderer) renderer = 'silent'
|
||||
|
||||
const rendererOptions = {
|
||||
renderer,
|
||||
@@ -189,15 +199,15 @@ function testBinary (version, binaryDir, options) {
|
||||
|
||||
const tasks = new Listr([
|
||||
{
|
||||
options: { title: util.titleize('Verifying Cypress can run', chalk.gray(binaryDir)) },
|
||||
task: (ctx, task) => {
|
||||
title: util.titleize('Verifying Cypress can run', chalk.gray(binaryDir)),
|
||||
task: (ctx: any, task: any) => {
|
||||
debug('clearing out the verified version')
|
||||
|
||||
return state.clearBinaryStateAsync(binaryDir)
|
||||
.then(() => {
|
||||
return Promise.all([
|
||||
return Bluebird.all([
|
||||
runSmokeTest(binaryDir, options),
|
||||
Promise.resolve().delay(1500), // good user experience
|
||||
Bluebird.delay(1500), // good user experience
|
||||
])
|
||||
})
|
||||
.then(() => {
|
||||
@@ -212,19 +222,19 @@ function testBinary (version, binaryDir, options) {
|
||||
chalk.green('Verified Cypress!'),
|
||||
chalk.gray(binaryDir),
|
||||
),
|
||||
rendererOptions.renderer,
|
||||
rendererOptions.renderer as string,
|
||||
)
|
||||
})
|
||||
},
|
||||
},
|
||||
], { rendererOptions })
|
||||
] as any, rendererOptions as any)
|
||||
|
||||
return tasks.run()
|
||||
}
|
||||
|
||||
const maybeVerify = (installedVersion, binaryDir, options) => {
|
||||
const maybeVerify = (installedVersion: string, binaryDir: string, options: any): any => {
|
||||
return state.getBinaryVerifiedAsync(binaryDir)
|
||||
.then((isVerified) => {
|
||||
.then((isVerified: boolean) => {
|
||||
debug('is Verified ?', isVerified)
|
||||
|
||||
let shouldVerify = !isVerified
|
||||
@@ -247,7 +257,7 @@ const maybeVerify = (installedVersion, binaryDir, options) => {
|
||||
})
|
||||
}
|
||||
|
||||
const start = (options = {}) => {
|
||||
const start = (options: any = {}): any => {
|
||||
debug('verifying Cypress app')
|
||||
|
||||
const packageVersion = util.pkgVersion()
|
||||
@@ -264,14 +274,14 @@ const start = (options = {}) => {
|
||||
if (options.skipVerify) {
|
||||
debug('skipping verification of the Cypress app')
|
||||
|
||||
return Promise.resolve()
|
||||
return Bluebird.resolve()
|
||||
}
|
||||
|
||||
if (options.dev) {
|
||||
return runSmokeTest('', options)
|
||||
}
|
||||
|
||||
const parseBinaryEnvVar = () => {
|
||||
const parseBinaryEnvVar = (): any => {
|
||||
const envBinaryPath = util.getEnv('CYPRESS_RUN_BINARY')
|
||||
|
||||
debug('CYPRESS_RUN_BINARY exists, =', envBinaryPath)
|
||||
@@ -285,33 +295,33 @@ const start = (options = {}) => {
|
||||
|
||||
logger.log()
|
||||
|
||||
return util.isExecutableAsync(envBinaryPath)
|
||||
.then((isExecutable) => {
|
||||
return util.isExecutableAsync(envBinaryPath as string)
|
||||
.then((isExecutable: boolean) => {
|
||||
debug('CYPRESS_RUN_BINARY is executable? :', isExecutable)
|
||||
if (!isExecutable) {
|
||||
return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath))(stripIndent`
|
||||
return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath as string))(stripIndent`
|
||||
The supplied binary path is not executable
|
||||
`)
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
return state.parseRealPlatformBinaryFolderAsync(envBinaryPath)
|
||||
return state.parseRealPlatformBinaryFolderAsync(envBinaryPath as string)
|
||||
})
|
||||
.then((envBinaryDir) => {
|
||||
.then((envBinaryDir: string) => {
|
||||
if (!envBinaryDir) {
|
||||
return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath))()
|
||||
return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath as string))()
|
||||
}
|
||||
|
||||
debug('CYPRESS_RUN_BINARY has binaryDir:', envBinaryDir)
|
||||
|
||||
binaryDir = envBinaryDir
|
||||
})
|
||||
.catch({ code: 'ENOENT' }, (err) => {
|
||||
return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath))(err.message)
|
||||
.catch({ code: 'ENOENT' }, (err: any) => {
|
||||
return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath as string))(err.message)
|
||||
})
|
||||
}
|
||||
|
||||
return Promise.try(() => {
|
||||
return Bluebird.try(() => {
|
||||
debug('checking environment variables')
|
||||
if (util.getEnv('CYPRESS_RUN_BINARY')) {
|
||||
return parseBinaryEnvVar()
|
||||
@@ -326,10 +336,10 @@ const start = (options = {}) => {
|
||||
.then(() => {
|
||||
return state.getBinaryPkgAsync(binaryDir)
|
||||
})
|
||||
.then((pkg) => {
|
||||
.then((pkg: any) => {
|
||||
return state.getBinaryPkgVersion(pkg)
|
||||
})
|
||||
.then((binaryVersion) => {
|
||||
.then((binaryVersion: string) => {
|
||||
if (!binaryVersion) {
|
||||
debug('no Cypress binary found for cli version ', packageVersion)
|
||||
|
||||
@@ -359,7 +369,7 @@ const start = (options = {}) => {
|
||||
return maybeVerify(binaryVersion, binaryDir, options)
|
||||
})
|
||||
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
if (err.known) {
|
||||
throw err
|
||||
}
|
||||
@@ -368,7 +378,7 @@ const start = (options = {}) => {
|
||||
})
|
||||
}
|
||||
|
||||
const isLinuxLike = () => os.platform() !== 'win32'
|
||||
const isLinuxLike = (): boolean => os.platform() !== 'win32'
|
||||
|
||||
/**
|
||||
* Returns true if running on a system where Electron needs "--no-sandbox" flag.
|
||||
@@ -379,10 +389,10 @@ const isLinuxLike = () => os.platform() !== 'win32'
|
||||
* Seems there is a lot of discussion around this issue among Electron users
|
||||
* @see https://github.com/electron/electron/issues/17972
|
||||
*/
|
||||
const needsSandbox = () => isLinuxLike()
|
||||
const needsSandbox = (): boolean => isLinuxLike()
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
start,
|
||||
VERIFY_TEST_RUNNER_TIMEOUT_MS,
|
||||
needsSandbox,
|
||||
VERIFY_TEST_RUNNER_TIMEOUT_MS,
|
||||
}
|
||||
@@ -1,27 +1,30 @@
|
||||
const _ = require('lodash')
|
||||
const arch = require('arch')
|
||||
const os = require('os')
|
||||
const ospath = require('ospath')
|
||||
const hasha = require('hasha')
|
||||
const la = require('lazy-ass')
|
||||
const is = require('check-more-types')
|
||||
const tty = require('tty')
|
||||
const path = require('path')
|
||||
const isCi = require('ci-info').isCI
|
||||
const execa = require('execa')
|
||||
const si = require('systeminformation')
|
||||
const chalk = require('chalk')
|
||||
const Promise = require('bluebird')
|
||||
const cachedir = require('cachedir')
|
||||
const logSymbols = require('log-symbols')
|
||||
const executable = require('executable')
|
||||
const { stripIndent } = require('common-tags')
|
||||
const supportsColor = require('supports-color')
|
||||
const isInstalledGlobally = require('is-installed-globally')
|
||||
const logger = require('./logger')
|
||||
const debug = require('debug')('cypress:cli')
|
||||
const fs = require('./fs')
|
||||
import _ from 'lodash'
|
||||
import arch from 'arch'
|
||||
import os from 'os'
|
||||
import ospath from 'ospath'
|
||||
import hasha from 'hasha'
|
||||
import la from 'lazy-ass'
|
||||
import is from 'check-more-types'
|
||||
import tty from 'tty'
|
||||
import path from 'path'
|
||||
import { isCI as isCi } from 'ci-info'
|
||||
import execa from 'execa'
|
||||
import si from 'systeminformation'
|
||||
import chalk from 'chalk'
|
||||
import Bluebird from 'bluebird'
|
||||
import cachedir from 'cachedir'
|
||||
import logSymbols from 'log-symbols'
|
||||
import executable from 'executable'
|
||||
import { stripIndent } from 'common-tags'
|
||||
import supportsColor from 'supports-color'
|
||||
import isInstalledGlobally from 'is-installed-globally'
|
||||
import logger from './logger'
|
||||
import Debug from 'debug'
|
||||
import fs from './fs'
|
||||
|
||||
const debug = Debug('cypress:cli')
|
||||
|
||||
// Import package.json dynamically to avoid TypeScript JSON import issues
|
||||
const pkg = require(path.join(__dirname, '..', 'package.json'))
|
||||
|
||||
const issuesUrl = 'https://github.com/cypress-io/cypress/issues'
|
||||
@@ -29,13 +32,13 @@ const issuesUrl = 'https://github.com/cypress-io/cypress/issues'
|
||||
/**
|
||||
* Returns SHA512 of a file
|
||||
*/
|
||||
const getFileChecksum = (filename) => {
|
||||
const getFileChecksum = (filename: string): any => {
|
||||
la(is.unemptyString(filename), 'expected filename', filename)
|
||||
|
||||
return hasha.fromFile(filename, { algorithm: 'sha512' })
|
||||
}
|
||||
|
||||
const getFileSize = (filename) => {
|
||||
const getFileSize = (filename: string): any => {
|
||||
la(is.unemptyString(filename), 'expected filename', filename)
|
||||
|
||||
return fs.statAsync(filename).get('size')
|
||||
@@ -43,11 +46,11 @@ const getFileSize = (filename) => {
|
||||
|
||||
const isBrokenGtkDisplayRe = /Gtk: cannot open display/
|
||||
|
||||
const stringify = (val) => {
|
||||
const stringify = (val: any): string => {
|
||||
return _.isObject(val) ? JSON.stringify(val) : val
|
||||
}
|
||||
|
||||
function normalizeModuleOptions (options = {}) {
|
||||
function normalizeModuleOptions (options: any = {}): any {
|
||||
return _.mapValues(options, stringify)
|
||||
}
|
||||
|
||||
@@ -55,7 +58,7 @@ function normalizeModuleOptions (options = {}) {
|
||||
* Returns true if the platform is Linux. We do a lot of different
|
||||
* stuff on Linux (like Xvfb) and it helps to has readable code
|
||||
*/
|
||||
const isLinux = () => {
|
||||
const isLinux = (): boolean => {
|
||||
return os.platform() === 'linux'
|
||||
}
|
||||
|
||||
@@ -66,15 +69,15 @@ const isLinux = () => {
|
||||
[1005:0509/184205.663837:WARNING:browser_main_loop.cc(258)] Gtk: cannot open display: 99
|
||||
```
|
||||
*/
|
||||
const isBrokenGtkDisplay = (str) => {
|
||||
const isBrokenGtkDisplay = (str: string): boolean => {
|
||||
return isBrokenGtkDisplayRe.test(str)
|
||||
}
|
||||
|
||||
const isPossibleLinuxWithIncorrectDisplay = () => {
|
||||
return isLinux() && process.env.DISPLAY
|
||||
const isPossibleLinuxWithIncorrectDisplay = (): boolean => {
|
||||
return isLinux() && !!process.env.DISPLAY
|
||||
}
|
||||
|
||||
const logBrokenGtkDisplayWarning = () => {
|
||||
const logBrokenGtkDisplayWarning = (): void => {
|
||||
debug('Cypress exited due to a broken gtk display because of a potential invalid DISPLAY env... retrying after starting Xvfb')
|
||||
|
||||
// if we get this error, we are on Linux and DISPLAY is set
|
||||
@@ -92,7 +95,7 @@ const logBrokenGtkDisplayWarning = () => {
|
||||
logger.warn()
|
||||
}
|
||||
|
||||
function stdoutLineMatches (expectedLine, stdout) {
|
||||
function stdoutLineMatches (expectedLine: string, stdout: string): boolean {
|
||||
const lines = stdout.split('\n').map((val) => val.trim())
|
||||
|
||||
return lines.some((line) => line === expectedLine)
|
||||
@@ -105,7 +108,7 @@ function stdoutLineMatches (expectedLine, stdout) {
|
||||
* @param {string} value
|
||||
* @example util.isValidCypressInternalEnvValue(process.env.CYPRESS_INTERNAL_ENV)
|
||||
*/
|
||||
function isValidCypressInternalEnvValue (value) {
|
||||
function isValidCypressInternalEnvValue (value: string | undefined): boolean {
|
||||
if (_.isUndefined(value)) {
|
||||
// will get default value
|
||||
return true
|
||||
@@ -124,7 +127,7 @@ function isValidCypressInternalEnvValue (value) {
|
||||
* @param {string} value
|
||||
* @example util.isNonProductionCypressInternalEnvValue(process.env.CYPRESS_INTERNAL_ENV)
|
||||
*/
|
||||
function isNonProductionCypressInternalEnvValue (value) {
|
||||
function isNonProductionCypressInternalEnvValue (value: string | undefined): boolean {
|
||||
return !_.isUndefined(value) && value !== 'production'
|
||||
}
|
||||
|
||||
@@ -132,7 +135,7 @@ function isNonProductionCypressInternalEnvValue (value) {
|
||||
* Prints NODE_OPTIONS using debug() module, but only
|
||||
* if DEBUG=cypress... is set
|
||||
*/
|
||||
function printNodeOptions (log = debug) {
|
||||
function printNodeOptions (log: any = debug): void {
|
||||
if (!log.enabled) {
|
||||
return
|
||||
}
|
||||
@@ -158,7 +161,8 @@ function printNodeOptions (log = debug) {
|
||||
// returns string 'foo'
|
||||
```
|
||||
*/
|
||||
const dequote = (str) => {
|
||||
const dequote = (str: string): string => {
|
||||
// @ts-expect-error method exists but is not typed
|
||||
la(is.string(str), 'expected a string to remove double quotes', str)
|
||||
if (str.length > 1 && str[0] === '"' && str[str.length - 1] === '"') {
|
||||
return str.substr(1, str.length - 2)
|
||||
@@ -167,7 +171,7 @@ const dequote = (str) => {
|
||||
return str
|
||||
}
|
||||
|
||||
const parseOpts = (opts) => {
|
||||
const parseOpts = (opts: any): any => {
|
||||
opts = _.pick(opts,
|
||||
'autoCancelAfterFailures',
|
||||
'browser',
|
||||
@@ -232,7 +236,7 @@ const parseOpts = (opts) => {
|
||||
* Copy of packages/server/lib/browsers/utils.ts
|
||||
* because we need same functionality in CLI to show the path :(
|
||||
*/
|
||||
const getApplicationDataFolder = (...paths) => {
|
||||
const getApplicationDataFolder = (...paths: string[]): string => {
|
||||
const { env } = process
|
||||
|
||||
// allow overriding the app_data folder
|
||||
@@ -259,25 +263,25 @@ const util = {
|
||||
isNonProductionCypressInternalEnvValue,
|
||||
printNodeOptions,
|
||||
|
||||
isCi () {
|
||||
isCi (): boolean {
|
||||
return isCi
|
||||
},
|
||||
|
||||
getEnvOverrides (options = {}) {
|
||||
getEnvOverrides (options: any = {}): any {
|
||||
return _
|
||||
.chain({})
|
||||
.extend(util.getEnvColors())
|
||||
.extend(util.getForceTty())
|
||||
.omitBy(_.isUndefined) // remove undefined values
|
||||
.mapValues((value) => { // stringify to 1 or 0
|
||||
.mapValues((value: any) => { // stringify to 1 or 0
|
||||
return value ? '1' : '0'
|
||||
})
|
||||
.extend(util.getOriginalNodeOptions())
|
||||
.value()
|
||||
},
|
||||
|
||||
getOriginalNodeOptions () {
|
||||
const opts = {}
|
||||
getOriginalNodeOptions (): any {
|
||||
const opts: any = {}
|
||||
|
||||
if (process.env.NODE_OPTIONS) {
|
||||
opts.ORIGINAL_NODE_OPTIONS = process.env.NODE_OPTIONS
|
||||
@@ -286,7 +290,7 @@ const util = {
|
||||
return opts
|
||||
},
|
||||
|
||||
getForceTty () {
|
||||
getForceTty (): any {
|
||||
return {
|
||||
FORCE_STDIN_TTY: util.isTty(process.stdin.fd),
|
||||
FORCE_STDOUT_TTY: util.isTty(process.stdout.fd),
|
||||
@@ -294,7 +298,7 @@ const util = {
|
||||
}
|
||||
},
|
||||
|
||||
getEnvColors () {
|
||||
getEnvColors (): any {
|
||||
const sc = util.supportsColor()
|
||||
|
||||
return {
|
||||
@@ -304,11 +308,11 @@ const util = {
|
||||
}
|
||||
},
|
||||
|
||||
isTty (fd) {
|
||||
isTty (fd: number): boolean {
|
||||
return tty.isatty(fd)
|
||||
},
|
||||
|
||||
supportsColor () {
|
||||
supportsColor (): boolean {
|
||||
// if we've been explicitly told not to support
|
||||
// color then turn this off
|
||||
if (process.env.NO_COLOR) {
|
||||
@@ -325,23 +329,23 @@ const util = {
|
||||
return Boolean(supportsColor.stdout) && Boolean(supportsColor.stderr)
|
||||
},
|
||||
|
||||
cwd () {
|
||||
cwd (): string {
|
||||
return process.cwd()
|
||||
},
|
||||
|
||||
pkgBuildInfo () {
|
||||
pkgBuildInfo (): any {
|
||||
return pkg.buildInfo
|
||||
},
|
||||
|
||||
pkgVersion () {
|
||||
pkgVersion (): string {
|
||||
return pkg.version
|
||||
},
|
||||
|
||||
exit (code) {
|
||||
exit (code: number): never {
|
||||
process.exit(code)
|
||||
},
|
||||
|
||||
logErrorExit1 (err) {
|
||||
logErrorExit1 (err: Error): never {
|
||||
logger.error(err.message)
|
||||
|
||||
process.exit(1)
|
||||
@@ -349,7 +353,7 @@ const util = {
|
||||
|
||||
dequote,
|
||||
|
||||
titleize (...args) {
|
||||
titleize (...args: any[]): string {
|
||||
// prepend first arg with space
|
||||
// and pad so that all messages line up
|
||||
args[0] = _.padEnd(` ${args[0]}`, 24)
|
||||
@@ -360,7 +364,7 @@ const util = {
|
||||
return chalk.blue(...args)
|
||||
},
|
||||
|
||||
calculateEta (percent, elapsed) {
|
||||
calculateEta (percent: number, elapsed: number): number {
|
||||
// returns the number of seconds remaining
|
||||
|
||||
// if we're at 100% already just return 0
|
||||
@@ -374,41 +378,41 @@ const util = {
|
||||
return elapsed * (1 / (percent / 100)) - elapsed
|
||||
},
|
||||
|
||||
convertPercentToPercentage (num) {
|
||||
convertPercentToPercentage (num: number): number {
|
||||
// convert a percent with values between 0 and 1
|
||||
// with decimals, so that it is between 0 and 100
|
||||
// and has no decimal places
|
||||
return Math.round(_.isFinite(num) ? (num * 100) : 0)
|
||||
},
|
||||
|
||||
secsRemaining (eta) {
|
||||
secsRemaining (eta: number): string {
|
||||
// calculate the seconds reminaing with no decimal places
|
||||
return (_.isFinite(eta) ? (eta / 1000) : 0).toFixed(0)
|
||||
},
|
||||
|
||||
setTaskTitle (task, title, renderer) {
|
||||
setTaskTitle (task: any, title: string, renderer: string): void {
|
||||
// only update the renderer title when not running in CI
|
||||
if (renderer === 'default' && task.title !== title) {
|
||||
task.title = title
|
||||
}
|
||||
},
|
||||
|
||||
isInstalledGlobally () {
|
||||
isInstalledGlobally (): boolean {
|
||||
return isInstalledGlobally
|
||||
},
|
||||
|
||||
isSemver (str) {
|
||||
isSemver (str: string): boolean {
|
||||
return /^(\d+\.)?(\d+\.)?(\*|\d+)$/.test(str)
|
||||
},
|
||||
|
||||
isExecutableAsync (filePath) {
|
||||
return Promise.resolve(executable(filePath))
|
||||
isExecutableAsync (filePath: string): any {
|
||||
return Bluebird.resolve(executable(filePath))
|
||||
},
|
||||
|
||||
isLinux,
|
||||
|
||||
getOsVersionAsync () {
|
||||
return Promise.try(() => {
|
||||
return Bluebird.try(() => {
|
||||
return si.osInfo()
|
||||
.then((osInfo) => {
|
||||
if (osInfo.distro && osInfo.release) {
|
||||
@@ -422,8 +426,8 @@ const util = {
|
||||
})
|
||||
},
|
||||
|
||||
async getPlatformInfo () {
|
||||
const [version, osArch] = await Promise.all([
|
||||
async getPlatformInfo (): Promise<string> {
|
||||
const [version, osArch] = await Bluebird.all([
|
||||
util.getOsVersionAsync(),
|
||||
this.getRealArch(),
|
||||
])
|
||||
@@ -434,15 +438,15 @@ const util = {
|
||||
`
|
||||
},
|
||||
|
||||
_cachedArch: undefined,
|
||||
_cachedArch: undefined as string | undefined,
|
||||
|
||||
/**
|
||||
* Attempt to return the real system arch (not process.arch, which is only the Node binary's arch)
|
||||
*/
|
||||
async getRealArch () {
|
||||
async getRealArch (): Promise<string> {
|
||||
if (this._cachedArch) return this._cachedArch
|
||||
|
||||
async function _getRealArch () {
|
||||
async function _getRealArch (): Promise<string> {
|
||||
const osPlatform = os.platform()
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
const osArch = os.arch()
|
||||
@@ -454,7 +458,7 @@ const util = {
|
||||
if (osPlatform === 'darwin') {
|
||||
// could possibly be x64 node on arm64 darwin, check if we are being translated by Rosetta
|
||||
// https://stackoverflow.com/a/65347893/3474615
|
||||
const { stdout } = await execa('sysctl', ['-n', 'sysctl.proc_translated']).catch(() => '')
|
||||
const { stdout } = await execa('sysctl', ['-n', 'sysctl.proc_translated']).catch(() => ({ stdout: '' }))
|
||||
|
||||
debug('rosetta check result: %o', { stdout })
|
||||
if (stdout === '1') return 'arm64'
|
||||
@@ -463,7 +467,7 @@ const util = {
|
||||
if (osPlatform === 'linux') {
|
||||
// could possibly be x64 node on arm64 linux, check the "machine hardware name"
|
||||
// list of names for reference: https://stackoverflow.com/a/45125525/3474615
|
||||
const { stdout } = await execa('uname', ['-m']).catch(() => '')
|
||||
const { stdout } = await execa('uname', ['-m']).catch(() => ({ stdout: '' }))
|
||||
|
||||
debug('arm uname -m result: %o ', { stdout })
|
||||
if (['aarch64_be', 'aarch64', 'armv8b', 'armv8l'].includes(stdout)) return 'arm64'
|
||||
@@ -484,7 +488,7 @@ const util = {
|
||||
// when passing relative path to NPM post install hook, the current working
|
||||
// directory is set to the `node_modules/cypress` folder
|
||||
// the user is probably passing relative path with respect to root package folder
|
||||
formAbsolutePath (filename) {
|
||||
formAbsolutePath (filename: string): string {
|
||||
if (path.isAbsolute(filename)) {
|
||||
return filename
|
||||
}
|
||||
@@ -492,14 +496,14 @@ const util = {
|
||||
return path.join(process.cwd(), '..', '..', filename)
|
||||
},
|
||||
|
||||
getEnv (varName, trim) {
|
||||
getEnv (varName: string, trim?: boolean): string | undefined {
|
||||
la(is.unemptyString(varName), 'expected environment variable name, not', varName)
|
||||
|
||||
const configVarName = `npm_config_${varName}`
|
||||
const configVarNameLower = configVarName.toLowerCase()
|
||||
const packageConfigVarName = `npm_package_config_${varName}`
|
||||
|
||||
let result
|
||||
let result: string | undefined
|
||||
|
||||
if (process.env.hasOwnProperty(varName)) {
|
||||
debug(`Using ${varName} from environment variable`)
|
||||
@@ -528,14 +532,14 @@ const util = {
|
||||
// so for sanity sake we should first trim whitespace characters and remove
|
||||
// double quotes around environment strings if the caller is expected to
|
||||
// use this environment string as a file path
|
||||
return trim ? dequote(_.trim(result)) : result
|
||||
return trim && (result !== null && result !== undefined) ? dequote(_.trim(result)) : result
|
||||
},
|
||||
|
||||
getCacheDir () {
|
||||
getCacheDir (): string {
|
||||
return cachedir('Cypress')
|
||||
},
|
||||
|
||||
isPostInstall () {
|
||||
isPostInstall (): boolean {
|
||||
return process.env.npm_lifecycle_event === 'postinstall'
|
||||
},
|
||||
|
||||
@@ -551,7 +555,8 @@ const util = {
|
||||
|
||||
isPossibleLinuxWithIncorrectDisplay,
|
||||
|
||||
getGitHubIssueUrl (number) {
|
||||
getGitHubIssueUrl (number: number): string {
|
||||
// @ts-expect-error method exists but is not typed
|
||||
la(is.positive(number), 'github issue should be a positive number', number)
|
||||
la(_.isInteger(number), 'github issue should be an integer', number)
|
||||
|
||||
@@ -565,4 +570,4 @@ const util = {
|
||||
getApplicationDataFolder,
|
||||
}
|
||||
|
||||
module.exports = util
|
||||
export default util
|
||||
@@ -4,12 +4,12 @@
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build-cli": "node ./scripts/build.js && node ./scripts/post-build.js",
|
||||
"clean": "node ./scripts/clean.js",
|
||||
"build-cli": "tsc && tsx ./scripts/build.ts && tsx ./scripts/post-build.ts",
|
||||
"clean": "tsx ./scripts/clean.ts",
|
||||
"dtslint": "dtslint types",
|
||||
"postinstall": "patch-package && node ./scripts/post-install.js",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json,.vue .",
|
||||
"prebuild": "yarn postinstall && node ./scripts/start-build.js",
|
||||
"postinstall": "patch-package && tsx ./scripts/post-install.ts",
|
||||
"lint": "eslint --ext .ts,.tsx,.json,.vue .",
|
||||
"prebuild": "yarn postinstall && tsx ./scripts/start-build.ts",
|
||||
"size": "t=\"cypress-v0.0.0.tgz\"; yarn pack --filename \"${t}\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";",
|
||||
"test": "yarn test-unit",
|
||||
"test-debug": "node --inspect-brk $(yarn bin mocha)",
|
||||
@@ -17,7 +17,7 @@
|
||||
"test-unit": "yarn unit",
|
||||
"test-watch": "yarn unit --watch",
|
||||
"types": "yarn dtslint",
|
||||
"unit": "cross-env BLUEBIRD_DEBUG=1 NODE_ENV=test mocha --reporter mocha-multi-reporters --reporter-options configFile=../mocha-reporter-config.json"
|
||||
"unit": "cross-env BLUEBIRD_DEBUG=1 NODE_ENV=test mocha -r ts-node/register/transpile-only --reporter mocha-multi-reporters --reporter-options configFile=../mocha-reporter-config.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cypress/request": "^3.0.9",
|
||||
@@ -66,8 +66,6 @@
|
||||
"yauzl": "^2.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.28.0",
|
||||
"@babel/preset-env": "7.28.0",
|
||||
"@cypress/angular": "0.0.0-development",
|
||||
"@cypress/grep": "0.0.0-development",
|
||||
"@cypress/mount-utils": "0.0.0-development",
|
||||
@@ -102,7 +100,9 @@
|
||||
"sinon": "7.2.2",
|
||||
"snap-shot-it": "7.9.10",
|
||||
"spawn-mock": "1.0.0",
|
||||
"strip-ansi": "6.0.1"
|
||||
"strip-ansi": "6.0.1",
|
||||
"tsx": "4.20.4",
|
||||
"typescript": "~5.9.2"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
@@ -163,7 +163,8 @@
|
||||
},
|
||||
"workspaces": {
|
||||
"nohoist": [
|
||||
"@types/*"
|
||||
"@types/*",
|
||||
"tsx"
|
||||
]
|
||||
},
|
||||
"nx": {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
const _ = require('lodash')
|
||||
const path = require('path')
|
||||
const shell = require('shelljs')
|
||||
const fs = require('../lib/fs')
|
||||
import _ from 'lodash'
|
||||
import path from 'path'
|
||||
import shell from 'shelljs'
|
||||
import fs from '../lib/fs'
|
||||
|
||||
// grab the current version and a few other properties
|
||||
// from the root package.json
|
||||
import rootPkg from '@packages/root'
|
||||
|
||||
const {
|
||||
version,
|
||||
description,
|
||||
@@ -13,17 +15,17 @@ const {
|
||||
bugs,
|
||||
repository,
|
||||
keywords,
|
||||
} = require('@packages/root')
|
||||
} = rootPkg as any
|
||||
|
||||
// the rest of properties should come from the package.json in CLI folder
|
||||
const packageJsonSrc = path.join('package.json')
|
||||
const packageJsonDest = path.join('build', 'package.json')
|
||||
|
||||
function getStdout (cmd) {
|
||||
function getStdout (cmd: string): string {
|
||||
return shell.exec(cmd).trim()
|
||||
}
|
||||
|
||||
function preparePackageForNpmRelease (json, branchName) {
|
||||
function preparePackageForNpmRelease (json: any, branchName?: string): any {
|
||||
// modify the existing package.json
|
||||
// to prepare it for releasing to npm
|
||||
delete json.devDependencies
|
||||
@@ -49,17 +51,17 @@ function preparePackageForNpmRelease (json, branchName) {
|
||||
types: 'types', // typescript types
|
||||
scripts: {
|
||||
postinstall: 'node index.js --exec install',
|
||||
size: 't=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";',
|
||||
size: 't="$(npm pack .)"; wc -c "${t}"; tar tvf "${t}"; rm "${t}";',
|
||||
},
|
||||
})
|
||||
|
||||
return json
|
||||
}
|
||||
|
||||
function makeUserPackageFile (branchName) {
|
||||
function makeUserPackageFile (branchName?: string): Promise<any> {
|
||||
return fs.readJsonAsync(packageJsonSrc)
|
||||
.then((json) => preparePackageForNpmRelease(json, branchName))
|
||||
.then((json) => {
|
||||
.then((json: any) => preparePackageForNpmRelease(json, branchName))
|
||||
.then((json: any) => {
|
||||
return fs.outputJsonAsync(packageJsonDest, json, {
|
||||
spaces: 2,
|
||||
})
|
||||
@@ -67,11 +69,11 @@ function makeUserPackageFile (branchName) {
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = makeUserPackageFile
|
||||
export default makeUserPackageFile
|
||||
|
||||
if (!module.parent) {
|
||||
makeUserPackageFile(process.env.BRANCH)
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
/* eslint-disable no-console */
|
||||
console.error('Could not write user package file')
|
||||
console.error(err)
|
||||
@@ -1,13 +0,0 @@
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const { includeTypes } = require('./utils')
|
||||
|
||||
fs.removeSync(path.join(__dirname, '..', 'build'))
|
||||
|
||||
includeTypes.forEach((folder) => {
|
||||
try {
|
||||
fs.removeSync(path.join(__dirname, '..', 'types', folder))
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
})
|
||||
13
cli/scripts/clean.ts
Normal file
13
cli/scripts/clean.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import fs from 'fs-extra'
|
||||
import path from 'path'
|
||||
import { includeTypes } from './utils'
|
||||
|
||||
fs.removeSync(path.join(__dirname, '..', 'build'))
|
||||
|
||||
includeTypes.forEach((folder: string) => {
|
||||
try {
|
||||
fs.removeSync(path.join(__dirname, '..', 'types', folder))
|
||||
} catch (e: any) {
|
||||
//
|
||||
}
|
||||
})
|
||||
@@ -1,12 +1,12 @@
|
||||
const shell = require('shelljs')
|
||||
const { resolve } = require('path')
|
||||
import shell from 'shelljs'
|
||||
import { resolve } from 'path'
|
||||
|
||||
shell.set('-v') // verbose
|
||||
shell.set('-e') // any error is fatal
|
||||
|
||||
// For each npm package that is re-published via cypress/*
|
||||
// make sure that it is also copied into the build directory
|
||||
const npmModulesToCopy = [
|
||||
const npmModulesToCopy: string[] = [
|
||||
'mount-utils',
|
||||
'react',
|
||||
'vue',
|
||||
@@ -14,10 +14,10 @@ const npmModulesToCopy = [
|
||||
'svelte',
|
||||
]
|
||||
|
||||
npmModulesToCopy.forEach((folder) => {
|
||||
npmModulesToCopy.forEach((folder: string) => {
|
||||
// cli/mount-utils => cli/build/mount-utils
|
||||
const from = resolve(`${__dirname}/../${folder}`)
|
||||
const to = resolve(`${__dirname}/../build/${folder}`)
|
||||
const from: string = resolve(`${__dirname}/../${folder}`)
|
||||
const to: string = resolve(`${__dirname}/../build/${folder}`)
|
||||
|
||||
shell.cp('-R', from, to)
|
||||
})
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
// @ts-check
|
||||
/* eslint-disable no-console */
|
||||
const fs = require('fs-extra')
|
||||
const { includeTypes } = require('./utils')
|
||||
const shell = require('shelljs')
|
||||
const { join } = require('path')
|
||||
const resolvePkg = require('resolve-pkg')
|
||||
import fs from 'fs-extra'
|
||||
import { includeTypes } from './utils'
|
||||
import shell from 'shelljs'
|
||||
import { join } from 'path'
|
||||
import resolvePkg from 'resolve-pkg'
|
||||
|
||||
require('./clean')
|
||||
import './clean'
|
||||
|
||||
shell.set('-v') // verbose
|
||||
shell.set('-e') // any error is fatal
|
||||
@@ -22,30 +22,30 @@ shell.set('-e') // any error is fatal
|
||||
|
||||
fs.ensureDirSync(join(__dirname, '..', 'types'))
|
||||
|
||||
includeTypes.forEach((folder) => {
|
||||
const source = resolvePkg(`@types/${folder}`, { cwd: __dirname })
|
||||
includeTypes.forEach((folder: string) => {
|
||||
const source: string = resolvePkg(`@types/${folder}`, { cwd: __dirname })
|
||||
|
||||
fs.copySync(source, join(__dirname, '..', 'types', folder))
|
||||
})
|
||||
|
||||
// jQuery v3.3.x includes "dist" folder that just references back to itself
|
||||
// causing dtslint to think there are double definitions. Remove that folder.
|
||||
const typesJqueryDistFolder = join('types', 'jquery', 'dist')
|
||||
const typesJqueryDistFolder: string = join('types', 'jquery', 'dist')
|
||||
|
||||
shell.rm('-rf', typesJqueryDistFolder)
|
||||
|
||||
/**
|
||||
* Replaces "reference types=<name>" comment with "reference path=..." line.
|
||||
* Replaces "reference types=<n>" comment with "reference path=..." line.
|
||||
* @param {string} typeName - like "chai" or "jquery"
|
||||
* @param {string} relativeTypesFilePath - relative path to .d.ts file like "../chai/index.d.ts"
|
||||
* @param {string} filename - the source file to change
|
||||
*/
|
||||
function makeReferenceTypesCommentRelative (typeName, relativeTypesFilePath, filename) {
|
||||
function makeReferenceTypesCommentRelative (typeName: string, relativeTypesFilePath: string, filename: string): void {
|
||||
console.log('in file %s changing reference for types %s to relative path %s',
|
||||
filename, typeName, relativeTypesFilePath)
|
||||
|
||||
const referenceTypes = `<reference types="${typeName}" />`
|
||||
const relativeTypes = `<reference path="${relativeTypesFilePath}" />`
|
||||
const referenceTypes: string = `<reference types="${typeName}" />`
|
||||
const relativeTypes: string = `<reference path="${relativeTypesFilePath}" />`
|
||||
|
||||
shell.sed(
|
||||
'-i',
|
||||
@@ -62,7 +62,7 @@ makeReferenceTypesCommentRelative('chai', '../chai/index.d.ts',
|
||||
makeReferenceTypesCommentRelative('jquery', '../jquery/index.d.ts',
|
||||
join('types', 'chai-jquery', 'index.d.ts'))
|
||||
|
||||
const sinonChaiFilename = join('types', 'sinon-chai', 'index.d.ts')
|
||||
const sinonChaiFilename: string = join('types', 'sinon-chai', 'index.d.ts')
|
||||
|
||||
makeReferenceTypesCommentRelative('chai', '../chai/index.d.ts', sinonChaiFilename)
|
||||
|
||||
@@ -71,7 +71,7 @@ makeReferenceTypesCommentRelative('chai', '../chai/index.d.ts', sinonChaiFilenam
|
||||
makeReferenceTypesCommentRelative('sinon', '../sinon/index.d.ts', sinonChaiFilename)
|
||||
|
||||
// and an import sinon line to be changed to relative path
|
||||
shell.sed('-i', 'from \"sinon\";', 'from \"../sinon\";', sinonChaiFilename)
|
||||
shell.sed('-i', 'from "sinon";', 'from "../sinon";', sinonChaiFilename)
|
||||
|
||||
// copy experimental network stubbing type definitions
|
||||
// so users can import: `import 'cypress/types/net-stubbing'`
|
||||
@@ -81,18 +81,18 @@ fs.copySync(resolvePkg('@packages/net-stubbing/lib/external-types.ts'), 'types/n
|
||||
// To avoid type clashes, some files should be commented out entirely by patch-package
|
||||
// and uncommented here.
|
||||
|
||||
const filesToUncomment = [
|
||||
const filesToUncomment: string[] = [
|
||||
'mocha/index.d.ts',
|
||||
'jquery/JQuery.d.ts',
|
||||
'jquery/legacy.d.ts',
|
||||
'jquery/misc.d.ts',
|
||||
]
|
||||
|
||||
filesToUncomment.forEach((file) => {
|
||||
const filePath = join(__dirname, '../types', file)
|
||||
const str = fs.readFileSync(filePath).toString()
|
||||
filesToUncomment.forEach((file: string) => {
|
||||
const filePath: string = join(__dirname, '../types', file)
|
||||
const str: string = fs.readFileSync(filePath).toString()
|
||||
|
||||
const result = str.split('\n').map((line) => {
|
||||
const result: string = str.split('\n').map((line: string) => {
|
||||
return line.startsWith('//z ') ? line.substring(4) : line
|
||||
}).join('\n')
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const { includeTypes } = require('./utils')
|
||||
const { join } = require('path')
|
||||
const shell = require('shelljs')
|
||||
|
||||
shell.set('-v') // verbose
|
||||
shell.set('-e') // any error is fatal
|
||||
|
||||
shell.rm('-rf', 'build')
|
||||
shell.mkdir('-p', 'build/bin')
|
||||
shell.mkdir('-p', 'build/types')
|
||||
shell.cp('bin/cypress', 'build/bin/cypress')
|
||||
shell.cp('NPM_README.md', 'build/README.md')
|
||||
shell.cp('.release.json', 'build/.release.json')
|
||||
// copies our typescript definitions
|
||||
shell.cp('-R', 'types/*.ts', 'build/types/')
|
||||
// copies 3rd party typescript definitions
|
||||
includeTypes.forEach((folder) => {
|
||||
const source = join('types', folder)
|
||||
|
||||
shell.cp('-R', source, 'build/types')
|
||||
})
|
||||
|
||||
// TODO: Add a typescript or rollup build step
|
||||
// The only reason start-build.js exists
|
||||
// is because the cli package does not have an actual
|
||||
// build process to compile index.js and lib
|
||||
shell.exec('babel lib -d build/lib')
|
||||
shell.exec('babel index.js -o build/index.js')
|
||||
shell.cp('index.mjs', 'build/index.mjs')
|
||||
38
cli/scripts/start-build.ts
Normal file
38
cli/scripts/start-build.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { includeTypes } from './utils'
|
||||
import { join } from 'path'
|
||||
import shell from 'shelljs'
|
||||
|
||||
shell.set('-v') // verbose
|
||||
shell.set('-e') // any error is fatal
|
||||
|
||||
shell.rm('-rf', 'build')
|
||||
shell.mkdir('-p', 'build/bin')
|
||||
shell.mkdir('-p', 'build/types')
|
||||
shell.cp('bin/cypress', 'build/bin/cypress')
|
||||
shell.cp('NPM_README.md', 'build/README.md')
|
||||
shell.cp('.release.json', 'build/.release.json')
|
||||
// copies our typescript definitions
|
||||
shell.cp('-R', 'types/*.ts', 'build/types/')
|
||||
// copies 3rd party typescript definitions
|
||||
includeTypes.forEach((folder: string) => {
|
||||
const source: string = join('types', folder)
|
||||
|
||||
shell.cp('-R', source, 'build/types')
|
||||
})
|
||||
|
||||
// build the project and copy the build files over to the build directory
|
||||
shell.exec('tsc')
|
||||
|
||||
shell.cp('index.js', 'build/index.js')
|
||||
shell.cp('index.mjs', 'build/index.mjs')
|
||||
|
||||
shell.mkdir('-p', 'build/lib')
|
||||
shell.cp('lib/*.js', 'build/lib/')
|
||||
|
||||
shell.mkdir('-p', 'build/lib/exec')
|
||||
shell.cp('lib/exec/*.js', 'build/lib/exec')
|
||||
|
||||
shell.mkdir('-p', 'build/lib/tasks')
|
||||
shell.cp('lib/tasks/*.js', 'build/lib/tasks')
|
||||
@@ -3,7 +3,7 @@
|
||||
* when we bundle Cypress NPM package. These folder have ".d.ts"
|
||||
* definition files that we will need to include with our NPM package.
|
||||
*/
|
||||
const includeTypes = [
|
||||
export const includeTypes: string[] = [
|
||||
'bluebird',
|
||||
'lodash',
|
||||
'mocha',
|
||||
@@ -14,5 +14,3 @@ const includeTypes = [
|
||||
'chai-jquery',
|
||||
'jquery',
|
||||
]
|
||||
|
||||
module.exports = { includeTypes }
|
||||
@@ -1,16 +1,15 @@
|
||||
require('../spec_helper')
|
||||
import '../spec_helper'
|
||||
import makeUserPackageFile from '../../scripts/build'
|
||||
import snapshot from '../support/snapshot'
|
||||
import la from 'lazy-ass'
|
||||
import is from 'check-more-types'
|
||||
import fs from '../../lib/fs'
|
||||
|
||||
const fs = require(`${lib}/fs`)
|
||||
const makeUserPackageFile = require('../../scripts/build')
|
||||
const snapshot = require('../support/snapshot')
|
||||
const la = require('lazy-ass')
|
||||
const is = require('check-more-types')
|
||||
|
||||
const hasVersion = (json) => {
|
||||
return la(is.semver(json.version), 'cannot find version', json)
|
||||
const hasVersion = (json: any): void => {
|
||||
la(is.semver(json.version), 'cannot find version', json)
|
||||
}
|
||||
|
||||
const normalizePackageJson = (o) => {
|
||||
const normalizePackageJson = (o: any): any => {
|
||||
expect(o.buildInfo).to.include({ stable: false })
|
||||
expect(o.buildInfo.commitBranch).to.match(/.+/)
|
||||
expect(o.buildInfo.commitSha).to.match(/[a-f0-9]+/)
|
||||
@@ -23,7 +22,7 @@ const normalizePackageJson = (o) => {
|
||||
}
|
||||
|
||||
describe('package.json build', () => {
|
||||
beforeEach(function () {
|
||||
beforeEach(function (): void {
|
||||
// stub package.json in CLI
|
||||
// with a few test props
|
||||
// the rest should come from root package.json file
|
||||
@@ -37,7 +36,11 @@ describe('package.json build', () => {
|
||||
|
||||
it('version', () => {
|
||||
return makeUserPackageFile()
|
||||
.tap(hasVersion)
|
||||
.then((result: any) => {
|
||||
hasVersion(result)
|
||||
|
||||
return result
|
||||
})
|
||||
})
|
||||
|
||||
it('outputs expected properties', () => {
|
||||
@@ -1,35 +1,42 @@
|
||||
require('../spec_helper')
|
||||
import '../spec_helper'
|
||||
import os from 'os'
|
||||
import snapshot from '../support/snapshot'
|
||||
import Debug from 'debug'
|
||||
import execa from 'execa-wrap'
|
||||
import mockedEnv from 'mocked-env'
|
||||
import { expect } from 'chai'
|
||||
import mochaBanner from 'mocha-banner'
|
||||
|
||||
const os = require('os')
|
||||
const cli = require(`${lib}/cli`)
|
||||
const util = require(`${lib}/util`)
|
||||
const logger = require(`${lib}/logger`)
|
||||
const info = require(`${lib}/exec/info`)
|
||||
const run = require(`${lib}/exec/run`)
|
||||
const open = require(`${lib}/exec/open`)
|
||||
const cache = require(`${lib}/tasks/cache`)
|
||||
const state = require(`${lib}/tasks/state`)
|
||||
const verify = require(`${lib}/tasks/verify`)
|
||||
const install = require(`${lib}/tasks/install`)
|
||||
const spawn = require(`${lib}/exec/spawn`)
|
||||
const snapshot = require('../support/snapshot')
|
||||
const debug = require('debug')('test')
|
||||
const execa = require('execa-wrap')
|
||||
const mockedEnv = require('mocked-env')
|
||||
const { expect } = require('chai')
|
||||
const debug = Debug('test')
|
||||
|
||||
// Import modules dynamically to handle template literal paths
|
||||
import cli from '../../lib/cli'
|
||||
import util from '../../lib/util'
|
||||
import logger from '../../lib/logger'
|
||||
import info from '../../lib/exec/info'
|
||||
import run from '../../lib/exec/run'
|
||||
import open from '../../lib/exec/open'
|
||||
import cache from '../../lib/tasks/cache'
|
||||
import state from '../../lib/tasks/state'
|
||||
import verify from '../../lib/tasks/verify'
|
||||
import install from '../../lib/tasks/install'
|
||||
import spawn from '../../lib/exec/spawn'
|
||||
|
||||
describe('cli', () => {
|
||||
require('mocha-banner').register()
|
||||
mochaBanner.register()
|
||||
|
||||
beforeEach(() => {
|
||||
beforeEach(function (): void {
|
||||
logger.reset()
|
||||
// @ts-expect-error
|
||||
sinon.stub(process, 'exit').returns(null)
|
||||
|
||||
os.platform.returns('darwin')
|
||||
;(os.platform as any).returns('darwin')
|
||||
// @ts-expect-error
|
||||
sinon.stub(util, 'logErrorExit1').returns(null)
|
||||
|
||||
sinon.stub(util, 'pkgBuildInfo').returns({ stable: true })
|
||||
this.exec = (args) => {
|
||||
|
||||
;(this as any).exec = (args: string): any => {
|
||||
const cliArgs = `node test ${args}`.split(' ')
|
||||
|
||||
debug('calling cli.init with: %o', cliArgs)
|
||||
@@ -41,13 +48,13 @@ describe('cli', () => {
|
||||
context('unknown option', () => {
|
||||
// note it shows help for that specific command
|
||||
it('shows help', () => {
|
||||
return execa('bin/cypress', ['open', '--foo']).then((result) => {
|
||||
return execa('bin/cypress', ['open', '--foo']).then((result: any) => {
|
||||
snapshot('shows help for open --foo 1', result)
|
||||
})
|
||||
})
|
||||
|
||||
it('shows help for run command', () => {
|
||||
return execa('bin/cypress', ['run', '--foo']).then((result) => {
|
||||
return execa('bin/cypress', ['run', '--foo']).then((result: any) => {
|
||||
snapshot('shows help for run --foo 1', result)
|
||||
})
|
||||
})
|
||||
@@ -90,7 +97,7 @@ describe('cli', () => {
|
||||
* Replaces line "Platform: ..." with "Platform: xxx"
|
||||
* @param {string} s
|
||||
*/
|
||||
const replacePlatform = (s) => {
|
||||
const replacePlatform = (s: string): string => {
|
||||
return s.replace(/Platform: .+/, 'Platform: xxx')
|
||||
}
|
||||
|
||||
@@ -98,15 +105,17 @@ describe('cli', () => {
|
||||
* Replaces line "Cypress Version: ..." with "Cypress Version: 1.2.3"
|
||||
* @param {string} s
|
||||
*/
|
||||
const replaceCypressVersion = (s) => {
|
||||
const replaceCypressVersion = (s: string): string => {
|
||||
return s.replace(/Cypress Version: .+/, 'Cypress Version: 1.2.3')
|
||||
}
|
||||
|
||||
const sanitizePlatform = (text) => {
|
||||
const sanitizePlatform = (text: any): any => {
|
||||
return text
|
||||
// @ts-expect-error
|
||||
.split(os.eol)
|
||||
.map(replacePlatform)
|
||||
.map(replaceCypressVersion)
|
||||
// @ts-expect-error
|
||||
.join(os.eol)
|
||||
}
|
||||
|
||||
@@ -136,9 +145,9 @@ describe('cli', () => {
|
||||
})
|
||||
})
|
||||
|
||||
;['--version', '-v', 'version'].forEach((versionCommand) => {
|
||||
;['--version', '-v', 'version'].forEach((versionCommand: string) => {
|
||||
context(`cypress ${versionCommand}`, () => {
|
||||
let restoreEnv
|
||||
let restoreEnv: any
|
||||
|
||||
afterEach(() => {
|
||||
if (restoreEnv) {
|
||||
@@ -149,12 +158,12 @@ describe('cli', () => {
|
||||
|
||||
const binaryDir = '/binary/dir'
|
||||
|
||||
beforeEach(() => {
|
||||
beforeEach((): void => {
|
||||
sinon.stub(state, 'getBinaryDir').returns(binaryDir)
|
||||
})
|
||||
|
||||
describe('individual package versions', () => {
|
||||
beforeEach(() => {
|
||||
beforeEach((): void => {
|
||||
sinon.stub(util, 'pkgVersion').returns('1.2.3')
|
||||
sinon
|
||||
.stub(state, 'getBinaryPkgAsync')
|
||||
@@ -166,39 +175,43 @@ describe('cli', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('reports just the package version', (done) => {
|
||||
this.exec(`${versionCommand} --component package`)
|
||||
process.exit.callsFake((exitCode) => {
|
||||
it('reports just the package version', function (done) {
|
||||
(this as any).exec(`${versionCommand} --component package`)
|
||||
|
||||
;(process.exit as any).callsFake((exitCode: any) => {
|
||||
expect(logger.print()).to.equal('1.2.3')
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('reports just the binary version', (done) => {
|
||||
this.exec(`${versionCommand} --component binary`)
|
||||
process.exit.callsFake(() => {
|
||||
it('reports just the binary version', function (done) {
|
||||
(this as any).exec(`${versionCommand} --component binary`)
|
||||
|
||||
;(process.exit as any).callsFake(() => {
|
||||
expect(logger.print()).to.equal('X.Y.Z')
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('reports just the electron version', (done) => {
|
||||
this.exec(`${versionCommand} --component electron`)
|
||||
process.exit.callsFake(() => {
|
||||
it('reports just the electron version', function (done) {
|
||||
(this as any).exec(`${versionCommand} --component electron`)
|
||||
|
||||
;(process.exit as any).callsFake(() => {
|
||||
expect(logger.print()).to.equal('10.9.8')
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('reports just the bundled Node version', (done) => {
|
||||
this.exec(`${versionCommand} --component node`)
|
||||
process.exit.callsFake(() => {
|
||||
it('reports just the bundled Node version', function (done) {
|
||||
(this as any).exec(`${versionCommand} --component node`)
|
||||
|
||||
;(process.exit as any).callsFake(() => {
|
||||
expect(logger.print()).to.equal('7.7.7')
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('handles not found bundled Node version', (done) => {
|
||||
it('handles not found bundled Node version', function (done) {
|
||||
state.getBinaryPkgAsync
|
||||
.withArgs(binaryDir)
|
||||
.resolves({
|
||||
@@ -206,15 +219,16 @@ describe('cli', () => {
|
||||
electronVersion: '10.9.8',
|
||||
})
|
||||
|
||||
this.exec(`${versionCommand} --component node`)
|
||||
process.exit.callsFake(() => {
|
||||
;(this as any).exec(`${versionCommand} --component node`)
|
||||
|
||||
;(process.exit as any).callsFake(() => {
|
||||
expect(logger.print()).to.equal('not found')
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('reports package version', (done) => {
|
||||
it('reports package version', function (done) {
|
||||
sinon.stub(util, 'pkgVersion').returns('1.2.3')
|
||||
sinon
|
||||
.stub(state, 'getBinaryPkgAsync')
|
||||
@@ -223,25 +237,27 @@ describe('cli', () => {
|
||||
version: 'X.Y.Z',
|
||||
})
|
||||
|
||||
this.exec(versionCommand)
|
||||
process.exit.callsFake(() => {
|
||||
;(this as any).exec(versionCommand)
|
||||
|
||||
;(process.exit as any).callsFake(() => {
|
||||
snapshot('cli version and binary version 1', logger.print(), { allowSharedSnapshot: true })
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('reports package and binary message', (done) => {
|
||||
it('reports package and binary message', function (done) {
|
||||
sinon.stub(util, 'pkgVersion').returns('1.2.3')
|
||||
sinon.stub(state, 'getBinaryPkgAsync').resolves({ version: 'X.Y.Z' })
|
||||
|
||||
this.exec(versionCommand)
|
||||
process.exit.callsFake(() => {
|
||||
;(this as any).exec(versionCommand)
|
||||
|
||||
;(process.exit as any).callsFake(() => {
|
||||
snapshot('cli version and binary version 2', logger.print(), { allowSharedSnapshot: true })
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('reports electron and node message', (done) => {
|
||||
it('reports electron and node message', function (done) {
|
||||
sinon.stub(util, 'pkgVersion').returns('1.2.3')
|
||||
sinon.stub(state, 'getBinaryPkgAsync').resolves({
|
||||
version: 'X.Y.Z',
|
||||
@@ -249,14 +265,15 @@ describe('cli', () => {
|
||||
electronNodeVersion: '11.10.3',
|
||||
})
|
||||
|
||||
this.exec(versionCommand)
|
||||
process.exit.callsFake(() => {
|
||||
;(this as any).exec(versionCommand)
|
||||
|
||||
;(process.exit as any).callsFake(() => {
|
||||
snapshot('cli version with electron and node 1', logger.print(), { allowSharedSnapshot: true })
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('reports package and binary message with npm log silent', (done) => {
|
||||
it('reports package and binary message with npm log silent', function (done) {
|
||||
restoreEnv = mockedEnv({
|
||||
npm_config_loglevel: 'silent',
|
||||
})
|
||||
@@ -264,15 +281,16 @@ describe('cli', () => {
|
||||
sinon.stub(util, 'pkgVersion').returns('1.2.3')
|
||||
sinon.stub(state, 'getBinaryPkgAsync').resolves({ version: 'X.Y.Z' })
|
||||
|
||||
this.exec(versionCommand)
|
||||
process.exit.callsFake(() => {
|
||||
;(this as any).exec(versionCommand)
|
||||
|
||||
;(process.exit as any).callsFake(() => {
|
||||
// should not be empty!
|
||||
snapshot('cli version and binary version with npm log silent', logger.print(), { allowSharedSnapshot: true })
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('reports package and binary message with npm log warn', (done) => {
|
||||
it('reports package and binary message with npm log warn', function (done) {
|
||||
restoreEnv = mockedEnv({
|
||||
npm_config_loglevel: 'warn',
|
||||
})
|
||||
@@ -282,20 +300,22 @@ describe('cli', () => {
|
||||
version: 'X.Y.Z',
|
||||
})
|
||||
|
||||
this.exec(versionCommand)
|
||||
process.exit.callsFake(() => {
|
||||
;(this as any).exec(versionCommand)
|
||||
|
||||
;(process.exit as any).callsFake(() => {
|
||||
// should not be empty!
|
||||
snapshot('cli version and binary version with npm log warn', logger.print(), { allowSharedSnapshot: true })
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('handles non-existent binary', (done) => {
|
||||
it('handles non-existent binary', function (done) {
|
||||
sinon.stub(util, 'pkgVersion').returns('1.2.3')
|
||||
sinon.stub(state, 'getBinaryPkgAsync').resolves(null)
|
||||
|
||||
this.exec(versionCommand)
|
||||
process.exit.callsFake(() => {
|
||||
;(this as any).exec(versionCommand)
|
||||
|
||||
;(process.exit as any).callsFake(() => {
|
||||
snapshot('cli version no binary version 1', logger.print(), { allowSharedSnapshot: true })
|
||||
done()
|
||||
})
|
||||
@@ -304,231 +324,245 @@ describe('cli', () => {
|
||||
})
|
||||
|
||||
context('cypress run', () => {
|
||||
beforeEach(() => {
|
||||
beforeEach((): void => {
|
||||
sinon.stub(run, 'start').resolves(0)
|
||||
sinon.stub(util, 'exit').withArgs(0)
|
||||
})
|
||||
|
||||
it('calls run.start with options + exits with code', (done) => {
|
||||
it('calls run.start with options + exits with code', function (done) {
|
||||
// @ts-expect-error
|
||||
run.start.resolves(10)
|
||||
this.exec('run')
|
||||
|
||||
util.exit.callsFake((code) => {
|
||||
;(this as any).exec('run')
|
||||
|
||||
// @ts-expect-error
|
||||
util.exit.callsFake((code: number) => {
|
||||
expect(code).to.eq(10)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('run.start with options + catches errors', (done) => {
|
||||
it('run.start with options + catches errors', function (done) {
|
||||
const err = new Error('foo')
|
||||
|
||||
// @ts-expect-error
|
||||
run.start.rejects(err)
|
||||
this.exec('run')
|
||||
|
||||
util.logErrorExit1.callsFake((e) => {
|
||||
;(this as any).exec('run')
|
||||
|
||||
// @ts-expect-error
|
||||
util.logErrorExit1.callsFake((e: Error) => {
|
||||
expect(e).to.eq(err)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('calls run with port', () => {
|
||||
this.exec('run --port 7878')
|
||||
it('calls run with port', function (): void {
|
||||
(this as any).exec('run --port 7878')
|
||||
expect(run.start).to.be.calledWith({ port: '7878' })
|
||||
})
|
||||
|
||||
it('calls run with port with -p arg', () => {
|
||||
this.exec('run -p 8989')
|
||||
it('calls run with port with -p arg', function (): void {
|
||||
(this as any).exec('run -p 8989')
|
||||
expect(run.start).to.be.calledWith({ port: '8989' })
|
||||
})
|
||||
|
||||
it('calls run with env variables', () => {
|
||||
this.exec('run --env foo=bar,host=http://localhost:8888')
|
||||
it('calls run with env variables', function (): void {
|
||||
(this as any).exec('run --env foo=bar,host=http://localhost:8888')
|
||||
expect(run.start).to.be.calledWith({
|
||||
env: 'foo=bar,host=http://localhost:8888',
|
||||
})
|
||||
})
|
||||
|
||||
it('calls run with config', () => {
|
||||
this.exec('run --config watchForFileChanges=false,baseUrl=localhost')
|
||||
it('calls run with config', function (): void {
|
||||
(this as any).exec('run --config watchForFileChanges=false,baseUrl=localhost')
|
||||
expect(run.start).to.be.calledWith({
|
||||
config: 'watchForFileChanges=false,baseUrl=localhost',
|
||||
})
|
||||
})
|
||||
|
||||
it('calls run with key', () => {
|
||||
this.exec('run --key asdf')
|
||||
it('calls run with key', function (): void {
|
||||
(this as any).exec('run --key asdf')
|
||||
expect(run.start).to.be.calledWith({ key: 'asdf' })
|
||||
})
|
||||
|
||||
it('calls run with --record', () => {
|
||||
this.exec('run --record')
|
||||
it('calls run with --record', function (): void {
|
||||
(this as any).exec('run --record')
|
||||
expect(run.start).to.be.calledWith({ record: true })
|
||||
})
|
||||
|
||||
it('calls run with --record false', () => {
|
||||
this.exec('run --record false')
|
||||
it('calls run with --record false', function (): void {
|
||||
(this as any).exec('run --record false')
|
||||
expect(run.start).to.be.calledWith({ record: false })
|
||||
})
|
||||
|
||||
it('calls run with relative --project folder', () => {
|
||||
this.exec('run --project foo/bar')
|
||||
it('calls run with relative --project folder', function (): void {
|
||||
(this as any).exec('run --project foo/bar')
|
||||
expect(run.start).to.be.calledWith({ project: 'foo/bar' })
|
||||
})
|
||||
|
||||
it('calls run with absolute --project folder', () => {
|
||||
this.exec('run --project /tmp/foo/bar')
|
||||
it('calls run with absolute --project folder', function (): void {
|
||||
(this as any).exec('run --project /tmp/foo/bar')
|
||||
expect(run.start).to.be.calledWith({ project: '/tmp/foo/bar' })
|
||||
})
|
||||
|
||||
it('calls run with headed', () => {
|
||||
this.exec('run --headed')
|
||||
it('calls run with headed', function (): void {
|
||||
(this as any).exec('run --headed')
|
||||
expect(run.start).to.be.calledWith({ headed: true })
|
||||
})
|
||||
|
||||
it('calls run with --no-exit', () => {
|
||||
this.exec('run --no-exit')
|
||||
it('calls run with --no-exit', function (): void {
|
||||
(this as any).exec('run --no-exit')
|
||||
expect(run.start).to.be.calledWith({ exit: false })
|
||||
})
|
||||
|
||||
it('calls run with --parallel', () => {
|
||||
this.exec('run --parallel')
|
||||
it('calls run with --parallel', function (): void {
|
||||
(this as any).exec('run --parallel')
|
||||
expect(run.start).to.be.calledWith({ parallel: true })
|
||||
})
|
||||
|
||||
it('calls run with --ci-build-id', () => {
|
||||
this.exec('run --ci-build-id 123')
|
||||
it('calls run with --ci-build-id', function (): void {
|
||||
(this as any).exec('run --ci-build-id 123')
|
||||
expect(run.start).to.be.calledWith({ ciBuildId: '123' })
|
||||
})
|
||||
|
||||
it('calls run with --group', () => {
|
||||
this.exec('run --group staging')
|
||||
it('calls run with --group', function (): void {
|
||||
(this as any).exec('run --group staging')
|
||||
expect(run.start).to.be.calledWith({ group: 'staging' })
|
||||
})
|
||||
|
||||
it('calls run with spec', () => {
|
||||
this.exec('run --spec cypress/integration/foo_spec.js')
|
||||
it('calls run with spec', function (): void {
|
||||
(this as any).exec('run --spec cypress/integration/foo_spec.js')
|
||||
expect(run.start).to.be.calledWith({
|
||||
spec: 'cypress/integration/foo_spec.js',
|
||||
})
|
||||
})
|
||||
|
||||
it('calls run with space-separated --spec', () => {
|
||||
this.exec('run --spec a b c d e f g')
|
||||
it('calls run with space-separated --spec', function (): void {
|
||||
(this as any).exec('run --spec a b c d e f g')
|
||||
expect(run.start).to.be.calledWith({ spec: 'a,b,c,d,e,f,g' })
|
||||
this.exec('run --dev bang --spec foo bar baz -P ./')
|
||||
|
||||
;(this as any).exec('run --dev bang --spec foo bar baz -P ./')
|
||||
expect(run.start).to.be.calledWithMatch({ spec: 'foo,bar,baz' })
|
||||
})
|
||||
|
||||
it('warns with space-separated --spec', (done) => {
|
||||
it('warns with space-separated --spec', function (done) {
|
||||
sinon.spy(logger, 'warn')
|
||||
this.exec('run --spec a b c d e f g --dev')
|
||||
|
||||
;(this as any).exec('run --spec a b c d e f g --dev')
|
||||
snapshot(logger.warn.getCall(0).args[0])
|
||||
done()
|
||||
})
|
||||
|
||||
it('calls run with --tag', () => {
|
||||
this.exec('run --tag nightly')
|
||||
it('calls run with --tag', function (): void {
|
||||
(this as any).exec('run --tag nightly')
|
||||
expect(run.start).to.be.calledWith({ tag: 'nightly' })
|
||||
})
|
||||
|
||||
it('calls run comma-separated --tag', () => {
|
||||
this.exec('run --tag nightly,staging')
|
||||
it('calls run comma-separated --tag', function (): void {
|
||||
(this as any).exec('run --tag nightly,staging')
|
||||
expect(run.start).to.be.calledWith({ tag: 'nightly,staging' })
|
||||
})
|
||||
|
||||
it('does not remove double quotes from --tag', () => {
|
||||
it('does not remove double quotes from --tag', function (): void {
|
||||
// I think it is a good idea to lock down this behavior
|
||||
// to make sure we either preserve it or change it in the future
|
||||
this.exec('run --tag "nightly"')
|
||||
(this as any).exec('run --tag "nightly"')
|
||||
expect(run.start).to.be.calledWith({ tag: '"nightly"' })
|
||||
})
|
||||
|
||||
it('calls run comma-separated --spec', () => {
|
||||
this.exec('run --spec main_spec.js,view_spec.js')
|
||||
it('calls run comma-separated --spec', function (): void {
|
||||
(this as any).exec('run --spec main_spec.js,view_spec.js')
|
||||
expect(run.start).to.be.calledWith({ spec: 'main_spec.js,view_spec.js' })
|
||||
})
|
||||
|
||||
it('calls run with space-separated --tag', () => {
|
||||
this.exec('run --tag a b c d e f g')
|
||||
it('calls run with space-separated --tag', function (): void {
|
||||
(this as any).exec('run --tag a b c d e f g')
|
||||
expect(run.start).to.be.calledWith({ tag: 'a,b,c,d,e,f,g' })
|
||||
this.exec('run --dev bang --tag foo bar baz -P ./')
|
||||
|
||||
;(this as any).exec('run --dev bang --tag foo bar baz -P ./')
|
||||
expect(run.start).to.be.calledWithMatch({ tag: 'foo,bar,baz' })
|
||||
})
|
||||
|
||||
it('warns with space-separated --tag', (done) => {
|
||||
it('warns with space-separated --tag', function (done) {
|
||||
sinon.spy(logger, 'warn')
|
||||
this.exec('run --tag a b c d e f g --dev')
|
||||
|
||||
;(this as any).exec('run --tag a b c d e f g --dev')
|
||||
snapshot(logger.warn.getCall(0).args[0])
|
||||
done()
|
||||
})
|
||||
|
||||
it('calls run with space-separated --tag and --spec', () => {
|
||||
this.exec('run --tag a b c d e f g --spec h i j k l')
|
||||
it('calls run with space-separated --tag and --spec', function (): void {
|
||||
(this as any).exec('run --tag a b c d e f g --spec h i j k l')
|
||||
expect(run.start).to.be.calledWith({ tag: 'a,b,c,d,e,f,g', spec: 'h,i,j,k,l' })
|
||||
this.exec('run --dev bang --tag foo bar baz -P ./ --spec fizz buzz --headed false')
|
||||
|
||||
;(this as any).exec('run --dev bang --tag foo bar baz -P ./ --spec fizz buzz --headed false')
|
||||
expect(run.start).to.be.calledWithMatch({ tag: 'foo,bar,baz', spec: 'fizz,buzz' })
|
||||
})
|
||||
|
||||
it('removes stray double quotes from --ci-build-id and --group', () => {
|
||||
this.exec('run --ci-build-id "123" --group "staging"')
|
||||
it('removes stray double quotes from --ci-build-id and --group', function (): void {
|
||||
(this as any).exec('run --ci-build-id "123" --group "staging"')
|
||||
expect(run.start).to.be.calledWith({ ciBuildId: '123', group: 'staging' })
|
||||
})
|
||||
|
||||
it('calls run with --auto-cancel-after-failures', () => {
|
||||
this.exec('run --auto-cancel-after-failures 4')
|
||||
it('calls run with --auto-cancel-after-failures', function (): void {
|
||||
(this as any).exec('run --auto-cancel-after-failures 4')
|
||||
expect(run.start).to.be.calledWith({ autoCancelAfterFailures: '4' })
|
||||
})
|
||||
|
||||
it('calls run with --auto-cancel-after-failures with false', () => {
|
||||
this.exec('run --auto-cancel-after-failures false')
|
||||
it('calls run with --auto-cancel-after-failures with false', function (): void {
|
||||
(this as any).exec('run --auto-cancel-after-failures false')
|
||||
expect(run.start).to.be.calledWith({ autoCancelAfterFailures: 'false' })
|
||||
})
|
||||
|
||||
it('calls run with --runner-ui', () => {
|
||||
this.exec('run --runner-ui')
|
||||
it('calls run with --runner-ui', function (): void {
|
||||
(this as any).exec('run --runner-ui')
|
||||
expect(run.start).to.be.calledWith({ runnerUi: true })
|
||||
})
|
||||
|
||||
it('calls run with --no-runner-ui', () => {
|
||||
this.exec('run --no-runner-ui')
|
||||
it('calls run with --no-runner-ui', function (): void {
|
||||
(this as any).exec('run --no-runner-ui')
|
||||
expect(run.start).to.be.calledWith({ runnerUi: false })
|
||||
})
|
||||
})
|
||||
|
||||
context('cypress open', () => {
|
||||
beforeEach(() => {
|
||||
beforeEach((): void => {
|
||||
sinon.stub(open, 'start').resolves(0)
|
||||
})
|
||||
|
||||
it('calls open.start with relative --project folder', () => {
|
||||
this.exec('open --project foo/bar')
|
||||
it('calls open.start with relative --project folder', function (): void {
|
||||
(this as any).exec('open --project foo/bar')
|
||||
expect(open.start).to.be.calledWith({ project: 'foo/bar' })
|
||||
})
|
||||
|
||||
it('calls open.start with absolute --project folder', () => {
|
||||
this.exec('open --project /tmp/foo/bar')
|
||||
it('calls open.start with absolute --project folder', function (): void {
|
||||
(this as any).exec('open --project /tmp/foo/bar')
|
||||
expect(open.start).to.be.calledWith({ project: '/tmp/foo/bar' })
|
||||
})
|
||||
|
||||
it('calls open.start with options', () => {
|
||||
it('calls open.start with options', function (): void {
|
||||
// sinon.stub(open, 'start').resolves()
|
||||
this.exec('open --port 7878')
|
||||
(this as any).exec('open --port 7878')
|
||||
expect(open.start).to.be.calledWith({ port: '7878' })
|
||||
})
|
||||
|
||||
it('calls open.start with global', () => {
|
||||
it('calls open.start with global', function (): void {
|
||||
// sinon.stub(open, 'start').resolves()
|
||||
this.exec('open --port 7878 --global')
|
||||
(this as any).exec('open --port 7878 --global')
|
||||
expect(open.start).to.be.calledWith({ port: '7878', global: true })
|
||||
})
|
||||
|
||||
it('calls open.start + catches errors', (done) => {
|
||||
it('calls open.start + catches errors', function (done) {
|
||||
const err = new Error('foo')
|
||||
|
||||
// @ts-expect-error
|
||||
open.start.rejects(err)
|
||||
this.exec('open --port 7878')
|
||||
|
||||
util.logErrorExit1.callsFake((e) => {
|
||||
;(this as any).exec('open --port 7878')
|
||||
|
||||
// @ts-expect-error
|
||||
util.logErrorExit1.callsFake((e: Error) => {
|
||||
expect(e).to.eq(err)
|
||||
done()
|
||||
})
|
||||
@@ -536,25 +570,29 @@ describe('cli', () => {
|
||||
})
|
||||
|
||||
context('cypress install', () => {
|
||||
it('calls install.start without forcing', () => {
|
||||
it('calls install.start without forcing', function (): void {
|
||||
sinon.stub(install, 'start').resolves()
|
||||
this.exec('install')
|
||||
|
||||
;(this as any).exec('install')
|
||||
expect(install.start).not.to.be.calledWith({ force: true })
|
||||
})
|
||||
|
||||
it('calls install.start with force: true when passed', () => {
|
||||
it('calls install.start with force: true when passed', function (): void {
|
||||
sinon.stub(install, 'start').resolves()
|
||||
this.exec('install --force')
|
||||
|
||||
;(this as any).exec('install --force')
|
||||
expect(install.start).to.be.calledWith({ force: true })
|
||||
})
|
||||
|
||||
it('install calls install.start + catches errors', (done) => {
|
||||
it('install calls install.start + catches errors', function (done) {
|
||||
const err = new Error('foo')
|
||||
|
||||
sinon.stub(install, 'start').rejects(err)
|
||||
this.exec('install')
|
||||
|
||||
util.logErrorExit1.callsFake((e) => {
|
||||
;(this as any).exec('install')
|
||||
|
||||
// @ts-expect-error
|
||||
util.logErrorExit1.callsFake((e: Error) => {
|
||||
expect(e).to.eq(err)
|
||||
done()
|
||||
})
|
||||
@@ -562,22 +600,25 @@ describe('cli', () => {
|
||||
})
|
||||
|
||||
context('cypress verify', () => {
|
||||
it('verify calls verify.start with force: true', () => {
|
||||
it('verify calls verify.start with force: true', function (): void {
|
||||
sinon.stub(verify, 'start').resolves()
|
||||
this.exec('verify')
|
||||
|
||||
;(this as any).exec('verify')
|
||||
expect(verify.start).to.be.calledWith({
|
||||
force: true,
|
||||
welcomeMessage: false,
|
||||
})
|
||||
})
|
||||
|
||||
it('verify calls verify.start + catches errors', (done) => {
|
||||
it('verify calls verify.start + catches errors', function (done) {
|
||||
const err = new Error('foo')
|
||||
|
||||
sinon.stub(verify, 'start').rejects(err)
|
||||
this.exec('verify')
|
||||
|
||||
util.logErrorExit1.callsFake((e) => {
|
||||
;(this as any).exec('verify')
|
||||
|
||||
// @ts-expect-error
|
||||
util.logErrorExit1.callsFake((e: Error) => {
|
||||
expect(e).to.eq(err)
|
||||
done()
|
||||
})
|
||||
@@ -585,39 +626,42 @@ describe('cli', () => {
|
||||
})
|
||||
|
||||
context('cypress info', () => {
|
||||
beforeEach(() => {
|
||||
beforeEach((): void => {
|
||||
sinon.stub(info, 'start').resolves(0)
|
||||
sinon.stub(util, 'exit').withArgs(0)
|
||||
})
|
||||
|
||||
it('calls info start', () => {
|
||||
this.exec('info')
|
||||
it('calls info start', function (): void {
|
||||
(this as any).exec('info')
|
||||
expect(info.start).to.have.been.calledWith()
|
||||
})
|
||||
})
|
||||
|
||||
context('cypress cache list', () => {
|
||||
it('prints explanation when no cache', (done) => {
|
||||
const err = new Error()
|
||||
it('prints explanation when no cache', function (done) {
|
||||
const err: any = new Error()
|
||||
|
||||
err.code = 'ENOENT'
|
||||
|
||||
sinon.stub(cache, 'list').rejects(err)
|
||||
this.exec('cache list')
|
||||
|
||||
process.exit.callsFake(() => {
|
||||
;(this as any).exec('cache list')
|
||||
|
||||
;(process.exit as any).callsFake(() => {
|
||||
snapshot('prints explanation when no cache', logger.print())
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('catches rejection and exits', (done) => {
|
||||
it('catches rejection and exits', function (done) {
|
||||
const err = new Error('cache list failed badly')
|
||||
|
||||
sinon.stub(cache, 'list').rejects(err)
|
||||
this.exec('cache list')
|
||||
|
||||
util.logErrorExit1.callsFake((e) => {
|
||||
;(this as any).exec('cache list')
|
||||
|
||||
// @ts-expect-error
|
||||
util.logErrorExit1.callsFake((e: Error) => {
|
||||
expect(e).to.eq(err)
|
||||
done()
|
||||
})
|
||||
@@ -625,19 +669,23 @@ describe('cli', () => {
|
||||
})
|
||||
|
||||
context('component-testing', () => {
|
||||
beforeEach(() => {
|
||||
beforeEach((): void => {
|
||||
sinon.stub(spawn, 'start').resolves()
|
||||
})
|
||||
|
||||
it('spawns server with correct args for component-testing', () => {
|
||||
this.exec('open --component --dev')
|
||||
it('spawns server with correct args for component-testing', function (): void {
|
||||
(this as any).exec('open --component --dev')
|
||||
// @ts-expect-error
|
||||
expect(spawn.start.firstCall.args[0]).to.include('--testing-type')
|
||||
// @ts-expect-error
|
||||
expect(spawn.start.firstCall.args[0]).to.include('component')
|
||||
})
|
||||
|
||||
it('runs server with correct args for component-testing', () => {
|
||||
this.exec('run --component --dev')
|
||||
it('runs server with correct args for component-testing', function (): void {
|
||||
(this as any).exec('run --component --dev')
|
||||
// @ts-expect-error
|
||||
expect(spawn.start.firstCall.args[0]).to.include('--testing-type')
|
||||
// @ts-expect-error
|
||||
expect(spawn.start.firstCall.args[0]).to.include('component')
|
||||
})
|
||||
})
|
||||
@@ -1,17 +1,17 @@
|
||||
require('../spec_helper')
|
||||
import '../spec_helper'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import _ from 'lodash'
|
||||
import snapshot from '../support/snapshot'
|
||||
import BluebirdPromise from 'bluebird'
|
||||
import tmpModule from 'tmp'
|
||||
import mockfs from 'mock-fs'
|
||||
import fs from '../../lib/fs'
|
||||
import open from '../../lib/exec/open'
|
||||
import run from '../../lib/exec/run'
|
||||
import cypress from '../../lib/cypress'
|
||||
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const _ = require('lodash')
|
||||
const snapshot = require('../support/snapshot')
|
||||
const Promise = require('bluebird')
|
||||
const tmp = Promise.promisifyAll(require('tmp'))
|
||||
const mockfs = require('mock-fs')
|
||||
|
||||
const fs = require(`${lib}/fs`)
|
||||
const open = require(`${lib}/exec/open`)
|
||||
const run = require(`${lib}/exec/run`)
|
||||
const cypress = require(`${lib}/cypress`)
|
||||
const tmp = BluebirdPromise.promisifyAll(tmpModule)
|
||||
|
||||
describe('cypress', function () {
|
||||
beforeEach(function () {
|
||||
@@ -36,7 +36,7 @@ describe('cypress', function () {
|
||||
it('calls open#start, passing in options', function () {
|
||||
return cypress.open({ foo: 'foo' })
|
||||
.then(getStartArgs)
|
||||
.then((args) => {
|
||||
.then((args: any) => {
|
||||
expect(args.foo).to.equal('foo')
|
||||
})
|
||||
})
|
||||
@@ -49,7 +49,7 @@ describe('cypress', function () {
|
||||
|
||||
return cypress.open({ config })
|
||||
.then(getStartArgs)
|
||||
.then((args) => {
|
||||
.then((args: any) => {
|
||||
expect(args).to.deep.eq({ config: JSON.stringify(config) })
|
||||
})
|
||||
})
|
||||
@@ -59,11 +59,12 @@ describe('cypress', function () {
|
||||
it('resolves with error object', function () {
|
||||
const outputPath = path.join(os.tmpdir(), 'cypress/monorepo/cypress_spec/output.json')
|
||||
|
||||
// @ts-expect-error - type doesn't exist
|
||||
sinon.stub(tmp, 'fileAsync').resolves(outputPath)
|
||||
sinon.stub(run, 'start').resolves(2)
|
||||
sinon.stub(fs, 'readJsonAsync').withArgs(outputPath).resolves()
|
||||
|
||||
return cypress.run().then((result) => {
|
||||
return cypress.run().then((result: any) => {
|
||||
expect(result).to.deep.equal({
|
||||
status: 'failed',
|
||||
failures: 2,
|
||||
@@ -74,10 +75,11 @@ describe('cypress', function () {
|
||||
})
|
||||
|
||||
context('.run', function () {
|
||||
let outputPath
|
||||
let outputPath: string
|
||||
|
||||
beforeEach(function () {
|
||||
outputPath = path.join(os.tmpdir(), 'cypress/monorepo/cypress_spec/output.json')
|
||||
// @ts-expect-error - type doesn't exist
|
||||
sinon.stub(tmp, 'fileAsync').resolves(outputPath)
|
||||
sinon.stub(run, 'start').resolves()
|
||||
|
||||
@@ -87,7 +89,7 @@ describe('cypress', function () {
|
||||
})
|
||||
})
|
||||
|
||||
const normalizeCallArgs = (args) => {
|
||||
const normalizeCallArgs = (args: any) => {
|
||||
expect(args.outputPath).to.equal(outputPath)
|
||||
delete args.outputPath
|
||||
|
||||
@@ -102,7 +104,7 @@ describe('cypress', function () {
|
||||
it('calls run#start, passing in options', () => {
|
||||
return cypress.run({ spec: 'foo', autoCancelAfterFailures: 4 })
|
||||
.then(getStartArgs)
|
||||
.then((args) => {
|
||||
.then((args: any) => {
|
||||
expect(args.spec).to.equal('foo')
|
||||
expect(args.autoCancelAfterFailures).to.equal(4)
|
||||
expect(args.runnerUi).to.be.undefined
|
||||
@@ -112,7 +114,7 @@ describe('cypress', function () {
|
||||
it('calls run#start, passing in autoCancelAfterFailures false', () => {
|
||||
return cypress.run({ autoCancelAfterFailures: false })
|
||||
.then(getStartArgs)
|
||||
.then((args) => {
|
||||
.then((args: any) => {
|
||||
expect(args.autoCancelAfterFailures).to.equal(false)
|
||||
})
|
||||
})
|
||||
@@ -120,7 +122,7 @@ describe('cypress', function () {
|
||||
it('calls run#start, passing in autoCancelAfterFailures 0', () => {
|
||||
return cypress.run({ autoCancelAfterFailures: 0 })
|
||||
.then(getStartArgs)
|
||||
.then((args) => {
|
||||
.then((args: any) => {
|
||||
expect(args.autoCancelAfterFailures).to.equal(0)
|
||||
})
|
||||
})
|
||||
@@ -133,7 +135,7 @@ describe('cypress', function () {
|
||||
|
||||
return cypress.run({ config })
|
||||
.then(getStartArgs)
|
||||
.then((args) => {
|
||||
.then((args: any) => {
|
||||
expect(args).to.deep.eq({ config: JSON.stringify(config) })
|
||||
})
|
||||
})
|
||||
@@ -143,14 +145,14 @@ describe('cypress', function () {
|
||||
|
||||
return cypress.run({ env })
|
||||
.then(getStartArgs)
|
||||
.then((args) => {
|
||||
.then((args: any) => {
|
||||
expect(args).to.deep.eq({ env: JSON.stringify(env) })
|
||||
})
|
||||
})
|
||||
|
||||
it('gets random tmp file and passes it to run#start', function () {
|
||||
return cypress.run().then(() => {
|
||||
expect(run.start.lastCall.args[0].outputPath).to.equal(outputPath)
|
||||
expect((run.start as any).lastCall.args[0].outputPath).to.equal(outputPath)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -177,7 +179,7 @@ describe('cypress', function () {
|
||||
|
||||
return cypress.run(opts)
|
||||
.then(getStartArgs)
|
||||
.then((args) => {
|
||||
.then((args: any) => {
|
||||
expect(args).to.deep.eq(opts)
|
||||
})
|
||||
})
|
||||
@@ -1,16 +1,16 @@
|
||||
require('../spec_helper')
|
||||
|
||||
const os = require('os')
|
||||
const snapshot = require('../support/snapshot')
|
||||
const { errors, getError, formErrorText } = require(`${lib}/errors`)
|
||||
const util = require(`${lib}/util`)
|
||||
import '../spec_helper'
|
||||
import os from 'os'
|
||||
import snapshot from '../support/snapshot'
|
||||
import util from '../../lib/util'
|
||||
import { errors, getError, formErrorText } from '../../lib/errors'
|
||||
|
||||
describe('errors', function () {
|
||||
const { missingXvfb } = errors
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(function (): void {
|
||||
sinon.stub(util, 'pkgVersion').returns('1.2.3')
|
||||
os.platform.returns('test platform')
|
||||
|
||||
;(os.platform as any).returns('test platform')
|
||||
})
|
||||
|
||||
describe('individual', () => {
|
||||
@@ -25,7 +25,7 @@ describe('errors', function () {
|
||||
|
||||
snapshot('child kill error object', errObject)
|
||||
|
||||
return getError(errObject).then((e) => {
|
||||
return getError(errObject).then((e: any) => {
|
||||
expect(e).to.be.an('Error')
|
||||
expect(e).to.have.property('known', true)
|
||||
snapshot('Error message', e.message)
|
||||
@@ -38,7 +38,7 @@ describe('errors', function () {
|
||||
expect(missingXvfb).to.be.an('object')
|
||||
|
||||
return formErrorText(missingXvfb)
|
||||
.then((text) => {
|
||||
.then((text: string) => {
|
||||
expect(text).to.be.a('string')
|
||||
snapshot(text)
|
||||
})
|
||||
@@ -52,7 +52,7 @@ describe('errors', function () {
|
||||
}
|
||||
|
||||
return formErrorText(error)
|
||||
.then((text) => {
|
||||
.then((text: string) => {
|
||||
snapshot(text)
|
||||
expect(solution).to.have.been.calledOnce
|
||||
})
|
||||
@@ -82,7 +82,7 @@ describe('errors', function () {
|
||||
|
||||
it('forms full text for invalid display error', () => {
|
||||
return formErrorText(errors.invalidSmokeTestDisplayError, 'current message', 'prev message')
|
||||
.then((text) => {
|
||||
.then((text: string) => {
|
||||
snapshot('invalid display error', text)
|
||||
})
|
||||
})
|
||||
@@ -1,22 +1,22 @@
|
||||
require('../../spec_helper')
|
||||
import '../../spec_helper'
|
||||
import os from 'os'
|
||||
import snapshot from '../../support/snapshot'
|
||||
import stdout from '../../support/stdout'
|
||||
import normalize from '../../support/normalize'
|
||||
|
||||
const os = require('os')
|
||||
const util = require(`${lib}/util`)
|
||||
const state = require(`${lib}/tasks/state`)
|
||||
const info = require(`${lib}/exec/info`)
|
||||
const spawn = require(`${lib}/exec/spawn`)
|
||||
|
||||
const snapshot = require('../../support/snapshot')
|
||||
const stdout = require('../../support/stdout')
|
||||
const normalize = require('../../support/normalize')
|
||||
import util from '../../../lib/util'
|
||||
import state from '../../../lib/tasks/state'
|
||||
import info from '../../../lib/exec/info'
|
||||
import spawn from '../../../lib/exec/spawn'
|
||||
|
||||
describe('exec info', function () {
|
||||
beforeEach(function () {
|
||||
beforeEach(function (): void {
|
||||
sinon.stub(process, 'exit')
|
||||
|
||||
// common stubs
|
||||
sinon.stub(spawn, 'start').resolves()
|
||||
os.platform.returns('linux')
|
||||
|
||||
;(os.platform as any).returns('linux')
|
||||
sinon.stub(os, 'totalmem').returns(1.2e+9)
|
||||
sinon.stub(os, 'freemem').returns(4e+8)
|
||||
sinon.stub(info, 'findProxyEnvironmentVariables').returns({})
|
||||
@@ -32,7 +32,7 @@ describe('exec info', function () {
|
||||
sinon.stub(state, 'getCacheDir').returns('/user/path/to/binary/cache')
|
||||
})
|
||||
|
||||
const startInfoAndSnapshot = async (snapshotName) => {
|
||||
const startInfoAndSnapshot = async (snapshotName: string): Promise<void> => {
|
||||
expect(snapshotName, 'missing snapshot name').to.be.a('string')
|
||||
|
||||
const output = stdout.capture()
|
||||
@@ -74,6 +74,7 @@ describe('exec info', function () {
|
||||
})
|
||||
|
||||
it('logs additional info about pre-releases', async () => {
|
||||
// @ts-expect-error - is shorthand stub on a function
|
||||
util.pkgBuildInfo.returns({
|
||||
stable: false,
|
||||
commitSha: 'abc123',
|
||||
@@ -85,6 +86,7 @@ describe('exec info', function () {
|
||||
})
|
||||
|
||||
it('logs if unbuilt development', async () => {
|
||||
// @ts-expect-error - is shorthand stub on a function
|
||||
util.pkgBuildInfo.returns(undefined)
|
||||
|
||||
await startInfoAndSnapshot('logs additional info about development')
|
||||
@@ -1,13 +1,13 @@
|
||||
require('../../spec_helper')
|
||||
import '../../spec_helper'
|
||||
|
||||
const verify = require(`${lib}/tasks/verify`)
|
||||
const spawn = require(`${lib}/exec/spawn`)
|
||||
const open = require(`${lib}/exec/open`)
|
||||
const util = require(`${lib}/util`)
|
||||
import util from '../../../lib/util'
|
||||
import verify from '../../../lib/tasks/verify'
|
||||
import spawn from '../../../lib/exec/spawn'
|
||||
import open from '../../../lib/exec/open'
|
||||
|
||||
describe('exec open', function () {
|
||||
context('.start', function () {
|
||||
beforeEach(function () {
|
||||
beforeEach(function (): void {
|
||||
sinon.stub(util, 'isInstalledGlobally').returns(true)
|
||||
sinon.stub(verify, 'start').resolves()
|
||||
sinon.stub(spawn, 'start').resolves()
|
||||
@@ -65,6 +65,7 @@ describe('exec open', function () {
|
||||
})
|
||||
|
||||
it('spawns with cwd as --project if not installed globally', function () {
|
||||
// @ts-expect-error - is shorthand stub on a function
|
||||
util.isInstalledGlobally.returns(false)
|
||||
|
||||
return open.start()
|
||||
@@ -76,6 +77,7 @@ describe('exec open', function () {
|
||||
})
|
||||
|
||||
it('spawns without --project if not installed globally and passing --global option', function () {
|
||||
// @ts-expect-error - is shorthand stub on a function
|
||||
util.isInstalledGlobally.returns(false)
|
||||
|
||||
return open.start({ global: true })
|
||||
@@ -87,6 +89,7 @@ describe('exec open', function () {
|
||||
})
|
||||
|
||||
it('spawns with --project passed in as options even when not installed globally', function () {
|
||||
// @ts-expect-error - is shorthand stub on a function
|
||||
util.isInstalledGlobally.returns(false)
|
||||
|
||||
return open.start({ project: '/path/to/project' })
|
||||
@@ -1,12 +1,10 @@
|
||||
require('../../spec_helper')
|
||||
|
||||
const os = require('os')
|
||||
const snapshot = require('../../support/snapshot')
|
||||
|
||||
const util = require(`${lib}/util`)
|
||||
const run = require(`${lib}/exec/run`)
|
||||
const spawn = require(`${lib}/exec/spawn`)
|
||||
const verify = require(`${lib}/tasks/verify`)
|
||||
import '../../spec_helper'
|
||||
import os from 'os'
|
||||
import snapshot from '../../support/snapshot'
|
||||
import util from '../../../lib/util'
|
||||
import run from '../../../lib/exec/run'
|
||||
import spawn from '../../../lib/exec/spawn'
|
||||
import verify from '../../../lib/tasks/verify'
|
||||
|
||||
describe('exec run', function () {
|
||||
beforeEach(function () {
|
||||
@@ -54,15 +52,16 @@ describe('exec run', function () {
|
||||
})
|
||||
|
||||
it('does not allow setting paradoxical --headed and --headless flags', () => {
|
||||
os.platform.returns('linux')
|
||||
process.exit.returns()
|
||||
(os.platform as any).returns('linux')
|
||||
|
||||
;(process.exit as any).returns()
|
||||
|
||||
expect(() => run.processRunOptions({ headed: true, headless: true })).to.throw()
|
||||
})
|
||||
|
||||
it('passes --headed according to --headless', () => {
|
||||
expect(run.processRunOptions({ headless: true })).to.deep.eq([
|
||||
'--run-project', undefined, '--headed', false,
|
||||
'--run-project', undefined, '--headed', 'false',
|
||||
])
|
||||
})
|
||||
|
||||
@@ -1,36 +1,34 @@
|
||||
require('../../spec_helper')
|
||||
import '../../spec_helper'
|
||||
import cp from 'child_process'
|
||||
import os from 'os'
|
||||
import tty from 'tty'
|
||||
import path from 'path'
|
||||
import { EventEmitter as EE } from 'events'
|
||||
import mockedEnv from 'mocked-env'
|
||||
import readline from 'readline'
|
||||
import createDebug from 'debug'
|
||||
import snapshot from '../../support/snapshot'
|
||||
import state from '../../../lib/tasks/state'
|
||||
import xvfb from '../../../lib/exec/xvfb'
|
||||
import spawn from '../../../lib/exec/spawn'
|
||||
import verify from '../../../lib/tasks/verify'
|
||||
import util from '../../../lib/util'
|
||||
|
||||
const cp = require('child_process')
|
||||
const os = require('os')
|
||||
const tty = require('tty')
|
||||
const path = require('path')
|
||||
const EE = require('events')
|
||||
const mockedEnv = require('mocked-env')
|
||||
const readline = require('readline')
|
||||
const proxyquire = require('proxyquire')
|
||||
|
||||
const debug = require('debug')('test')
|
||||
|
||||
const state = require(`${lib}/tasks/state`)
|
||||
const xvfb = require(`${lib}/exec/xvfb`)
|
||||
const spawn = require(`${lib}/exec/spawn`)
|
||||
const verify = require(`${lib}/tasks/verify`)
|
||||
const util = require(`${lib}/util.js`)
|
||||
const expect = require('chai').expect
|
||||
const snapshot = require('../../support/snapshot')
|
||||
const debug = createDebug('test')
|
||||
|
||||
const cwd = process.cwd()
|
||||
const execPath = process.execPath
|
||||
const nodeVersion = process.versions.node
|
||||
|
||||
const defaultBinaryDir = '/default/binary/dir'
|
||||
let mockReadlineEE
|
||||
let mockReadlineEE: any
|
||||
|
||||
describe('lib/exec/spawn', function () {
|
||||
beforeEach(function () {
|
||||
os.platform.returns('darwin')
|
||||
(os.platform as any).returns('darwin')
|
||||
sinon.stub(process, 'exit')
|
||||
this.spawnedProcess = {
|
||||
|
||||
;(this as any).spawnedProcess = {
|
||||
on: sinon.stub().returns(undefined),
|
||||
unref: sinon.stub().returns(undefined),
|
||||
stdin: {
|
||||
@@ -51,13 +49,13 @@ describe('lib/exec/spawn', function () {
|
||||
}
|
||||
|
||||
// process.stdin is both an event emitter and a readable stream
|
||||
this.processStdin = new EE()
|
||||
;(this as any).processStdin = new EE()
|
||||
mockReadlineEE = new EE()
|
||||
|
||||
this.processStdin.pipe = sinon.stub().returns(undefined)
|
||||
sinon.stub(process, 'stdin').value(this.processStdin)
|
||||
;(this as any).processStdin.pipe = sinon.stub().returns(undefined)
|
||||
sinon.stub(process, 'stdin').value((this as any).processStdin)
|
||||
sinon.stub(readline, 'createInterface').returns(mockReadlineEE)
|
||||
sinon.stub(cp, 'spawn').returns(this.spawnedProcess)
|
||||
sinon.stub(cp, 'spawn').returns((this as any).spawnedProcess)
|
||||
sinon.stub(xvfb, 'start').resolves()
|
||||
sinon.stub(xvfb, 'stop').resolves()
|
||||
sinon.stub(xvfb, 'isNeeded').returns(false)
|
||||
@@ -75,7 +73,7 @@ describe('lib/exec/spawn', function () {
|
||||
// the environment variables when running tests on CI.
|
||||
|
||||
it('passes args + options to spawn', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
sinon.stub(verify, 'needsSandbox').returns(false)
|
||||
|
||||
return spawn.start('--foo', { foo: 'bar' })
|
||||
@@ -97,7 +95,7 @@ describe('lib/exec/spawn', function () {
|
||||
})
|
||||
|
||||
it('uses --no-sandbox when needed', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
sinon.stub(verify, 'needsSandbox').returns(true)
|
||||
|
||||
return spawn.start('--foo', { foo: 'bar' })
|
||||
@@ -105,7 +103,7 @@ describe('lib/exec/spawn', function () {
|
||||
// skip the options argument: we do not need anything about it
|
||||
// and also less risk that a failed assertion would dump the
|
||||
// entire ENV object with possible sensitive variables
|
||||
const args = cp.spawn.firstCall.args.slice(0, 2)
|
||||
const args = (cp.spawn as any).firstCall.args.slice(0, 2)
|
||||
// it is important for "--no-sandbox" to appear before "--" separator
|
||||
const expectedCliArgs = [
|
||||
'--no-sandbox',
|
||||
@@ -124,7 +122,7 @@ describe('lib/exec/spawn', function () {
|
||||
})
|
||||
|
||||
it('uses npm command when running in dev mode', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
sinon.stub(verify, 'needsSandbox').returns(false)
|
||||
|
||||
const p = path.resolve('..', 'scripts', 'start.js')
|
||||
@@ -149,7 +147,7 @@ describe('lib/exec/spawn', function () {
|
||||
})
|
||||
|
||||
it('does not pass --no-sandbox when running in dev mode', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
sinon.stub(verify, 'needsSandbox').returns(true)
|
||||
|
||||
const p = path.resolve('..', 'scripts', 'start.js')
|
||||
@@ -174,9 +172,9 @@ describe('lib/exec/spawn', function () {
|
||||
})
|
||||
|
||||
it('starts xvfb when needed', function () {
|
||||
xvfb.isNeeded.returns(true)
|
||||
(xvfb.isNeeded as any).returns(true)
|
||||
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
;(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
return spawn.start('--foo')
|
||||
.then(() => {
|
||||
@@ -187,15 +185,16 @@ describe('lib/exec/spawn', function () {
|
||||
context('closes', function () {
|
||||
['close', 'exit'].forEach((event) => {
|
||||
it(`if '${event}' event fired`, function () {
|
||||
this.spawnedProcess.on.withArgs(event).yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs(event).yieldsAsync(0)
|
||||
|
||||
return spawn.start('--foo')
|
||||
})
|
||||
})
|
||||
|
||||
it('if exit event fired and close event fired', function () {
|
||||
this.spawnedProcess.on.withArgs('exit').yieldsAsync(0)
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('exit').yieldsAsync(0)
|
||||
|
||||
;(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
return spawn.start('--foo')
|
||||
})
|
||||
@@ -203,12 +202,12 @@ describe('lib/exec/spawn', function () {
|
||||
|
||||
context('detects kill signal', function () {
|
||||
it('exits with error on SIGKILL', function () {
|
||||
this.spawnedProcess.on.withArgs('exit').yieldsAsync(null, 'SIGKILL')
|
||||
(this as any).spawnedProcess.on.withArgs('exit').yieldsAsync(null, 'SIGKILL')
|
||||
|
||||
return spawn.start('--foo')
|
||||
.then(() => {
|
||||
throw new Error('should have hit error handler but did not')
|
||||
}, (e) => {
|
||||
}, (e: any) => {
|
||||
debug('error message', e.message)
|
||||
snapshot(e.message)
|
||||
})
|
||||
@@ -216,7 +215,7 @@ describe('lib/exec/spawn', function () {
|
||||
})
|
||||
|
||||
it('does not start xvfb when its not needed', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
return spawn.start('--foo')
|
||||
.then(() => {
|
||||
@@ -225,10 +224,11 @@ describe('lib/exec/spawn', function () {
|
||||
})
|
||||
|
||||
it('stops xvfb when spawn closes', function () {
|
||||
xvfb.isNeeded.returns(true)
|
||||
(xvfb.isNeeded as any).returns(true)
|
||||
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
this.spawnedProcess.on.withArgs('close').yields()
|
||||
;(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
;(this as any).spawnedProcess.on.withArgs('close').yields()
|
||||
|
||||
return spawn.start('--foo')
|
||||
.then(() => {
|
||||
@@ -237,16 +237,16 @@ describe('lib/exec/spawn', function () {
|
||||
})
|
||||
|
||||
it('resolves with spawned close code in the message', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(10)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(10)
|
||||
|
||||
return spawn.start('--foo')
|
||||
.then((code) => {
|
||||
.then((code: any) => {
|
||||
expect(code).to.equal(10)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Linux display', () => {
|
||||
let restore
|
||||
let restore: any
|
||||
|
||||
beforeEach(() => {
|
||||
restore = mockedEnv({
|
||||
@@ -259,19 +259,20 @@ describe('lib/exec/spawn', function () {
|
||||
})
|
||||
|
||||
it('retries with xvfb if fails with display exit code', function () {
|
||||
this.spawnedProcess.on.withArgs('close').onFirstCall().yieldsAsync(1)
|
||||
this.spawnedProcess.on.withArgs('close').onSecondCall().yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').onFirstCall().yieldsAsync(1)
|
||||
|
||||
;(this as any).spawnedProcess.on.withArgs('close').onSecondCall().yieldsAsync(0)
|
||||
|
||||
const buf1 = '[some noise here] Gtk: cannot open display: 987'
|
||||
|
||||
this.spawnedProcess.stderr.on
|
||||
;(this as any).spawnedProcess.stderr.on
|
||||
.withArgs('data')
|
||||
.yields(buf1)
|
||||
|
||||
os.platform.returns('linux')
|
||||
;(os.platform as any).returns('linux')
|
||||
|
||||
return spawn.start('--foo')
|
||||
.then((code) => {
|
||||
.then((code: any) => {
|
||||
expect(xvfb.start).to.have.been.calledOnce
|
||||
expect(xvfb.stop).to.have.been.calledOnce
|
||||
expect(cp.spawn).to.have.been.calledTwice
|
||||
@@ -284,154 +285,173 @@ describe('lib/exec/spawn', function () {
|
||||
it('rejects with error from spawn', function () {
|
||||
const msg = 'the error message'
|
||||
|
||||
this.spawnedProcess.on.withArgs('error').yieldsAsync(new Error(msg))
|
||||
;(this as any).spawnedProcess.on.withArgs('error').yieldsAsync(new Error(msg))
|
||||
|
||||
return spawn.start('--foo')
|
||||
.then(() => {
|
||||
throw new Error('should have hit error handler but did not')
|
||||
}, (e) => {
|
||||
}, (e: any) => {
|
||||
debug('error message', e.message)
|
||||
expect(e.message).to.include(msg)
|
||||
})
|
||||
})
|
||||
|
||||
it('unrefs if options.detached is true', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
return spawn.start(null, { detached: true })
|
||||
.then(() => {
|
||||
expect(this.spawnedProcess.unref).to.be.calledOnce
|
||||
expect((this as any).spawnedProcess.unref).to.be.calledOnce
|
||||
})
|
||||
})
|
||||
|
||||
it('does not unref by default', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
// @ts-expect-error - invalid number of arguments for given type
|
||||
return spawn.start()
|
||||
.then(() => {
|
||||
expect(this.spawnedProcess.unref).not.to.be.called
|
||||
expect((this as any).spawnedProcess.unref).not.to.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('sets process.env to options.env', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
process.env.FOO = 'bar'
|
||||
|
||||
// @ts-expect-error - invalid number of arguments for given type
|
||||
return spawn.start()
|
||||
.then(() => {
|
||||
expect(cp.spawn.firstCall.args[2].env.FOO).to.eq('bar')
|
||||
expect((cp.spawn as any).firstCall.args[2].env.FOO).to.eq('bar')
|
||||
})
|
||||
})
|
||||
|
||||
it('forces colors and streams when supported', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
sinon.stub(util, 'supportsColor').returns(true)
|
||||
sinon.stub(tty, 'isatty').returns(true)
|
||||
|
||||
return spawn.start([], { env: {} })
|
||||
.then(() => {
|
||||
snapshot(cp.spawn.firstCall.args[2].env)
|
||||
snapshot((cp.spawn as any).firstCall.args[2].env)
|
||||
})
|
||||
})
|
||||
|
||||
it('sets windowsHide:false property in windows', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
os.platform.returns('win32')
|
||||
;(os.platform as any).returns('win32')
|
||||
|
||||
return spawn.start([], { env: {} })
|
||||
.then(() => {
|
||||
expect(cp.spawn.firstCall.args[2].windowsHide).to.be.false
|
||||
expect((cp.spawn as any).firstCall.args[2].windowsHide).to.be.false
|
||||
})
|
||||
})
|
||||
|
||||
it('propagates treeKill if SIGINT is detected in windows console', async function () {
|
||||
this.spawnedProcess.pid = 7
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.pid = 7
|
||||
|
||||
os.platform.returns('win32')
|
||||
;(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
;(os.platform as any).returns('win32')
|
||||
|
||||
const treeKillMock = sinon.stub().returns(0)
|
||||
|
||||
const spawn = proxyquire(`${lib}/exec/spawn`, { 'tree-kill': treeKillMock })
|
||||
const proxyquire = await import('proxyquire')
|
||||
const spawn = proxyquire.default(`../../../lib/exec/spawn`, { 'tree-kill': treeKillMock }).default
|
||||
|
||||
await spawn.start([], { env: {} })
|
||||
|
||||
mockReadlineEE.emit('SIGINT')
|
||||
// since the import of tree-kill is async inside spawn, we need to wait for it to be imported and called
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(resolve)
|
||||
})
|
||||
|
||||
expect(treeKillMock).to.have.been.calledWith(7, 'SIGINT')
|
||||
})
|
||||
|
||||
it('does not set windowsHide property when in darwin', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
return spawn.start([], { env: {} })
|
||||
.then(() => {
|
||||
expect(cp.spawn.firstCall.args[2].windowsHide).to.be.undefined
|
||||
expect((cp.spawn as any).firstCall.args[2].windowsHide).to.be.undefined
|
||||
})
|
||||
})
|
||||
|
||||
it('does not force colors and streams when not supported', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
sinon.stub(util, 'supportsColor').returns(false)
|
||||
sinon.stub(tty, 'isatty').returns(false)
|
||||
|
||||
return spawn.start([], { env: {} })
|
||||
.then(() => {
|
||||
snapshot(cp.spawn.firstCall.args[2].env)
|
||||
snapshot((cp.spawn as any).firstCall.args[2].env)
|
||||
})
|
||||
})
|
||||
|
||||
it('pipes when on win32', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
os.platform.returns('win32')
|
||||
xvfb.isNeeded.returns(false)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
;(os.platform as any).returns('win32')
|
||||
|
||||
;(xvfb.isNeeded as any).returns(false)
|
||||
|
||||
// @ts-expect-error - invalid number of arguments for given type
|
||||
return spawn.start()
|
||||
.then(() => {
|
||||
expect(cp.spawn.firstCall.args[2].stdio).to.deep.eq('pipe')
|
||||
expect((cp.spawn as any).firstCall.args[2].stdio).to.deep.eq('pipe')
|
||||
// parent process STDIN was piped to child process STDIN
|
||||
expect(this.processStdin.pipe, 'process.stdin').to.have.been.calledOnce
|
||||
.and.to.have.been.calledWith(this.spawnedProcess.stdin)
|
||||
expect((this as any).processStdin.pipe, 'process.stdin').to.have.been.calledOnce
|
||||
.and.to.have.been.calledWith((this as any).spawnedProcess.stdin)
|
||||
})
|
||||
})
|
||||
|
||||
it('inherits when on linux and xvfb isn\'t needed', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
os.platform.returns('linux')
|
||||
xvfb.isNeeded.returns(false)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
;(os.platform as any).returns('linux')
|
||||
|
||||
;(xvfb.isNeeded as any).returns(false)
|
||||
|
||||
// @ts-expect-error - invalid number of arguments for given type
|
||||
return spawn.start()
|
||||
.then(() => {
|
||||
expect(cp.spawn.firstCall.args[2].stdio).to.deep.eq('inherit')
|
||||
expect((cp.spawn as any).firstCall.args[2].stdio).to.deep.eq('inherit')
|
||||
})
|
||||
})
|
||||
|
||||
it('uses [inherit, inherit, pipe] when linux and xvfb is needed', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
xvfb.isNeeded.returns(true)
|
||||
os.platform.returns('linux')
|
||||
;(xvfb.isNeeded as any).returns(true)
|
||||
|
||||
;(os.platform as any).returns('linux')
|
||||
|
||||
// @ts-expect-error - invalid number of arguments for given type
|
||||
return spawn.start()
|
||||
.then(() => {
|
||||
expect(cp.spawn.firstCall.args[2].stdio).to.deep.eq([
|
||||
expect((cp.spawn as any).firstCall.args[2].stdio).to.deep.eq([
|
||||
'inherit', 'inherit', 'pipe',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
it('uses [inherit, inherit, pipe] on darwin', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
xvfb.isNeeded.returns(false)
|
||||
os.platform.returns('darwin')
|
||||
;(xvfb.isNeeded as any).returns(false)
|
||||
|
||||
;(os.platform as any).returns('darwin')
|
||||
|
||||
// @ts-expect-error - invalid number of arguments for given type
|
||||
return spawn.start()
|
||||
.then(() => {
|
||||
expect(cp.spawn.firstCall.args[2].stdio).to.deep.eq([
|
||||
expect((cp.spawn as any).firstCall.args[2].stdio).to.deep.eq([
|
||||
'inherit', 'inherit', 'pipe',
|
||||
])
|
||||
})
|
||||
@@ -440,18 +460,21 @@ describe('lib/exec/spawn', function () {
|
||||
it('writes everything on win32', function () {
|
||||
const buf1 = Buffer.from('asdf')
|
||||
|
||||
this.spawnedProcess.stdin.pipe.withArgs(process.stdin)
|
||||
this.spawnedProcess.stdout.pipe.withArgs(process.stdout)
|
||||
;(this as any).spawnedProcess.stdin.pipe.withArgs(process.stdin)
|
||||
|
||||
this.spawnedProcess.stderr.on
|
||||
;(this as any).spawnedProcess.stdout.pipe.withArgs(process.stdout)
|
||||
|
||||
;(this as any).spawnedProcess.stderr.on
|
||||
.withArgs('data')
|
||||
.yields(buf1)
|
||||
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
;(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
sinon.stub(process.stderr, 'write').withArgs(buf1)
|
||||
os.platform.returns('win32')
|
||||
|
||||
;(os.platform as any).returns('win32')
|
||||
|
||||
// @ts-expect-error - invalid number of arguments for given type
|
||||
return spawn.start()
|
||||
})
|
||||
|
||||
@@ -459,15 +482,16 @@ describe('lib/exec/spawn', function () {
|
||||
// https://github.com/cypress-io/cypress/issues/5241
|
||||
;['EPIPE', 'ENOTCONN'].forEach((errCode) => {
|
||||
it(`catches process.stdin errors and returns when code=${errCode}`, function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
// @ts-expect-error - invalid number of arguments for given type
|
||||
return spawn.start()
|
||||
.then(() => {
|
||||
let called = false
|
||||
|
||||
const fn = () => {
|
||||
called = true
|
||||
const err = new Error()
|
||||
const err: any = new Error()
|
||||
|
||||
err.code = errCode
|
||||
|
||||
@@ -481,12 +505,13 @@ describe('lib/exec/spawn', function () {
|
||||
})
|
||||
|
||||
it('throws process.stdin errors code!=EPIPE', function () {
|
||||
this.spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
(this as any).spawnedProcess.on.withArgs('close').yieldsAsync(0)
|
||||
|
||||
// @ts-expect-error - invalid number of arguments for given type
|
||||
return spawn.start()
|
||||
.then(() => {
|
||||
const fn = () => {
|
||||
const err = new Error('wattttt')
|
||||
const err: any = new Error('wattttt')
|
||||
|
||||
err.code = 'FAILWHALE'
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
const { expect } = require('chai')
|
||||
import { expect } from 'chai'
|
||||
import '../../spec_helper'
|
||||
|
||||
require('../../spec_helper')
|
||||
|
||||
const util = require(`${lib}/util`)
|
||||
const state = require(`${lib}/tasks/state`)
|
||||
const versions = require(`${lib}/exec/versions`)
|
||||
import util from '../../../lib/util'
|
||||
import state from '../../../lib/tasks/state'
|
||||
import versions from '../../../lib/exec/versions'
|
||||
|
||||
describe('lib/exec/versions', function () {
|
||||
const binaryDir = '/cache/1.2.3/Cypress.app'
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(function (): void {
|
||||
sinon.stub(state, 'getBinaryDir').returns(binaryDir)
|
||||
sinon.stub(state, 'getBinaryPkgAsync').withArgs(binaryDir).resolves({
|
||||
version: '1.2.3',
|
||||
@@ -23,14 +22,14 @@ describe('lib/exec/versions', function () {
|
||||
|
||||
describe('.getVersions', function () {
|
||||
it('gets the correct binary and package version', function () {
|
||||
return versions.getVersions().then(({ package, binary }) => {
|
||||
expect(package, 'package version').to.eql('4.5.6')
|
||||
return versions.getVersions().then(({ package: pkg, binary }: any) => {
|
||||
expect(pkg, 'package version').to.eql('4.5.6')
|
||||
expect(binary, 'binary version').to.eql('1.2.3')
|
||||
})
|
||||
})
|
||||
|
||||
it('gets the correct Electron and bundled Node version', function () {
|
||||
return versions.getVersions().then(({ electronVersion, electronNodeVersion }) => {
|
||||
return versions.getVersions().then(({ electronVersion, electronNodeVersion }: any) => {
|
||||
expect(electronVersion, 'electron version').to.eql('10.1.2')
|
||||
expect(electronNodeVersion, 'node version').to.eql('12.16.3')
|
||||
})
|
||||
@@ -40,18 +39,20 @@ describe('lib/exec/versions', function () {
|
||||
sinon.stub(state, 'parseRealPlatformBinaryFolderAsync').resolves('/my/cypress/path')
|
||||
process.env.CYPRESS_RUN_BINARY = '/my/cypress/path'
|
||||
state.getBinaryPkgAsync
|
||||
// @ts-expect-error - is shorthand stub on a function
|
||||
.withArgs('/my/cypress/path')
|
||||
.resolves({
|
||||
version: '7.8.9',
|
||||
})
|
||||
|
||||
return versions.getVersions().then(({ package, binary }) => {
|
||||
expect(package).to.eql('4.5.6')
|
||||
return versions.getVersions().then(({ package: pkg, binary }: any) => {
|
||||
expect(pkg).to.eql('4.5.6')
|
||||
expect(binary).to.eql('7.8.9')
|
||||
})
|
||||
})
|
||||
|
||||
it('appends pre-release if not stable', async function () {
|
||||
// @ts-expect-error - is shorthand stub on a function
|
||||
util.pkgBuildInfo.returns({ stable: false })
|
||||
|
||||
const v = await versions.getVersions()
|
||||
@@ -60,6 +61,7 @@ describe('lib/exec/versions', function () {
|
||||
})
|
||||
|
||||
it('appends development if missing buildInfo', async function () {
|
||||
// @ts-expect-error - is shorthand stub on a function
|
||||
util.pkgBuildInfo.returns(undefined)
|
||||
|
||||
const v = await versions.getVersions()
|
||||
@@ -69,11 +71,12 @@ describe('lib/exec/versions', function () {
|
||||
|
||||
it('reports default versions if not found', function () {
|
||||
// imagine package.json only has version there
|
||||
// @ts-expect-error - is shorthand stub on a function
|
||||
state.getBinaryPkgAsync.withArgs(binaryDir).resolves({
|
||||
version: '90.9.9',
|
||||
})
|
||||
|
||||
return versions.getVersions().then((versions) => {
|
||||
return versions.getVersions().then((versions: any) => {
|
||||
expect(versions).to.deep.equal({
|
||||
'package': '4.5.6',
|
||||
'binary': '90.9.9',
|
||||
@@ -1,11 +1,11 @@
|
||||
require('../../spec_helper')
|
||||
import '../../spec_helper'
|
||||
import os from 'os'
|
||||
|
||||
const os = require('os')
|
||||
const xvfb = require(`${lib}/exec/xvfb`)
|
||||
import xvfb from '../../../lib/exec/xvfb'
|
||||
|
||||
describe('lib/exec/xvfb', function () {
|
||||
beforeEach(function () {
|
||||
os.platform.returns('win32')
|
||||
beforeEach(function (): void {
|
||||
(os.platform as any).returns('win32')
|
||||
})
|
||||
|
||||
context('debugXvfb', function () {
|
||||
@@ -63,13 +63,13 @@ describe('lib/exec/xvfb', function () {
|
||||
.then(() => {
|
||||
throw new Error('Should have thrown an error')
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: Error) => {
|
||||
expect(err.message).to.include(message)
|
||||
})
|
||||
})
|
||||
|
||||
it('fails when xvfb exited with non zero exit code', function () {
|
||||
const e = new Error('something bad happened')
|
||||
const e: any = new Error('something bad happened')
|
||||
|
||||
e.nonZeroExitCode = true
|
||||
|
||||
@@ -79,7 +79,7 @@ describe('lib/exec/xvfb', function () {
|
||||
.then(() => {
|
||||
throw new Error('Should have thrown an error')
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
expect(err.known).to.be.true
|
||||
expect(err.message).to.include('something bad happened')
|
||||
expect(err.message).to.include('Xvfb exited with a non zero exit code.')
|
||||
@@ -89,13 +89,13 @@ describe('lib/exec/xvfb', function () {
|
||||
|
||||
context('#isNeeded', function () {
|
||||
it('does not need xvfb on osx', function () {
|
||||
os.platform.returns('darwin')
|
||||
(os.platform as any).returns('darwin')
|
||||
|
||||
expect(xvfb.isNeeded()).to.be.false
|
||||
})
|
||||
|
||||
it('does not need xvfb on linux when DISPLAY is set', function () {
|
||||
os.platform.returns('linux')
|
||||
(os.platform as any).returns('linux')
|
||||
|
||||
process.env.DISPLAY = ':99'
|
||||
|
||||
@@ -103,7 +103,7 @@ describe('lib/exec/xvfb', function () {
|
||||
})
|
||||
|
||||
it('does need xvfb on linux when no DISPLAY is set', function () {
|
||||
os.platform.returns('linux')
|
||||
(os.platform as any).returns('linux')
|
||||
|
||||
expect(xvfb.isNeeded()).to.be.true
|
||||
})
|
||||
@@ -1,8 +1,7 @@
|
||||
require('../spec_helper')
|
||||
|
||||
const la = require('lazy-ass')
|
||||
const { stripIndent, stripIndents } = require('common-tags')
|
||||
const snapshot = require('../support/snapshot')
|
||||
import '../spec_helper'
|
||||
import la from 'lazy-ass'
|
||||
import { stripIndent, stripIndents } from 'common-tags'
|
||||
import snapshot from '../support/snapshot'
|
||||
|
||||
describe('stripIndent', () => {
|
||||
it('removes indent from literal string', () => {
|
||||
@@ -1,23 +1,23 @@
|
||||
require('../../spec_helper')
|
||||
|
||||
const mockfs = require('mock-fs')
|
||||
|
||||
const fs = require(`${lib}/fs`)
|
||||
const state = require(`${lib}/tasks/state`)
|
||||
const util = require(`${lib}/util`)
|
||||
const cache = require(`${lib}/tasks/cache`)
|
||||
const stdout = require('../../support/stdout')
|
||||
const snapshot = require('../../support/snapshot')
|
||||
const dayjs = require('dayjs')
|
||||
const stripAnsi = require('strip-ansi')
|
||||
const path = require('path')
|
||||
const termToHtml = require('term-to-html')
|
||||
const mockedEnv = require('mocked-env')
|
||||
import '../../spec_helper'
|
||||
import mockfs from 'mock-fs'
|
||||
import stdout from '../../support/stdout'
|
||||
import snapshot from '../../support/snapshot'
|
||||
import dayjs from 'dayjs'
|
||||
import stripAnsi from 'strip-ansi'
|
||||
import path from 'path'
|
||||
import termToHtml from 'term-to-html'
|
||||
import mockedEnv from 'mocked-env'
|
||||
import fs from '../../../lib/fs'
|
||||
import state from '../../../lib/tasks/state'
|
||||
import util from '../../../lib/util'
|
||||
import cache from '../../../lib/tasks/cache'
|
||||
|
||||
const outputHtmlFolder = path.join(__dirname, '..', '..', 'html')
|
||||
|
||||
describe('lib/tasks/cache', () => {
|
||||
beforeEach(() => {
|
||||
let stdoutCapture: any
|
||||
|
||||
beforeEach(async function () {
|
||||
mockfs({
|
||||
'/.cache/Cypress': {
|
||||
'1.2.3': {
|
||||
@@ -37,12 +37,13 @@ describe('lib/tasks/cache', () => {
|
||||
sinon.stub(state, 'getCacheDir').returns('/.cache/Cypress')
|
||||
sinon.stub(state, 'getBinaryDir').returns('/.cache/Cypress')
|
||||
sinon.stub(util, 'pkgVersion').returns('1.2.3')
|
||||
this.stdout = stdout.capture()
|
||||
|
||||
stdoutCapture = stdout.capture()
|
||||
})
|
||||
|
||||
const getSnapshotText = () => {
|
||||
this.stdout = this.stdout.toString().split('\n').slice(0, -1).join('\n')
|
||||
const stdoutAsString = this.stdout.toString() || '[no output]'
|
||||
const output = stdoutCapture.toString().split('\n').slice(0, -1).join('\n')
|
||||
const stdoutAsString = output || '[no output]'
|
||||
|
||||
// first restore the STDOUT, then confirm the value
|
||||
// otherwise the error might not even appear or appear twice!
|
||||
@@ -51,7 +52,7 @@ describe('lib/tasks/cache', () => {
|
||||
return stdoutAsString
|
||||
}
|
||||
|
||||
const saveHtml = async (filename, html) => {
|
||||
const saveHtml = async (filename: string, html: string) => {
|
||||
await fs.ensureDirAsync(outputHtmlFolder)
|
||||
const htmlFilename = path.join(outputHtmlFolder, filename)
|
||||
|
||||
@@ -62,8 +63,9 @@ describe('lib/tasks/cache', () => {
|
||||
mockfs.restore()
|
||||
})
|
||||
|
||||
const defaultSnapshot = (snapshotName) => {
|
||||
const defaultSnapshot = (snapshotName?: string) => {
|
||||
const stdoutAsString = getSnapshotText()
|
||||
|
||||
const withoutAnsi = stripAnsi(stdoutAsString)
|
||||
|
||||
if (snapshotName) {
|
||||
@@ -73,7 +75,7 @@ describe('lib/tasks/cache', () => {
|
||||
}
|
||||
}
|
||||
|
||||
const snapshotWithHtml = async (htmlFilename) => {
|
||||
const snapshotWithHtml = async (htmlFilename: string) => {
|
||||
const stdoutAsString = getSnapshotText()
|
||||
|
||||
snapshot(stripAnsi(stdoutAsString))
|
||||
@@ -85,7 +87,7 @@ describe('lib/tasks/cache', () => {
|
||||
}
|
||||
|
||||
describe('.path', () => {
|
||||
let restoreEnv
|
||||
let restoreEnv: any
|
||||
|
||||
afterEach(() => {
|
||||
if (restoreEnv) {
|
||||
@@ -94,37 +96,37 @@ describe('lib/tasks/cache', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('lists path to cache', () => {
|
||||
it('lists path to cache', function () {
|
||||
cache.path()
|
||||
expect(this.stdout.toString()).to.eql('/.cache/Cypress\n')
|
||||
expect(stdoutCapture.toString()).to.eql('/.cache/Cypress\n')
|
||||
defaultSnapshot()
|
||||
})
|
||||
|
||||
it('lists path to cache with silent npm loglevel', () => {
|
||||
it('lists path to cache with silent npm loglevel', function () {
|
||||
restoreEnv = mockedEnv({
|
||||
npm_config_loglevel: 'silent',
|
||||
})
|
||||
|
||||
cache.path()
|
||||
expect(this.stdout.toString()).to.eql('/.cache/Cypress\n')
|
||||
expect(stdoutCapture.toString()).to.eql('/.cache/Cypress\n')
|
||||
})
|
||||
|
||||
it('lists path to cache with silent npm warn', () => {
|
||||
it('lists path to cache with silent npm warn', function () {
|
||||
restoreEnv = mockedEnv({
|
||||
npm_config_loglevel: 'warn',
|
||||
})
|
||||
|
||||
cache.path()
|
||||
expect(this.stdout.toString()).to.eql('/.cache/Cypress\n')
|
||||
expect(stdoutCapture.toString()).to.eql('/.cache/Cypress\n')
|
||||
})
|
||||
})
|
||||
|
||||
describe('.clear', () => {
|
||||
it('deletes cache folder and everything inside it', () => {
|
||||
it('deletes cache folder and everything inside it', function () {
|
||||
return cache.clear()
|
||||
.then(() => {
|
||||
return fs.pathExistsAsync('/.cache/Cypress')
|
||||
.then((exists) => {
|
||||
.then((exists: any) => {
|
||||
expect(exists).to.eql(false)
|
||||
defaultSnapshot()
|
||||
})
|
||||
@@ -133,7 +135,7 @@ describe('lib/tasks/cache', () => {
|
||||
})
|
||||
|
||||
describe('.prune', () => {
|
||||
it('deletes cache binaries for all version but the current one', async () => {
|
||||
it('deletes cache binaries for all version but the current one', async function () {
|
||||
await cache.prune()
|
||||
|
||||
const checkedInBinaryVersion = util.pkgVersion()
|
||||
@@ -142,17 +144,18 @@ describe('lib/tasks/cache', () => {
|
||||
|
||||
expect(files.length).to.eq(1)
|
||||
|
||||
files.forEach((file) => {
|
||||
files.forEach((file: any) => {
|
||||
expect(file).to.eq(checkedInBinaryVersion)
|
||||
})
|
||||
|
||||
defaultSnapshot()
|
||||
})
|
||||
|
||||
it('doesn\'t delete any cache binaries', async () => {
|
||||
it('doesn\'t delete any cache binaries', async function () {
|
||||
const dir = path.join(state.getCacheDir(), '2.3.4')
|
||||
|
||||
await fs.removeAsync(dir)
|
||||
|
||||
await cache.prune()
|
||||
|
||||
const checkedInBinaryVersion = util.pkgVersion()
|
||||
@@ -161,14 +164,14 @@ describe('lib/tasks/cache', () => {
|
||||
|
||||
expect(files.length).to.eq(1)
|
||||
|
||||
files.forEach((file) => {
|
||||
files.forEach((file: any) => {
|
||||
expect(file).to.eq(checkedInBinaryVersion)
|
||||
})
|
||||
|
||||
defaultSnapshot()
|
||||
})
|
||||
|
||||
it('exits cleanly if cache dir DNE', async () => {
|
||||
it('exits cleanly if cache dir DNE', async function () {
|
||||
await fs.removeAsync(state.getCacheDir())
|
||||
await cache.prune()
|
||||
|
||||
@@ -177,7 +180,7 @@ describe('lib/tasks/cache', () => {
|
||||
})
|
||||
|
||||
describe('.list', () => {
|
||||
let restoreEnv
|
||||
let restoreEnv: any
|
||||
|
||||
afterEach(() => {
|
||||
if (restoreEnv) {
|
||||
@@ -204,7 +207,6 @@ describe('lib/tasks/cache', () => {
|
||||
sinon.stub(state, 'getPathToExecutable').returns('/.cache/Cypress/1.2.3/app/cypress')
|
||||
|
||||
await cache.list()
|
||||
|
||||
// log output snapshot should have a grid of versions
|
||||
defaultSnapshot('cache list with silent log level')
|
||||
})
|
||||
@@ -4,22 +4,22 @@
|
||||
* or the root of their project. Currently, these two dependencies are 'buffer' and 'process'
|
||||
*/
|
||||
describe('dependencies', () => {
|
||||
it('process dependency exists in package.json and is available', () => {
|
||||
const { dependencies } = require('../../../package.json')
|
||||
it('process dependency exists in package.json and is available', async () => {
|
||||
const { dependencies } = (await import('../../../package.json')).default
|
||||
|
||||
expect(dependencies.process).to.be.ok
|
||||
|
||||
const process = require('process')
|
||||
const process = await import('process')
|
||||
|
||||
expect(typeof process).to.equal('object')
|
||||
})
|
||||
|
||||
it('buffer dependency exists in package.json and is available', () => {
|
||||
const { dependencies } = require('../../../package.json')
|
||||
it('buffer dependency exists in package.json and is available', async () => {
|
||||
const { dependencies } = (await import('../../../package.json')).default
|
||||
|
||||
expect(dependencies.buffer).to.be.ok
|
||||
|
||||
const buffer = require('buffer')
|
||||
const buffer = await import('buffer')
|
||||
|
||||
expect(typeof buffer).to.equal('object')
|
||||
})
|
||||
@@ -1,45 +1,48 @@
|
||||
require('../../spec_helper')
|
||||
import '../../spec_helper'
|
||||
import _ from 'lodash'
|
||||
import os from 'os'
|
||||
import cp from 'child_process'
|
||||
import la from 'lazy-ass'
|
||||
import is from 'check-more-types'
|
||||
import path from 'path'
|
||||
import nock from 'nock'
|
||||
import hasha from 'hasha'
|
||||
import createDebug from 'debug'
|
||||
import snapshot from '../../support/snapshot'
|
||||
import stdout from '../../support/stdout'
|
||||
import normalize from '../../support/normalize'
|
||||
import mockSpawnModule from '../../support/spawn-mock'
|
||||
import fs from '../../../lib/fs'
|
||||
import logger from '../../../lib/logger'
|
||||
import util from '../../../lib/util'
|
||||
import download from '../../../lib/tasks/download'
|
||||
|
||||
const _ = require('lodash')
|
||||
const os = require('os')
|
||||
const cp = require('child_process')
|
||||
const la = require('lazy-ass')
|
||||
const is = require('check-more-types')
|
||||
const path = require('path')
|
||||
const nock = require('nock')
|
||||
const hasha = require('hasha')
|
||||
const debug = require('debug')('test')
|
||||
const snapshot = require('../../support/snapshot')
|
||||
|
||||
const fs = require(`${lib}/fs`)
|
||||
const logger = require(`${lib}/logger`)
|
||||
const util = require(`${lib}/util`)
|
||||
const download = require(`${lib}/tasks/download`)
|
||||
|
||||
const stdout = require('../../support/stdout')
|
||||
const normalize = require('../../support/normalize')
|
||||
const { mockSpawn } = require('../../support/spawn-mock')
|
||||
const debug = createDebug('test')
|
||||
|
||||
const downloadDestination = path.join(os.tmpdir(), 'Cypress', 'download', 'cypress.zip')
|
||||
const version = '1.2.3'
|
||||
const examplePath = 'test/fixture/example.zip'
|
||||
|
||||
describe('lib/tasks/download', function () {
|
||||
require('mocha-banner').register()
|
||||
before(async function () {
|
||||
const mochaMain = await import('mocha-banner')
|
||||
|
||||
mochaMain.register()
|
||||
})
|
||||
|
||||
const rootFolder = '/home/user/git'
|
||||
|
||||
beforeEach(function () {
|
||||
logger.reset()
|
||||
|
||||
this.stdout = stdout.capture()
|
||||
;(this as any).stdout = stdout.capture()
|
||||
|
||||
this.options = {
|
||||
;(this as any).options = {
|
||||
downloadDestination,
|
||||
version,
|
||||
}
|
||||
|
||||
os.platform.returns('OS')
|
||||
;(os.platform as any).returns('OS')
|
||||
sinon.stub(util, 'pkgVersion').returns('1.2.3')
|
||||
sinon.stub(util, 'cwd').returns(rootFolder)
|
||||
})
|
||||
@@ -52,7 +55,7 @@ describe('lib/tasks/download', function () {
|
||||
it('returns url', () => {
|
||||
const url = download.getUrl('ARCH')
|
||||
|
||||
la(is.url(url), url)
|
||||
la((is as any).url(url), url)
|
||||
})
|
||||
|
||||
it('returns latest desktop url', () => {
|
||||
@@ -172,11 +175,11 @@ describe('lib/tasks/download', function () {
|
||||
const onProgress = sinon.stub().returns(undefined)
|
||||
|
||||
return download.start({
|
||||
downloadDestination: this.options.downloadDestination,
|
||||
version: this.options.version,
|
||||
downloadDestination: (this as any).options.downloadDestination,
|
||||
version: (this as any).options.version,
|
||||
progress: { onProgress },
|
||||
})
|
||||
.then((responseVersion) => {
|
||||
.then((responseVersion: any) => {
|
||||
expect(responseVersion).to.eq('0.11.1')
|
||||
|
||||
return fs.statAsync(downloadDestination)
|
||||
@@ -185,11 +188,13 @@ describe('lib/tasks/download', function () {
|
||||
|
||||
context('verify downloaded file', function () {
|
||||
before(function () {
|
||||
this.expectedChecksum = hasha.fromFileSync(examplePath)
|
||||
this.expectedFileSize = fs.statSync(examplePath).size
|
||||
this.onProgress = sinon.stub().returns(undefined)
|
||||
(this as any).expectedChecksum = hasha.fromFileSync(examplePath)
|
||||
|
||||
;(this as any).expectedFileSize = fs.statSync(examplePath).size
|
||||
|
||||
;(this as any).onProgress = sinon.stub().returns(undefined)
|
||||
debug('example file %s should have checksum %s and file size %d',
|
||||
examplePath, this.expectedChecksum, this.expectedFileSize)
|
||||
examplePath, (this as any).expectedChecksum, (this as any).expectedFileSize)
|
||||
})
|
||||
|
||||
it('throws if file size is different from expected', function () {
|
||||
@@ -204,9 +209,9 @@ describe('lib/tasks/download', function () {
|
||||
})
|
||||
|
||||
return expect(download.start({
|
||||
downloadDestination: this.options.downloadDestination,
|
||||
version: this.options.version,
|
||||
progress: { onProgress: this.onProgress },
|
||||
downloadDestination: (this as any).options.downloadDestination,
|
||||
version: (this as any).options.version,
|
||||
progress: { onProgress: (this as any).onProgress },
|
||||
})).to.be.rejected
|
||||
})
|
||||
|
||||
@@ -222,9 +227,9 @@ describe('lib/tasks/download', function () {
|
||||
})
|
||||
|
||||
return expect(download.start({
|
||||
downloadDestination: this.options.downloadDestination,
|
||||
version: this.options.version,
|
||||
progress: { onProgress: this.onProgress },
|
||||
downloadDestination: (this as any).options.downloadDestination,
|
||||
version: (this as any).options.version,
|
||||
progress: { onProgress: (this as any).onProgress },
|
||||
})).to.be.rejected
|
||||
})
|
||||
|
||||
@@ -239,9 +244,9 @@ describe('lib/tasks/download', function () {
|
||||
})
|
||||
|
||||
return expect(download.start({
|
||||
downloadDestination: this.options.downloadDestination,
|
||||
version: this.options.version,
|
||||
progress: { onProgress: this.onProgress },
|
||||
downloadDestination: (this as any).options.downloadDestination,
|
||||
version: (this as any).options.version,
|
||||
progress: { onProgress: (this as any).onProgress },
|
||||
})).to.be.rejected
|
||||
})
|
||||
|
||||
@@ -257,9 +262,9 @@ describe('lib/tasks/download', function () {
|
||||
})
|
||||
|
||||
return expect(download.start({
|
||||
downloadDestination: this.options.downloadDestination,
|
||||
version: this.options.version,
|
||||
progress: { onProgress: this.onProgress },
|
||||
downloadDestination: (this as any).options.downloadDestination,
|
||||
version: (this as any).options.version,
|
||||
progress: { onProgress: (this as any).onProgress },
|
||||
})).to.be.rejected
|
||||
})
|
||||
|
||||
@@ -272,17 +277,17 @@ describe('lib/tasks/download', function () {
|
||||
|
||||
return fs.createReadStream(examplePath)
|
||||
}, {
|
||||
'x-amz-meta-checksum': this.expectedChecksum,
|
||||
'x-amz-meta-size': String(this.expectedFileSize),
|
||||
'x-amz-meta-checksum': (this as any).expectedChecksum,
|
||||
'x-amz-meta-size': String((this as any).expectedFileSize),
|
||||
})
|
||||
|
||||
debug('downloading %s to %s for test version %s',
|
||||
examplePath, this.options.downloadDestination, this.options.version)
|
||||
examplePath, (this as any).options.downloadDestination, (this as any).options.version)
|
||||
|
||||
return download.start({
|
||||
downloadDestination: this.options.downloadDestination,
|
||||
version: this.options.version,
|
||||
progress: { onProgress: this.onProgress },
|
||||
downloadDestination: (this as any).options.downloadDestination,
|
||||
version: (this as any).options.version,
|
||||
progress: { onProgress: (this as any).onProgress },
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -302,7 +307,7 @@ describe('lib/tasks/download', function () {
|
||||
'x-version': '0.11.1',
|
||||
})
|
||||
|
||||
return download.start(this.options).then((responseVersion) => {
|
||||
return download.start((this as any).options).then((responseVersion: any) => {
|
||||
expect(responseVersion).to.eq('0.11.1')
|
||||
})
|
||||
})
|
||||
@@ -346,7 +351,7 @@ describe('lib/tasks/download', function () {
|
||||
'x-version': '0.11.1',
|
||||
})
|
||||
|
||||
return download.start(this.options).then((responseVersion) => {
|
||||
return download.start((this as any).options).then((responseVersion: any) => {
|
||||
expect(responseVersion).to.eq('0.11.4')
|
||||
})
|
||||
})
|
||||
@@ -450,7 +455,7 @@ describe('lib/tasks/download', function () {
|
||||
|
||||
stubRedirects()
|
||||
|
||||
await download.start(this.options).catch((error) => {
|
||||
await download.start((this as any).options).catch((error: any) => {
|
||||
expect(error).to.be.instanceof(Error)
|
||||
expect(error.message).to.contain('redirect loop')
|
||||
})
|
||||
@@ -458,13 +463,13 @@ describe('lib/tasks/download', function () {
|
||||
stubRedirects()
|
||||
|
||||
// Double check to make sure that raising redirectTTL changes result
|
||||
await download.start({ ...this.options, redirectTTL: 12 }).then((responseVersion) => {
|
||||
await download.start({ ...(this as any).options, redirectTTL: 12 }).then((responseVersion: any) => {
|
||||
expect(responseVersion).to.eq('0.11.11')
|
||||
})
|
||||
})
|
||||
|
||||
it('can specify cypress version in arguments', function () {
|
||||
this.options.version = '0.13.0'
|
||||
(this as any).options.version = '0.13.0'
|
||||
|
||||
nock('https://aws.amazon.com')
|
||||
.get('/some.zip')
|
||||
@@ -480,7 +485,7 @@ describe('lib/tasks/download', function () {
|
||||
'x-version': '0.13.0',
|
||||
})
|
||||
|
||||
return download.start(this.options).then((responseVersion) => {
|
||||
return download.start((this as any).options).then((responseVersion: any) => {
|
||||
expect(responseVersion).to.eq('0.13.0')
|
||||
|
||||
return fs.statAsync(downloadDestination)
|
||||
@@ -499,11 +504,12 @@ describe('lib/tasks/download', function () {
|
||||
}
|
||||
|
||||
it('downloads darwin-arm64 on M1', async function () {
|
||||
os.platform.returns('darwin')
|
||||
os.arch.returns('arm64')
|
||||
(os.platform as any).returns('darwin')
|
||||
|
||||
;(os.arch as any).returns('arm64')
|
||||
nockDarwinArm64()
|
||||
|
||||
const responseVersion = await download.start(this.options)
|
||||
const responseVersion = await download.start((this as any).options)
|
||||
|
||||
expect(responseVersion).to.eq('1.2.3')
|
||||
|
||||
@@ -511,18 +517,19 @@ describe('lib/tasks/download', function () {
|
||||
})
|
||||
|
||||
it('downloads darwin-arm64 on M1 translated by Rosetta', async function () {
|
||||
os.platform.returns('darwin')
|
||||
os.arch.returns('x64')
|
||||
(os.platform as any).returns('darwin')
|
||||
|
||||
;(os.arch as any).returns('x64')
|
||||
nockDarwinArm64()
|
||||
|
||||
sinon.stub(cp, 'spawn').withArgs('sysctl', ['-n', 'sysctl.proc_translated'])
|
||||
.callsFake(mockSpawn(((cp) => {
|
||||
.callsFake(mockSpawnModule.mockSpawn(((cp: any) => {
|
||||
cp.stdout.write('1')
|
||||
cp.emit('exit', 0, null)
|
||||
cp.end()
|
||||
})))
|
||||
|
||||
const responseVersion = await download.start(this.options)
|
||||
const responseVersion = await download.start((this as any).options)
|
||||
|
||||
expect(responseVersion).to.eq('1.2.3')
|
||||
|
||||
@@ -541,11 +548,12 @@ describe('lib/tasks/download', function () {
|
||||
}
|
||||
|
||||
it('downloads linux-arm64 on arm64 processor', async function () {
|
||||
os.platform.returns('linux')
|
||||
os.arch.returns('arm64')
|
||||
(os.platform as any).returns('linux')
|
||||
|
||||
;(os.arch as any).returns('arm64')
|
||||
nockLinuxArm64()
|
||||
|
||||
const responseVersion = await download.start(this.options)
|
||||
const responseVersion = await download.start((this as any).options)
|
||||
|
||||
expect(responseVersion).to.eq('1.2.3')
|
||||
|
||||
@@ -553,20 +561,22 @@ describe('lib/tasks/download', function () {
|
||||
})
|
||||
|
||||
it('downloads linux-arm64 on non-arm64 node running on arm machine', async function () {
|
||||
os.platform.returns('linux')
|
||||
os.arch.returns('x64')
|
||||
(os.platform as any).returns('linux')
|
||||
|
||||
;(os.arch as any).returns('x64')
|
||||
sinon.stub(cp, 'spawn')
|
||||
|
||||
for (const arch of ['aarch64_be', 'aarch64', 'armv8b', 'armv8l']) {
|
||||
nockLinuxArm64()
|
||||
cp.spawn.withArgs('uname', ['-m'])
|
||||
.callsFake(mockSpawn(((cp) => {
|
||||
|
||||
;(cp.spawn as any).withArgs('uname', ['-m'])
|
||||
.callsFake(mockSpawnModule.mockSpawn(((cp: any) => {
|
||||
cp.stdout.write(arch)
|
||||
cp.emit('exit', 0, null)
|
||||
cp.end()
|
||||
})))
|
||||
|
||||
const responseVersion = await download.start(this.options)
|
||||
const responseVersion = await download.start((this as any).options)
|
||||
|
||||
expect(responseVersion).to.eq('1.2.3')
|
||||
|
||||
@@ -579,25 +589,26 @@ describe('lib/tasks/download', function () {
|
||||
it('catches download status errors and exits', function () {
|
||||
const ctx = this
|
||||
|
||||
const err = new Error()
|
||||
const err: any = new Error()
|
||||
|
||||
err.statusCode = 404
|
||||
err.statusMessage = 'Not Found'
|
||||
this.options.version = null
|
||||
|
||||
;(this as any).options.version = null
|
||||
|
||||
// not really the download error, but the easiest way to
|
||||
// test the error handling
|
||||
sinon.stub(fs, 'ensureDirAsync').rejects(err)
|
||||
|
||||
return download
|
||||
.start(this.options)
|
||||
.start((this as any).options)
|
||||
.then(() => {
|
||||
throw new Error('should have caught')
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
logger.error(err)
|
||||
|
||||
return snapshot('download status errors 1', normalize(ctx.stdout.toString()))
|
||||
return snapshot('download status errors 1', normalize((ctx as any).stdout.toString()))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -606,7 +617,7 @@ describe('lib/tasks/download', function () {
|
||||
const testUriHttps = 'https://anything.com'
|
||||
|
||||
beforeEach(function () {
|
||||
this.env = _.clone(process.env)
|
||||
(this as any).env = _.clone(process.env)
|
||||
// prevent ambient environment masking of environment variables referenced in this test
|
||||
|
||||
;([
|
||||
@@ -623,7 +634,7 @@ describe('lib/tasks/download', function () {
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
process.env = this.env
|
||||
process.env = (this as any).env
|
||||
})
|
||||
|
||||
it('uses http_proxy on http request', () => {
|
||||
@@ -672,15 +683,15 @@ describe('lib/tasks/download', function () {
|
||||
|
||||
context('with CA and CAFILE env vars', () => {
|
||||
beforeEach(function () {
|
||||
this.env = _.clone(process.env)
|
||||
(this as any).env = _.clone(process.env)
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
process.env = this.env
|
||||
process.env = (this as any).env
|
||||
})
|
||||
|
||||
it('returns undefined if not set', () => {
|
||||
return download.getCA().then((ca) => {
|
||||
return download.getCA().then((ca: any) => {
|
||||
expect(ca).to.be.undefined
|
||||
})
|
||||
})
|
||||
@@ -688,7 +699,7 @@ describe('lib/tasks/download', function () {
|
||||
it('returns CA from npm_config_ca', () => {
|
||||
process.env.npm_config_ca = 'foo'
|
||||
|
||||
return download.getCA().then((ca) => {
|
||||
return download.getCA().then((ca: any) => {
|
||||
expect(ca).to.eqls('foo')
|
||||
})
|
||||
})
|
||||
@@ -696,7 +707,7 @@ describe('lib/tasks/download', function () {
|
||||
it('returns CA from npm_config_cafile', () => {
|
||||
process.env.npm_config_cafile = 'test/fixture/cafile.pem'
|
||||
|
||||
return download.getCA().then((ca) => {
|
||||
return download.getCA().then((ca: any) => {
|
||||
expect(ca).to.eqls('bar\n')
|
||||
})
|
||||
})
|
||||
@@ -704,7 +715,7 @@ describe('lib/tasks/download', function () {
|
||||
it('returns undefined if failed reading npm_config_cafile', () => {
|
||||
process.env.npm_config_cafile = 'test/fixture/not-exists.pem'
|
||||
|
||||
return download.getCA().then((ca) => {
|
||||
return download.getCA().then((ca: any) => {
|
||||
expect(ca).to.be.undefined
|
||||
})
|
||||
})
|
||||
@@ -1,32 +1,33 @@
|
||||
require('../../spec_helper')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const chalk = require('chalk')
|
||||
const Promise = require('bluebird')
|
||||
const mockfs = require('mock-fs')
|
||||
const snapshot = require('../../support/snapshot')
|
||||
|
||||
const stdout = require('../../support/stdout')
|
||||
|
||||
const fs = require(`${lib}/fs`)
|
||||
const download = require(`${lib}/tasks/download`)
|
||||
const install = require(`${lib}/tasks/install`)
|
||||
const state = require(`${lib}/tasks/state`)
|
||||
const unzip = require(`${lib}/tasks/unzip`)
|
||||
const logger = require(`${lib}/logger`)
|
||||
const util = require(`${lib}/util`)
|
||||
|
||||
const normalize = require('../../support/normalize')
|
||||
import '../../spec_helper'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import chalk from 'chalk'
|
||||
import BluebirdPromise from 'bluebird'
|
||||
import mockfs from 'mock-fs'
|
||||
import snapshot from '../../support/snapshot'
|
||||
import stdout from '../../support/stdout'
|
||||
import normalize from '../../support/normalize'
|
||||
import fs from '../../../lib/fs'
|
||||
import logger from '../../../lib/logger'
|
||||
import util from '../../../lib/util'
|
||||
import download from '../../../lib/tasks/download'
|
||||
import unzip from '../../../lib/tasks/unzip'
|
||||
import install from '../../../lib/tasks/install'
|
||||
import state from '../../../lib/tasks/state'
|
||||
|
||||
const packageVersion = '1.2.3'
|
||||
const downloadDestination = path.join(os.tmpdir(), `cypress-${process.pid}.zip`)
|
||||
const installDir = '/cache/Cypress/1.2.3'
|
||||
|
||||
describe('/lib/tasks/install', function () {
|
||||
require('mocha-banner').register()
|
||||
before(async function () {
|
||||
const mochaMain = await import('mocha-banner')
|
||||
|
||||
mochaMain.register()
|
||||
})
|
||||
|
||||
beforeEach(function () {
|
||||
this.stdout = stdout.capture()
|
||||
(this as any).stdout = stdout.capture()
|
||||
|
||||
// allow simpler log message comparison without
|
||||
// chalk's terminal control strings
|
||||
@@ -48,13 +49,14 @@ describe('/lib/tasks/install', function () {
|
||||
sinon.stub(util, 'pkgVersion').returns(packageVersion)
|
||||
sinon.stub(download, 'start').resolves(packageVersion)
|
||||
sinon.stub(unzip, 'start').resolves()
|
||||
sinon.stub(Promise, 'delay').resolves()
|
||||
sinon.stub(BluebirdPromise, 'delay').resolves()
|
||||
sinon.stub(fs, 'removeAsync').resolves()
|
||||
sinon.stub(state, 'getVersionDir').returns('/cache/Cypress/1.2.3')
|
||||
sinon.stub(state, 'getBinaryDir').returns('/cache/Cypress/1.2.3/Cypress.app')
|
||||
sinon.stub(state, 'getBinaryPkgAsync').resolves()
|
||||
sinon.stub(fs, 'ensureDirAsync').resolves(undefined)
|
||||
os.platform.returns('darwin')
|
||||
|
||||
;(os.platform as any).returns('darwin')
|
||||
})
|
||||
|
||||
describe('skips install', function () {
|
||||
@@ -67,7 +69,7 @@ describe('/lib/tasks/install', function () {
|
||||
|
||||
snapshot(
|
||||
'skip installation 1',
|
||||
normalize(this.stdout.toString()),
|
||||
normalize((this as any).stdout.toString()),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -95,11 +97,11 @@ describe('/lib/tasks/install', function () {
|
||||
|
||||
it('logs a warning about installing a pre-release', async function () {
|
||||
await runInstall()
|
||||
snapshot(normalize(this.stdout.toString()))
|
||||
snapshot(normalize((this as any).stdout.toString()))
|
||||
})
|
||||
|
||||
it('installs to the expected pre-release cache dir', async function () {
|
||||
state.getVersionDir.restore()
|
||||
(state.getVersionDir as any).restore()
|
||||
await runInstall()
|
||||
expect(unzip.start).to.be.calledWithMatch({ installDir: sinon.match(/\/Cypress\/beta\-1\.2\.3\-aBranchName\-3b7f0b5c$/) })
|
||||
})
|
||||
@@ -123,7 +125,7 @@ describe('/lib/tasks/install', function () {
|
||||
|
||||
snapshot(
|
||||
'specify version in env vars 1',
|
||||
normalize(this.stdout.toString()),
|
||||
normalize((this as any).stdout.toString()),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -210,7 +212,7 @@ describe('/lib/tasks/install', function () {
|
||||
|
||||
describe('when version is already installed', function () {
|
||||
beforeEach(function () {
|
||||
state.getBinaryPkgAsync.resolves({ version: packageVersion })
|
||||
(state.getBinaryPkgAsync as any).resolves({ version: packageVersion })
|
||||
})
|
||||
|
||||
it('doesn\'t attempt to download', function () {
|
||||
@@ -226,19 +228,19 @@ describe('/lib/tasks/install', function () {
|
||||
.then(() => {
|
||||
return snapshot(
|
||||
'version already installed - cypress install 1',
|
||||
normalize(this.stdout.toString()),
|
||||
normalize((this as any).stdout.toString()),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('logs when already installed when run from postInstall', function () {
|
||||
util.isPostInstall.returns(true)
|
||||
(util.isPostInstall as any).returns(true)
|
||||
|
||||
return install.start()
|
||||
.then(() => {
|
||||
snapshot(
|
||||
'version already installed - postInstall 1',
|
||||
normalize(this.stdout.toString()),
|
||||
normalize((this as any).stdout.toString()),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -246,7 +248,7 @@ describe('/lib/tasks/install', function () {
|
||||
|
||||
describe('when getting installed version fails', function () {
|
||||
beforeEach(function () {
|
||||
state.getBinaryPkgAsync.resolves(null)
|
||||
(state.getBinaryPkgAsync as any).resolves(null)
|
||||
|
||||
return install.start()
|
||||
})
|
||||
@@ -262,14 +264,14 @@ describe('/lib/tasks/install', function () {
|
||||
|
||||
snapshot(
|
||||
'continues installing on failure 1',
|
||||
normalize(this.stdout.toString()),
|
||||
normalize((this as any).stdout.toString()),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there is no install version', function () {
|
||||
beforeEach(function () {
|
||||
state.getBinaryPkgAsync.resolves(null)
|
||||
(state.getBinaryPkgAsync as any).resolves(null)
|
||||
|
||||
return install.start()
|
||||
})
|
||||
@@ -290,14 +292,14 @@ describe('/lib/tasks/install', function () {
|
||||
|
||||
snapshot(
|
||||
'installs without existing installation 1',
|
||||
normalize(this.stdout.toString()),
|
||||
normalize((this as any).stdout.toString()),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when getting installed version does not match needed version', function () {
|
||||
beforeEach(function () {
|
||||
state.getBinaryPkgAsync.resolves({ version: 'x.x.x' })
|
||||
(state.getBinaryPkgAsync as any).resolves({ version: 'x.x.x' })
|
||||
|
||||
return install.start()
|
||||
})
|
||||
@@ -313,14 +315,14 @@ describe('/lib/tasks/install', function () {
|
||||
|
||||
snapshot(
|
||||
'installed version does not match needed version 1',
|
||||
normalize(this.stdout.toString()),
|
||||
normalize((this as any).stdout.toString()),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('with force: true', function () {
|
||||
beforeEach(function () {
|
||||
state.getBinaryPkgAsync.resolves({ version: packageVersion })
|
||||
(state.getBinaryPkgAsync as any).resolves({ version: packageVersion })
|
||||
|
||||
return install.start({ force: true })
|
||||
})
|
||||
@@ -336,7 +338,7 @@ describe('/lib/tasks/install', function () {
|
||||
|
||||
snapshot(
|
||||
'forcing true always installs 1',
|
||||
normalize(this.stdout.toString()),
|
||||
normalize((this as any).stdout.toString()),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -345,7 +347,7 @@ describe('/lib/tasks/install', function () {
|
||||
beforeEach(function () {
|
||||
sinon.stub(util, 'isInstalledGlobally').returns(true)
|
||||
|
||||
state.getBinaryPkgAsync.resolves({ version: 'x.x.x' })
|
||||
;(state.getBinaryPkgAsync as any).resolves({ version: 'x.x.x' })
|
||||
|
||||
return install.start()
|
||||
})
|
||||
@@ -361,16 +363,16 @@ describe('/lib/tasks/install', function () {
|
||||
|
||||
snapshot(
|
||||
'warning installing as global 1',
|
||||
normalize(this.stdout.toString()),
|
||||
normalize((this as any).stdout.toString()),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when running in CI', function () {
|
||||
beforeEach(function () {
|
||||
util.isCi.returns(true)
|
||||
(util.isCi as any).returns(true)
|
||||
|
||||
state.getBinaryPkgAsync.resolves({ version: 'x.x.x' })
|
||||
;(state.getBinaryPkgAsync as any).resolves({ version: 'x.x.x' })
|
||||
|
||||
return install.start()
|
||||
})
|
||||
@@ -378,31 +380,32 @@ describe('/lib/tasks/install', function () {
|
||||
it('uses verbose renderer', function () {
|
||||
snapshot(
|
||||
'installing in ci 1',
|
||||
normalize(this.stdout.toString()),
|
||||
normalize((this as any).stdout.toString()),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('failed write access to cache directory', function () {
|
||||
it('logs error on failure', function () {
|
||||
os.platform.returns('darwin')
|
||||
(os.platform as any).returns('darwin')
|
||||
sinon.stub(state, 'getCacheDir').returns('/invalid/cache/dir')
|
||||
|
||||
const err = new Error('EACCES: permission denied, mkdir \'/invalid\'')
|
||||
const err: any = new Error('EACCES: permission denied, mkdir \'/invalid\'')
|
||||
|
||||
err.code = 'EACCES'
|
||||
fs.ensureDirAsync.rejects(err)
|
||||
|
||||
;(fs.ensureDirAsync as any).rejects(err)
|
||||
|
||||
return install.start()
|
||||
.then(() => {
|
||||
throw new Error('should have caught error')
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
logger.error(err)
|
||||
|
||||
snapshot(
|
||||
'invalid cache directory 1',
|
||||
normalize(this.stdout.toString()),
|
||||
normalize((this as any).stdout.toString()),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -410,8 +413,9 @@ describe('/lib/tasks/install', function () {
|
||||
|
||||
describe('CYPRESS_INSTALL_BINARY is URL or Zip', function () {
|
||||
it('uses cache when correct version installed given URL', function () {
|
||||
state.getBinaryPkgAsync.resolves({ version: '1.2.3' })
|
||||
util.pkgVersion.returns('1.2.3')
|
||||
(state.getBinaryPkgAsync as any).resolves({ version: '1.2.3' })
|
||||
|
||||
;(util.pkgVersion as any).returns('1.2.3')
|
||||
process.env.CYPRESS_INSTALL_BINARY = 'www.cypress.io/cannot-download/2.4.5'
|
||||
|
||||
return install.start()
|
||||
@@ -421,8 +425,9 @@ describe('/lib/tasks/install', function () {
|
||||
})
|
||||
|
||||
it('uses cache when mismatch version given URL ', function () {
|
||||
state.getBinaryPkgAsync.resolves({ version: '1.2.3' })
|
||||
util.pkgVersion.returns('4.0.0')
|
||||
(state.getBinaryPkgAsync as any).resolves({ version: '1.2.3' })
|
||||
|
||||
;(util.pkgVersion as any).returns('4.0.0')
|
||||
process.env.CYPRESS_INSTALL_BINARY = 'www.cypress.io/cannot-download/2.4.5'
|
||||
|
||||
return install.start()
|
||||
@@ -434,8 +439,9 @@ describe('/lib/tasks/install', function () {
|
||||
it('uses cache when correct version installed given Zip', function () {
|
||||
sinon.stub(fs, 'pathExistsAsync').withArgs('/path/to/zip.zip').resolves(true)
|
||||
|
||||
state.getBinaryPkgAsync.resolves({ version: '1.2.3' })
|
||||
util.pkgVersion.returns('1.2.3')
|
||||
;(state.getBinaryPkgAsync as any).resolves({ version: '1.2.3' })
|
||||
|
||||
;(util.pkgVersion as any).returns('1.2.3')
|
||||
|
||||
process.env.CYPRESS_INSTALL_BINARY = '/path/to/zip.zip'
|
||||
|
||||
@@ -448,8 +454,9 @@ describe('/lib/tasks/install', function () {
|
||||
it('uses cache when mismatch version given Zip ', function () {
|
||||
sinon.stub(fs, 'pathExistsAsync').withArgs('/path/to/zip.zip').resolves(true)
|
||||
|
||||
state.getBinaryPkgAsync.resolves({ version: '1.2.3' })
|
||||
util.pkgVersion.returns('4.0.0')
|
||||
;(state.getBinaryPkgAsync as any).resolves({ version: '1.2.3' })
|
||||
|
||||
;(util.pkgVersion as any).returns('4.0.0')
|
||||
process.env.CYPRESS_INSTALL_BINARY = '/path/to/zip.zip'
|
||||
|
||||
return install.start()
|
||||
@@ -467,7 +474,7 @@ describe('/lib/tasks/install', function () {
|
||||
.then(() => {
|
||||
return snapshot(
|
||||
'silent install 1',
|
||||
normalize(`[no output]${this.stdout.toString()}`),
|
||||
normalize(`[no output]${(this as any).stdout.toString()}`),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -479,12 +486,12 @@ describe('/lib/tasks/install', function () {
|
||||
.then(() => {
|
||||
throw new Error('should have caught error')
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
logger.error(err)
|
||||
|
||||
snapshot(
|
||||
'error when installing on unsupported os',
|
||||
normalize(this.stdout.toString()),
|
||||
normalize((this as any).stdout.toString()),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -497,14 +504,14 @@ describe('/lib/tasks/install', function () {
|
||||
}
|
||||
|
||||
it('generates the expected URL', () => {
|
||||
os.platform.returns('linux')
|
||||
(os.platform as any).returns('linux')
|
||||
|
||||
expect(install._getBinaryUrlFromBuildInfo('x64', buildInfo))
|
||||
.to.eq(`https://cdn.cypress.io/beta/binary/0.0.0-development/linux-x64/aBranchName-abc123/cypress.zip`)
|
||||
})
|
||||
|
||||
it('overrides win32-arm64 to win32-x64 for pre-release', () => {
|
||||
os.platform.returns('win32')
|
||||
(os.platform as any).returns('win32')
|
||||
|
||||
expect(install._getBinaryUrlFromBuildInfo('arm64', buildInfo))
|
||||
.to.eq(`https://cdn.cypress.io/beta/binary/0.0.0-development/win32-x64/aBranchName-abc123/cypress.zip`)
|
||||
@@ -1,17 +1,16 @@
|
||||
require('../../spec_helper')
|
||||
import '../../spec_helper'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import BluebirdPromise from 'bluebird'
|
||||
import mockfs from 'mock-fs'
|
||||
import { expect } from 'chai'
|
||||
import createDebug from 'debug'
|
||||
import fs from '../../../lib/fs'
|
||||
import logger from '../../../lib/logger'
|
||||
import util from '../../../lib/util'
|
||||
import state from '../../../lib/tasks/state'
|
||||
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const Promise = require('bluebird')
|
||||
const proxyquire = require('proxyquire')
|
||||
const mockfs = require('mock-fs')
|
||||
const { expect } = require('chai')
|
||||
const debug = require('debug')('test')
|
||||
|
||||
const fs = require(`${lib}/fs`)
|
||||
const logger = require(`${lib}/logger`)
|
||||
const util = require(`${lib}/util`)
|
||||
const state = require(`${lib}/tasks/state`)
|
||||
const debug = createDebug('test')
|
||||
|
||||
const cacheDir = path.join('.cache/Cypress')
|
||||
const versionDir = path.join(cacheDir, '1.2.3')
|
||||
@@ -30,7 +29,8 @@ describe('lib/tasks/state', function () {
|
||||
logger.reset()
|
||||
sinon.stub(process, 'exit')
|
||||
sinon.stub(util, 'pkgVersion').returns('1.2.3')
|
||||
os.platform.returns('darwin')
|
||||
|
||||
;(os.platform as any).returns('darwin')
|
||||
})
|
||||
|
||||
context('.getBinaryPkgVersion', function () {
|
||||
@@ -55,7 +55,7 @@ describe('lib/tasks/state', function () {
|
||||
.withArgs(binaryPkgPath)
|
||||
.resolves({ version: '2.0.48' })
|
||||
|
||||
return state.getBinaryPkgAsync(binaryDir).then((result) => {
|
||||
return state.getBinaryPkgAsync(binaryDir).then((result: any) => {
|
||||
expect(result).to.deep.equal({ version: '2.0.48' })
|
||||
})
|
||||
})
|
||||
@@ -65,7 +65,7 @@ describe('lib/tasks/state', function () {
|
||||
|
||||
return state
|
||||
.getBinaryPkgAsync(binaryDir)
|
||||
.then((result) => {
|
||||
.then((result: any) => {
|
||||
return expect(result).to.equal(null)
|
||||
})
|
||||
})
|
||||
@@ -87,7 +87,7 @@ describe('lib/tasks/state', function () {
|
||||
|
||||
return state
|
||||
.getBinaryPkgAsync(customBinaryDir)
|
||||
.then((result) => {
|
||||
.then((result: any) => {
|
||||
return expect(result).to.deep.equal({ version: '3.4.5' })
|
||||
})
|
||||
})
|
||||
@@ -104,7 +104,7 @@ describe('lib/tasks/state', function () {
|
||||
})
|
||||
|
||||
it('resolves path on linux', function () {
|
||||
os.platform.returns('linux')
|
||||
(os.platform as any).returns('linux')
|
||||
const linuxExecutable = '.cache/Cypress/1.2.3/Cypress/Cypress'
|
||||
|
||||
expect(state.getPathToExecutable(state.getBinaryDir())).to.equal(
|
||||
@@ -113,8 +113,8 @@ describe('lib/tasks/state', function () {
|
||||
})
|
||||
|
||||
it('resolves path on windows', function () {
|
||||
os.platform.returns('win32')
|
||||
expect(state.getPathToExecutable(state.getBinaryDir())).to.endWith('.exe')
|
||||
(os.platform as any).returns('win32')
|
||||
expect(state.getPathToExecutable(state.getBinaryDir())).to.match(/\.exe$/)
|
||||
})
|
||||
|
||||
it('resolves from custom binaryDir', function () {
|
||||
@@ -134,15 +134,16 @@ describe('lib/tasks/state', function () {
|
||||
})
|
||||
|
||||
it('resolves path on linux', function () {
|
||||
os.platform.returns('linux')
|
||||
(os.platform as any).returns('linux')
|
||||
expect(state.getBinaryDir()).to.equal(path.join(versionDir, 'Cypress'))
|
||||
})
|
||||
|
||||
it('resolves path on windows', function () {
|
||||
const state = proxyquire(`${lib}/tasks/state`, { path: path.win32 })
|
||||
it('resolves path on windows', async function () {
|
||||
const proxyquire = await import('proxyquire')
|
||||
const stateWithWin32Path = proxyquire.default(`../../../lib/tasks/state`, { path: path.win32 }).default
|
||||
|
||||
os.platform.returns('win32')
|
||||
const pathToExec = state.getBinaryDir()
|
||||
;(os.platform as any).returns('win32')
|
||||
const pathToExec = stateWithWin32Path.getBinaryDir()
|
||||
|
||||
expect(pathToExec).to.be.equal(path.win32.join(versionDir, 'Cypress'))
|
||||
})
|
||||
@@ -158,7 +159,7 @@ describe('lib/tasks/state', function () {
|
||||
})
|
||||
|
||||
it('rejects on anything else', function () {
|
||||
os.platform.returns('unknown')
|
||||
(os.platform as any).returns('unknown')
|
||||
expect(() => {
|
||||
return state.getBinaryDir().to.throw('Platform: "unknown" is not supported.')
|
||||
})
|
||||
@@ -171,20 +172,20 @@ describe('lib/tasks/state', function () {
|
||||
|
||||
return state
|
||||
.getBinaryVerifiedAsync('/asdf')
|
||||
.then((isVerified) => {
|
||||
.then((isVerified: any) => {
|
||||
return expect(isVerified).to.be.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
it('resolves undefined if not verified', function () {
|
||||
const err = new Error()
|
||||
const err: any = new Error()
|
||||
|
||||
err.code = 'ENOENT'
|
||||
sinon.stub(fs, 'readJsonAsync').rejects(err)
|
||||
|
||||
return state
|
||||
.getBinaryVerifiedAsync('/asdf')
|
||||
.then((isVerified) => {
|
||||
.then((isVerified: any) => {
|
||||
return expect(isVerified).to.be.equal(undefined)
|
||||
})
|
||||
})
|
||||
@@ -206,7 +207,7 @@ describe('lib/tasks/state', function () {
|
||||
|
||||
return state
|
||||
.getBinaryVerifiedAsync(customBinaryDir)
|
||||
.then((isVerified) => {
|
||||
.then((isVerified: any) => {
|
||||
return expect(isVerified).to.be.equal(true)
|
||||
})
|
||||
})
|
||||
@@ -311,69 +312,69 @@ describe('lib/tasks/state', function () {
|
||||
|
||||
context('.parseRealPlatformBinaryFolderAsync', function () {
|
||||
beforeEach(function () {
|
||||
sinon.stub(fs, 'realpathAsync').callsFake((path) => {
|
||||
return Promise.resolve(path)
|
||||
sinon.stub(fs, 'realpathAsync').callsFake((path: any) => {
|
||||
return BluebirdPromise.resolve(path)
|
||||
})
|
||||
})
|
||||
|
||||
it('can parse on darwin', function () {
|
||||
os.platform.returns('darwin')
|
||||
(os.platform as any).returns('darwin')
|
||||
|
||||
return state
|
||||
.parseRealPlatformBinaryFolderAsync(
|
||||
'/Documents/Cypress.app/Contents/MacOS/Cypress',
|
||||
)
|
||||
.then((path) => {
|
||||
.then((path: any) => {
|
||||
return expect(path).to.eql('/Documents/Cypress.app')
|
||||
})
|
||||
})
|
||||
|
||||
it('can parse on linux', function () {
|
||||
os.platform.returns('linux')
|
||||
(os.platform as any).returns('linux')
|
||||
|
||||
return state
|
||||
.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress')
|
||||
.then((path) => {
|
||||
.then((path: any) => {
|
||||
return expect(path).to.eql('/Documents/Cypress')
|
||||
})
|
||||
})
|
||||
|
||||
it('can parse on darwin', function () {
|
||||
os.platform.returns('win32')
|
||||
(os.platform as any).returns('win32')
|
||||
|
||||
return state
|
||||
.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress.exe')
|
||||
.then((path) => {
|
||||
.then((path: any) => {
|
||||
return expect(path).to.eql('/Documents/Cypress')
|
||||
})
|
||||
})
|
||||
|
||||
it('throws when invalid on darwin', function () {
|
||||
os.platform.returns('darwin')
|
||||
(os.platform as any).returns('darwin')
|
||||
|
||||
return state
|
||||
.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress.exe')
|
||||
.then((path) => {
|
||||
.then((path: any) => {
|
||||
return expect(path).to.eql(false)
|
||||
})
|
||||
})
|
||||
|
||||
it('throws when invalid on linux', function () {
|
||||
os.platform.returns('linux')
|
||||
(os.platform as any).returns('linux')
|
||||
|
||||
return state
|
||||
.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress.exe')
|
||||
.then((path) => {
|
||||
.then((path: any) => {
|
||||
return expect(path).to.eql(false)
|
||||
})
|
||||
})
|
||||
|
||||
it('throws when invalid on windows', function () {
|
||||
os.platform.returns('win32')
|
||||
(os.platform as any).returns('win32')
|
||||
|
||||
return state
|
||||
.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress')
|
||||
.then((path) => {
|
||||
.then((path: any) => {
|
||||
return expect(path).to.eql(false)
|
||||
})
|
||||
})
|
||||
@@ -1,30 +1,34 @@
|
||||
require('../../spec_helper')
|
||||
import '../../spec_helper'
|
||||
import events from 'events'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import snapshot from '../../support/snapshot'
|
||||
import cp from 'child_process'
|
||||
import createDebug from 'debug'
|
||||
import readline from 'readline'
|
||||
import stdout from '../../support/stdout'
|
||||
import normalize from '../../support/normalize'
|
||||
import fs from '../../../lib/fs'
|
||||
import logger from '../../../lib/logger'
|
||||
import util from '../../../lib/util'
|
||||
import unzip from '../../../lib/tasks/unzip'
|
||||
|
||||
const events = require('events')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const snapshot = require('../../support/snapshot')
|
||||
const cp = require('child_process')
|
||||
const debug = require('debug')('test')
|
||||
const readline = require('readline')
|
||||
|
||||
const fs = require(`${lib}/fs`)
|
||||
const util = require(`${lib}/util`)
|
||||
const logger = require(`${lib}/logger`)
|
||||
const unzip = require(`${lib}/tasks/unzip`)
|
||||
|
||||
const stdout = require('../../support/stdout')
|
||||
const normalize = require('../../support/normalize')
|
||||
const debug = createDebug('test')
|
||||
|
||||
const version = '1.2.3'
|
||||
const installDir = path.join(os.tmpdir(), 'Cypress', version)
|
||||
|
||||
describe('lib/tasks/unzip', function () {
|
||||
require('mocha-banner').register()
|
||||
beforeEach(function () {
|
||||
this.stdout = stdout.capture()
|
||||
before(async function () {
|
||||
const mochaMain = await import('mocha-banner')
|
||||
|
||||
os.platform.returns('darwin')
|
||||
mochaMain.register()
|
||||
})
|
||||
|
||||
beforeEach(function () {
|
||||
(this as any).stdout = stdout.capture()
|
||||
|
||||
;(os.platform as any).returns('darwin')
|
||||
sinon.stub(util, 'pkgVersion').returns(version)
|
||||
})
|
||||
|
||||
@@ -41,19 +45,19 @@ describe('lib/tasks/unzip', function () {
|
||||
} catch (err) {
|
||||
logger.error(err)
|
||||
|
||||
return snapshot(normalize(this.stdout.toString()))
|
||||
return snapshot(normalize((this as any).stdout.toString()))
|
||||
}
|
||||
|
||||
throw new Error('should have failed')
|
||||
})
|
||||
|
||||
it('throws max path length error when cannot unzip due to realpath ENOENT on windows', async function () {
|
||||
const err = new Error('failed')
|
||||
const err: any = new Error('failed')
|
||||
|
||||
err.code = 'ENOENT'
|
||||
err.syscall = 'realpath'
|
||||
|
||||
os.platform.returns('win32')
|
||||
;(os.platform as any).returns('win32')
|
||||
sinon.stub(fs, 'ensureDirAsync').rejects(err)
|
||||
|
||||
try {
|
||||
@@ -64,7 +68,7 @@ describe('lib/tasks/unzip', function () {
|
||||
} catch (err) {
|
||||
logger.error(err)
|
||||
|
||||
return snapshot(normalize(this.stdout.toString()))
|
||||
return snapshot(normalize((this as any).stdout.toString()))
|
||||
}
|
||||
|
||||
throw new Error('should have failed')
|
||||
@@ -88,30 +92,31 @@ describe('lib/tasks/unzip', function () {
|
||||
|
||||
context('on linux', () => {
|
||||
beforeEach(() => {
|
||||
os.platform.returns('linux')
|
||||
(os.platform as any).returns('linux')
|
||||
})
|
||||
|
||||
it('can try unzip first then fall back to node unzip', function (done) {
|
||||
const zipFilePath = path.join('test', 'fixture', 'example.zip')
|
||||
|
||||
sinon.stub(unzip.utils.unzipTools, 'extract').callsFake((filePath, opts) => {
|
||||
sinon.stub(unzip.utils.unzipTools, 'extract').callsFake((filePath: any, opts: any) => {
|
||||
debug('unzip extract called with %s', filePath)
|
||||
expect(filePath, 'zipfile is the same').to.equal(zipFilePath)
|
||||
|
||||
return new Promise((resolve) => resolve())
|
||||
return new Promise((resolve, reject) => resolve(undefined))
|
||||
})
|
||||
|
||||
const unzipChildProcess = new events.EventEmitter()
|
||||
|
||||
unzipChildProcess.stdout = {
|
||||
;(unzipChildProcess as any).stdout = {
|
||||
on () {},
|
||||
}
|
||||
|
||||
unzipChildProcess.stderr = {
|
||||
;(unzipChildProcess as any).stderr = {
|
||||
on () {},
|
||||
}
|
||||
|
||||
sinon.stub(cp, 'spawn').withArgs('unzip').returns(unzipChildProcess)
|
||||
// @ts-expect-error - invalid number of arguments for given type
|
||||
sinon.stub(cp, 'spawn').withArgs('unzip').returns(unzipChildProcess as any)
|
||||
|
||||
setTimeout(() => {
|
||||
debug('emitting unzip error')
|
||||
@@ -141,15 +146,16 @@ describe('lib/tasks/unzip', function () {
|
||||
|
||||
const unzipChildProcess = new events.EventEmitter()
|
||||
|
||||
unzipChildProcess.stdout = {
|
||||
;(unzipChildProcess as any).stdout = {
|
||||
on () {},
|
||||
}
|
||||
|
||||
unzipChildProcess.stderr = {
|
||||
;(unzipChildProcess as any).stderr = {
|
||||
on () {},
|
||||
}
|
||||
|
||||
sinon.stub(cp, 'spawn').withArgs('unzip').returns(unzipChildProcess)
|
||||
// @ts-expect-error - invalid number of arguments for given type
|
||||
sinon.stub(cp, 'spawn').withArgs('unzip').returns(unzipChildProcess as any)
|
||||
|
||||
setTimeout(() => {
|
||||
debug('emitting unzip error')
|
||||
@@ -162,7 +168,7 @@ describe('lib/tasks/unzip', function () {
|
||||
zipFilePath,
|
||||
installDir,
|
||||
})
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
logger.error(err)
|
||||
expect(err.message).to.include('Unknown error with Node extract tool')
|
||||
|
||||
@@ -174,24 +180,25 @@ describe('lib/tasks/unzip', function () {
|
||||
it('calls node unzip just once', function (done) {
|
||||
const zipFilePath = path.join('test', 'fixture', 'example.zip')
|
||||
|
||||
sinon.stub(unzip.utils.unzipTools, 'extract').callsFake((filePath, opts) => {
|
||||
sinon.stub(unzip.utils.unzipTools, 'extract').callsFake((filePath: any, opts: any) => {
|
||||
debug('unzip extract called with %s', filePath)
|
||||
expect(filePath, 'zipfile is the same').to.equal(zipFilePath)
|
||||
|
||||
return new Promise((resolve) => resolve())
|
||||
return new Promise((resolve, reject) => resolve(undefined))
|
||||
})
|
||||
|
||||
const unzipChildProcess = new events.EventEmitter()
|
||||
|
||||
unzipChildProcess.stdout = {
|
||||
;(unzipChildProcess as any).stdout = {
|
||||
on () {},
|
||||
}
|
||||
|
||||
unzipChildProcess.stderr = {
|
||||
;(unzipChildProcess as any).stderr = {
|
||||
on () {},
|
||||
}
|
||||
|
||||
sinon.stub(cp, 'spawn').withArgs('unzip').returns(unzipChildProcess)
|
||||
// @ts-expect-error - invalid number of arguments for given type
|
||||
sinon.stub(cp, 'spawn').withArgs('unzip').returns(unzipChildProcess as any)
|
||||
|
||||
setTimeout(() => {
|
||||
debug('emitting unzip error')
|
||||
@@ -220,33 +227,34 @@ describe('lib/tasks/unzip', function () {
|
||||
|
||||
context('on Mac', () => {
|
||||
beforeEach(() => {
|
||||
os.platform.returns('darwin')
|
||||
(os.platform as any).returns('darwin')
|
||||
})
|
||||
|
||||
it('calls node unzip just once', function (done) {
|
||||
const zipFilePath = path.join('test', 'fixture', 'example.zip')
|
||||
|
||||
sinon.stub(unzip.utils.unzipTools, 'extract').callsFake((filePath, opts) => {
|
||||
sinon.stub(unzip.utils.unzipTools, 'extract').callsFake((filePath: any, opts: any) => {
|
||||
debug('unzip extract called with %s', filePath)
|
||||
expect(filePath, 'zipfile is the same').to.equal(zipFilePath)
|
||||
|
||||
return new Promise((resolve) => resolve())
|
||||
return new Promise((resolve) => resolve(undefined))
|
||||
})
|
||||
|
||||
const unzipChildProcess = new events.EventEmitter()
|
||||
|
||||
unzipChildProcess.stdout = {
|
||||
;(unzipChildProcess as any).stdout = {
|
||||
on () {},
|
||||
}
|
||||
|
||||
unzipChildProcess.stderr = {
|
||||
;(unzipChildProcess as any).stderr = {
|
||||
on () {},
|
||||
}
|
||||
|
||||
sinon.stub(cp, 'spawn').withArgs('ditto').returns(unzipChildProcess)
|
||||
// @ts-expect-error - invalid number of arguments for given type
|
||||
sinon.stub(cp, 'spawn').withArgs('ditto').returns(unzipChildProcess as any)
|
||||
sinon.stub(readline, 'createInterface').returns({
|
||||
on: () => {},
|
||||
})
|
||||
} as any)
|
||||
|
||||
setTimeout(() => {
|
||||
debug('emitting ditto error')
|
||||
@@ -1,26 +1,23 @@
|
||||
/* eslint-disable no-restricted-properties */
|
||||
require('../../spec_helper')
|
||||
import '../../spec_helper'
|
||||
import path from 'path'
|
||||
import _ from 'lodash'
|
||||
import os from 'os'
|
||||
import cp from 'child_process'
|
||||
import BluebirdPromise from 'bluebird'
|
||||
import { stripIndent } from 'common-tags'
|
||||
import mockfs from 'mock-fs'
|
||||
import mockedEnv from 'mocked-env'
|
||||
import Stdout from '../../support/stdout'
|
||||
import normalize from '../../support/normalize'
|
||||
import snapshot from '../../support/snapshot'
|
||||
import mockSpawnModule from '../../support/spawn-mock'
|
||||
|
||||
const path = require('path')
|
||||
const _ = require('lodash')
|
||||
const os = require('os')
|
||||
const cp = require('child_process')
|
||||
const Promise = require('bluebird')
|
||||
const { stripIndent } = require('common-tags')
|
||||
|
||||
const mockfs = require('mock-fs')
|
||||
const mockedEnv = require('mocked-env')
|
||||
|
||||
const fs = require(`${lib}/fs`)
|
||||
const util = require(`${lib}/util`)
|
||||
const logger = require(`${lib}/logger`)
|
||||
const xvfb = require(`${lib}/exec/xvfb`)
|
||||
const verify = require(`${lib}/tasks/verify`)
|
||||
|
||||
const Stdout = require('../../support/stdout')
|
||||
const normalize = require('../../support/normalize')
|
||||
const snapshot = require('../../support/snapshot')
|
||||
const { mockSpawn } = require('../../support/spawn-mock')
|
||||
import fs from '../../../lib/fs'
|
||||
import util from '../../../lib/util'
|
||||
import logger from '../../../lib/logger'
|
||||
import xvfb from '../../../lib/exec/xvfb'
|
||||
import verify from '../../../lib/tasks/verify'
|
||||
|
||||
const packageVersion = '1.2.3'
|
||||
const cacheDir = '/cache/Cypress'
|
||||
@@ -28,13 +25,17 @@ const executablePath = '/cache/Cypress/1.2.3/Cypress.app/Contents/MacOS/Cypress'
|
||||
const binaryStatePath = '/cache/Cypress/1.2.3/binary_state.json'
|
||||
const DEFAULT_VERIFY_TIMEOUT = 30000
|
||||
|
||||
let stdout
|
||||
let spawnedProcess
|
||||
let stdout: any
|
||||
let spawnedProcess: any
|
||||
|
||||
/* eslint-disable no-octal */
|
||||
|
||||
context('lib/tasks/verify', () => {
|
||||
require('mocha-banner').register()
|
||||
before(async function () {
|
||||
const mochaMain = await import('mocha-banner')
|
||||
|
||||
mochaMain.register()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
stdout = Stdout.capture()
|
||||
@@ -44,8 +45,9 @@ context('lib/tasks/verify', () => {
|
||||
stdout: '222',
|
||||
}
|
||||
|
||||
os.platform.returns('darwin')
|
||||
os.release.returns('0.0.0')
|
||||
;(os.platform as any).returns('darwin')
|
||||
|
||||
;(os.release as any).returns('0.0.0')
|
||||
|
||||
sinon.stub(util, 'getCacheDir').returns(cacheDir)
|
||||
sinon.stub(util, 'isCi').returns(false)
|
||||
@@ -55,12 +57,13 @@ context('lib/tasks/verify', () => {
|
||||
sinon.stub(xvfb, 'start').resolves()
|
||||
sinon.stub(xvfb, 'stop').resolves()
|
||||
sinon.stub(xvfb, 'isNeeded').returns(false)
|
||||
sinon.stub(Promise.prototype, 'delay').resolves()
|
||||
sinon.stub(BluebirdPromise.prototype, 'delay').resolves()
|
||||
sinon.stub(process, 'geteuid').returns(1000)
|
||||
|
||||
sinon.stub(_, 'random').returns('222')
|
||||
sinon.stub(_, 'random').returns(222)
|
||||
|
||||
util.exec
|
||||
// @ts-expect-error - is a sinon stub
|
||||
.withArgs(executablePath, ['--no-sandbox', '--smoke-test', '--ping=222'])
|
||||
.resolves(spawnedProcess)
|
||||
})
|
||||
@@ -73,47 +76,49 @@ context('lib/tasks/verify', () => {
|
||||
expect(verify.VERIFY_TEST_RUNNER_TIMEOUT_MS).to.eql(DEFAULT_VERIFY_TIMEOUT)
|
||||
})
|
||||
|
||||
it('accepts custom verify task timeout', () => {
|
||||
it('accepts custom verify task timeout', async () => {
|
||||
process.env.CYPRESS_VERIFY_TIMEOUT = '500000'
|
||||
delete require.cache[require.resolve(`${lib}/tasks/verify`)]
|
||||
const newVerifyInstance = require(`${lib}/tasks/verify`)
|
||||
const proxyquire = await import('proxyquire')
|
||||
const newVerifyInstance = proxyquire.default(`../../../lib/tasks/verify`, {}).default
|
||||
|
||||
expect(newVerifyInstance.VERIFY_TEST_RUNNER_TIMEOUT_MS).to.eql(500000)
|
||||
})
|
||||
|
||||
it('accepts custom verify task timeout from npm', () => {
|
||||
it('accepts custom verify task timeout from npm', async () => {
|
||||
process.env.npm_config_CYPRESS_VERIFY_TIMEOUT = '500000'
|
||||
delete require.cache[require.resolve(`${lib}/tasks/verify`)]
|
||||
const newVerifyInstance = require(`${lib}/tasks/verify`)
|
||||
const proxyquire = await import('proxyquire')
|
||||
const newVerifyInstance = proxyquire.default(`../../../lib/tasks/verify`, {}).default
|
||||
|
||||
expect(newVerifyInstance.VERIFY_TEST_RUNNER_TIMEOUT_MS).to.eql(500000)
|
||||
})
|
||||
|
||||
it('falls back to default verify task timeout if custom value is invalid', () => {
|
||||
it('falls back to default verify task timeout if custom value is invalid', async () => {
|
||||
process.env.CYPRESS_VERIFY_TIMEOUT = 'foobar'
|
||||
delete require.cache[require.resolve(`${lib}/tasks/verify`)]
|
||||
const newVerifyInstance = require(`${lib}/tasks/verify`)
|
||||
|
||||
const proxyquire = await import('proxyquire')
|
||||
const newVerifyInstance = proxyquire.default(`../../../lib/tasks/verify`, {}).default
|
||||
|
||||
expect(newVerifyInstance.VERIFY_TEST_RUNNER_TIMEOUT_MS).to.eql(DEFAULT_VERIFY_TIMEOUT)
|
||||
})
|
||||
|
||||
it('returns early when `CYPRESS_SKIP_VERIFY` is set to true', () => {
|
||||
it('returns early when `CYPRESS_SKIP_VERIFY` is set to true', async () => {
|
||||
process.env.CYPRESS_SKIP_VERIFY = 'true'
|
||||
delete require.cache[require.resolve(`${lib}/tasks/verify`)]
|
||||
const newVerifyInstance = require(`${lib}/tasks/verify`)
|
||||
|
||||
return newVerifyInstance.start().then((result) => {
|
||||
const proxyquire = await import('proxyquire')
|
||||
const newVerifyInstance = proxyquire.default(`../../../lib/tasks/verify`, {}).default
|
||||
|
||||
return newVerifyInstance.start({ listrRenderer: 'silent' }).then((result: any) => {
|
||||
expect(result).to.eq(undefined)
|
||||
})
|
||||
})
|
||||
|
||||
it('logs error and exits when no version of Cypress is installed', () => {
|
||||
return verify
|
||||
.start()
|
||||
.start({ listrRenderer: 'silent' })
|
||||
.then(() => {
|
||||
throw new Error('should have caught error')
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
logger.error(err)
|
||||
|
||||
snapshot(
|
||||
@@ -131,13 +136,14 @@ context('lib/tasks/verify', () => {
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
process.geteuid.returns(0) // user is root
|
||||
;(process.geteuid as any).returns(0) // user is root
|
||||
// @ts-expect-error - is a sinon stub
|
||||
util.exec.resolves({
|
||||
stdout: '222',
|
||||
stderr: '',
|
||||
})
|
||||
|
||||
return verify.start()
|
||||
return verify.start({ listrRenderer: 'silent' })
|
||||
.then(() => {
|
||||
expect(util.exec).to.be.calledWith(executablePath, ['--no-sandbox', '--smoke-test', '--ping=222'])
|
||||
})
|
||||
@@ -151,13 +157,14 @@ context('lib/tasks/verify', () => {
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
process.geteuid.returns(1000) // user is non-root
|
||||
;(process.geteuid as any).returns(1000) // user is non-root
|
||||
// @ts-expect-error - is a sinon stub
|
||||
util.exec.resolves({
|
||||
stdout: '222',
|
||||
stderr: '',
|
||||
})
|
||||
|
||||
return verify.start()
|
||||
return verify.start({ listrRenderer: 'silent' })
|
||||
.then(() => {
|
||||
expect(util.exec).to.be.calledWith(executablePath, ['--no-sandbox', '--smoke-test', '--ping=222'])
|
||||
})
|
||||
@@ -171,7 +178,7 @@ context('lib/tasks/verify', () => {
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
return verify.start().then(() => {
|
||||
return verify.start({ listrRenderer: 'silent' }).then(() => {
|
||||
// nothing should have been logged to stdout
|
||||
// since no verification took place
|
||||
expect(stdout.toString()).to.be.empty
|
||||
@@ -188,7 +195,7 @@ context('lib/tasks/verify', () => {
|
||||
})
|
||||
|
||||
return verify
|
||||
.start()
|
||||
.start({ listrRenderer: 'silent' })
|
||||
.then(() => {
|
||||
throw new Error('should have caught error')
|
||||
})
|
||||
@@ -202,11 +209,11 @@ context('lib/tasks/verify', () => {
|
||||
|
||||
it('logs error and exits when executable cannot be found', () => {
|
||||
return verify
|
||||
.start()
|
||||
.start({ listrRenderer: 'silent' })
|
||||
.then(() => {
|
||||
throw new Error('should have caught error')
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
logger.error(err)
|
||||
|
||||
snapshot('executable cannot be found 1', normalize(stdout.toString()))
|
||||
@@ -220,20 +227,22 @@ context('lib/tasks/verify', () => {
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
sinon.stub(cp, 'spawn').withArgs('/cache/Cypress/1.2.3/Cypress.app/Contents/MacOS/Cypress').callsFake(mockSpawn((cp) => {
|
||||
// @ts-expect-error - invalid number of arguments for given type
|
||||
sinon.stub(cp, 'spawn').withArgs('/cache/Cypress/1.2.3/Cypress.app/Contents/MacOS/Cypress').callsFake(mockSpawnModule.mockSpawn((cp: any) => {
|
||||
cp.stderr.write('some stderr')
|
||||
cp.stdout.write('some stdout')
|
||||
}))
|
||||
|
||||
// @ts-expect-error - is a sinon stub
|
||||
util.exec.restore()
|
||||
|
||||
return verify
|
||||
.start({ smokeTestTimeout: 1 })
|
||||
.catch((err) => {
|
||||
.start({ smokeTestTimeout: 1, listrRenderer: 'silent' })
|
||||
.catch((err: any) => {
|
||||
logger.error(err)
|
||||
})
|
||||
.then(() => {
|
||||
snapshot(normalize(slice(stdout.toString())))
|
||||
snapshot(normalize(stdout.toString()))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -244,22 +253,23 @@ context('lib/tasks/verify', () => {
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
sinon.stub(cp, 'spawn').callsFake(mockSpawn((cp) => {
|
||||
sinon.stub(cp, 'spawn').callsFake(mockSpawnModule.mockSpawn((cp: any) => {
|
||||
cp.stderr.write('some stderr')
|
||||
cp.stdout.write('some stdout')
|
||||
cp.emit('exit', 0, null)
|
||||
cp.end()
|
||||
}))
|
||||
|
||||
// @ts-expect-error - is a sinon stub
|
||||
util.exec.restore()
|
||||
|
||||
return verify
|
||||
.start()
|
||||
.catch((err) => {
|
||||
.start({ listrRenderer: 'silent' })
|
||||
.catch((err: any) => {
|
||||
logger.error(err)
|
||||
})
|
||||
.then(() => {
|
||||
snapshot(normalize(slice(stdout.toString())))
|
||||
snapshot(normalize(stdout.toString()))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -270,31 +280,32 @@ context('lib/tasks/verify', () => {
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
sinon.stub(cp, 'spawn').callsFake(mockSpawn((cp) => {
|
||||
sinon.stub(cp, 'spawn').callsFake(mockSpawnModule.mockSpawn((cp: any) => {
|
||||
cp.stdout.write('some stdout')
|
||||
cp.emit('exit', 0, null)
|
||||
cp.end()
|
||||
}))
|
||||
|
||||
// @ts-expect-error - is a sinon stub
|
||||
util.exec.restore()
|
||||
|
||||
return verify
|
||||
.start()
|
||||
.catch((err) => {
|
||||
.start({ listrRenderer: 'silent' })
|
||||
.catch((err: any) => {
|
||||
logger.error(err)
|
||||
})
|
||||
.then(() => {
|
||||
snapshot(normalize(slice(stdout.toString())))
|
||||
snapshot(normalize(stdout.toString()))
|
||||
})
|
||||
})
|
||||
|
||||
describe('FORCE_COLOR', () => {
|
||||
let previousForceColors
|
||||
let previousForceColors: any
|
||||
|
||||
beforeEach(() => {
|
||||
previousForceColors = process.env.FORCE_COLOR
|
||||
|
||||
process.env.FORCE_COLOR = true
|
||||
process.env.FORCE_COLOR = 'true' as any
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@@ -309,17 +320,18 @@ context('lib/tasks/verify', () => {
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
// @ts-expect-error - is a sinon stub
|
||||
util.exec.resolves({
|
||||
stdout: '222',
|
||||
stderr: '',
|
||||
})
|
||||
|
||||
return verify.start()
|
||||
return verify.start({ listrRenderer: 'silent' })
|
||||
.then(() => {
|
||||
expect(util.exec).to.be.calledWith(executablePath, ['--no-sandbox', '--smoke-test', '--ping=222'],
|
||||
sinon.match({
|
||||
env: {
|
||||
FORCE_COLOR: 0,
|
||||
FORCE_COLOR: '0',
|
||||
},
|
||||
}))
|
||||
})
|
||||
@@ -336,12 +348,13 @@ context('lib/tasks/verify', () => {
|
||||
})
|
||||
|
||||
it('shows full path to executable when verifying', () => {
|
||||
return verify.start({ force: true }).then(() => {
|
||||
return verify.start({ force: true, listrRenderer: 'silent' }).then(() => {
|
||||
snapshot('verification with executable 1', normalize(stdout.toString()))
|
||||
})
|
||||
})
|
||||
|
||||
it('clears verified version from state if verification fails', () => {
|
||||
// @ts-expect-error - is a sinon stub
|
||||
util.exec.restore()
|
||||
sinon
|
||||
.stub(util, 'exec')
|
||||
@@ -352,23 +365,23 @@ context('lib/tasks/verify', () => {
|
||||
})
|
||||
|
||||
return verify
|
||||
.start({ force: true })
|
||||
.start({ force: true, listrRenderer: 'silent' })
|
||||
.then(() => {
|
||||
throw new Error('Should have thrown')
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
logger.error(err)
|
||||
})
|
||||
.then(() => {
|
||||
return fs.pathExistsAsync(binaryStatePath)
|
||||
})
|
||||
.then((exists) => {
|
||||
.then((exists: any) => {
|
||||
return expect(exists).to.eq(false)
|
||||
})
|
||||
.then(() => {
|
||||
return snapshot(
|
||||
'fails verifying Cypress 1',
|
||||
normalize(slice(stdout.toString())),
|
||||
normalize(stdout.toString()),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -383,6 +396,7 @@ context('lib/tasks/verify', () => {
|
||||
after that more text
|
||||
`
|
||||
|
||||
// @ts-expect-error - is a sinon stub
|
||||
util.exec.withArgs(executablePath).resolves({
|
||||
stdout: stdoutWithDebugOutput,
|
||||
})
|
||||
@@ -395,14 +409,14 @@ context('lib/tasks/verify', () => {
|
||||
})
|
||||
|
||||
it('finds ping value in the verbose output', () => {
|
||||
return verify.start().then(() => {
|
||||
return verify.start({ listrRenderer: 'silent' }).then(() => {
|
||||
snapshot('verbose stdout output 1', normalize(stdout.toString()))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('smoke test retries on bad display with our Xvfb', () => {
|
||||
let restore
|
||||
let restore: any
|
||||
|
||||
beforeEach(() => {
|
||||
restore = mockedEnv({
|
||||
@@ -415,6 +429,7 @@ context('lib/tasks/verify', () => {
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
// @ts-expect-error - is a sinon stub
|
||||
util.exec.restore()
|
||||
sinon.spy(logger, 'warn')
|
||||
})
|
||||
@@ -425,11 +440,13 @@ context('lib/tasks/verify', () => {
|
||||
|
||||
it('successfully retries with our Xvfb on Linux', () => {
|
||||
// initially we think the user has everything set
|
||||
// @ts-expect-error - is a sinon stub
|
||||
xvfb.isNeeded.returns(false)
|
||||
sinon.stub(util, 'isPossibleLinuxWithIncorrectDisplay').returns(true)
|
||||
|
||||
// @ts-expect-error - is a sinon stub
|
||||
sinon.stub(util, 'exec').callsFake(() => {
|
||||
const firstSpawnError = new Error('')
|
||||
const firstSpawnError: any = new Error('')
|
||||
|
||||
// this message contains typical Gtk error shown if X11 is incorrect
|
||||
// like in the case of DISPLAY=987
|
||||
@@ -441,14 +458,15 @@ context('lib/tasks/verify', () => {
|
||||
firstSpawnError.stdout = ''
|
||||
|
||||
// the second time the binary returns expected ping
|
||||
// @ts-expect-error - is a sinon stub
|
||||
util.exec.withArgs(executablePath).resolves({
|
||||
stdout: '222',
|
||||
})
|
||||
|
||||
return Promise.reject(firstSpawnError)
|
||||
return BluebirdPromise.reject(firstSpawnError)
|
||||
})
|
||||
|
||||
return verify.start().then(() => {
|
||||
return verify.start({ listrRenderer: 'silent' }).then(() => {
|
||||
expect(util.exec).to.have.been.calledTwice
|
||||
// user should have been warned
|
||||
expect(logger.warn).to.have.been.calledWithMatch(
|
||||
@@ -459,15 +477,17 @@ context('lib/tasks/verify', () => {
|
||||
|
||||
it('fails on both retries with our Xvfb on Linux', () => {
|
||||
// initially we think the user has everything set
|
||||
// @ts-expect-error - is a sinon stub
|
||||
xvfb.isNeeded.returns(false)
|
||||
|
||||
sinon.stub(util, 'isPossibleLinuxWithIncorrectDisplay').returns(true)
|
||||
|
||||
// @ts-expect-error - is a sinon stub
|
||||
sinon.stub(util, 'exec').callsFake(() => {
|
||||
os.platform.returns('linux')
|
||||
(os.platform as any).returns('linux')
|
||||
expect(xvfb.start).to.not.have.been.called
|
||||
|
||||
const firstSpawnError = new Error('')
|
||||
const firstSpawnError: any = new Error('')
|
||||
|
||||
// this message contains typical Gtk error shown if X11 is incorrect
|
||||
// like in the case of DISPLAY=987
|
||||
@@ -486,15 +506,16 @@ context('lib/tasks/verify', () => {
|
||||
some weird indent
|
||||
`
|
||||
|
||||
// @ts-expect-error - is a sinon stub
|
||||
util.exec.withArgs(executablePath).rejects(new Error(secondMessage))
|
||||
|
||||
return Promise.reject(firstSpawnError)
|
||||
return BluebirdPromise.reject(firstSpawnError)
|
||||
})
|
||||
|
||||
return verify.start().then(() => {
|
||||
return verify.start({ listrRenderer: 'silent' }).then(() => {
|
||||
throw new Error('Should have failed')
|
||||
})
|
||||
.catch((e) => {
|
||||
.catch((e: any) => {
|
||||
expect(util.exec).to.have.been.calledTwice
|
||||
// second time around we should have called Xvfb
|
||||
expect(xvfb.start).to.have.been.calledOnce
|
||||
@@ -516,11 +537,11 @@ context('lib/tasks/verify', () => {
|
||||
})
|
||||
|
||||
return verify
|
||||
.start()
|
||||
.start({ listrRenderer: 'silent' })
|
||||
.then(() => {
|
||||
throw new Error('Should have thrown')
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
stdout = Stdout.capture()
|
||||
logger.error(err)
|
||||
|
||||
@@ -537,11 +558,11 @@ context('lib/tasks/verify', () => {
|
||||
})
|
||||
|
||||
return verify
|
||||
.start()
|
||||
.start({ listrRenderer: 'silent' })
|
||||
.then(() => {
|
||||
throw new Error('Should have thrown')
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
stdout = Stdout.capture()
|
||||
logger.error(err)
|
||||
|
||||
@@ -559,7 +580,7 @@ context('lib/tasks/verify', () => {
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
return verify.start().then(() => {
|
||||
return verify.start({ listrRenderer: 'silent' }).then(() => {
|
||||
return snapshot(
|
||||
'current version has not been verified 1',
|
||||
normalize(stdout.toString()),
|
||||
@@ -574,7 +595,7 @@ context('lib/tasks/verify', () => {
|
||||
packageVersion: '7.8.9',
|
||||
})
|
||||
|
||||
return verify.start().then(() => {
|
||||
return verify.start({ listrRenderer: 'silent' }).then(() => {
|
||||
return snapshot(
|
||||
'different version installed 1',
|
||||
normalize(stdout.toString()),
|
||||
@@ -591,7 +612,7 @@ context('lib/tasks/verify', () => {
|
||||
|
||||
process.env.npm_config_loglevel = 'silent'
|
||||
|
||||
return verify.start().then(() => {
|
||||
return verify.start({ listrRenderer: 'silent' }).then(() => {
|
||||
return snapshot(
|
||||
'silent verify 1',
|
||||
normalize(`[no output]${stdout.toString()}`),
|
||||
@@ -622,6 +643,7 @@ context('lib/tasks/verify', () => {
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
// @ts-expect-error - is a sinon stub
|
||||
util.exec.restore()
|
||||
sinon.stub(util, 'exec').rejects({
|
||||
stderr: '',
|
||||
@@ -630,11 +652,11 @@ context('lib/tasks/verify', () => {
|
||||
})
|
||||
|
||||
return verify
|
||||
.start()
|
||||
.start({ listrRenderer: 'silent' })
|
||||
.then(() => {
|
||||
throw new Error('Should have thrown')
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
stdout = Stdout.capture()
|
||||
logger.error(err)
|
||||
|
||||
@@ -644,6 +666,7 @@ context('lib/tasks/verify', () => {
|
||||
|
||||
describe('on linux', () => {
|
||||
beforeEach(() => {
|
||||
// @ts-expect-error - is a sinon stub
|
||||
xvfb.isNeeded.returns(true)
|
||||
|
||||
createfs({
|
||||
@@ -654,36 +677,37 @@ context('lib/tasks/verify', () => {
|
||||
})
|
||||
|
||||
it('starts xvfb', () => {
|
||||
return verify.start().then(() => {
|
||||
return verify.start({ listrRenderer: 'silent' }).then(() => {
|
||||
expect(xvfb.start).to.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('stops xvfb on spawned process close', () => {
|
||||
return verify.start().then(() => {
|
||||
return verify.start({ listrRenderer: 'silent' }).then(() => {
|
||||
expect(xvfb.stop).to.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('logs error and exits when starting xvfb fails', () => {
|
||||
const err = new Error('test without xvfb')
|
||||
const err: any = new Error('test without xvfb')
|
||||
|
||||
// @ts-expect-error - is a sinon stub
|
||||
xvfb.start.restore()
|
||||
|
||||
err.nonZeroExitCode = true
|
||||
err.stack = 'xvfb? no dice'
|
||||
sinon.stub(xvfb._xvfb, 'startAsync').rejects(err)
|
||||
|
||||
return verify.start()
|
||||
return verify.start({ listrRenderer: 'silent' })
|
||||
.then(() => {
|
||||
throw new Error('should have thrown')
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
expect(xvfb.stop).to.be.calledOnce
|
||||
|
||||
logger.error(err)
|
||||
|
||||
snapshot('xvfb fails 1', normalize(slice(stdout.toString())))
|
||||
snapshot('xvfb fails 1', normalize(stdout.toString()))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -696,11 +720,12 @@ context('lib/tasks/verify', () => {
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
// @ts-expect-error - is a sinon stub
|
||||
util.isCi.returns(true)
|
||||
})
|
||||
|
||||
it('uses verbose renderer', () => {
|
||||
return verify.start().then(() => {
|
||||
return verify.start({ listrRenderer: 'silent' }).then(() => {
|
||||
snapshot('verifying in ci 1', normalize(stdout.toString()))
|
||||
})
|
||||
})
|
||||
@@ -709,11 +734,11 @@ context('lib/tasks/verify', () => {
|
||||
mockfs({})
|
||||
|
||||
return verify
|
||||
.start()
|
||||
.start({ listrRenderer: 'silent' })
|
||||
.then(() => {
|
||||
throw new Error('Should have thrown')
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
logger.error(err)
|
||||
snapshot('error binary not found in ci 1', normalize(stdout.toString()))
|
||||
})
|
||||
@@ -734,10 +759,12 @@ context('lib/tasks/verify', () => {
|
||||
})
|
||||
|
||||
util.exec
|
||||
// @ts-expect-error - is a sinon stub
|
||||
.withArgs(realEnvBinaryPath, ['--no-sandbox', '--smoke-test', '--ping=222'])
|
||||
.resolves(spawnedProcess)
|
||||
|
||||
return verify.start().then(() => {
|
||||
return verify.start({ listrRenderer: 'silent' }).then(() => {
|
||||
// @ts-expect-error - is a sinon stub
|
||||
expect(util.exec.firstCall.args[0]).to.equal(realEnvBinaryPath)
|
||||
snapshot('valid CYPRESS_RUN_BINARY 1', normalize(stdout.toString()))
|
||||
})
|
||||
@@ -746,14 +773,15 @@ context('lib/tasks/verify', () => {
|
||||
_.each(['darwin', 'linux', 'win32'], (platform) => {
|
||||
return it('can log error to user', () => {
|
||||
process.env.CYPRESS_RUN_BINARY = '/custom/'
|
||||
os.platform.returns(platform)
|
||||
|
||||
;(os.platform as any).returns(platform)
|
||||
|
||||
return verify
|
||||
.start()
|
||||
.start({ listrRenderer: 'silent' })
|
||||
.then(() => {
|
||||
throw new Error('Should have thrown')
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: any) => {
|
||||
logger.error(err)
|
||||
snapshot(
|
||||
`${platform}: error when invalid CYPRESS_RUN_BINARY 1`,
|
||||
@@ -767,32 +795,35 @@ context('lib/tasks/verify', () => {
|
||||
// tests for when Electron needs "--no-sandbox" CLI flag
|
||||
context('.needsSandbox', () => {
|
||||
it('needs --no-sandbox on Linux as a root', () => {
|
||||
os.platform.returns('linux')
|
||||
process.geteuid.returns(0) // user is root
|
||||
(os.platform as any).returns('linux')
|
||||
|
||||
;(process.geteuid as any).returns(0) // user is root
|
||||
expect(verify.needsSandbox()).to.be.true
|
||||
})
|
||||
|
||||
it('needs --no-sandbox on Linux as a non-root', () => {
|
||||
os.platform.returns('linux')
|
||||
process.geteuid.returns(1000) // user is non-root
|
||||
(os.platform as any).returns('linux')
|
||||
|
||||
;(process.geteuid as any).returns(1000) // user is non-root
|
||||
expect(verify.needsSandbox()).to.be.true
|
||||
})
|
||||
|
||||
it('needs --no-sandbox on Mac as a non-root', () => {
|
||||
os.platform.returns('darwin')
|
||||
process.geteuid.returns(1000) // user is non-root
|
||||
(os.platform as any).returns('darwin')
|
||||
|
||||
;(process.geteuid as any).returns(1000) // user is non-root
|
||||
expect(verify.needsSandbox()).to.be.true
|
||||
})
|
||||
|
||||
it('does not need --no-sandbox on Windows', () => {
|
||||
os.platform.returns('win32')
|
||||
(os.platform as any).returns('win32')
|
||||
expect(verify.needsSandbox()).to.be.false
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// TODO this needs documentation with examples badly.
|
||||
function createfs ({ alreadyVerified, executable, packageVersion, customDir }) {
|
||||
function createfs ({ alreadyVerified, executable, packageVersion, customDir }: any) {
|
||||
if (!customDir) {
|
||||
customDir = '/cache/Cypress/1.2.3/Cypress.app'
|
||||
}
|
||||
@@ -806,7 +837,7 @@ function createfs ({ alreadyVerified, executable, packageVersion, customDir }) {
|
||||
}
|
||||
const binaryStateText = JSON.stringify(binaryState)
|
||||
|
||||
let mockFiles = {
|
||||
let mockFiles: any = {
|
||||
[binaryStateFolder]: {
|
||||
'binary_state.json': binaryStateText,
|
||||
},
|
||||
@@ -835,20 +866,3 @@ function createfs ({ alreadyVerified, executable, packageVersion, customDir }) {
|
||||
|
||||
return mockfs(mockFiles)
|
||||
}
|
||||
|
||||
function slice (str) {
|
||||
// strip answer and split by new lines
|
||||
str = str.split('\n')
|
||||
|
||||
// find the line about verifying cypress can run
|
||||
const index = _.findIndex(str, (line) => {
|
||||
return line.includes('Verifying Cypress can run')
|
||||
})
|
||||
|
||||
// get rid of whatever the next line is because
|
||||
// i cannot figure out why this line fails in CI
|
||||
// its likely due to some UTF code
|
||||
str.splice(index + 1, 1, 'STRIPPED')
|
||||
|
||||
return str.join('\n')
|
||||
}
|
||||
@@ -1,16 +1,13 @@
|
||||
require('../spec_helper')
|
||||
|
||||
const os = require('os')
|
||||
const tty = require('tty')
|
||||
const snapshot = require('../support/snapshot')
|
||||
const mockedEnv = require('mocked-env')
|
||||
const supportsColor = require('supports-color')
|
||||
const proxyquire = require('proxyquire')
|
||||
const hasha = require('hasha')
|
||||
const la = require('lazy-ass')
|
||||
|
||||
const util = require(`${lib}/util`)
|
||||
const logger = require(`${lib}/logger`)
|
||||
import '../spec_helper'
|
||||
import os from 'os'
|
||||
import tty from 'tty'
|
||||
import snapshot from '../support/snapshot'
|
||||
import mockedEnv from 'mocked-env'
|
||||
import supportsColor from 'supports-color'
|
||||
import hasha from 'hasha'
|
||||
import la from 'lazy-ass'
|
||||
import util from '../../lib/util'
|
||||
import logger from '../../lib/logger'
|
||||
|
||||
describe('util', () => {
|
||||
beforeEach(() => {
|
||||
@@ -20,7 +17,7 @@ describe('util', () => {
|
||||
|
||||
context('.isBrokenGtkDisplay', () => {
|
||||
it('detects only GTK message', () => {
|
||||
os.platform.returns('linux')
|
||||
(os.platform as any).returns('linux')
|
||||
const text = '[some noise here] Gtk: cannot open display: 99'
|
||||
|
||||
expect(util.isBrokenGtkDisplay(text)).to.be.true
|
||||
@@ -52,49 +49,45 @@ describe('util', () => {
|
||||
})
|
||||
|
||||
context('.stdoutLineMatches', () => {
|
||||
const { stdoutLineMatches } = util
|
||||
|
||||
it('is a function', () => {
|
||||
expect(stdoutLineMatches).to.be.a.function
|
||||
expect(util.stdoutLineMatches).to.be.a('function')
|
||||
})
|
||||
|
||||
it('matches entire output', () => {
|
||||
const line = '444'
|
||||
|
||||
expect(stdoutLineMatches(line, line)).to.be.true
|
||||
expect(util.stdoutLineMatches(line, line)).to.be.true
|
||||
})
|
||||
|
||||
it('matches a line in output', () => {
|
||||
const line = '444'
|
||||
const stdout = ['start', line, 'something else'].join('\n')
|
||||
|
||||
expect(stdoutLineMatches(line, stdout)).to.be.true
|
||||
expect(util.stdoutLineMatches(line, stdout)).to.be.true
|
||||
})
|
||||
|
||||
it('matches a trimmed line in output', () => {
|
||||
const line = '444'
|
||||
const stdout = ['start', ` ${line} `, 'something else'].join('\n')
|
||||
|
||||
expect(stdoutLineMatches(line, stdout)).to.be.true
|
||||
expect(util.stdoutLineMatches(line, stdout)).to.be.true
|
||||
})
|
||||
|
||||
it('does not find match', () => {
|
||||
const line = '445'
|
||||
const stdout = ['start', '444', 'something else'].join('\n')
|
||||
|
||||
expect(stdoutLineMatches(line, stdout)).to.be.false
|
||||
expect(util.stdoutLineMatches(line, stdout)).to.be.false
|
||||
})
|
||||
})
|
||||
|
||||
context('.normalizeModuleOptions', () => {
|
||||
const { normalizeModuleOptions } = util
|
||||
|
||||
it('does not change other properties', () => {
|
||||
const options = {
|
||||
foo: 'bar',
|
||||
}
|
||||
|
||||
snapshot('others_unchanged 1', normalizeModuleOptions(options))
|
||||
snapshot('others_unchanged 1', util.normalizeModuleOptions(options))
|
||||
})
|
||||
|
||||
it('passes string env unchanged', () => {
|
||||
@@ -102,7 +95,7 @@ describe('util', () => {
|
||||
env: 'foo=bar',
|
||||
}
|
||||
|
||||
snapshot('env_as_string 1', normalizeModuleOptions(options))
|
||||
snapshot('env_as_string 1', util.normalizeModuleOptions(options))
|
||||
})
|
||||
|
||||
it('converts environment object', () => {
|
||||
@@ -114,7 +107,7 @@ describe('util', () => {
|
||||
},
|
||||
}
|
||||
|
||||
snapshot('env_as_object 1', normalizeModuleOptions(options))
|
||||
snapshot('env_as_object 1', util.normalizeModuleOptions(options))
|
||||
})
|
||||
|
||||
it('converts config object', () => {
|
||||
@@ -125,7 +118,7 @@ describe('util', () => {
|
||||
},
|
||||
}
|
||||
|
||||
snapshot('config_as_object 1', normalizeModuleOptions(options))
|
||||
snapshot('config_as_object 1', util.normalizeModuleOptions(options))
|
||||
})
|
||||
|
||||
it('converts reporterOptions object', () => {
|
||||
@@ -136,7 +129,7 @@ describe('util', () => {
|
||||
},
|
||||
}
|
||||
|
||||
snapshot('reporter_options_as_object 1', normalizeModuleOptions(options))
|
||||
snapshot('reporter_options_as_object 1', util.normalizeModuleOptions(options))
|
||||
})
|
||||
|
||||
it('converts specs array', () => {
|
||||
@@ -146,7 +139,7 @@ describe('util', () => {
|
||||
],
|
||||
}
|
||||
|
||||
snapshot('spec_as_array 1', normalizeModuleOptions(options))
|
||||
snapshot('spec_as_array 1', util.normalizeModuleOptions(options))
|
||||
})
|
||||
|
||||
it('does not convert spec when string', () => {
|
||||
@@ -154,7 +147,7 @@ describe('util', () => {
|
||||
spec: 'x,y,z',
|
||||
}
|
||||
|
||||
snapshot('spec_as_string 1', normalizeModuleOptions(options))
|
||||
snapshot('spec_as_string 1', util.normalizeModuleOptions(options))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -197,7 +190,7 @@ describe('util', () => {
|
||||
sinon.stub(supportsColor, 'stdout').value({})
|
||||
sinon.stub(supportsColor, 'stderr').value({})
|
||||
|
||||
expect(util.supportsColor()).to.be.FALSE
|
||||
expect(util.supportsColor()).to.be.false
|
||||
})
|
||||
})
|
||||
|
||||
@@ -216,8 +209,9 @@ describe('util', () => {
|
||||
MOCHA_COLORS: '1',
|
||||
})
|
||||
|
||||
util.supportsColor.returns(false)
|
||||
tty.isatty.returns(false)
|
||||
;(util.supportsColor as any).returns(false)
|
||||
|
||||
;(tty.isatty as any).returns(false)
|
||||
|
||||
expect(util.getEnvOverrides()).to.deep.eq({
|
||||
FORCE_STDIN_TTY: '0',
|
||||
@@ -242,7 +236,7 @@ describe('util', () => {
|
||||
FORCE_STDERR_TTY: true,
|
||||
})
|
||||
|
||||
tty.isatty
|
||||
;(tty.isatty as any)
|
||||
.withArgs(0).returns(false)
|
||||
.withArgs(1).returns(false)
|
||||
.withArgs(2).returns(false)
|
||||
@@ -256,7 +250,7 @@ describe('util', () => {
|
||||
})
|
||||
|
||||
context('.getOriginalNodeOptions', () => {
|
||||
let restoreEnv
|
||||
let restoreEnv: any
|
||||
const sandbox = sinon.createSandbox()
|
||||
|
||||
afterEach(() => {
|
||||
@@ -282,7 +276,7 @@ describe('util', () => {
|
||||
|
||||
context('.exit', () => {
|
||||
it('calls process.exit', () => {
|
||||
process.exit.withArgs(2).withArgs(0)
|
||||
(process.exit as any).withArgs(2).withArgs(0)
|
||||
util.exit(2)
|
||||
util.exit(0)
|
||||
})
|
||||
@@ -292,8 +286,9 @@ describe('util', () => {
|
||||
it('calls logger.error and process.exit', () => {
|
||||
const err = new Error('foo')
|
||||
|
||||
logger.error.withArgs('foo')
|
||||
process.exit.withArgs(1)
|
||||
;(logger.error as any).withArgs('foo')
|
||||
|
||||
;(process.exit as any).withArgs(1)
|
||||
|
||||
util.logErrorExit1(err)
|
||||
})
|
||||
@@ -350,7 +345,7 @@ describe('util', () => {
|
||||
it('does nothing if debug is not enabled', () => {
|
||||
const log = sinon.spy()
|
||||
|
||||
log.enabled = false
|
||||
;(log as any).enabled = false
|
||||
util.printNodeOptions(log)
|
||||
expect(log).not.have.been.called
|
||||
})
|
||||
@@ -358,7 +353,7 @@ describe('util', () => {
|
||||
it('prints message when debug is enabled', () => {
|
||||
const log = sinon.spy()
|
||||
|
||||
log.enabled = true
|
||||
;(log as any).enabled = true
|
||||
util.printNodeOptions(log)
|
||||
expect(log).to.be.calledWith('NODE_OPTIONS is not set')
|
||||
})
|
||||
@@ -372,7 +367,7 @@ describe('util', () => {
|
||||
it('does nothing if debug is not enabled', () => {
|
||||
const log = sinon.spy()
|
||||
|
||||
log.enabled = false
|
||||
;(log as any).enabled = false
|
||||
util.printNodeOptions(log)
|
||||
expect(log).not.have.been.called
|
||||
})
|
||||
@@ -380,7 +375,7 @@ describe('util', () => {
|
||||
it('prints value when debug is enabled', () => {
|
||||
const log = sinon.spy()
|
||||
|
||||
log.enabled = true
|
||||
;(log as any).enabled = true
|
||||
util.printNodeOptions(log)
|
||||
expect(log).to.be.calledWith('NODE_OPTIONS=%s', 'foo')
|
||||
})
|
||||
@@ -393,13 +388,16 @@ describe('util', () => {
|
||||
osInfo: sinon.stub(),
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
util = proxyquire(`${lib}/util`, { systeminformation })
|
||||
beforeEach(async () => {
|
||||
const proxyquire = await import('proxyquire')
|
||||
|
||||
util = proxyquire.default(`../../lib/util`, { systeminformation }).default
|
||||
})
|
||||
|
||||
it('calls os.release when systeminformation fails', () => {
|
||||
os.platform.returns('darwin')
|
||||
os.release.returns('some-release')
|
||||
(os.platform as any).returns('darwin')
|
||||
|
||||
;(os.release as any).returns('some-release')
|
||||
systeminformation.osInfo.rejects(new Error('systeminformation failed'))
|
||||
|
||||
return util.getOsVersionAsync()
|
||||
@@ -410,7 +408,7 @@ describe('util', () => {
|
||||
})
|
||||
|
||||
it('uses systeminformation when it succeeds', () => {
|
||||
os.platform.returns('linux')
|
||||
(os.platform as any).returns('linux')
|
||||
systeminformation.osInfo.resolves({
|
||||
distro: 'Ubuntu',
|
||||
release: '22.04',
|
||||
@@ -426,8 +424,10 @@ describe('util', () => {
|
||||
})
|
||||
|
||||
it('falls back to os.release when systeminformation returns incomplete data', () => {
|
||||
os.platform.returns('linux')
|
||||
os.release.returns('5.15.0')
|
||||
(os.platform as any).returns('linux')
|
||||
|
||||
;(os.release as any).returns('5.15.0')
|
||||
|
||||
systeminformation.osInfo.resolves({
|
||||
distro: 'Ubuntu',
|
||||
// missing release property
|
||||
@@ -1,17 +1,20 @@
|
||||
const _ = require('lodash')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const sinon = require('sinon')
|
||||
const mockfs = require('mock-fs')
|
||||
const Promise = require('bluebird')
|
||||
const util = require('../lib/util')
|
||||
const nock = require('nock')
|
||||
const { MockChildProcess } = require('spawn-mock')
|
||||
import _ from 'lodash'
|
||||
import os from 'os'
|
||||
import sinon from 'sinon'
|
||||
import mockfs from 'mock-fs'
|
||||
import Bluebird from 'bluebird'
|
||||
import util from '../lib/util'
|
||||
import nock from 'nock'
|
||||
import { MockChildProcess } from 'spawn-mock'
|
||||
import chai from 'chai'
|
||||
import chaiAsPromised from 'chai-as-promised'
|
||||
import chaiString from 'chai-string'
|
||||
import sinonChai from '@cypress/sinon-chai'
|
||||
|
||||
const _kill = MockChildProcess.prototype.kill
|
||||
|
||||
const patchMockSpawn = () => {
|
||||
MockChildProcess.prototype.kill = function (...args) {
|
||||
const patchMockSpawn = (): void => {
|
||||
MockChildProcess.prototype.kill = function (...args: any[]): any {
|
||||
this.emit('exit')
|
||||
|
||||
return _kill.apply(this, args)
|
||||
@@ -20,16 +23,23 @@ const patchMockSpawn = () => {
|
||||
|
||||
patchMockSpawn()
|
||||
|
||||
global.sinon = sinon
|
||||
global.expect = require('chai').expect
|
||||
global.lib = path.join(__dirname, '..', 'lib')
|
||||
// Set up global variables for test environment
|
||||
declare global {
|
||||
const sinon: typeof import('sinon')
|
||||
const expect: typeof import('chai').expect
|
||||
const lib: string
|
||||
}
|
||||
|
||||
require('chai')
|
||||
.use(require('@cypress/sinon-chai'))
|
||||
.use(require('chai-string'))
|
||||
.use(require('chai-as-promised'))
|
||||
(global as any).sinon = sinon
|
||||
|
||||
sinon.usingPromise(Promise)
|
||||
;(global as any).expect = chai.expect
|
||||
|
||||
chai
|
||||
.use(sinonChai)
|
||||
.use(chaiString)
|
||||
.use(chaiAsPromised)
|
||||
|
||||
sinon.usingPromise(Bluebird as any)
|
||||
|
||||
delete process.env.CYPRESS_RUN_BINARY
|
||||
delete process.env.CYPRESS_INSTALL_BINARY
|
||||
@@ -42,10 +52,10 @@ process.env.npm_config_loglevel = 'notice'
|
||||
|
||||
const env = _.clone(process.env)
|
||||
|
||||
function throwIfFnNotStubbed (stub, method) {
|
||||
function throwIfFnNotStubbed (stub: any, method: string): void {
|
||||
const sig = `.${method}(...)`
|
||||
|
||||
stub.callsFake(function (...args) {
|
||||
stub.callsFake(function (...args: any[]): void {
|
||||
const err = new Error(`${sig} was called without being stubbed.
|
||||
|
||||
${sig} was called with arguments:
|
||||
@@ -56,7 +66,7 @@ function throwIfFnNotStubbed (stub, method) {
|
||||
err.stack = _
|
||||
.chain(err.stack)
|
||||
.split('\n')
|
||||
.reject((str) => {
|
||||
.reject((str: string) => {
|
||||
return _.includes(str, 'sinon')
|
||||
})
|
||||
.join('\n')
|
||||
@@ -68,9 +78,9 @@ function throwIfFnNotStubbed (stub, method) {
|
||||
|
||||
const $stub = sinon.stub
|
||||
|
||||
sinon.stub = function (obj, method) {
|
||||
sinon.stub = function (obj?: any, method?: string): any {
|
||||
/* eslint-disable prefer-rest-params */
|
||||
const stub = $stub.apply(this, arguments)
|
||||
const stub = $stub.apply(this, arguments as any)
|
||||
|
||||
let fns = [method]
|
||||
|
||||
@@ -84,7 +94,7 @@ sinon.stub = function (obj, method) {
|
||||
return stub
|
||||
}
|
||||
|
||||
fns.forEach((name) => {
|
||||
fns.forEach((name: string) => {
|
||||
const fn = obj[name]
|
||||
|
||||
if (_.isFunction(fn)) {
|
||||
@@ -95,19 +105,20 @@ sinon.stub = function (obj, method) {
|
||||
return stub
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(function (): void {
|
||||
sinon.stub(os, 'platform')
|
||||
sinon.stub(os, 'arch')
|
||||
sinon.stub(os, 'release')
|
||||
sinon.stub(util, 'getOsVersionAsync').resolves('Foo-OsVersion')
|
||||
|
||||
os.arch.returns('x64')
|
||||
;(os.arch as any).returns('x64')
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
afterEach(function (): void {
|
||||
mockfs.restore()
|
||||
process.env = _.clone(env)
|
||||
sinon.restore()
|
||||
nock.cleanAll()
|
||||
util._cachedArch = undefined
|
||||
|
||||
;(util as any)._cachedArch = undefined
|
||||
})
|
||||
@@ -1,10 +1,10 @@
|
||||
const stripAnsi = require('strip-ansi')
|
||||
import stripAnsi from 'strip-ansi'
|
||||
|
||||
const whitespaceAtEndOfLineRe = /\s+$/g
|
||||
const datesRe = /(\d+:\d+:\d+)/g
|
||||
const downloadQueryRe = /(\?platform=(darwin|linux|win32)&arch=x64)/
|
||||
|
||||
const removeExcessWhiteSpace = (str) => {
|
||||
const removeExcessWhiteSpace = (str: string): string => {
|
||||
return str.replace(whitespaceAtEndOfLineRe, '')
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ const removeExcessWhiteSpace = (str) => {
|
||||
* @param {string} str input string
|
||||
* @returns {string} cleaned output string
|
||||
*/
|
||||
const normalize = (str) => {
|
||||
const normalize = (str: string): string => {
|
||||
return stripAnsi(
|
||||
str
|
||||
.replace(datesRe, 'xx:xx:xx')
|
||||
@@ -24,4 +24,4 @@ const normalize = (str) => {
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = normalize
|
||||
export default normalize
|
||||
@@ -1,9 +0,0 @@
|
||||
const _snapshot = require('snap-shot-it')
|
||||
const mockfs = require('mock-fs')
|
||||
|
||||
const snapshot = (...args) => {
|
||||
mockfs.restore()
|
||||
_snapshot(...args)
|
||||
}
|
||||
|
||||
module.exports = snapshot
|
||||
12
cli/test/support/snapshot.ts
Normal file
12
cli/test/support/snapshot.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import _snapshot from 'snap-shot-it'
|
||||
import mockfs from 'mock-fs'
|
||||
|
||||
// Type as any to avoid strict typing issues with rest parameters
|
||||
const snapshotAny: any = _snapshot
|
||||
|
||||
const snapshot = (...args: any[]): void => {
|
||||
mockfs.restore()
|
||||
snapshotAny(...args)
|
||||
}
|
||||
|
||||
export default snapshot
|
||||
@@ -1,12 +0,0 @@
|
||||
const spawnMock = require('spawn-mock')
|
||||
|
||||
module.exports = {
|
||||
mockSpawn (cb) {
|
||||
return spawnMock.mockSpawn((cp) => {
|
||||
// execa expects .cancel to exist
|
||||
cp.cancel = sinon.stub()
|
||||
|
||||
return cb(cp)
|
||||
})
|
||||
},
|
||||
}
|
||||
15
cli/test/support/spawn-mock.ts
Normal file
15
cli/test/support/spawn-mock.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import spawnMock from 'spawn-mock'
|
||||
|
||||
// sinon is assumed to be available globally in test environment
|
||||
declare const sinon: any
|
||||
|
||||
export default {
|
||||
mockSpawn (cb: (cp: any) => any): any {
|
||||
return spawnMock.mockSpawn((cp: any) => {
|
||||
// execa expects .cancel to exist
|
||||
cp.cancel = sinon.stub()
|
||||
|
||||
return cb(cp)
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
const _write = process.stdout.write
|
||||
|
||||
module.exports = {
|
||||
capture () {
|
||||
const logs = []
|
||||
|
||||
const write = process.stdout.write
|
||||
|
||||
process.stdout.write = function (str) {
|
||||
logs.push(str)
|
||||
|
||||
/* eslint-disable prefer-rest-params */
|
||||
write.apply(this, arguments)
|
||||
}
|
||||
|
||||
return {
|
||||
data: logs,
|
||||
|
||||
toString: () => {
|
||||
return logs.join('')
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
restore () {
|
||||
process.stdout.write = _write
|
||||
},
|
||||
}
|
||||
30
cli/test/support/stdout.ts
Normal file
30
cli/test/support/stdout.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
const _write = process.stdout.write
|
||||
|
||||
const stdoutModule = {
|
||||
capture (): { data: string[], toString: () => string } {
|
||||
const logs: string[] = []
|
||||
|
||||
const write = process.stdout.write
|
||||
|
||||
process.stdout.write = function (str: any): boolean {
|
||||
logs.push(str)
|
||||
|
||||
/* eslint-disable prefer-rest-params */
|
||||
return write.apply(this, arguments as any)
|
||||
}
|
||||
|
||||
return {
|
||||
data: logs,
|
||||
|
||||
toString: (): string => {
|
||||
return logs.join('')
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
restore (): void {
|
||||
process.stdout.write = _write
|
||||
},
|
||||
}
|
||||
|
||||
export default stdoutModule
|
||||
10
cli/test/tsconfig.json
Normal file
10
cli/test/tsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true,
|
||||
"noImplicitAny": false,
|
||||
"types": [
|
||||
"mocha", "chai", "sinon"
|
||||
]
|
||||
}
|
||||
}
|
||||
22
cli/tsconfig.json
Normal file
22
cli/tsconfig.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
"module": "commonjs", /* Specify what module code is generated. */
|
||||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
|
||||
"noImplicitAny": false,
|
||||
"types": [
|
||||
"mocha"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"index.ts",
|
||||
"lib/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"types",
|
||||
"scripts"
|
||||
]
|
||||
}
|
||||
@@ -62,7 +62,7 @@
|
||||
"server-destroy": "1.0.1",
|
||||
"simple-git": "^3.27.0",
|
||||
"stringify-object": "^3.0.0",
|
||||
"tsx": "4.19.3",
|
||||
"tsx": "4.20.4",
|
||||
"underscore.string": "^3.3.6",
|
||||
"wonka": "^4.0.15"
|
||||
},
|
||||
|
||||
@@ -66,7 +66,6 @@ describe('ProjectConfigIpc', () => {
|
||||
|
||||
PROJECTS.forEach((project) => {
|
||||
it(`${project}: tsx generic loader (esm/commonjs/typescript)`, async () => {
|
||||
// @ts-expect-error ignoring due to nested directories in the system-test project directory not being included in the type.
|
||||
const projectPath = await scaffoldProject(project)
|
||||
|
||||
projectConfigIpc = new ProjectConfigIpc(
|
||||
|
||||
@@ -113,9 +113,9 @@ async function makeE2ETasks () {
|
||||
const Fixtures = require('@tooling/system-tests') as FixturesShape
|
||||
const { scaffoldCommonNodeModules, scaffoldProjectNodeModules } = require('@tooling/system-tests/lib/dep-installer')
|
||||
|
||||
const cli = require('../../../../cli/lib/cli')
|
||||
const cliUtil = require('../../../../cli/lib/util')
|
||||
const cliOpen = require('../../../../cli/lib/exec/open')
|
||||
const cli = require('../../../../cli/lib/cli').default
|
||||
const cliUtil = require('../../../../cli/lib/util').default
|
||||
const cliOpen = require('../../../../cli/lib/exec/open').default
|
||||
|
||||
// Remove all the fixtures when the plugin starts
|
||||
Fixtures.remove()
|
||||
|
||||
@@ -21,7 +21,7 @@ const {
|
||||
getIndexJscHash,
|
||||
DUMMY_INDEX_JSC_HASH,
|
||||
} = require('./binary/binary-sources')
|
||||
const verify = require('../cli/lib/tasks/verify')
|
||||
const verify = require('../cli/lib/tasks/verify').default
|
||||
const execa = require('execa')
|
||||
const meta = require('./binary/meta')
|
||||
|
||||
|
||||
@@ -23,9 +23,9 @@ const uploadUtils = require('./util/upload')
|
||||
const { uploadArtifactToS3 } = require('./upload-build-artifact')
|
||||
const { moveBinaries } = require('./move-binaries')
|
||||
const { exec } = require('child_process')
|
||||
const xvfb = require('../../cli/lib/exec/xvfb')
|
||||
const xvfb = require('../../cli/lib/exec/xvfb').default
|
||||
const smoke = require('./smoke')
|
||||
const verify = require('../../cli/lib/tasks/verify')
|
||||
const verify = require('../../cli/lib/tasks/verify').default
|
||||
const execa = require('execa')
|
||||
|
||||
const log = function (msg) {
|
||||
|
||||
@@ -5,7 +5,7 @@ const execa = require('execa')
|
||||
const path = require('path')
|
||||
const Promise = require('bluebird')
|
||||
const os = require('os')
|
||||
const verify = require('../../cli/lib/tasks/verify')
|
||||
const verify = require('../../cli/lib/tasks/verify').default
|
||||
const Fixtures = require('@tooling/system-tests')
|
||||
const { scaffoldCommonNodeModules } = require('@tooling/system-tests/lib/dep-installer')
|
||||
|
||||
|
||||
40
yarn.lock
40
yarn.lock
@@ -1495,22 +1495,6 @@
|
||||
"@smithy/types" "^2.8.0"
|
||||
tslib "^2.5.0"
|
||||
|
||||
"@babel/cli@7.28.0":
|
||||
version "7.28.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.28.0.tgz#26959456cbedff569a2c3ac909e8a268ca6cb7e2"
|
||||
integrity sha512-CYrZG7FagtE8ReKDBfItxnrEBf2khq2eTMnPuqO8UVN0wzhp1eMX1wfda8b1a32l2aqYLwRRIOGNovm8FVzmMw==
|
||||
dependencies:
|
||||
"@jridgewell/trace-mapping" "^0.3.28"
|
||||
commander "^6.2.0"
|
||||
convert-source-map "^2.0.0"
|
||||
fs-readdir-recursive "^1.1.0"
|
||||
glob "^7.2.0"
|
||||
make-dir "^2.1.0"
|
||||
slash "^2.0.0"
|
||||
optionalDependencies:
|
||||
"@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3"
|
||||
chokidar "^3.6.0"
|
||||
|
||||
"@babel/code-frame@7.27.1", "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.26.2", "@babel/code-frame@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be"
|
||||
@@ -5132,11 +5116,6 @@
|
||||
"@emnapi/runtime" "^1.4.3"
|
||||
"@tybys/wasm-util" "^0.10.0"
|
||||
|
||||
"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3":
|
||||
version "2.1.8-no-fsevents.3"
|
||||
resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b"
|
||||
integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==
|
||||
|
||||
"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1":
|
||||
version "5.1.1-v1"
|
||||
resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129"
|
||||
@@ -12951,7 +12930,7 @@ commander@2.x.x, commander@^2.12.1, commander@^2.18.0, commander@^2.20.0:
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||
|
||||
commander@6.2.1, commander@^6.1.0, commander@^6.2.0, commander@^6.2.1:
|
||||
commander@6.2.1, commander@^6.1.0, commander@^6.2.1:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
|
||||
integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
|
||||
@@ -17466,11 +17445,6 @@ fs-monkey@^1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.6.tgz#8ead082953e88d992cf3ff844faa907b26756da2"
|
||||
integrity sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==
|
||||
|
||||
fs-readdir-recursive@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27"
|
||||
integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
@@ -18040,7 +18014,7 @@ glob@^11.0.0:
|
||||
package-json-from-dist "^1.0.0"
|
||||
path-scurry "^2.0.0"
|
||||
|
||||
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0:
|
||||
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
|
||||
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
|
||||
@@ -31089,10 +31063,10 @@ tsutils@^2.29.0:
|
||||
dependencies:
|
||||
tslib "^1.8.1"
|
||||
|
||||
tsx@4.19.3:
|
||||
version "4.19.3"
|
||||
resolved "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz#2bdbcb87089374d933596f8645615142ed727666"
|
||||
integrity sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==
|
||||
tsx@4.20.4:
|
||||
version "4.20.4"
|
||||
resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.20.4.tgz#3fcf255dbc8826bdde2820f1cff47e31075c1d30"
|
||||
integrity sha512-yyxBKfORQ7LuRt/BQKBXrpcq59ZvSW0XxwfjAt3w2/8PmdxaFzijtMhTawprSHhpzeM5BgU2hXHG3lklIERZXg==
|
||||
dependencies:
|
||||
esbuild "~0.25.0"
|
||||
get-tsconfig "^4.7.5"
|
||||
@@ -31327,7 +31301,7 @@ typescript@5.4.5, typescript@~5.4.5:
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611"
|
||||
integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==
|
||||
|
||||
"typescript@>=3 < 6", typescript@^5.4.3, typescript@^5.8.2:
|
||||
"typescript@>=3 < 6", typescript@^5.4.3, typescript@^5.8.2, typescript@~5.9.2:
|
||||
version "5.9.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.2.tgz#d93450cddec5154a2d5cabe3b8102b83316fb2a6"
|
||||
integrity sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==
|
||||
|
||||
Reference in New Issue
Block a user