mirror of
https://github.com/cypress-io/cypress.git
synced 2026-05-06 15:00:50 -05:00
[internal] Lint typescript, json, new eslint rules (#4449)
* temp 07/01/19 [skip ci] main lint files * use lint-staged scripts * fix all auto-fixable eslint errors * manually fix lint issues in files * temp 07/01/19 [skip ci] * bump eslint plugin versions, update circle.yml * [lint fix] remaining js files * update vscode/settings.json * add back stop-only * use stop-only for linting .onlys * fix verify_spec, build_spec * update json plugin * relint & apply corrections * fix appveyor.yml not cleansing env vars (very bad) * dont echo commit message in appveyor script * retry build & * re-add & upgrade lint-staged * update contributing docs * only let stop-only catch staged changes
This commit is contained in:
+25
-3
@@ -1,6 +1,28 @@
|
||||
__snapshots__
|
||||
# unignore hidden files
|
||||
!.*
|
||||
|
||||
**/__snapshots__
|
||||
**/build
|
||||
**/cypress/fixtures
|
||||
**/dist
|
||||
**/dist-test
|
||||
**/node_modules
|
||||
**/support/fixtures
|
||||
**/test/fixtures
|
||||
**/vendor
|
||||
|
||||
# cli/types is linted by tslint/dtslint
|
||||
cli/types
|
||||
# packages/example is not linted (think about changing this)
|
||||
packages/example
|
||||
|
||||
packages/extension/test/helpers/background.js
|
||||
packages/server/lib/scaffold/plugins/index.js
|
||||
packages/server/lib/scaffold/support/index.js
|
||||
packages/server/lib/scaffold/support/commands.js
|
||||
packages/server/test/fixtures
|
||||
packages/example/cypress
|
||||
|
||||
packages/launcher/lib/**/*.js
|
||||
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/.vscode
|
||||
|
||||
@@ -1,72 +1,9 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:cypress-dev/general"
|
||||
"plugins": [
|
||||
"@cypress/dev"
|
||||
],
|
||||
"rules": {
|
||||
"no-multiple-empty-lines": ["error", { "max": 1 } ],
|
||||
"no-else-return": [ "error", { "allowElseIf": false } ],
|
||||
"brace-style": ["error", "1tbs", { "allowSingleLine": false }],
|
||||
"no-unneeded-ternary": ["error"],
|
||||
"array-bracket-newline": ["error", "consistent"],
|
||||
"arrow-body-style": ["error", "always"],
|
||||
"padding-line-between-statements": [
|
||||
"error",
|
||||
{
|
||||
"blankLine": "always",
|
||||
"prev": "*",
|
||||
"next": "return"
|
||||
},
|
||||
{
|
||||
"blankLine": "always",
|
||||
"prev": [
|
||||
"const",
|
||||
"let",
|
||||
"var",
|
||||
"if",
|
||||
"while",
|
||||
"export",
|
||||
"cjs-export",
|
||||
"import",
|
||||
"cjs-import"
|
||||
],
|
||||
"next": "*"
|
||||
},
|
||||
{
|
||||
"blankLine": "any",
|
||||
"prev": [
|
||||
"const",
|
||||
"let",
|
||||
"var",
|
||||
"import",
|
||||
"cjs-import"
|
||||
],
|
||||
"next": [
|
||||
"const",
|
||||
"let",
|
||||
"var",
|
||||
"import",
|
||||
"cjs-import"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"env": {
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"legacyDecorators": true
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"**/*.jsx"
|
||||
],
|
||||
"rules": {
|
||||
"arrow-body-style": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
"extends": [
|
||||
"plugin:@cypress/dev/general"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ _test-output
|
||||
cypress.zip
|
||||
tmp/
|
||||
.nyc_output
|
||||
.vscode/settings.json
|
||||
|
||||
# from extension
|
||||
Cached Theme.pak
|
||||
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"eslint.validate": [
|
||||
{
|
||||
"language": "javascript",
|
||||
"autoFix": true
|
||||
},
|
||||
{
|
||||
"language": "javascriptreact",
|
||||
"autoFix": true
|
||||
},
|
||||
{
|
||||
"language": "typescript",
|
||||
"autoFix": true
|
||||
},
|
||||
{
|
||||
"language": "typescriptreact",
|
||||
"autoFix": true
|
||||
},
|
||||
{
|
||||
"language": "json",
|
||||
"autoFix": true
|
||||
},
|
||||
{
|
||||
"language": "coffeescript",
|
||||
"autoFix": false
|
||||
},
|
||||
],
|
||||
}
|
||||
+5
-4
@@ -354,15 +354,16 @@ DEBUG=cypress:launcher
|
||||
### Coding Style
|
||||
|
||||
We use [eslint](https://eslint.org/) to lint all JavaScript code and follow rules specified in
|
||||
[eslint-plugin-cypress-dev](https://github.com/cypress-io/eslint-plugin-cypress-dev) plugin.
|
||||
[@cypress/eslint-plugin-dev](https://github.com/cypress-io/cypress-eslint-plugin-dev) plugin.
|
||||
|
||||
When you edit files, you can quickly fix all changed files before committing using
|
||||
When you edit files, you can quickly fix all changed files before you commit using
|
||||
|
||||
```bash
|
||||
npm run lint-changed
|
||||
npm run lint-changed-fix
|
||||
```
|
||||
|
||||
When committing files, we run Git pre-commit hook to fix the staged JS files. See the `precommit-lint` script in [package.json](package.json). This might change JS files and you would need to commit the changes again.
|
||||
When committing files, we run a Git pre-commit hook to lint the staged JS files. See the [`lint-staged` project](https://github.com/okonet/lint-staged).
|
||||
If this command fails, you may need to run `npm run lint-changed-fix` and commit those changes.
|
||||
|
||||
### Tests
|
||||
|
||||
|
||||
+1
-3
@@ -78,11 +78,9 @@ install:
|
||||
# Post-install test scripts.
|
||||
test_script:
|
||||
# Output useful info for debugging.
|
||||
# beware of echo-ing environment variables that may have batch syntax (e.g. commit messages)
|
||||
- node --version
|
||||
- npm --version
|
||||
- echo Commit message
|
||||
- echo %APPVEYOR_REPO_COMMIT_MESSAGE%
|
||||
- echo body of commit message, if any
|
||||
- 7z
|
||||
- cd packages/launcher && node index.js && cd ../..
|
||||
# make sure mocha runs
|
||||
|
||||
+5
-5
@@ -189,7 +189,7 @@ jobs:
|
||||
paths:
|
||||
- packages/ts/node_modules
|
||||
|
||||
- run: npm run stop-only
|
||||
- run: npm run stop-only-all
|
||||
## now go build all of subpackages
|
||||
- run: npm run prebuild -- --serial
|
||||
- run: npm run build -- --serial
|
||||
@@ -205,8 +205,8 @@ jobs:
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run: npm run lint
|
||||
- run: npm run all lint
|
||||
## this will catch .only's in js/coffee as well
|
||||
- run: npm run lint-all
|
||||
|
||||
unit-tests:
|
||||
<<: *defaults
|
||||
@@ -237,7 +237,7 @@ jobs:
|
||||
- store_test_results:
|
||||
path: /tmp/cypress
|
||||
|
||||
lint-typescript:
|
||||
lint-types:
|
||||
<<: *defaults
|
||||
parallelism: 1
|
||||
steps:
|
||||
@@ -723,7 +723,7 @@ linux-workflow: &linux-workflow
|
||||
name: Linux lint
|
||||
requires:
|
||||
- build
|
||||
- lint-typescript:
|
||||
- lint-types:
|
||||
requires:
|
||||
- build
|
||||
# unit, integration and e2e tests
|
||||
|
||||
@@ -14,19 +14,19 @@ exports['package.json build outputs expected properties 1'] = {
|
||||
"url": "https://github.com/cypress-io/cypress.git"
|
||||
},
|
||||
"keywords": [
|
||||
"automation",
|
||||
"browser",
|
||||
"cypress",
|
||||
"cypress.io",
|
||||
"automation",
|
||||
"end-to-end",
|
||||
"e2e",
|
||||
"end-to-end",
|
||||
"integration",
|
||||
"mocks",
|
||||
"test",
|
||||
"testing",
|
||||
"runner",
|
||||
"spies",
|
||||
"stubs"
|
||||
"stubs",
|
||||
"test",
|
||||
"testing"
|
||||
],
|
||||
"types": "types",
|
||||
"scripts": {
|
||||
|
||||
+2
-2
@@ -40,6 +40,7 @@ const spaceDelimitedSpecsMsg = (files) => {
|
||||
If you are trying to pass multiple spec filenames, separate them by commas instead:
|
||||
cypress run --spec spec1,spec2,spec3
|
||||
`)
|
||||
|
||||
logger.log()
|
||||
}
|
||||
|
||||
@@ -73,8 +74,7 @@ const parseOpts = (opts) => {
|
||||
'project', 'spec', 'reporter', 'reporterOptions', 'path', 'destination',
|
||||
'port', 'env', 'cypressVersion', 'config', 'record', 'key',
|
||||
'browser', 'detached', 'headed', 'global', 'dev', 'force', 'exit',
|
||||
'cachePath', 'cacheList', 'cacheClear', 'parallel', 'group', 'ciBuildId'
|
||||
)
|
||||
'cachePath', 'cacheList', 'cacheClear', 'parallel', 'group', 'ciBuildId')
|
||||
|
||||
if (opts.exit) {
|
||||
opts = _.omit(opts, 'exit')
|
||||
|
||||
@@ -111,7 +111,8 @@ const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => {
|
||||
debug(text)
|
||||
|
||||
throw new Error(text)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (expectedChecksum) {
|
||||
@@ -211,6 +212,7 @@ const downloadFromUrl = ({ url, downloadDestination, progress }) => {
|
||||
// see https://github.com/cypress-io/cypress/pull/4092
|
||||
expectedSize = response.headers['x-amz-meta-size'] ||
|
||||
response.headers['content-length']
|
||||
|
||||
expectedChecksum = response.headers['x-amz-meta-checksum']
|
||||
|
||||
if (expectedChecksum) {
|
||||
@@ -274,9 +276,11 @@ const downloadFromUrl = ({ url, downloadDestination, progress }) => {
|
||||
* @param [string] version Could be "3.3.0" or full URL
|
||||
* @param [string] downloadDestination Local filename to save as
|
||||
*/
|
||||
const start = ({ version, downloadDestination, progress }) => {
|
||||
const start = (opts) => {
|
||||
let { version, downloadDestination, progress } = opts
|
||||
|
||||
if (!downloadDestination) {
|
||||
la(is.unemptyString(downloadDestination), 'missing download dir', arguments)
|
||||
la(is.unemptyString(downloadDestination), 'missing download dir', opts)
|
||||
}
|
||||
|
||||
if (!progress) {
|
||||
|
||||
@@ -164,7 +164,9 @@ const start = (options = {}) => {
|
||||
debug('environment variable CYPRESS_INSTALL_BINARY = 0, skipping install')
|
||||
logger.log(
|
||||
stripIndent`
|
||||
${chalk.yellow('Note:')} Skipping binary installation: Environment variable CYPRESS_INSTALL_BINARY = 0.`)
|
||||
${chalk.yellow('Note:')} Skipping binary installation: Environment variable CYPRESS_INSTALL_BINARY = 0.`
|
||||
)
|
||||
|
||||
logger.log()
|
||||
|
||||
return Promise.resolve()
|
||||
@@ -187,7 +189,9 @@ const start = (options = {}) => {
|
||||
${chalk.yellow('Note:')} Overriding Cypress cache directory to: ${chalk.cyan(envCache)}
|
||||
|
||||
Previous installs of Cypress may not be found.
|
||||
`)
|
||||
`
|
||||
)
|
||||
|
||||
logger.log()
|
||||
}
|
||||
|
||||
@@ -220,6 +224,7 @@ const start = (options = {}) => {
|
||||
logger.log(stripIndent`
|
||||
Cypress ${chalk.green(binaryVersion)} is installed in ${chalk.cyan(installDir)}
|
||||
`)
|
||||
|
||||
logger.log()
|
||||
|
||||
if (options.force) {
|
||||
@@ -257,6 +262,7 @@ const start = (options = {}) => {
|
||||
These versions may not work properly together.
|
||||
`)
|
||||
)
|
||||
|
||||
logger.log()
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,8 @@ const writeBinaryVerifiedAsync = (verified, binaryDir) => {
|
||||
return fs.outputJsonAsync(
|
||||
getBinaryStatePath(binaryDir),
|
||||
_.extend(contents, { verified }),
|
||||
{ spaces: 2 })
|
||||
{ spaces: 2 }
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -260,6 +260,7 @@ const start = (options = {}) => {
|
||||
|
||||
This overrides the default Cypress binary path used.
|
||||
`)
|
||||
|
||||
logger.log()
|
||||
|
||||
return util.isExecutableAsync(envBinaryPath)
|
||||
|
||||
@@ -108,6 +108,7 @@ const logBrokenGtkDisplayWarning = () => {
|
||||
|
||||
Cypress will attempt to fix the problem and rerun.
|
||||
`)
|
||||
|
||||
logger.warn()
|
||||
}
|
||||
|
||||
|
||||
+25
-26
@@ -1,36 +1,34 @@
|
||||
{
|
||||
"name": "cypress",
|
||||
"version": "0.0.0",
|
||||
"main": "index.js",
|
||||
"private": true,
|
||||
"bin": {
|
||||
"cypress": "bin/cypress"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"lib",
|
||||
"index.js",
|
||||
"types/**/*.d.ts"
|
||||
],
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"prebuild": "npm run test-dependencies && node ./scripts/start-build.js",
|
||||
"build": "node ./scripts/build.js",
|
||||
"check-deps": "node ../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"dtslint": "dtslint types",
|
||||
"postinstall": "node ./scripts/post-install.js",
|
||||
"prerelease": "npm run build",
|
||||
"release": "cd build && releaser --no-node --no-changelog",
|
||||
"size": "t=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";",
|
||||
"pretest": "npm run check-deps-pre",
|
||||
"test": "npm run test-unit",
|
||||
"test-debug": "node --inspect --debug-brk $(bin-up _mocha)",
|
||||
"test-dependencies": "npm run check-deps && dependency-check . --no-dev",
|
||||
"pretest-unit": "npm run check-deps-pre",
|
||||
"test-unit": "npm run unit",
|
||||
"pretest-watch": "npm run check-deps-pre",
|
||||
"test-watch": "npm run unit -- --watch",
|
||||
"check-deps": "node ../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"test-dependencies": "npm run check-deps && dependency-check . --no-dev",
|
||||
"test-debug": "node --inspect --debug-brk $(bin-up _mocha)",
|
||||
"unit": "BLUEBIRD_DEBUG=1 NODE_ENV=test bin-up mocha --reporter mocha-multi-reporters --reporter-options configFile=../mocha-reporter-config.json",
|
||||
"lint": "bin-up eslint --fix *.js scripts/*.js bin/* lib/*.js lib/**/*.js test/*.js test/**/*.js",
|
||||
"dtslint": "dtslint types",
|
||||
"prebuild": "npm run test-dependencies && node ./scripts/start-build.js",
|
||||
"build": "node ./scripts/build.js",
|
||||
"prerelease": "npm run build",
|
||||
"release": "cd build && releaser --no-node --no-changelog",
|
||||
"size": "t=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";"
|
||||
"unit": "BLUEBIRD_DEBUG=1 NODE_ENV=test bin-up mocha --reporter mocha-multi-reporters --reporter-options configFile=../mocha-reporter-config.json"
|
||||
},
|
||||
"types": "types",
|
||||
"dependencies": {
|
||||
"@cypress/listr-verbose-renderer": "0.4.1",
|
||||
"@cypress/xvfb": "1.2.4",
|
||||
@@ -95,10 +93,11 @@
|
||||
"snap-shot-it": "7.7.1",
|
||||
"spawn-mock": "1.0.0"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"lib",
|
||||
"index.js",
|
||||
"types/**/*.d.ts"
|
||||
]
|
||||
"bin": {
|
||||
"cypress": "bin/cypress"
|
||||
},
|
||||
"types": "types",
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"baseUrl" : {
|
||||
"baseUrl": {
|
||||
"type": "string",
|
||||
"description": "Url used as prefix for cy.visit() or cy.request() command’s url. Example http://localhost:3030 or https://test.my-domain.com"
|
||||
},
|
||||
@@ -13,7 +13,10 @@
|
||||
"body": {}
|
||||
},
|
||||
"ignoreTestFiles": {
|
||||
"type": ["string", "array"],
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -79,13 +82,16 @@
|
||||
"default": 30000,
|
||||
"description": "Time, in milliseconds, to wait until a response in a cy.request(), cy.wait(), cy.fixture(), cy.getCookie(), cy.getCookies(), cy.setCookie(), cy.clearCookie(), cy.clearCookies(), and cy.screenshot() commands"
|
||||
},
|
||||
"fileServerFolder": {
|
||||
"fileServerFolder": {
|
||||
"type": "string",
|
||||
"default": "root project folder",
|
||||
"description": "Path to folder where application files will attempt to be served from"
|
||||
},
|
||||
"fixturesFolder": {
|
||||
"type": ["string", "boolean"],
|
||||
"type": [
|
||||
"string",
|
||||
"boolean"
|
||||
],
|
||||
"default": "cypress/fixtures",
|
||||
"description": "Path to folder containing fixture files (Pass false to disable)"
|
||||
},
|
||||
@@ -95,7 +101,10 @@
|
||||
"description": "Path to folder containing integration test files"
|
||||
},
|
||||
"pluginsFile": {
|
||||
"type": ["string", "boolean"],
|
||||
"type": [
|
||||
"string",
|
||||
"boolean"
|
||||
],
|
||||
"default": "cypress/plugins/index.js",
|
||||
"description": "Path to plugins file. (Pass false to disable)"
|
||||
},
|
||||
@@ -105,11 +114,14 @@
|
||||
"description": "Path to folder where screenshots will be saved from cy.screenshot() command or after a test fails during cypress run"
|
||||
},
|
||||
"supportFile": {
|
||||
"type": ["string", "boolean"],
|
||||
"type": [
|
||||
"string",
|
||||
"boolean"
|
||||
],
|
||||
"default": "cypress/support/index.js",
|
||||
"description": "Path to file to load before test files load. This file is compiled and bundled. (Pass false to disable)"
|
||||
},
|
||||
"videosFolder": {
|
||||
"videosFolder": {
|
||||
"type": "string",
|
||||
"default": "cypress/videos",
|
||||
"description": "Path to folder where videos will be saved during cypress run"
|
||||
@@ -119,8 +131,11 @@
|
||||
"default": true,
|
||||
"description": "Whether Cypress will trash assets within the screenshotsFolder and videosFolder before tests run with cypress run"
|
||||
},
|
||||
"videoCompression": {
|
||||
"type": ["number", "boolean"],
|
||||
"videoCompression": {
|
||||
"type": [
|
||||
"number",
|
||||
"boolean"
|
||||
],
|
||||
"default": 32,
|
||||
"description": "The quality setting for the video compression, in Constant Rate Factor (CRF). The value can be false to disable compression or a value between 0 and 51, where a lower value results in better quality (at the expense of a higher file size)."
|
||||
},
|
||||
@@ -145,7 +160,10 @@
|
||||
"description": "Enables you to override the default user agent the browser sends in all request headers. User agent values are typically used by servers to help identify the operating system, browser, and browser version. See User-Agent MDN Documentation for example user agent values here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent"
|
||||
},
|
||||
"blacklistHosts": {
|
||||
"type": ["string", "array"],
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -157,7 +175,7 @@
|
||||
"default": true,
|
||||
"description": "Whether Cypress will search for and replace obstructive JS code found in .js or .html files that prevent Cypress from working. Please read the notes for more information on this setting. https://on.cypress.io/configuration#modifyObstructiveCode"
|
||||
},
|
||||
"viewportHeight": {
|
||||
"viewportHeight": {
|
||||
"type": "number",
|
||||
"default": 660,
|
||||
"description": "Default height in pixels for the application under tests’ viewport (Override with cy.viewport() command)"
|
||||
@@ -167,7 +185,7 @@
|
||||
"default": 1000,
|
||||
"description": "Default width in pixels for the application under tests’ viewport. (Override with cy.viewport() command)"
|
||||
},
|
||||
"animationDistanceThreshold": {
|
||||
"animationDistanceThreshold": {
|
||||
"type": "number",
|
||||
"default": 5,
|
||||
"description": "The distance in pixels an element must exceed over time to be considered animating"
|
||||
|
||||
@@ -27,6 +27,7 @@ shell.sed(
|
||||
'<reference path="../chai/index.d.ts" />',
|
||||
join('types', 'chai-jquery', 'index.d.ts')
|
||||
)
|
||||
|
||||
shell.sed(
|
||||
'-i',
|
||||
'<reference types="jquery" />',
|
||||
@@ -42,6 +43,7 @@ shell.sed(
|
||||
'<reference path="../chai/index.d.ts" />',
|
||||
sinonChaiFilename
|
||||
)
|
||||
|
||||
// also use relative import via path for sinon-chai
|
||||
// there is reference comment line we need to fix to be relative
|
||||
shell.sed(
|
||||
@@ -50,5 +52,6 @@ shell.sed(
|
||||
'<reference path="../sinon/index.d.ts" />',
|
||||
sinonChaiFilename
|
||||
)
|
||||
|
||||
// and an import sinon line to be changed to relative path
|
||||
shell.sed('-i', 'from \'sinon\';', 'from \'../sinon\';', sinonChaiFilename)
|
||||
|
||||
+1
-1
@@ -4,6 +4,6 @@
|
||||
"sinon": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:cypress-dev/tests"
|
||||
"plugin:@cypress/dev/tests"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ describe('package.json build', () => {
|
||||
name: 'test',
|
||||
engines: 'test engines',
|
||||
})
|
||||
|
||||
sinon.stub(fs, 'outputJsonAsync').resolves()
|
||||
})
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ describe('cli', () => {
|
||||
beforeEach(() => {
|
||||
sinon.stub(state, 'getBinaryDir').returns(binaryDir)
|
||||
})
|
||||
|
||||
it('reports package version', (done) => {
|
||||
sinon.stub(util, 'pkgVersion').returns('1.2.3')
|
||||
sinon
|
||||
@@ -325,6 +326,7 @@ describe('cli', () => {
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
context('cypress verify', () => {
|
||||
it('verify calls verify.start with force: true', () => {
|
||||
sinon.stub(verify, 'start').resolves()
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"parserOptions": {
|
||||
"sourceType": "script"
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ describe('lib/exec/spawn', function () {
|
||||
on: sinon.stub().returns(undefined),
|
||||
},
|
||||
}
|
||||
|
||||
sinon.stub(process, 'stdin').value(new EE)
|
||||
sinon.stub(cp, 'spawn').returns(this.spawnedProcess)
|
||||
sinon.stub(xvfb, 'start').resolves()
|
||||
|
||||
@@ -10,6 +10,7 @@ describe('lib/exec/versions', function () {
|
||||
sinon.stub(state, 'getBinaryPkgVersionAsync').withArgs('/cache/1.2.3/Cypress.app').resolves('1.2.3')
|
||||
sinon.stub(util, 'pkgVersion').returns('4.5.6')
|
||||
})
|
||||
|
||||
describe('.getVersions', function () {
|
||||
it('gets the correct binary and package version', function () {
|
||||
return versions.getVersions().then(({ package, binary }) => {
|
||||
@@ -17,12 +18,14 @@ describe('lib/exec/versions', function () {
|
||||
expect(binary).to.eql('1.2.3')
|
||||
})
|
||||
})
|
||||
|
||||
it('gets correct binary version if CYPRESS_RUN_BINARY', function () {
|
||||
sinon.stub(state, 'parseRealPlatformBinaryFolderAsync').resolves('/my/cypress/path')
|
||||
process.env.CYPRESS_RUN_BINARY = '/my/cypress/path'
|
||||
state.getBinaryPkgVersionAsync
|
||||
.withArgs('/my/cypress/path')
|
||||
.resolves('7.8.9')
|
||||
|
||||
return versions.getVersions().then(({ package, binary }) => {
|
||||
expect(package).to.eql('4.5.6')
|
||||
expect(binary).to.eql('7.8.9')
|
||||
|
||||
@@ -20,6 +20,7 @@ describe('lib/tasks/cache', () => {
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
sinon.stub(state, 'getCacheDir').returns('/.cache/Cypress')
|
||||
this.stdout = stdout.capture()
|
||||
})
|
||||
@@ -37,6 +38,7 @@ describe('lib/tasks/cache', () => {
|
||||
expect(this.stdout.toString()).to.eql('/.cache/Cypress\n')
|
||||
})
|
||||
})
|
||||
|
||||
describe('.clear', () => {
|
||||
it('deletes cache folder and everything inside it', () => {
|
||||
return cache.clear()
|
||||
@@ -45,10 +47,10 @@ describe('lib/tasks/cache', () => {
|
||||
.then((exists) => {
|
||||
return expect(exists).to.eql(false)
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.list', () => {
|
||||
it('lists all versions of cached binary', () => {
|
||||
return cache.list()
|
||||
|
||||
@@ -164,6 +164,7 @@ describe('/lib/tasks/install', function () {
|
||||
mockfs({
|
||||
[version]: 'asdf',
|
||||
})
|
||||
|
||||
process.env.CYPRESS_INSTALL_BINARY = version
|
||||
|
||||
const installDir = state.getVersionDir()
|
||||
@@ -394,6 +395,7 @@ describe('/lib/tasks/install', function () {
|
||||
expect(download.start).to.not.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('uses cache when mismatch version given URL ', function () {
|
||||
state.getBinaryPkgVersionAsync.resolves('1.2.3')
|
||||
util.pkgVersion.returns('4.0.0')
|
||||
@@ -404,6 +406,7 @@ describe('/lib/tasks/install', function () {
|
||||
expect(download.start).to.not.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('uses cache when correct version installed given Zip', function () {
|
||||
sinon.stub(fs, 'pathExistsAsync').withArgs('/path/to/zip.zip').resolves(true)
|
||||
|
||||
@@ -417,6 +420,7 @@ describe('/lib/tasks/install', function () {
|
||||
expect(unzip.start).to.not.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('uses cache when mismatch version given Zip ', function () {
|
||||
sinon.stub(fs, 'pathExistsAsync').withArgs('/path/to/zip.zip').resolves(true)
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ describe('lib/tasks/state', function () {
|
||||
.stub(fs, 'pathExistsAsync')
|
||||
.withArgs(binaryPkgPath)
|
||||
.resolves(true)
|
||||
|
||||
sinon
|
||||
.stub(fs, 'readJsonAsync')
|
||||
.withArgs(binaryPkgPath)
|
||||
@@ -66,6 +67,7 @@ describe('lib/tasks/state', function () {
|
||||
.stub(fs, 'pathExistsAsync')
|
||||
.withArgs(customBinaryPackageDir)
|
||||
.resolves(true)
|
||||
|
||||
sinon
|
||||
.stub(fs, 'readJsonAsync')
|
||||
.withArgs(customBinaryPackageDir)
|
||||
@@ -88,6 +90,7 @@ describe('lib/tasks/state', function () {
|
||||
macExecutable
|
||||
)
|
||||
})
|
||||
|
||||
it('resolves path on linux', function () {
|
||||
os.platform.returns('linux')
|
||||
const linuxExecutable = '.cache/Cypress/1.2.3/Cypress/Cypress'
|
||||
@@ -96,10 +99,12 @@ describe('lib/tasks/state', function () {
|
||||
linuxExecutable
|
||||
)
|
||||
})
|
||||
|
||||
it('resolves path on windows', function () {
|
||||
os.platform.returns('win32')
|
||||
expect(state.getPathToExecutable(state.getBinaryDir())).to.endWith('.exe')
|
||||
})
|
||||
|
||||
it('resolves from custom binaryDir', function () {
|
||||
const customBinaryDir = 'home/downloads/cypress.app'
|
||||
|
||||
@@ -144,8 +149,7 @@ describe('lib/tasks/state', function () {
|
||||
os.platform.returns('unknown')
|
||||
expect(() => {
|
||||
return state.getBinaryDir().to.throw('Platform: "unknown" is not supported.')
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -159,6 +163,7 @@ describe('lib/tasks/state', function () {
|
||||
return expect(isVerified).to.be.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
it('resolves undefined if not verified', function () {
|
||||
const err = new Error()
|
||||
|
||||
@@ -171,6 +176,7 @@ describe('lib/tasks/state', function () {
|
||||
return expect(isVerified).to.be.equal(undefined)
|
||||
})
|
||||
})
|
||||
|
||||
it('can accept custom binaryDir', function () {
|
||||
const customBinaryDir = '/custom/binary/dir'
|
||||
|
||||
@@ -178,6 +184,7 @@ describe('lib/tasks/state', function () {
|
||||
.stub(fs, 'pathExistsAsync')
|
||||
.withArgs('/custom/binary/dir/binary_state.json')
|
||||
.resolves({ verified: true })
|
||||
|
||||
sinon
|
||||
.stub(fs, 'readJsonAsync')
|
||||
.withArgs('/custom/binary/dir/binary_state.json')
|
||||
@@ -190,13 +197,16 @@ describe('lib/tasks/state', function () {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('.writeBinaryVerified', function () {
|
||||
beforeEach(() => {
|
||||
mockfs({})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
mockfs.restore()
|
||||
})
|
||||
|
||||
it('writes to binary state verified:true', function () {
|
||||
sinon.stub(fs, 'outputJsonAsync').resolves()
|
||||
|
||||
@@ -224,10 +234,10 @@ describe('lib/tasks/state', function () {
|
||||
{ verified: false },
|
||||
{ spaces: 2 }
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('.getCacheDir', function () {
|
||||
it('uses cachedir()', function () {
|
||||
const ret = state.getCacheDir()
|
||||
@@ -249,6 +259,7 @@ describe('lib/tasks/state', function () {
|
||||
expect(ret).to.eql(path.resolve('local-cache/folder'))
|
||||
})
|
||||
})
|
||||
|
||||
context('.parseRealPlatformBinaryFolderAsync', function () {
|
||||
beforeEach(function () {
|
||||
sinon.stub(fs, 'realpathAsync').callsFake((path) => {
|
||||
@@ -267,6 +278,7 @@ describe('lib/tasks/state', function () {
|
||||
return expect(path).to.eql('/Documents/Cypress.app')
|
||||
})
|
||||
})
|
||||
|
||||
it('can parse on linux', function () {
|
||||
os.platform.returns('linux')
|
||||
|
||||
@@ -276,6 +288,7 @@ describe('lib/tasks/state', function () {
|
||||
return expect(path).to.eql('/Documents/Cypress')
|
||||
})
|
||||
})
|
||||
|
||||
it('can parse on darwin', function () {
|
||||
os.platform.returns('win32')
|
||||
|
||||
@@ -285,6 +298,7 @@ describe('lib/tasks/state', function () {
|
||||
return expect(path).to.eql('/Documents/Cypress')
|
||||
})
|
||||
})
|
||||
|
||||
it('throws when invalid on darwin', function () {
|
||||
os.platform.returns('darwin')
|
||||
|
||||
@@ -294,6 +308,7 @@ describe('lib/tasks/state', function () {
|
||||
return expect(path).to.eql(false)
|
||||
})
|
||||
})
|
||||
|
||||
it('throws when invalid on linux', function () {
|
||||
os.platform.returns('linux')
|
||||
|
||||
@@ -303,6 +318,7 @@ describe('lib/tasks/state', function () {
|
||||
return expect(path).to.eql(false)
|
||||
})
|
||||
})
|
||||
|
||||
it('throws when invalid on windows', function () {
|
||||
os.platform.returns('win32')
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ context('lib/tasks/verify', () => {
|
||||
// make it think the executable exists and is verified
|
||||
createfs({
|
||||
alreadyVerified: true,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
@@ -102,7 +102,7 @@ context('lib/tasks/verify', () => {
|
||||
it('logs warning when installed version does not match verified version', () => {
|
||||
createfs({
|
||||
alreadyVerified: true,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion: 'bloop',
|
||||
})
|
||||
|
||||
@@ -135,7 +135,7 @@ context('lib/tasks/verify', () => {
|
||||
it('logs error when child process hangs', () => {
|
||||
createfs({
|
||||
alreadyVerified: false,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
@@ -160,7 +160,7 @@ context('lib/tasks/verify', () => {
|
||||
it('logs error when child process returns incorrect stdout (stderr when exists)', () => {
|
||||
createfs({
|
||||
alreadyVerified: false,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
@@ -187,7 +187,7 @@ context('lib/tasks/verify', () => {
|
||||
it('logs error when child process returns incorrect stdout (stdout when no stderr)', () => {
|
||||
createfs({
|
||||
alreadyVerified: false,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
@@ -213,7 +213,7 @@ context('lib/tasks/verify', () => {
|
||||
it('sets ELECTRON_ENABLE_LOGGING without mutating process.env', () => {
|
||||
createfs({
|
||||
alreadyVerified: false,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
@@ -243,7 +243,7 @@ context('lib/tasks/verify', () => {
|
||||
beforeEach(() => {
|
||||
createfs({
|
||||
alreadyVerified: true,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion,
|
||||
})
|
||||
})
|
||||
@@ -302,7 +302,7 @@ context('lib/tasks/verify', () => {
|
||||
|
||||
createfs({
|
||||
alreadyVerified: false,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion,
|
||||
})
|
||||
})
|
||||
@@ -324,7 +324,7 @@ context('lib/tasks/verify', () => {
|
||||
|
||||
createfs({
|
||||
alreadyVerified: false,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
@@ -350,6 +350,7 @@ context('lib/tasks/verify', () => {
|
||||
[some noise here] Gtk: cannot open display: 987
|
||||
and maybe a few other lines here with weird indent
|
||||
`
|
||||
|
||||
firstSpawnError.stdout = ''
|
||||
|
||||
// the second time the binary returns expected ping
|
||||
@@ -387,6 +388,7 @@ context('lib/tasks/verify', () => {
|
||||
[some noise here] Gtk: cannot open display: 987
|
||||
and maybe a few other lines here with weird indent
|
||||
`
|
||||
|
||||
firstSpawnError.stdout = ''
|
||||
|
||||
// the second time it runs, it fails for some other reason
|
||||
@@ -443,7 +445,7 @@ context('lib/tasks/verify', () => {
|
||||
mockfs.restore()
|
||||
createfs({
|
||||
alreadyVerified: false,
|
||||
executable: mockfs.file({ mode: 0666 }),
|
||||
executable: mockfs.file({ mode: 0o666 }),
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
@@ -466,7 +468,7 @@ context('lib/tasks/verify', () => {
|
||||
it('logs and runs when current version has not been verified', () => {
|
||||
createfs({
|
||||
alreadyVerified: false,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
@@ -481,7 +483,7 @@ context('lib/tasks/verify', () => {
|
||||
it('logs and runs when installed version is different than package version', () => {
|
||||
createfs({
|
||||
alreadyVerified: false,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion: '7.8.9',
|
||||
})
|
||||
|
||||
@@ -496,7 +498,7 @@ context('lib/tasks/verify', () => {
|
||||
it('is silent when logLevel is silent', () => {
|
||||
createfs({
|
||||
alreadyVerified: false,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
@@ -513,7 +515,7 @@ context('lib/tasks/verify', () => {
|
||||
it('turns off Opening Cypress...', () => {
|
||||
createfs({
|
||||
alreadyVerified: true,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion: '7.8.9',
|
||||
})
|
||||
|
||||
@@ -529,7 +531,7 @@ context('lib/tasks/verify', () => {
|
||||
it('logs error when fails smoke test unexpectedly without stderr', () => {
|
||||
createfs({
|
||||
alreadyVerified: false,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
@@ -559,7 +561,7 @@ context('lib/tasks/verify', () => {
|
||||
|
||||
createfs({
|
||||
alreadyVerified: false,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion,
|
||||
})
|
||||
})
|
||||
@@ -603,9 +605,10 @@ context('lib/tasks/verify', () => {
|
||||
beforeEach(() => {
|
||||
createfs({
|
||||
alreadyVerified: false,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion,
|
||||
})
|
||||
|
||||
util.isCi.returns(true)
|
||||
})
|
||||
|
||||
@@ -638,10 +641,11 @@ context('lib/tasks/verify', () => {
|
||||
process.env.CYPRESS_RUN_BINARY = envBinaryPath
|
||||
createfs({
|
||||
alreadyVerified: false,
|
||||
executable: mockfs.file({ mode: 0777 }),
|
||||
executable: mockfs.file({ mode: 0o777 }),
|
||||
packageVersion,
|
||||
customDir: '/real/custom',
|
||||
})
|
||||
|
||||
util.exec
|
||||
.withArgs(realEnvBinaryPath, ['--smoke-test', '--ping=222'])
|
||||
.resolves(spawnedProcess)
|
||||
@@ -696,7 +700,7 @@ function createfs ({ alreadyVerified, executable, packageVersion, customDir }) {
|
||||
if (customDir) {
|
||||
mockFiles['/custom/Contents/MacOS/Cypress'] = mockfs.symlink({
|
||||
path: '/real/custom/Contents/MacOS/Cypress',
|
||||
mode: 0777,
|
||||
mode: 0o777,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -39,9 +39,11 @@ describe('util', () => {
|
||||
expect(() => {
|
||||
return util.getGitHubIssueUrl('4034')
|
||||
}).to.throw
|
||||
|
||||
expect(() => {
|
||||
return util.getGitHubIssueUrl(-5)
|
||||
}).to.throw
|
||||
|
||||
expect(() => {
|
||||
return util.getGitHubIssueUrl(5.19)
|
||||
}).to.throw
|
||||
@@ -275,15 +277,19 @@ describe('util', () => {
|
||||
it('is true with 3-digit version', () => {
|
||||
expect(util.isSemver('1.2.3')).to.equal(true)
|
||||
})
|
||||
|
||||
it('is true with 2-digit version', () => {
|
||||
expect(util.isSemver('1.2')).to.equal(true)
|
||||
})
|
||||
|
||||
it('is true with 1-digit version', () => {
|
||||
expect(util.isSemver('1')).to.equal(true)
|
||||
})
|
||||
|
||||
it('is false with URL', () => {
|
||||
expect(util.isSemver('www.cypress.io/download/1.2.3')).to.equal(false)
|
||||
})
|
||||
|
||||
it('is false with file path', () => {
|
||||
expect(util.isSemver('0/path/1.2.3/mypath/2.3')).to.equal(false)
|
||||
})
|
||||
@@ -363,6 +369,7 @@ describe('util', () => {
|
||||
beforeEach(() => {
|
||||
util = proxyquire(`${lib}/util`, { getos })
|
||||
})
|
||||
|
||||
it('calls os.release on non-linux', () => {
|
||||
os.platform.returns('darwin')
|
||||
os.release.returns('some-release')
|
||||
@@ -372,6 +379,7 @@ describe('util', () => {
|
||||
expect(getos).to.not.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('NOT calls os.release on linux', () => {
|
||||
os.platform.returns('linux')
|
||||
util.getOsVersionAsync()
|
||||
@@ -413,24 +421,29 @@ describe('util', () => {
|
||||
process.env.npm_package_config_CYPRESS_FOO = 'bar'
|
||||
expect(util.getEnv('CYPRESS_FOO')).to.eql('bar')
|
||||
})
|
||||
|
||||
it('reads from .npmrc config', () => {
|
||||
process.env.npm_config_CYPRESS_FOO = 'bar'
|
||||
expect(util.getEnv('CYPRESS_FOO')).to.eql('bar')
|
||||
})
|
||||
|
||||
it('reads from env var', () => {
|
||||
process.env.CYPRESS_FOO = 'bar'
|
||||
expect(util.getEnv('CYPRESS_FOO')).to.eql('bar')
|
||||
})
|
||||
|
||||
it('prefers env var over .npmrc config', () => {
|
||||
process.env.CYPRESS_FOO = 'bar'
|
||||
process.env.npm_config_CYPRESS_FOO = 'baz'
|
||||
expect(util.getEnv('CYPRESS_FOO')).to.eql('bar')
|
||||
})
|
||||
|
||||
it('prefers .npmrc config over package config', () => {
|
||||
process.env.npm_package_config_CYPRESS_FOO = 'baz'
|
||||
process.env.npm_config_CYPRESS_FOO = 'bloop'
|
||||
expect(util.getEnv('CYPRESS_FOO')).to.eql('bloop')
|
||||
})
|
||||
|
||||
it('throws on non-string name', () => {
|
||||
expect(() => {
|
||||
util.getEnv()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"mac": {
|
||||
"forceCodeSigning": true,
|
||||
"publish": null,
|
||||
"target": "zip"
|
||||
}
|
||||
"mac": {
|
||||
"forceCodeSigning": true,
|
||||
"publish": null,
|
||||
"target": "zip"
|
||||
}
|
||||
}
|
||||
|
||||
+76
-67
@@ -1,78 +1,74 @@
|
||||
{
|
||||
"name": "cypress",
|
||||
"productName": "Cypress",
|
||||
"version": "3.4.0",
|
||||
"description": "Cypress.io end to end testing tool",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=8.9.3"
|
||||
},
|
||||
"scripts": {
|
||||
"prestart": "npm run check-deps-pre",
|
||||
"start": "node ./cli/bin/cypress open --dev --global",
|
||||
"cypress:open": "node ./cli/bin/cypress open --dev --global",
|
||||
"cypress:run": "node ./cli/bin/cypress run --dev",
|
||||
"cypress:verify": "node ./cli/bin/cypress verify --dev",
|
||||
"cypress:open:debug": "node ./scripts/debug.js cypress:open",
|
||||
"cypress:run:debug": "node ./scripts/debug.js cypress:run",
|
||||
"dev": "node ./scripts/start.js",
|
||||
"dev-debug": "node ./scripts/debug.js dev",
|
||||
"watch": "npm run all watch",
|
||||
"test-debug-package": "node ./scripts/test-debug-package.js",
|
||||
"jscodeshift": "jscodeshift -t ./node_modules/js-codemod/transforms/arrow-function-arguments.js",
|
||||
"decaffeinate": "decaffeinate --use-cs2 --loose",
|
||||
"decaffeinate-bulk": "bulk-decaffeinate",
|
||||
"check-deps": "node ./scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "node ./scripts/check-deps.js --verbose --prescript",
|
||||
"all": "node ./scripts/run.js",
|
||||
"binary-build": "node ./scripts/binary.js build",
|
||||
"binary-deploy": "node ./scripts/binary.js deploy",
|
||||
"binary-deploy-linux": "./scripts/build-linux-binary.sh",
|
||||
"binary-purge": "node ./scripts/binary.js purge-version",
|
||||
"binary-release": "node ./scripts/binary.js release",
|
||||
"binary-upload": "node ./scripts/binary.js upload",
|
||||
"binary-zip": "node ./scripts/binary.js zip",
|
||||
"prebuild": "npm run check-deps-pre && npm run all prebuild",
|
||||
"build": "npm run all build",
|
||||
"all": "node ./scripts/run.js",
|
||||
"test": "echo '⚠️ This root monorepo is only for local development and new contributions. There are no tests.'",
|
||||
"link": "node ./scripts/link-packages.js",
|
||||
"install-filtered": "npm run all install -- --package $(node ./scripts/check-deps.js --list)",
|
||||
"postinstall": "echo 'root postinstall' && npm run link && npm run all install && npm run build",
|
||||
"clean-deps": "npm run all clean-deps && rm -rf node_modules",
|
||||
"docker": "./scripts/run-docker-local.sh",
|
||||
"lint-js": "eslint --fix scripts/*.js packages/ts/*.js cli/*.js cli/**/*.js",
|
||||
"lint-changed": "git diff --name-only | grep '\\.js$' | xargs npx eslint --fix",
|
||||
"lint-coffee": "coffeelint scripts/**/*.coffee",
|
||||
"lint": "npm run lint-js && npm run lint-coffee",
|
||||
"pretest": "npm run lint && npm run all lint && npm run test-scripts",
|
||||
"precommit": "npm run warn-only && lint-staged",
|
||||
"precommit-lint": "eslint --fix",
|
||||
"prepush": "npm run stop-only",
|
||||
"stop-only": "stop-only --folder packages --skip .cy,.publish,.projects,node_modules,dist,dist-test,fixtures,lib,bower_components,spec_helper.coffee",
|
||||
"warn-only": "stop-only --warn --folder packages --skip .cy,.publish,.projects,node_modules,dist,dist-test,fixtures,lib,bower_components,spec_helper.coffee",
|
||||
"bump": "node ./scripts/binary.js bump",
|
||||
"set-next-ci-version": "node ./scripts/binary.js setNextVersion",
|
||||
"binary-build": "node ./scripts/binary.js build",
|
||||
"binary-zip": "node ./scripts/binary.js zip",
|
||||
"binary-upload": "node ./scripts/binary.js upload",
|
||||
"binary-deploy": "node ./scripts/binary.js deploy",
|
||||
"binary-purge": "node ./scripts/binary.js purge-version",
|
||||
"binary-deploy-linux": "./scripts/build-linux-binary.sh",
|
||||
"move-binaries": "node ./scripts/binary.js move-binaries",
|
||||
"binary-release": "node ./scripts/binary.js release",
|
||||
"test-scripts": "mocha -r packages/coffee/register -r packages/ts/register --reporter spec 'scripts/unit/**/*spec.js'",
|
||||
"test-s3-api": "node -r ./packages/coffee/register -r ./packages/ts/register scripts/binary/s3-api-demo.ts",
|
||||
"test-mocha": "mocha --reporter spec scripts/spec.js",
|
||||
"test-mocha-snapshot": "mocha scripts/mocha-snapshot-spec.js",
|
||||
"check-deps": "node ./scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "node ./scripts/check-deps.js --verbose --prescript",
|
||||
"check-node-version": "node scripts/check-node-version.js",
|
||||
"check-terminal": "node scripts/check-terminal.js",
|
||||
"effective:circle:config": "circleci config process circle.yml | sed /^#/d"
|
||||
"clean-deps": "npm run all clean-deps && rm -rf node_modules",
|
||||
"cypress:open": "node ./cli/bin/cypress open --dev --global",
|
||||
"cypress:open:debug": "node ./scripts/debug.js cypress:open",
|
||||
"cypress:run": "node ./cli/bin/cypress run --dev",
|
||||
"cypress:run:debug": "node ./scripts/debug.js cypress:run",
|
||||
"cypress:verify": "node ./cli/bin/cypress verify --dev",
|
||||
"decaffeinate": "decaffeinate --use-cs2 --loose",
|
||||
"decaffeinate-bulk": "bulk-decaffeinate",
|
||||
"dev": "node ./scripts/start.js",
|
||||
"dev-debug": "node ./scripts/debug.js dev",
|
||||
"docker": "./scripts/run-docker-local.sh",
|
||||
"effective:circle:config": "circleci config process circle.yml | sed /^#/d",
|
||||
"postinstall": "echo 'root postinstall' && npm run link && npm run all install && npm run build",
|
||||
"install-filtered": "npm run all install -- --package $(node ./scripts/check-deps.js --list)",
|
||||
"jscodeshift": "jscodeshift -t ./node_modules/js-codemod/transforms/arrow-function-arguments.js",
|
||||
"link": "node ./scripts/link-packages.js",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json,.eslintrc .",
|
||||
"lint-all": "npm run lint-coffee && npm run lint",
|
||||
"lint-changed": "lint-changed",
|
||||
"lint-changed-fix": "npm run lint-changed -- --fix",
|
||||
"lint-coffee": "coffeelint scripts/**/*.coffee && npm run all lint-coffee && npm run stop-only-all",
|
||||
"lint-fix": "npm run lint -- --fix",
|
||||
"move-binaries": "node ./scripts/binary.js move-binaries",
|
||||
"set-next-ci-version": "node ./scripts/binary.js setNextVersion",
|
||||
"prestart": "npm run check-deps-pre",
|
||||
"start": "node ./cli/bin/cypress open --dev --global",
|
||||
"stop-only": "stop-only --skip .cy,.publish,.projects,node_modules,dist,dist-test,fixtures,lib,bower_components,spec_helper.coffee",
|
||||
"stop-only-all": "npm run stop-only -- --folder packages",
|
||||
"test": "echo '⚠️ This root monorepo is only for local development and new contributions. There are no tests.'",
|
||||
"test-debug-package": "node ./scripts/test-debug-package.js",
|
||||
"test-mocha": "mocha --reporter spec scripts/spec.js",
|
||||
"test-mocha-snapshot": "mocha scripts/mocha-snapshot-spec.js",
|
||||
"test-s3-api": "node -r ./packages/coffee/register -r ./packages/ts/register scripts/binary/s3-api-demo.ts",
|
||||
"test-scripts": "mocha -r packages/coffee/register -r packages/ts/register --reporter spec 'scripts/unit/**/*spec.js'",
|
||||
"watch": "npm run all watch"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.js": [
|
||||
"npm run precommit-lint"
|
||||
]
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/bumpercar": "2.0.9",
|
||||
"@cypress/commit-message-install": "2.7.0",
|
||||
"@cypress/env-or-json-file": "2.0.0",
|
||||
"@cypress/eslint-plugin-dev": "3.2.0",
|
||||
"@cypress/eslint-plugin-json": "3.2.0",
|
||||
"@cypress/github-commit-status-check": "1.5.0",
|
||||
"@cypress/npm-run-all": "4.0.5",
|
||||
"@cypress/questions-remain": "1.0.1",
|
||||
"@cypress/github-commit-status-check": "1.5.0",
|
||||
"@fellow/eslint-plugin-coffee": "0.4.13",
|
||||
"@types/bluebird": "3.5.21",
|
||||
"@types/chai": "3.5.2",
|
||||
"@types/debug": "4.1.4",
|
||||
@@ -84,6 +80,8 @@
|
||||
"@types/ramda": "0.25.47",
|
||||
"@types/request-promise": "4.1.42",
|
||||
"@types/sinon-chai": "3.2.2",
|
||||
"@typescript-eslint/eslint-plugin": "1.11.0",
|
||||
"@typescript-eslint/parser": "1.11.0",
|
||||
"ansi-styles": "3.2.1",
|
||||
"arg": "4.1.0",
|
||||
"ascii-table": "0.0.9",
|
||||
@@ -106,7 +104,6 @@
|
||||
"electron-builder": "20.39.0",
|
||||
"eslint": "5.16.0",
|
||||
"eslint-plugin-cypress": "2.2.1",
|
||||
"eslint-plugin-cypress-dev": "2.1.0",
|
||||
"eslint-plugin-mocha": "5.3.0",
|
||||
"eslint-plugin-react": "7.12.4",
|
||||
"execa": "1.0.0",
|
||||
@@ -123,7 +120,7 @@
|
||||
"gulp-typescript": "3.2.4",
|
||||
"hasha": "5.0.0",
|
||||
"human-interval": "0.1.6",
|
||||
"husky": "2.3.0",
|
||||
"husky": "2.4.1",
|
||||
"inquirer": "3.3.0",
|
||||
"inquirer-confirm": "2.0.3",
|
||||
"js-codemod": "cpojer/js-codemod#29dafed",
|
||||
@@ -155,9 +152,14 @@
|
||||
"typescript": "3.4.5",
|
||||
"vinyl-paths": "2.1.0"
|
||||
},
|
||||
"author": "Brian Mann",
|
||||
"license": "MIT",
|
||||
"description": "Cypress.io end to end testing tool",
|
||||
"homepage": "https://github.com/cypress-io/cypress",
|
||||
"license": "MIT",
|
||||
"author": "Brian Mann",
|
||||
"productName": "Cypress",
|
||||
"engines": {
|
||||
"node": ">=8.9.3"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cypress-io/cypress.git"
|
||||
@@ -166,18 +168,25 @@
|
||||
"url": "https://github.com/cypress-io/cypress/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"automation",
|
||||
"browser",
|
||||
"cypress",
|
||||
"cypress.io",
|
||||
"automation",
|
||||
"end-to-end",
|
||||
"e2e",
|
||||
"end-to-end",
|
||||
"integration",
|
||||
"mocks",
|
||||
"test",
|
||||
"testing",
|
||||
"runner",
|
||||
"spies",
|
||||
"stubs"
|
||||
]
|
||||
"stubs",
|
||||
"test",
|
||||
"testing"
|
||||
],
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,ts,tsx,coffee,json,eslintrc}": [
|
||||
"npm run stop-only -- --folder",
|
||||
"eslint --fix",
|
||||
"git add"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@packages/coffee",
|
||||
"main": "index.js",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"coffeescript": "1.12.7"
|
||||
},
|
||||
"files": [
|
||||
"register.js"
|
||||
],
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"check-deps": "node ../../scripts/check-deps.js --verbose",
|
||||
"clean-deps": "rm -rf node_modules"
|
||||
},
|
||||
"dependencies": {
|
||||
"coffeescript": "1.12.7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:@cypress/dev/tests",
|
||||
"plugin:@cypress/dev/react"
|
||||
],
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "16.8"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:cypress-dev/react",
|
||||
"plugin:cypress-dev/tests"
|
||||
]
|
||||
}
|
||||
@@ -1,28 +1,27 @@
|
||||
{
|
||||
"name": "@packages/desktop-gui",
|
||||
"version": "0.0.0",
|
||||
"main": "lib/gui.js",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"postinstall": "echo '@packages/desktop-gui needs: npm run build'",
|
||||
"prebuild": "npm run check-deps-pre && rebuild-node-sass",
|
||||
"build": "node ./scripts/build-dev.js",
|
||||
"prebuild-prod": "npm run check-deps-pre",
|
||||
"build-prod": "node ./scripts/build-prod.js",
|
||||
"prewatch": "npm run check-deps-pre",
|
||||
"watch": "node ./scripts/watch.js",
|
||||
"check-deps": "node ../../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"clean": "zunder clean",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"lint": "$(bin-up eslint) --fix lib/*.js src/*.js* src/**/*.js*",
|
||||
"cypress:open": "TZ=America/New_York node ../../scripts/cypress open --project .",
|
||||
"cypress:run": "TZ=America/New_York node ../../scripts/cypress run --project ."
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"lib"
|
||||
],
|
||||
"main": "lib/gui.js",
|
||||
"scripts": {
|
||||
"prebuild": "npm run check-deps-pre && rebuild-node-sass",
|
||||
"build": "node ./scripts/build-dev.js",
|
||||
"prebuild-prod": "npm run check-deps-pre",
|
||||
"build-prod": "node ./scripts/build-prod.js",
|
||||
"check-deps": "node ../../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"clean": "zunder clean",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"cypress:open": "TZ=America/New_York node ../../scripts/cypress open --project .",
|
||||
"cypress:run": "TZ=America/New_York node ../../scripts/cypress run --project .",
|
||||
"postinstall": "echo '@packages/desktop-gui needs: npm run build'",
|
||||
"prewatch": "npm run check-deps-pre",
|
||||
"watch": "node ./scripts/watch.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-object-rest-spread": "7.4.4",
|
||||
"@cypress/icons": "0.7.0",
|
||||
|
||||
@@ -6,6 +6,7 @@ module.exports = () => {
|
||||
'node_modules/fira/woff/**/*': '/woff',
|
||||
'node_modules/font-awesome/fonts/*.+(eot|svg|ttf|woff|woff2|otf)': '/fonts',
|
||||
}
|
||||
|
||||
staticGlobs[cyIcons.getPathToLogo('cypress-inverse.png')] = '/img'
|
||||
|
||||
zunder.setConfig({
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:cypress-dev/react",
|
||||
"plugin:cypress-dev/tests"
|
||||
]
|
||||
}
|
||||
@@ -29,6 +29,7 @@ class Dropdown extends Component {
|
||||
this.setState({ open: false })
|
||||
}
|
||||
}
|
||||
|
||||
document.body.addEventListener('click', this.outsideClickHandler)
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ const register = (eventName, isPromiseApi = true) => {
|
||||
// console.log('ipc', eventName, 'called with', args) // NOTE: uncomment to debug ipc
|
||||
return ipcBus(eventName, ...args)
|
||||
}
|
||||
|
||||
if (!isPromiseApi) {
|
||||
ipc[_.camelCase(`off:${eventName}`)] = () => {
|
||||
return ipcBus.off(eventName)
|
||||
|
||||
@@ -158,6 +158,7 @@ export default class Project {
|
||||
this.browsers = _.map(browsers, (browser) => {
|
||||
return new Browser(browser)
|
||||
})
|
||||
|
||||
// use a custom browser if one is supplied. or, if they already have
|
||||
// a browser chosen that's been saved in localStorage, then select that
|
||||
// otherwise just do the default.
|
||||
|
||||
@@ -72,8 +72,7 @@ class Project extends Component {
|
||||
const { warnings } = this.props.project
|
||||
|
||||
return warnings.map((warning, i) =>
|
||||
(<WarningMessage key={i} warning={warning} onClearWarning={() => this._removeWarning(warning)}/>)
|
||||
)
|
||||
(<WarningMessage key={i} warning={warning} onClearWarning={() => this._removeWarning(warning)}/>))
|
||||
}
|
||||
|
||||
_removeWarning = (warning) => {
|
||||
|
||||
@@ -77,6 +77,7 @@ class ProjectsStore {
|
||||
_.each(this.projects, (project) => {
|
||||
project.isChosen = false
|
||||
})
|
||||
|
||||
project.isChosen = true
|
||||
}
|
||||
|
||||
|
||||
@@ -408,6 +408,7 @@ class SetupProject extends Component {
|
||||
this.setState({
|
||||
isSubmitting: true,
|
||||
})
|
||||
|
||||
this._setupProject()
|
||||
} else {
|
||||
this.setState({
|
||||
@@ -426,6 +427,7 @@ class SetupProject extends Component {
|
||||
this.setState({
|
||||
isSubmitting: false,
|
||||
})
|
||||
|
||||
this.props.onSetup(projectDetails)
|
||||
|
||||
return null
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
module.exports = require("./lib/driver")
|
||||
module.exports = require('./lib/driver')
|
||||
|
||||
@@ -2,6 +2,7 @@ const path = require('path')
|
||||
|
||||
function dist (...args) {
|
||||
const paths = [__dirname, '..', 'dist'].concat(args)
|
||||
|
||||
return path.join(...paths)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
"name": "@packages/driver",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"browser": "src/main",
|
||||
"scripts": {
|
||||
"prestart": "npm run check-deps-pre",
|
||||
"start": "../coffee/node_modules/.bin/coffee test/support/server.coffee",
|
||||
"cypress:open": "node ../../scripts/cypress open --project ./test",
|
||||
"cypress:run": "node ../../scripts/cypress run --project ./test",
|
||||
"check-deps": "node ../../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"clean-deps": "rm -rf node_modules"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"main": "index.js",
|
||||
"browser": "src/main",
|
||||
"scripts": {
|
||||
"check-deps": "node ../../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"cypress:open": "node ../../scripts/cypress open --project ./test",
|
||||
"cypress:run": "node ../../scripts/cypress run --project ./test",
|
||||
"prestart": "npm run check-deps-pre",
|
||||
"start": "../coffee/node_modules/.bin/coffee test/support/server.coffee"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/bower-kendo-ui": "0.0.2",
|
||||
"@cypress/sinon-chai": "1.1.0",
|
||||
|
||||
@@ -302,4 +302,3 @@ module.exports = (Commands, Cypress, cy, state, config) => {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -493,6 +493,7 @@ const $Keyboard = {
|
||||
_.extend(event, {
|
||||
data: key,
|
||||
})
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
@@ -510,6 +511,7 @@ const $Keyboard = {
|
||||
location: 0,
|
||||
repeat: false,
|
||||
})
|
||||
|
||||
this.mixinModifiers(event)
|
||||
}
|
||||
|
||||
|
||||
@@ -363,8 +363,7 @@ const _moveCursorUpOrDown = function (el, up) {
|
||||
return $elements.callNativeMethod(selection, 'modify',
|
||||
'move',
|
||||
up ? 'backward' : 'forward',
|
||||
'line'
|
||||
)
|
||||
'line')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:@cypress/dev/tests"
|
||||
],
|
||||
"rules": {
|
||||
"mocha/no-global-tests": "off"
|
||||
}
|
||||
}
|
||||
@@ -217,6 +217,7 @@ describe('src/cy/commands/actions/click', () => {
|
||||
'Inherited From',
|
||||
'Error',
|
||||
])
|
||||
|
||||
expect(consoleProps['But it has CSS']).to.eq('pointer-events: none')
|
||||
|
||||
expect(consoleProps['Inherited From']).to.eq(this.ptrNone.get(0))
|
||||
@@ -324,12 +325,15 @@ describe('src/cy/commands/actions/click', () => {
|
||||
$btn.on('focus', () => {
|
||||
return fail('should not have gotten focus')
|
||||
})
|
||||
|
||||
$btn.on('focusin', () => {
|
||||
return fail('should not have gotten focusin')
|
||||
})
|
||||
|
||||
$btn.on('mouseup', () => {
|
||||
return fail('should not have gotten mouseup')
|
||||
})
|
||||
|
||||
$btn.on('click', () => {
|
||||
return fail('should not have gotten click')
|
||||
})
|
||||
|
||||
@@ -2129,6 +2129,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
'<div>foo</div>' +
|
||||
'<div>bar</div>' +
|
||||
'<div>baz</div>'
|
||||
|
||||
//# select 'bar'
|
||||
const line = cy.$$('[contenteditable]:first div:nth-child(1)').get(0)
|
||||
|
||||
@@ -2223,6 +2224,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
'<div>foo</div>' +
|
||||
'<div>bar</div>' +
|
||||
'<div>baz</div>'
|
||||
|
||||
//# select 'foo'
|
||||
const line = cy.$$('[contenteditable]:first div:first').get(0)
|
||||
|
||||
@@ -2589,9 +2591,11 @@ describe('src/cy/commands/actions/type', () => {
|
||||
$button.on('mousedown', (e) => {
|
||||
mouseDownEvent = e
|
||||
})
|
||||
|
||||
$button.on('mouseup', (e) => {
|
||||
mouseUpEvent = e
|
||||
})
|
||||
|
||||
$button.on('click', (e) => {
|
||||
clickEvent = e
|
||||
})
|
||||
@@ -2681,9 +2685,11 @@ describe('src/cy/commands/actions/type', () => {
|
||||
$button.on('mousedown', (e) => {
|
||||
mouseDownEvent = e
|
||||
})
|
||||
|
||||
$button.on('mouseup', (e) => {
|
||||
mouseUpEvent = e
|
||||
})
|
||||
|
||||
$button.on('click', (e) => {
|
||||
clickEvent = e
|
||||
})
|
||||
@@ -3260,6 +3266,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
<div>foo</div><div>bar</div><div>baz</div> \
|
||||
</div>\
|
||||
'))
|
||||
|
||||
const win = cy.state('window')
|
||||
const doc = window.document
|
||||
|
||||
@@ -4088,6 +4095,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
expect(table.columns).to.deep.eq([
|
||||
'typed', 'which', 'keydown', 'keypress', 'textInput', 'input', 'keyup', 'change', 'modifiers',
|
||||
])
|
||||
|
||||
expect(table.name).to.eq('Key Events Table')
|
||||
const expectedTable = {
|
||||
1: { typed: '<meta>', which: 91, keydown: true, modifiers: 'meta' },
|
||||
|
||||
@@ -303,7 +303,7 @@ describe "src/cy/commands/navigation", ->
|
||||
|
||||
return null
|
||||
|
||||
_.each [null, undefined, NaN, Infinity, {}, [], ->], (val) =>
|
||||
_.each [null, undefined, NaN, Infinity, {}, [], ->{}], (val) =>
|
||||
it "throws on: '#{val}'", (done) ->
|
||||
cy.on "fail", (err) ->
|
||||
expect(err.message).to.eq("cy.go() accepts only a string or number argument")
|
||||
|
||||
@@ -6,6 +6,7 @@ describe('src/cypress/log', function () {
|
||||
this.cy = {
|
||||
createSnapshot: cy.stub().returns({}),
|
||||
}
|
||||
|
||||
this.state = cy.stub()
|
||||
this.config = cy.stub()
|
||||
this.config.withArgs('isInteractive').returns(true)
|
||||
|
||||
@@ -53,6 +53,7 @@ const windowHasFocus = function () {
|
||||
window.addEventListener('focus', function () {
|
||||
hasFocus = true
|
||||
})
|
||||
|
||||
window.focus()
|
||||
|
||||
return hasFocus
|
||||
@@ -311,8 +312,7 @@ describe('polyfill programmatic blur events', () => {
|
||||
expect(stub, 'should not send focus if already focused el').not.called
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/1176
|
||||
it('simulated events when window is out of focus when .blur called', () => {
|
||||
@@ -437,8 +437,7 @@ describe('polyfill programmatic blur events', () => {
|
||||
expect(stub, 'should not send focus if already focused el').not.called
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/1176
|
||||
it('SVGElement simulated events when window is out of focus when .blur called', () => {
|
||||
@@ -536,6 +535,7 @@ describe('intercept blur methods correctly', () => {
|
||||
cy.state('document').onselectionchange = cy.stub().as('selectionchange')
|
||||
})
|
||||
})
|
||||
|
||||
it('focus <a>', () => {
|
||||
const $el = cy.$$('<a href="#">foo</a>')
|
||||
|
||||
@@ -550,6 +550,7 @@ describe('intercept blur methods correctly', () => {
|
||||
cy.wait(0).get('@selectionchange').should('not.be.called')
|
||||
|
||||
})
|
||||
|
||||
it('focus <select>', () => {
|
||||
const $el = cy.$$('<select>')
|
||||
|
||||
@@ -561,6 +562,7 @@ describe('intercept blur methods correctly', () => {
|
||||
cy.wait(0).get('@selectionchange').should('not.be.called')
|
||||
|
||||
})
|
||||
|
||||
it('focus <button>', () => {
|
||||
const $el = cy.$$('<button/>')
|
||||
|
||||
@@ -572,6 +574,7 @@ describe('intercept blur methods correctly', () => {
|
||||
cy.wait(0).get('@selectionchange').should('not.be.called')
|
||||
|
||||
})
|
||||
|
||||
it('focus <iframe>', () => {
|
||||
const $el = cy.$$('<iframe src="" />')
|
||||
|
||||
@@ -583,6 +586,7 @@ describe('intercept blur methods correctly', () => {
|
||||
cy.wait(0).get('@selectionchange').should('not.be.called')
|
||||
|
||||
})
|
||||
|
||||
it('focus [tabindex]', () => {
|
||||
const $el = cy.$$('<div tabindex="1">tabindex</div>')
|
||||
|
||||
@@ -594,6 +598,7 @@ describe('intercept blur methods correctly', () => {
|
||||
cy.wait(0).get('@selectionchange').should('not.be.called')
|
||||
|
||||
})
|
||||
|
||||
it('focus <textarea>', () => {
|
||||
const $el = cy.$$('<textarea/>')
|
||||
|
||||
@@ -605,6 +610,7 @@ describe('intercept blur methods correctly', () => {
|
||||
cy.get('@selectionchange').should('be.calledOnce')
|
||||
|
||||
})
|
||||
|
||||
it('focus [contenteditable]', () => {
|
||||
const $el = cy.$$('<div contenteditable>contenteditable</div>')
|
||||
|
||||
@@ -615,6 +621,7 @@ describe('intercept blur methods correctly', () => {
|
||||
|
||||
cy.get('@selectionchange').should('be.calledOnce')
|
||||
})
|
||||
|
||||
it('cannot focus a [contenteditable] child', () => {
|
||||
const outer = cy.$$('<div contenteditable>contenteditable</div>').appendTo(cy.$$('body'))
|
||||
const inner = cy.$$('<div>first inner contenteditable</div>').appendTo(outer)
|
||||
@@ -632,6 +639,7 @@ describe('intercept blur methods correctly', () => {
|
||||
|
||||
cy.get('@selectionchange').should('not.be.called')
|
||||
})
|
||||
|
||||
it('focus svg', () => {
|
||||
const $svg = cy.$$(`<svg tabindex="1" width="900px" height="500px" viewBox="0 0 95 50" style="border: solid red 1px;"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -654,6 +662,7 @@ describe('intercept blur methods correctly', () => {
|
||||
cy.wrap($svg).focus().should('have.focus')
|
||||
|
||||
})
|
||||
|
||||
it('focus area', () => {
|
||||
cy.visit('http://localhost:3500/fixtures/active-elements.html').then(() => {
|
||||
cy.$$(`
|
||||
|
||||
@@ -10,4 +10,3 @@ describe('video', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ describe('issue #1854', () => {
|
||||
|
||||
win.setTimeout('foo(true)', 100)
|
||||
})
|
||||
|
||||
cy.window().its('bar').should('be.true')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -24,6 +24,7 @@ describe('issue #2850: invoking cy.clock() before two visits', () => {
|
||||
// manually restore the clock
|
||||
clock.restore()
|
||||
})
|
||||
|
||||
cy.clock().then((clock2) => {
|
||||
clock2.restore()
|
||||
})
|
||||
|
||||
@@ -11,6 +11,7 @@ describe('issue #761 - aborted XHRs from previous tests', () => {
|
||||
// and should not throw
|
||||
xhr.abort()
|
||||
}
|
||||
|
||||
xhr.send()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -19,6 +19,7 @@ describe('driver/src/util/limited_map', () => {
|
||||
_.each(_.times(100), (i) => {
|
||||
limitedMap.set(`foo-${i}`, i)
|
||||
})
|
||||
|
||||
expect(limitedMap.size).to.equal(100)
|
||||
expect(Array.from(limitedMap.values())[0]).to.equal(0)
|
||||
expect(Array.from(limitedMap.values())[99]).to.equal(99)
|
||||
@@ -45,6 +46,7 @@ describe('driver/src/util/limited_map', () => {
|
||||
_.each(_.times(5), (i) => {
|
||||
limitedMap.set(`foo-${i}`, i)
|
||||
})
|
||||
|
||||
expect(limitedMap.size).to.equal(5)
|
||||
expect(Array.from(limitedMap.values())[0]).to.equal(0)
|
||||
expect(Array.from(limitedMap.values())[4]).to.equal(4)
|
||||
|
||||
@@ -18,6 +18,7 @@ module.exports = (on) => {
|
||||
}).join('\n\n')
|
||||
|
||||
fs.outputFileSync(filePath, longText)
|
||||
|
||||
return null
|
||||
},
|
||||
})
|
||||
|
||||
@@ -44,7 +44,7 @@ describe.skip "$Cypress.Commands API", ->
|
||||
beforeEach ->
|
||||
@commands.splice(0, 1, {name: "get", args: ["form:first"]})
|
||||
@commands.splice(1, 2, {name: "click", args: [{multiple: true}]})
|
||||
@commands.splice(2, 3, {name: "then", args: [->]})
|
||||
@commands.splice(2, 3, {name: "then", args: [->{}]})
|
||||
@commands.splice(3, 4, {name: "get", args: ["body", {timeout: 1000}]})
|
||||
@commands.splice(4, 5, {name: "should", args: ["have.prop", "class", "active"]})
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
require("@packages/coffee/register")
|
||||
require('@packages/coffee/register')
|
||||
|
||||
module.exports = require("./lib/electron")
|
||||
module.exports = require('./lib/electron')
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
{
|
||||
"name": "@packages/electron",
|
||||
"version": "0.0.0",
|
||||
"electronVersion": "2.0.18",
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"postinstall": "echo '@packages/electron needs: npm run build'",
|
||||
"prestart": "npm run check-deps-pre",
|
||||
"start": "./bin/cypress-electron",
|
||||
"pretest": "npm run check-deps-pre",
|
||||
"test": "mocha --compilers coffee:@packages/coffee/register",
|
||||
"prebuild": "npm run check-deps-pre",
|
||||
"build": "node ./bin/cypress-electron --install",
|
||||
"check-deps": "node ../../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"clean-deps": "rm -rf node_modules"
|
||||
},
|
||||
"bin": {
|
||||
"cypress-electron": "./bin/cypress-electron"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"lib"
|
||||
],
|
||||
"devDependencies": {
|
||||
"chai": "3.5.0",
|
||||
"mocha": "3.5.3"
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"prebuild": "npm run check-deps-pre",
|
||||
"build": "node ./bin/cypress-electron --install",
|
||||
"check-deps": "node ../../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"postinstall": "echo '@packages/electron needs: npm run build'",
|
||||
"prestart": "npm run check-deps-pre",
|
||||
"start": "./bin/cypress-electron",
|
||||
"pretest": "npm run check-deps-pre",
|
||||
"test": "mocha --compilers coffee:@packages/coffee/register"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cypress/icons": "0.7.0",
|
||||
@@ -35,5 +27,13 @@
|
||||
"fs-extra": "8.1.0",
|
||||
"lodash": "4.17.13",
|
||||
"minimist": "1.2.0"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "3.5.0",
|
||||
"mocha": "3.5.3"
|
||||
},
|
||||
"bin": {
|
||||
"cypress-electron": "./bin/cypress-electron"
|
||||
},
|
||||
"electronVersion": "2.0.18"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:@cypress/dev/tests"
|
||||
]
|
||||
}
|
||||
@@ -8,14 +8,13 @@
|
||||
"check-deps": "node ../../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"pretest": "npm run check-deps-pre && npm run lint",
|
||||
"pretest": "npm run check-deps-pre",
|
||||
"test": "cross-env NODE_ENV=test mocha",
|
||||
"test-e2e": "cypress run",
|
||||
"prebuild": "npm run check-deps-pre",
|
||||
"build": "node ./bin/build.js && gulp build",
|
||||
"predeploy": "npm run build",
|
||||
"deploy": "gulp deploy",
|
||||
"lint": "bin-up eslint --fix *.js bin/*.js lib/*.js test/*.js"
|
||||
"deploy": "gulp deploy"
|
||||
},
|
||||
"files": [
|
||||
"cypress",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name" : "Cypress",
|
||||
"description" : "Adds chrome.* API's for testing with Cypress",
|
||||
"name": "Cypress",
|
||||
"description": "Adds chrome.* API's for testing with Cypress",
|
||||
"permissions": [
|
||||
"cookies",
|
||||
"tabs",
|
||||
@@ -10,8 +10,8 @@
|
||||
],
|
||||
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAugoxpSqfoblTYUGvyXZpmBgjYQUY9k2Hx3PaDwquyaTH6GBxitwVMSu5sZuDYgPHpGYoF4ol6A4PZHhd6JvfuUDS9ZrxTW0XzP+dSS9AwmJo3uLuP88zBs4mhpje1+WE5NGM0pTzyCXYTPoyzyPRmToALWD96cahSGuhG8bSmaBw3py+16qNKm8SOlANbUvHtEaTpmrSWBUIq7YV8SIPLtR8G47vjqPTE1yEsBQ3GAgllhi0cJolwk/629fRLr3KVckICmU6spXD/jVhIgAeyHhFuFGYNuubzbel8trBVw5Q/HE5F6j66sBvEvW64tH4lPxnM5JPv0qie5wouPiT0wIDAQAB",
|
||||
"icons": {
|
||||
"16": "icons/icon_16x16.png",
|
||||
"48": "icons/icon_48x48.png",
|
||||
"16": "icons/icon_16x16.png",
|
||||
"48": "icons/icon_48x48.png",
|
||||
"128": "icons/icon_128x128.png"
|
||||
},
|
||||
"browser_action": {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
require("@packages/coffee/register")
|
||||
require('@packages/coffee/register')
|
||||
|
||||
module.exports = require("./lib/extension")
|
||||
module.exports = require('./lib/extension')
|
||||
|
||||
@@ -2,30 +2,34 @@
|
||||
"name": "@packages/extension",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"postinstall": "echo '@packages/extension needs: npm run build'",
|
||||
"prewatch": "npm run check-deps-pre",
|
||||
"watch": "gulp watch",
|
||||
"prebuild": "npm run check-deps-pre",
|
||||
"build": "gulp build",
|
||||
"prebuild-prod": "npm run check-deps-pre",
|
||||
"build-prod": "gulp build",
|
||||
"pretest": "npm run check-deps-pre",
|
||||
"test": "cross-env NODE_ENV=test bin-up mocha --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json",
|
||||
"pretest-watch": "npm run check-deps-pre",
|
||||
"test-watch": "npm run test -- --watch",
|
||||
"check-deps": "node ../../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"clean": "gulp clean",
|
||||
"clean-deps": "rm -rf node_modules"
|
||||
},
|
||||
"files": [
|
||||
"app",
|
||||
"dist",
|
||||
"lib",
|
||||
"theme"
|
||||
],
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"prebuild": "npm run check-deps-pre",
|
||||
"build": "gulp build",
|
||||
"prebuild-prod": "npm run check-deps-pre",
|
||||
"build-prod": "gulp build",
|
||||
"check-deps": "node ../../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"clean": "gulp clean",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"postinstall": "echo '@packages/extension needs: npm run build'",
|
||||
"pretest": "npm run check-deps-pre",
|
||||
"test": "cross-env NODE_ENV=test bin-up mocha --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json",
|
||||
"pretest-watch": "npm run check-deps-pre",
|
||||
"test-watch": "npm run test -- --watch",
|
||||
"prewatch": "npm run check-deps-pre",
|
||||
"watch": "gulp watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"bluebird": "3.5.3",
|
||||
"lodash": "4.17.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/icons": "0.7.0",
|
||||
"bin-up": "1.2.0",
|
||||
@@ -42,9 +46,5 @@
|
||||
"sinon": "1.17.7",
|
||||
"sinon-chai": "3.3.0",
|
||||
"vinyl-source-stream": "1.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"bluebird": "3.5.3",
|
||||
"lodash": "4.17.13"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:@cypress/dev/tests"
|
||||
]
|
||||
}
|
||||
@@ -4,16 +4,36 @@
|
||||
"manifest_version": 2,
|
||||
"theme": {
|
||||
"colors": {
|
||||
"bookmark_text": [ 0, 0, 0 ],
|
||||
"frame": [ 29, 31, 33 ],
|
||||
"ntp_section": [ 255, 255, 255 ]
|
||||
"bookmark_text": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"frame": [
|
||||
29,
|
||||
31,
|
||||
33
|
||||
],
|
||||
"ntp_section": [
|
||||
255,
|
||||
255,
|
||||
255
|
||||
]
|
||||
},
|
||||
"images": {
|
||||
"theme_frame": "images/theme_frame.png"
|
||||
"theme_frame": "images/theme_frame.png"
|
||||
},
|
||||
"tints": {
|
||||
"frame_inactive": [-1.0, -1.0, -1.0],
|
||||
"background_tab": [-1.0, -1.0, -1.0]
|
||||
"frame_inactive": [
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"background_tab": [
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,34 +2,22 @@
|
||||
"name": "@packages/https-proxy",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"prestart": "npm run check-deps-pre",
|
||||
"start": "node index.js",
|
||||
"check-deps": "node ../../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"https": "node https.js",
|
||||
"prestart": "npm run check-deps-pre",
|
||||
"start": "node index.js",
|
||||
"pretest": "npm run check-deps-pre",
|
||||
"test": "cross-env NODE_ENV=test bin-up mocha --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json",
|
||||
"test-debug": "cross-env NODE_ENV=test bin-up mocha --inspect-brk --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json",
|
||||
"pretest-watch": "npm run check-deps-pre",
|
||||
"test-watch": "cross-env NODE_ENV=test bin-up mocha --watch",
|
||||
"https": "node https.js"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"devDependencies": {
|
||||
"bin-up": "1.2.0",
|
||||
"chai": "3.5.0",
|
||||
"cross-env": "5.2.0",
|
||||
"@cypress/debugging-proxy": "2.0.1",
|
||||
"request": "2.88.0",
|
||||
"request-promise": "4.2.4",
|
||||
"sinon": "1.17.7",
|
||||
"sinon-as-promised": "4.0.3",
|
||||
"sinon-chai": "3.3.0",
|
||||
"supertest": "4.0.2"
|
||||
"test-watch": "cross-env NODE_ENV=test bin-up mocha --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"bluebird": "3.5.3",
|
||||
@@ -41,5 +29,17 @@
|
||||
"semaphore": "1.1.0",
|
||||
"server-destroy-vvo": "1.0.1",
|
||||
"ssl-root-cas": "1.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/debugging-proxy": "2.0.1",
|
||||
"bin-up": "1.2.0",
|
||||
"chai": "3.5.0",
|
||||
"cross-env": "5.2.0",
|
||||
"request": "2.88.0",
|
||||
"request-promise": "4.2.4",
|
||||
"sinon": "1.17.7",
|
||||
"sinon-as-promised": "4.0.3",
|
||||
"sinon-chai": "3.3.0",
|
||||
"supertest": "4.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:@cypress/dev/tests"
|
||||
]
|
||||
}
|
||||
@@ -10,7 +10,7 @@ export const browsers: Browser[] = [
|
||||
displayName: 'Chrome',
|
||||
versionRegex: /Google Chrome (\S+)/,
|
||||
profile: true,
|
||||
binary: ['google-chrome', 'chrome', 'google-chrome-stable']
|
||||
binary: ['google-chrome', 'chrome', 'google-chrome-stable'],
|
||||
},
|
||||
{
|
||||
name: 'chromium',
|
||||
@@ -18,7 +18,7 @@ export const browsers: Browser[] = [
|
||||
displayName: 'Chromium',
|
||||
versionRegex: /Chromium (\S+)/,
|
||||
profile: true,
|
||||
binary: ['chromium-browser', 'chromium']
|
||||
binary: ['chromium-browser', 'chromium'],
|
||||
},
|
||||
{
|
||||
name: 'canary',
|
||||
@@ -26,12 +26,12 @@ export const browsers: Browser[] = [
|
||||
displayName: 'Canary',
|
||||
versionRegex: /Google Chrome Canary (\S+)/,
|
||||
profile: true,
|
||||
binary: 'google-chrome-canary'
|
||||
}
|
||||
binary: 'google-chrome-canary',
|
||||
},
|
||||
]
|
||||
|
||||
/** starts a found browser and opens URL if given one */
|
||||
export function launch(
|
||||
export function launch (
|
||||
browser: FoundBrowser,
|
||||
url: string,
|
||||
args: string[] = []
|
||||
@@ -47,5 +47,6 @@ export function launch(
|
||||
}
|
||||
|
||||
log('spawning browser %o with args %s', browser, args.join(' '))
|
||||
|
||||
return cp.spawn(browser.path, args, { stdio: 'ignore' })
|
||||
}
|
||||
|
||||
@@ -7,17 +7,17 @@ import { merge, partial } from 'ramda'
|
||||
const detectCanary = partial(findApp, [
|
||||
'Contents/MacOS/Google Chrome Canary',
|
||||
'com.google.Chrome.canary',
|
||||
'KSVersion'
|
||||
'KSVersion',
|
||||
])
|
||||
const detectChrome = partial(findApp, [
|
||||
'Contents/MacOS/Google Chrome',
|
||||
'com.google.Chrome',
|
||||
'KSVersion'
|
||||
'KSVersion',
|
||||
])
|
||||
const detectChromium = partial(findApp, [
|
||||
'Contents/MacOS/Chromium',
|
||||
'org.chromium.Chromium',
|
||||
'CFBundleShortVersionString'
|
||||
'CFBundleShortVersionString',
|
||||
])
|
||||
|
||||
type Detectors = {
|
||||
@@ -27,27 +27,29 @@ type Detectors = {
|
||||
const browsers: Detectors = {
|
||||
chrome: detectChrome,
|
||||
canary: detectCanary,
|
||||
chromium: detectChromium
|
||||
chromium: detectChromium,
|
||||
}
|
||||
|
||||
export function getVersionString(path: string) {
|
||||
export function getVersionString (path: string) {
|
||||
return linuxHelper.getVersionString(path)
|
||||
}
|
||||
|
||||
export function detect(browser: Browser): Promise<FoundBrowser> {
|
||||
export function detect (browser: Browser): Promise<FoundBrowser> {
|
||||
let fn = browsers[browser.name]
|
||||
|
||||
if (!fn) {
|
||||
// ok, maybe it is custom alias?
|
||||
log('detecting custom browser %s on darwin', browser.name)
|
||||
|
||||
return linuxHelper.detect(browser)
|
||||
}
|
||||
|
||||
return fn()
|
||||
.then(merge({ name: browser.name }))
|
||||
.catch(() => {
|
||||
log('could not detect %s using traditional Mac methods', browser.name)
|
||||
log('trying linux search')
|
||||
return linuxHelper.detect(browser)
|
||||
})
|
||||
.then(merge({ name: browser.name }))
|
||||
.catch(() => {
|
||||
log('could not detect %s using traditional Mac methods', browser.name)
|
||||
log('trying linux search')
|
||||
|
||||
return linuxHelper.detect(browser)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,32 +7,36 @@ import * as path from 'path'
|
||||
import * as plist from 'plist'
|
||||
|
||||
/** parses Info.plist file from given application and returns a property */
|
||||
export function parse(p: string, property: string): Promise<string> {
|
||||
export function parse (p: string, property: string): Promise<string> {
|
||||
const pl = path.join(p, 'Contents', 'Info.plist')
|
||||
|
||||
log('reading property file "%s"', pl)
|
||||
|
||||
const failed = (e: Error) => {
|
||||
const msg = `Info.plist not found: ${pl}
|
||||
${e.message}`
|
||||
|
||||
log('could not read Info.plist for %s', pl)
|
||||
throw notInstalledErr('', msg)
|
||||
}
|
||||
|
||||
return fs
|
||||
.readFile(pl, 'utf8')
|
||||
.then(plist.parse)
|
||||
.then(prop(property))
|
||||
.then(String) // explicitly convert value to String type
|
||||
.catch(failed) // to make TS compiler happy
|
||||
.readFile(pl, 'utf8')
|
||||
.then(plist.parse)
|
||||
.then(prop(property))
|
||||
.then(String) // explicitly convert value to String type
|
||||
.catch(failed) // to make TS compiler happy
|
||||
}
|
||||
|
||||
/** uses mdfind to find app using Ma app id like 'com.google.Chrome.canary' */
|
||||
export function mdfind(id: string): Promise<string> {
|
||||
export function mdfind (id: string): Promise<string> {
|
||||
const cmd = `mdfind 'kMDItemCFBundleIdentifier=="${id}"' | head -1`
|
||||
|
||||
log('looking for bundle id %s using command: %s', id, cmd)
|
||||
|
||||
const logFound = (str: string) => {
|
||||
log('found %s at %s', id, str)
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
@@ -42,10 +46,10 @@ export function mdfind(id: string): Promise<string> {
|
||||
}
|
||||
|
||||
return execa
|
||||
.shell(cmd)
|
||||
.then(result => result.stdout)
|
||||
.then(tap(logFound))
|
||||
.catch(failedToFind)
|
||||
.shell(cmd)
|
||||
.then((result) => result.stdout)
|
||||
.then(tap(logFound))
|
||||
.catch(failedToFind)
|
||||
}
|
||||
|
||||
export type AppInfo = {
|
||||
@@ -53,28 +57,30 @@ export type AppInfo = {
|
||||
version: string
|
||||
}
|
||||
|
||||
function formApplicationPath(executable: string) {
|
||||
function formApplicationPath (executable: string) {
|
||||
const parts = executable.split('/')
|
||||
const name = parts[parts.length - 1]
|
||||
const appName = `${name}.app`
|
||||
|
||||
return path.join('/Applications', appName)
|
||||
}
|
||||
|
||||
/** finds an application and its version */
|
||||
export function findApp(
|
||||
export function findApp (
|
||||
executable: string,
|
||||
appId: string,
|
||||
versionProperty: string
|
||||
): Promise<AppInfo> {
|
||||
log('looking for app %s id %s', executable, appId)
|
||||
|
||||
const findVersion = (foundPath: string) =>
|
||||
parse(foundPath, versionProperty).then(version => {
|
||||
const findVersion = (foundPath: string) => {
|
||||
return parse(foundPath, versionProperty).then((version) => {
|
||||
return {
|
||||
path: path.join(foundPath, executable),
|
||||
version
|
||||
version,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const tryMdFind = () => {
|
||||
return mdfind(appId).then(findVersion)
|
||||
@@ -82,7 +88,9 @@ export function findApp(
|
||||
|
||||
const tryFullApplicationFind = () => {
|
||||
const applicationPath = formApplicationPath(executable)
|
||||
|
||||
log('looking for application %s', applicationPath)
|
||||
|
||||
return findVersion(applicationPath)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
Browser,
|
||||
FoundBrowser,
|
||||
NotDetectedAtPathError,
|
||||
NotInstalledError
|
||||
NotInstalledError,
|
||||
} from './types'
|
||||
import * as windowsHelper from './windows'
|
||||
|
||||
@@ -25,6 +25,7 @@ const setMajorVersion = (browser: FoundBrowser) => {
|
||||
browser.majorVersion
|
||||
)
|
||||
}
|
||||
|
||||
return browser
|
||||
}
|
||||
|
||||
@@ -40,22 +41,24 @@ type Helpers = {
|
||||
const helpers: Helpers = {
|
||||
darwin: darwinHelper,
|
||||
linux: linuxHelper,
|
||||
win32: windowsHelper
|
||||
win32: windowsHelper,
|
||||
}
|
||||
|
||||
function getHelper(platform?: NodeJS.Platform): PlatformHelper {
|
||||
function getHelper (platform?: NodeJS.Platform): PlatformHelper {
|
||||
return helpers[platform || os.platform()]
|
||||
}
|
||||
|
||||
function lookup(
|
||||
function lookup (
|
||||
platform: NodeJS.Platform,
|
||||
browser: Browser
|
||||
): Promise<FoundBrowser> {
|
||||
log('looking up %s on %s platform', browser.name, platform)
|
||||
const helper = getHelper(platform)
|
||||
|
||||
if (!helper) {
|
||||
throw new Error(`Cannot lookup browser ${browser.name} on ${platform}`)
|
||||
}
|
||||
|
||||
return helper.detect(browser)
|
||||
}
|
||||
|
||||
@@ -64,16 +67,17 @@ function lookup(
|
||||
* one for each binary. If Windows is detected, only one `checkOneBrowser` will be called, because
|
||||
* we don't use the `binary` field on Windows.
|
||||
*/
|
||||
function checkBrowser(browser: Browser): Bluebird<(boolean | FoundBrowser)[]> {
|
||||
function checkBrowser (browser: Browser): Bluebird<(boolean | FoundBrowser)[]> {
|
||||
if (Array.isArray(browser.binary) && os.platform() !== 'win32') {
|
||||
return Bluebird.map(browser.binary, (binary: string) => {
|
||||
return checkOneBrowser(extend({}, browser, { binary }))
|
||||
})
|
||||
}
|
||||
|
||||
return Bluebird.map([browser], checkOneBrowser)
|
||||
}
|
||||
|
||||
function checkOneBrowser(browser: Browser): Promise<boolean | FoundBrowser> {
|
||||
function checkOneBrowser (browser: Browser): Promise<boolean | FoundBrowser> {
|
||||
const platform = os.platform()
|
||||
const pickBrowserProps = pick([
|
||||
'name',
|
||||
@@ -82,7 +86,7 @@ function checkOneBrowser(browser: Browser): Promise<boolean | FoundBrowser> {
|
||||
'type',
|
||||
'version',
|
||||
'path',
|
||||
'custom'
|
||||
'custom',
|
||||
])
|
||||
|
||||
const logBrowser = (props: any) => {
|
||||
@@ -92,18 +96,21 @@ function checkOneBrowser(browser: Browser): Promise<boolean | FoundBrowser> {
|
||||
const failed = (err: NotInstalledError) => {
|
||||
if (err.notInstalled) {
|
||||
log('browser %s not installed', browser.name)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
throw err
|
||||
}
|
||||
|
||||
log('checking one browser %s', browser.name)
|
||||
|
||||
return lookup(platform, browser)
|
||||
.then(merge(browser))
|
||||
.then(pickBrowserProps)
|
||||
.then(tap(logBrowser))
|
||||
.then(setMajorVersion)
|
||||
.catch(failed)
|
||||
.then(merge(browser))
|
||||
.then(pickBrowserProps)
|
||||
.then(tap(logBrowser))
|
||||
.then(setMajorVersion)
|
||||
.catch(failed)
|
||||
}
|
||||
|
||||
/** returns list of detected browsers */
|
||||
@@ -114,15 +121,15 @@ export const detect = (goalBrowsers?: Browser[]): Bluebird<FoundBrowser[]> => {
|
||||
goalBrowsers = browsers
|
||||
}
|
||||
|
||||
const removeDuplicates = uniqBy((browser: FoundBrowser) =>
|
||||
props(['name', 'version'], browser)
|
||||
)
|
||||
const removeDuplicates = uniqBy((browser: FoundBrowser) => {
|
||||
return props(['name', 'version'], browser)
|
||||
})
|
||||
const compactFalse = (browsers: any[]) => compact(browsers) as FoundBrowser[]
|
||||
|
||||
return Bluebird.mapSeries(goalBrowsers, checkBrowser)
|
||||
.then(flatten)
|
||||
.then(compactFalse)
|
||||
.then(removeDuplicates)
|
||||
.then(flatten)
|
||||
.then(compactFalse)
|
||||
.then(removeDuplicates)
|
||||
}
|
||||
|
||||
export const detectByPath = (
|
||||
@@ -152,17 +159,18 @@ export const detectByPath = (
|
||||
custom: true,
|
||||
path,
|
||||
version: regexExec[1],
|
||||
majorVersion: regexExec[1].split('.', 2)[0]
|
||||
majorVersion: regexExec[1].split('.', 2)[0],
|
||||
})
|
||||
}
|
||||
|
||||
return helper
|
||||
.getVersionString(path)
|
||||
.then(detectBrowserByVersionString)
|
||||
.catch((err: NotDetectedAtPathError) => {
|
||||
if (err.notDetectedAtPath) {
|
||||
throw err
|
||||
}
|
||||
throw notDetectedAtPathErr(err.message)
|
||||
})
|
||||
.getVersionString(path)
|
||||
.then(detectBrowserByVersionString)
|
||||
.catch((err: NotDetectedAtPathError) => {
|
||||
if (err.notDetectedAtPath) {
|
||||
throw err
|
||||
}
|
||||
|
||||
throw notDetectedAtPathErr(err.message)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,12 +4,16 @@ export const notInstalledErr = (name: string, message?: string) => {
|
||||
const err = new Error(
|
||||
message || `Browser not installed: ${name}`
|
||||
) as NotInstalledError
|
||||
|
||||
err.notInstalled = true
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
export const notDetectedAtPathErr = (stdout: string) => {
|
||||
const err = new Error(stdout) as NotDetectedAtPathError
|
||||
|
||||
err.notDetectedAtPath = true
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,5 +2,7 @@ import { launch } from './browsers'
|
||||
import { detect, detectByPath } from './detect'
|
||||
|
||||
export { detect }
|
||||
|
||||
export { detectByPath }
|
||||
|
||||
export { launch }
|
||||
|
||||
@@ -4,21 +4,24 @@ import { FoundBrowser, Browser } from '../types'
|
||||
import { notInstalledErr } from '../errors'
|
||||
import execa from 'execa'
|
||||
|
||||
function getLinuxBrowser(
|
||||
function getLinuxBrowser (
|
||||
name: string,
|
||||
binary: string,
|
||||
versionRegex: RegExp
|
||||
): Promise<FoundBrowser> {
|
||||
const getVersion = (stdout: string) => {
|
||||
const m = versionRegex.exec(stdout)
|
||||
|
||||
if (m) {
|
||||
return m[1]
|
||||
}
|
||||
|
||||
log(
|
||||
'Could not extract version from %s using regex %s',
|
||||
stdout,
|
||||
versionRegex
|
||||
)
|
||||
|
||||
throw notInstalledErr(binary)
|
||||
}
|
||||
|
||||
@@ -28,30 +31,32 @@ function getLinuxBrowser(
|
||||
binary,
|
||||
err.message
|
||||
)
|
||||
|
||||
throw notInstalledErr(binary)
|
||||
}
|
||||
|
||||
return getVersionString(binary)
|
||||
.then(getVersion)
|
||||
.then((version: string) => {
|
||||
return {
|
||||
name,
|
||||
version,
|
||||
path: binary
|
||||
} as FoundBrowser
|
||||
})
|
||||
.catch(logAndThrowError)
|
||||
.then(getVersion)
|
||||
.then((version: string) => {
|
||||
return {
|
||||
name,
|
||||
version,
|
||||
path: binary,
|
||||
} as FoundBrowser
|
||||
})
|
||||
.catch(logAndThrowError)
|
||||
}
|
||||
|
||||
export function getVersionString(path: string) {
|
||||
export function getVersionString (path: string) {
|
||||
log('finding version string using command "%s --version"', path)
|
||||
|
||||
return execa
|
||||
.stdout(path, ['--version'])
|
||||
.then(trim)
|
||||
.then(tap(partial(log, ['stdout: %s'])))
|
||||
.stdout(path, ['--version'])
|
||||
.then(trim)
|
||||
.then(tap(partial(log, ['stdout: %s'])))
|
||||
}
|
||||
|
||||
export function detect(browser: Browser) {
|
||||
export function detect (browser: Browser) {
|
||||
return getLinuxBrowser(
|
||||
browser.name,
|
||||
browser.binary as string,
|
||||
|
||||
@@ -7,17 +7,19 @@ import { notInstalledErr } from '../errors'
|
||||
import { log } from '../log'
|
||||
import { Browser, FoundBrowser } from '../types'
|
||||
|
||||
function formFullAppPath(name: string) {
|
||||
function formFullAppPath (name: string) {
|
||||
const prefix = 'C:/Program Files (x86)/Google/Chrome/Application'
|
||||
|
||||
return normalize(join(prefix, `${name}.exe`))
|
||||
}
|
||||
|
||||
function formChromiumAppPath() {
|
||||
function formChromiumAppPath () {
|
||||
const exe = 'C:/Program Files (x86)/Google/chrome-win32/chrome.exe'
|
||||
|
||||
return normalize(exe)
|
||||
}
|
||||
|
||||
function formChromeCanaryAppPath() {
|
||||
function formChromeCanaryAppPath () {
|
||||
const home = homedir()
|
||||
const exe = join(
|
||||
home,
|
||||
@@ -28,6 +30,7 @@ function formChromeCanaryAppPath() {
|
||||
'Application',
|
||||
'chrome.exe'
|
||||
)
|
||||
|
||||
return normalize(exe)
|
||||
}
|
||||
|
||||
@@ -43,52 +46,56 @@ interface WindowsBrowserPaths {
|
||||
const formPaths: WindowsBrowserPaths = {
|
||||
chrome: formFullAppPath,
|
||||
canary: formChromeCanaryAppPath,
|
||||
chromium: formChromiumAppPath
|
||||
chromium: formChromiumAppPath,
|
||||
}
|
||||
|
||||
function getWindowsBrowser(name: string): Promise<FoundBrowser> {
|
||||
function getWindowsBrowser (name: string): Promise<FoundBrowser> {
|
||||
const getVersion = (stdout: string): string => {
|
||||
// result from wmic datafile
|
||||
// "Version=61.0.3163.100"
|
||||
const wmicVersion = /^Version=(\S+)$/
|
||||
const m = wmicVersion.exec(stdout)
|
||||
|
||||
if (m) {
|
||||
return m[1]
|
||||
}
|
||||
|
||||
log('Could not extract version from %s using regex %s', stdout, wmicVersion)
|
||||
throw notInstalledErr(name)
|
||||
}
|
||||
|
||||
const formFullAppPathFn: any = formPaths[name] || formFullAppPath
|
||||
const exePath = formFullAppPathFn(name)
|
||||
|
||||
log('exe path %s', exePath)
|
||||
|
||||
return pathExists(exePath)
|
||||
.then(exists => {
|
||||
log('found %s ?', exePath, exists)
|
||||
.then((exists) => {
|
||||
log('found %s ?', exePath, exists)
|
||||
|
||||
if (!exists) {
|
||||
throw notInstalledErr(`Browser ${name} file not found at ${exePath}`)
|
||||
}
|
||||
if (!exists) {
|
||||
throw notInstalledErr(`Browser ${name} file not found at ${exePath}`)
|
||||
}
|
||||
|
||||
return getVersionString(exePath)
|
||||
.then(tap(log))
|
||||
.then(getVersion)
|
||||
.then((version: string) => {
|
||||
log("browser %s at '%s' version %s", name, exePath, version)
|
||||
return {
|
||||
name,
|
||||
version,
|
||||
path: exePath
|
||||
} as FoundBrowser
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
throw notInstalledErr(name)
|
||||
return getVersionString(exePath)
|
||||
.then(tap(log))
|
||||
.then(getVersion)
|
||||
.then((version: string) => {
|
||||
log('browser %s at \'%s\' version %s', name, exePath, version)
|
||||
|
||||
return {
|
||||
name,
|
||||
version,
|
||||
path: exePath,
|
||||
} as FoundBrowser
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
throw notInstalledErr(name)
|
||||
})
|
||||
}
|
||||
|
||||
export function getVersionString(path: string) {
|
||||
export function getVersionString (path: string) {
|
||||
const doubleEscape = (s: string) => s.replace(/\\/g, '\\\\')
|
||||
|
||||
// on Windows using "--version" seems to always start the full
|
||||
@@ -100,14 +107,14 @@ export function getVersionString(path: string) {
|
||||
`name="${doubleEscape(path)}"`,
|
||||
'get',
|
||||
'Version',
|
||||
'/value'
|
||||
'/value',
|
||||
]
|
||||
|
||||
return execa('wmic', args)
|
||||
.then(result => result.stdout)
|
||||
.then(trim)
|
||||
.then((result) => result.stdout)
|
||||
.then(trim)
|
||||
}
|
||||
|
||||
export function detect(browser: Browser) {
|
||||
export function detect (browser: Browser) {
|
||||
return getWindowsBrowser(browser.name)
|
||||
}
|
||||
|
||||
@@ -2,38 +2,23 @@
|
||||
"name": "@packages/launcher",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"types": "../ts/index.d.ts",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"pretest": "npm run check-deps-pre && npm run lint",
|
||||
"test": "npm run unit",
|
||||
"unit": "bin-up mocha --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json",
|
||||
"check-deps": "node ../../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"preclean": "npm run check-deps-pre",
|
||||
"clean": "node scripts/clean.js || true",
|
||||
"clean-js": "npm run clean",
|
||||
"lint": "npm run format-ts && npm run lint-ts && npm run lint-js",
|
||||
"lint-js": "bin-up eslint --fix *.js",
|
||||
"lint-ts": "tslint --project . --fix --format stylish lib/*.ts lib/**/*.ts",
|
||||
"format-ts": "prettier --no-semi --single-quote --write lib/*.ts lib/**/*.ts",
|
||||
"build": "bin-up tsc --project .",
|
||||
"build-js": "bin-up tsc --project .",
|
||||
"size": "t=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bin-up": "1.2.0",
|
||||
"chai": "3.5.0",
|
||||
"prettier": "1.17.0",
|
||||
"shelljs": "0.8.3",
|
||||
"sinon": "2.4.1",
|
||||
"sinon-chai": "3.3.0",
|
||||
"tslint": "5.16.0",
|
||||
"tslint-config-standard": "8.0.1"
|
||||
"check-deps": "node ../../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"preclean": "npm run check-deps-pre",
|
||||
"clean": "node scripts/clean.js || true",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"clean-js": "npm run clean",
|
||||
"size": "t=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";",
|
||||
"pretest": "npm run check-deps-pre",
|
||||
"test": "npm run unit",
|
||||
"unit": "bin-up mocha --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"bluebird": "3.5.3",
|
||||
@@ -44,5 +29,13 @@
|
||||
"plist": "2.1.0",
|
||||
"pluralize": "8.0.0",
|
||||
"ramda": "0.24.1"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"bin-up": "1.2.0",
|
||||
"chai": "3.5.0",
|
||||
"shelljs": "0.8.3",
|
||||
"sinon": "2.4.1",
|
||||
"sinon-chai": "3.3.0"
|
||||
},
|
||||
"types": "../ts/index.d.ts"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:@cypress/dev/tests"
|
||||
]
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { browsers } from '../../lib/browsers'
|
||||
const snapshot = require('snap-shot-it')
|
||||
|
||||
describe('browsers', () => {
|
||||
it('returns the expected list of browsers', () => {
|
||||
snapshot(browsers)
|
||||
})
|
||||
it('returns the expected list of browsers', () => {
|
||||
snapshot(browsers)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import { detect } from '../../lib/detect'
|
||||
const os = require('os')
|
||||
import { log } from '../log'
|
||||
import {project} from 'ramda'
|
||||
import { project } from 'ramda'
|
||||
|
||||
const isWindows = () =>
|
||||
os.platform() === 'win32'
|
||||
const isWindows = () => {
|
||||
return os.platform() === 'win32'
|
||||
}
|
||||
|
||||
describe('browser detection', () => {
|
||||
// making simple to debug tests
|
||||
// using DEBUG=... flag
|
||||
const checkBrowsers = browsers => {
|
||||
const checkBrowsers = (browsers) => {
|
||||
log('detected browsers %j', browsers)
|
||||
expect(browsers).to.be.an.array
|
||||
|
||||
const mainProps = project(['name', 'version'], browsers)
|
||||
|
||||
log('%d browsers\n%j', browsers.length, mainProps)
|
||||
|
||||
if (isWindows()) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
require("../spec_helper");
|
||||
require('../spec_helper')
|
||||
|
||||
const api = require('../..')
|
||||
|
||||
describe("launcher", function() {
|
||||
it('has all needed methods', function() {
|
||||
describe('launcher', function () {
|
||||
it('has all needed methods', function () {
|
||||
expect(api.launch).to.be.a.function
|
||||
expect(api.detect).to.be.a.function
|
||||
expect(api.detectByPath).to.be.a.function
|
||||
|
||||
@@ -10,34 +10,41 @@ const goalBrowsers = [
|
||||
name: 'test-browser-name',
|
||||
versionRegex: /test-browser v(\S+)$/,
|
||||
profile: true,
|
||||
binary: 'test-browser'
|
||||
binary: 'test-browser',
|
||||
},
|
||||
{
|
||||
displayName: 'Foo Browser',
|
||||
name: 'foo-browser',
|
||||
versionRegex: /foo-browser v(\S+)$/,
|
||||
profile: true,
|
||||
binary: ['foo-browser', 'foo-bar-browser']
|
||||
}
|
||||
binary: ['foo-browser', 'foo-bar-browser'],
|
||||
},
|
||||
]
|
||||
|
||||
describe('linux browser detection', () => {
|
||||
beforeEach(function stubShell () {
|
||||
const stdout = sinon.stub(execa, 'stdout')
|
||||
|
||||
stdout.withArgs('test-browser', ['--version'])
|
||||
.resolves('test-browser v100.1.2.3')
|
||||
.resolves('test-browser v100.1.2.3')
|
||||
|
||||
stdout.withArgs('foo-browser', ['--version'])
|
||||
.resolves('foo-browser v100.1.2.3')
|
||||
.resolves('foo-browser v100.1.2.3')
|
||||
|
||||
stdout.withArgs('foo-bar-browser', ['--version'])
|
||||
.resolves('foo-browser v100.1.2.3')
|
||||
.resolves('foo-browser v100.1.2.3')
|
||||
|
||||
stdout.withArgs('/Applications/My Shiny New Browser.app', ['--version'])
|
||||
.resolves('foo-browser v100.1.2.3')
|
||||
.resolves('foo-browser v100.1.2.3')
|
||||
|
||||
stdout.withArgs('/foo/bar/browser', ['--version'])
|
||||
.resolves('foo-browser v9001.1.2.3')
|
||||
.resolves('foo-browser v9001.1.2.3')
|
||||
|
||||
stdout.withArgs('/not/a/browser', ['--version'])
|
||||
.resolves('not a browser version string')
|
||||
.resolves('not a browser version string')
|
||||
|
||||
stdout.withArgs('/not/a/real/path', ['--version'])
|
||||
.rejects()
|
||||
.rejects()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@@ -50,9 +57,10 @@ describe('linux browser detection', () => {
|
||||
expect(browser).to.deep.equal({
|
||||
name: 'test-browser-name',
|
||||
path: 'test-browser',
|
||||
version: '100.1.2.3'
|
||||
version: '100.1.2.3',
|
||||
})
|
||||
}
|
||||
|
||||
return linuxHelper.detect(goal).then(checkBrowser)
|
||||
})
|
||||
|
||||
@@ -66,18 +74,18 @@ describe('linux browser detection', () => {
|
||||
name: 'test-browser-name',
|
||||
version: '100.1.2.3',
|
||||
path: 'test-browser',
|
||||
majorVersion: '100'
|
||||
majorVersion: '100',
|
||||
},
|
||||
{
|
||||
displayName: 'Foo Browser',
|
||||
name: 'foo-browser',
|
||||
version: '100.1.2.3',
|
||||
path: 'foo-browser',
|
||||
majorVersion: '100'
|
||||
}
|
||||
majorVersion: '100',
|
||||
},
|
||||
]
|
||||
|
||||
return detect(goalBrowsers).then(browsers => {
|
||||
return detect(goalBrowsers).then((browsers) => {
|
||||
log('Browsers: %o', browsers)
|
||||
log('Expected browsers: %o', expected)
|
||||
expect(browsers).to.deep.equal(expected)
|
||||
@@ -90,8 +98,8 @@ describe('linux browser detection', () => {
|
||||
name: 'foo-browser',
|
||||
versionRegex: /v(\S+)$/,
|
||||
profile: true,
|
||||
binary: ['foo-browser', 'foo-bar-browser']
|
||||
}
|
||||
binary: ['foo-browser', 'foo-bar-browser'],
|
||||
},
|
||||
]
|
||||
|
||||
const expected = [
|
||||
@@ -99,11 +107,11 @@ describe('linux browser detection', () => {
|
||||
name: 'foo-browser',
|
||||
version: '100.1.2.3',
|
||||
path: 'foo-browser',
|
||||
majorVersion: '100'
|
||||
}
|
||||
majorVersion: '100',
|
||||
},
|
||||
]
|
||||
|
||||
return detect(goalBrowsers).then(browsers => {
|
||||
return detect(goalBrowsers).then((browsers) => {
|
||||
log('Browsers: %o', browsers)
|
||||
log('Expected browsers: %o', expected)
|
||||
expect(browsers).to.deep.equal(expected)
|
||||
@@ -113,15 +121,17 @@ describe('linux browser detection', () => {
|
||||
describe('detectByPath', () => {
|
||||
it('detects by path', () => {
|
||||
return detectByPath('/foo/bar/browser', goalBrowsers)
|
||||
.then(browser => {
|
||||
.then((browser) => {
|
||||
return expect(browser).to.deep.equal(
|
||||
Object.assign({}, goalBrowsers.find(gb => gb.name === 'foo-browser'), {
|
||||
Object.assign({}, goalBrowsers.find((gb) => {
|
||||
return gb.name === 'foo-browser'
|
||||
}), {
|
||||
displayName: 'Custom Foo Browser',
|
||||
info: 'Loaded from /foo/bar/browser',
|
||||
custom: true,
|
||||
version: '9001.1.2.3',
|
||||
majorVersion: '9001',
|
||||
path: '/foo/bar/browser'
|
||||
path: '/foo/bar/browser',
|
||||
})
|
||||
)
|
||||
})
|
||||
@@ -129,36 +139,37 @@ describe('linux browser detection', () => {
|
||||
|
||||
it('rejects when there was no matching versionRegex', () => {
|
||||
return detectByPath('/not/a/browser', goalBrowsers)
|
||||
.then(browser => {
|
||||
.then(() => {
|
||||
throw Error('Should not find a browser')
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
expect(err.notDetectedAtPath).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
it('rejects when there was an error executing the command', () => {
|
||||
return detectByPath('/not/a/real/path', goalBrowsers)
|
||||
.then(browser => {
|
||||
.then(() => {
|
||||
throw Error('Should not find a browser')
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
expect(err.notDetectedAtPath).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
it('works with spaces in the path', () => {
|
||||
return detectByPath('/Applications/My Shiny New Browser.app', goalBrowsers)
|
||||
.then(browser => {
|
||||
.then((browser) => {
|
||||
return expect(browser).to.deep.equal(
|
||||
Object.assign({}, goalBrowsers.find(gb => gb.name === 'foo-browser'), {
|
||||
Object.assign({}, goalBrowsers.find((gb) => {
|
||||
return gb.name === 'foo-browser'
|
||||
}), {
|
||||
displayName: 'Custom Foo Browser',
|
||||
info: 'Loaded from /Applications/My Shiny New Browser.app',
|
||||
custom: true,
|
||||
version: '100.1.2.3',
|
||||
majorVersion: '100',
|
||||
path: '/Applications/My Shiny New Browser.app'
|
||||
path: '/Applications/My Shiny New Browser.app',
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
@@ -6,5 +6,8 @@
|
||||
],
|
||||
"files": [
|
||||
"./../ts/index.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"test"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ type FamilyCache = {
|
||||
[host: string] : 4 | 6
|
||||
}
|
||||
|
||||
export function buildConnectReqHead(hostname: string, port: string, proxy: url.Url) {
|
||||
export function buildConnectReqHead (hostname: string, port: string, proxy: url.Url) {
|
||||
const connectReq = [`CONNECT ${hostname}:${port} HTTP/1.1`]
|
||||
|
||||
connectReq.push(`Host: ${hostname}:${port}`)
|
||||
@@ -54,7 +54,7 @@ export const createProxySock = (opts: CreateProxySockOpts, cb: CreateProxySockCb
|
||||
let connectOpts: any = {
|
||||
port: Number(port),
|
||||
host: opts.proxy.hostname,
|
||||
useTls: isHttps
|
||||
useTls: isHttps,
|
||||
}
|
||||
|
||||
if (!opts.shouldRetry) {
|
||||
@@ -78,6 +78,7 @@ export const isRequestHttps = (options: http.RequestOptions) => {
|
||||
export const isResponseStatusCode200 = (head: string) => {
|
||||
// read status code from proxy's response
|
||||
const matches = head.match(statusCodeRe)
|
||||
|
||||
return _.get(matches, 1) === '200'
|
||||
}
|
||||
|
||||
@@ -88,6 +89,7 @@ export const regenerateRequestHead = (req: http.ClientRequest) => {
|
||||
// the _header has already been queued to be written to the socket
|
||||
const first = req.output[0]
|
||||
const endOfHeaders = first.indexOf(_.repeat(CRLF, 2)) + 4
|
||||
|
||||
req.output[0] = req._header + first.substring(endOfHeaders)
|
||||
}
|
||||
}
|
||||
@@ -103,6 +105,7 @@ const getFirstWorkingFamily = (
|
||||
// https://github.com/cypress-io/cypress/issues/112
|
||||
|
||||
const isIP = net.isIP(host)
|
||||
|
||||
if (isIP) {
|
||||
// isIP conveniently returns the family of the address
|
||||
return cb(isIP)
|
||||
@@ -120,6 +123,7 @@ const getFirstWorkingFamily = (
|
||||
return getAddress(port, host)
|
||||
.then((firstWorkingAddress: net.Address) => {
|
||||
familyCache[host] = firstWorkingAddress.family
|
||||
|
||||
return cb(firstWorkingAddress.family)
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -132,13 +136,13 @@ export class CombinedAgent {
|
||||
httpsAgent: HttpsAgent
|
||||
familyCache: FamilyCache = {}
|
||||
|
||||
constructor(httpOpts: http.AgentOptions = {}, httpsOpts: https.AgentOptions = {}) {
|
||||
constructor (httpOpts: http.AgentOptions = {}, httpsOpts: https.AgentOptions = {}) {
|
||||
this.httpAgent = new HttpAgent(httpOpts)
|
||||
this.httpsAgent = new HttpsAgent(httpsOpts)
|
||||
}
|
||||
|
||||
// called by Node.js whenever a new request is made internally
|
||||
addRequest(req: http.ClientRequest, options: http.RequestOptions, port?: number, localAddress?: string) {
|
||||
addRequest (req: http.ClientRequest, options: http.RequestOptions, port?: number, localAddress?: string) {
|
||||
// Legacy API: addRequest(req, host, port, localAddress)
|
||||
// https://github.com/nodejs/node/blob/cb68c04ce1bc4534b2d92bc7319c6ff6dda0180d/lib/_http_agent.js#L148-L155
|
||||
if (typeof options === 'string') {
|
||||
@@ -146,7 +150,7 @@ export class CombinedAgent {
|
||||
options = {
|
||||
host: options,
|
||||
port: port!,
|
||||
localAddress
|
||||
localAddress,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,8 +280,10 @@ class HttpsAgent extends https.Agent {
|
||||
createProxySock({ proxy, shouldRetry: options.shouldRetry }, (originalErr?, proxySocket?, triggerRetry?) => {
|
||||
if (originalErr) {
|
||||
const err: any = new Error(`A connection to the upstream proxy could not be established: ${originalErr.message}`)
|
||||
|
||||
err[0] = originalErr
|
||||
err.upstreamProxyConnect = true
|
||||
|
||||
return cb(err, undefined)
|
||||
}
|
||||
|
||||
@@ -300,6 +306,7 @@ class HttpsAgent extends https.Agent {
|
||||
if (!_.includes(buffer, _.repeat(CRLF, 2))) {
|
||||
// haven't received end of headers yet, keep buffering
|
||||
proxySocket.once('data', onData)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -316,6 +323,7 @@ class HttpsAgent extends https.Agent {
|
||||
// https.Agent will upgrade and reuse this socket now
|
||||
options.socket = proxySocket
|
||||
options.servername = hostname
|
||||
|
||||
return cb(undefined, super.createConnection(options, undefined))
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ export function getAddress (port: number, hostname: string) {
|
||||
return lookupAsync(hostname, { all: true })
|
||||
.then((addresses: net.Address[]) => {
|
||||
debug('got addresses %o', { hostname, port, addresses })
|
||||
|
||||
// convert to an array if string
|
||||
return Array.prototype.concat.call(addresses).map(fn)
|
||||
})
|
||||
@@ -58,7 +59,7 @@ interface RetryingOptions {
|
||||
getDelayMsForRetry: (iteration: number, err: Error) => number | undefined
|
||||
}
|
||||
|
||||
function createSocket(opts: RetryingOptions, onConnect): net.Socket {
|
||||
function createSocket (opts: RetryingOptions, onConnect): net.Socket {
|
||||
const netOpts = _.pick(opts, 'host', 'port')
|
||||
|
||||
if (opts.useTls) {
|
||||
@@ -76,40 +77,42 @@ export function createRetryingSocket (
|
||||
opts.getDelayMsForRetry = getDelayForRetry
|
||||
}
|
||||
|
||||
function tryConnect(iteration = 0) {
|
||||
function tryConnect (iteration = 0) {
|
||||
const retry = (err) => {
|
||||
const delay = opts.getDelayMsForRetry(iteration, err)
|
||||
|
||||
if (typeof delay === 'undefined') {
|
||||
debug("retries exhausted, bubbling up error %o", { iteration, err })
|
||||
debug('retries exhausted, bubbling up error %o', { iteration, err })
|
||||
|
||||
return cb(err)
|
||||
}
|
||||
|
||||
debug("received error on connect, retrying %o", { iteration, delay, err })
|
||||
debug('received error on connect, retrying %o', { iteration, delay, err })
|
||||
|
||||
setTimeout(() => {
|
||||
tryConnect(iteration + 1)
|
||||
}, delay)
|
||||
}
|
||||
|
||||
function onError(err) {
|
||||
sock.on("error", (err) => {
|
||||
debug("second error received on retried socket %o", { opts, iteration, err })
|
||||
function onError (err) {
|
||||
sock.on('error', (err) => {
|
||||
debug('second error received on retried socket %o', { opts, iteration, err })
|
||||
})
|
||||
|
||||
retry(err)
|
||||
}
|
||||
|
||||
function onConnect() {
|
||||
debug("successfully connected %o", { opts, iteration })
|
||||
function onConnect () {
|
||||
debug('successfully connected %o', { opts, iteration })
|
||||
// connection successfully established, pass control of errors/retries to consuming function
|
||||
sock.removeListener("error", onError)
|
||||
sock.removeListener('error', onError)
|
||||
|
||||
cb(undefined, sock, retry)
|
||||
}
|
||||
|
||||
const sock = createSocket(opts, onConnect)
|
||||
sock.once("error", onError)
|
||||
|
||||
sock.once('error', onError)
|
||||
}
|
||||
|
||||
tryConnect()
|
||||
|
||||
@@ -2,4 +2,5 @@ import agent from './agent'
|
||||
import * as connect from './connect'
|
||||
|
||||
export { agent }
|
||||
|
||||
export { connect }
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
"name": "@packages/network",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"types": "./lib/index.ts",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build-js": "bin-up tsc --project .",
|
||||
"test": "bin-up mocha --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json"
|
||||
@@ -18,12 +17,13 @@
|
||||
"proxy-from-env": "1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bin-up": "1.2.0",
|
||||
"@cypress/debugging-proxy": "2.0.1",
|
||||
"bin-up": "1.2.0",
|
||||
"express": "4.16.4",
|
||||
"request": "2.88.0",
|
||||
"request-promise": "4.2.4",
|
||||
"sinon": "7.3.1",
|
||||
"sinon-chai": "3.3.0"
|
||||
}
|
||||
},
|
||||
"types": "./lib/index.ts"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:@cypress/dev/tests"
|
||||
]
|
||||
}
|
||||
@@ -6,16 +6,17 @@ import sinonChai from 'sinon-chai'
|
||||
import * as connect from '../../lib/connect'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
chai.use(sinonChai)
|
||||
|
||||
describe('lib/connect', function() {
|
||||
context('.getAddress', function() {
|
||||
it('resolves localhost on 127.0.0.1 immediately', function() {
|
||||
describe('lib/connect', function () {
|
||||
context('.getAddress', function () {
|
||||
it('resolves localhost on 127.0.0.1 immediately', function () {
|
||||
this.timeout(50)
|
||||
|
||||
const server = net.createServer(_.partialRight(_.invoke, 'close'))
|
||||
|
||||
return Bluebird.fromCallback(cb => {
|
||||
return Bluebird.fromCallback((cb) => {
|
||||
server.listen(0, '127.0.0.1', cb)
|
||||
})
|
||||
.then(() => {
|
||||
@@ -24,19 +25,19 @@ describe('lib/connect', function() {
|
||||
.then((address) => {
|
||||
expect(address).to.deep.eq({
|
||||
family: 4,
|
||||
address: '127.0.0.1'
|
||||
address: '127.0.0.1',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Error: listen EADDRNOTAVAIL ::1
|
||||
// TODO: add an ipv6 lo if to the docker container
|
||||
it.skip('resolves localhost on ::1 immediately', function() {
|
||||
it.skip('resolves localhost on ::1 immediately', function () {
|
||||
this.timeout(50)
|
||||
|
||||
const server = net.createServer(_.partialRight(_.invoke, 'close'))
|
||||
|
||||
return Bluebird.fromCallback(cb => {
|
||||
return Bluebird.fromCallback((cb) => {
|
||||
server.listen(0, '::1', cb)
|
||||
})
|
||||
.then(() => {
|
||||
@@ -45,7 +46,7 @@ describe('lib/connect', function() {
|
||||
.then((address) => {
|
||||
expect(address).to.deep.eq({
|
||||
family: 6,
|
||||
address: '::1'
|
||||
address: '::1',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -11,14 +11,14 @@ export interface AsyncServer {
|
||||
listenAsync: (port) => Promise<void>
|
||||
}
|
||||
|
||||
function addDestroy(server: http.Server | https.Server) {
|
||||
function addDestroy (server: http.Server | https.Server) {
|
||||
let connections = []
|
||||
|
||||
function trackConn(conn) {
|
||||
function trackConn (conn) {
|
||||
connections.push(conn)
|
||||
|
||||
conn.on('close', () => {
|
||||
connections = connections.filter(connection => connection !== conn)
|
||||
connections = connections.filter((connection) => connection !== conn)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -26,15 +26,15 @@ function addDestroy(server: http.Server | https.Server) {
|
||||
server.on('secureConnection', trackConn)
|
||||
|
||||
// @ts-ignore Property 'destroy' does not exist on type 'Server'.
|
||||
server.destroy = function(cb) {
|
||||
server.destroy = function (cb) {
|
||||
server.close(cb)
|
||||
connections.map(connection => connection.destroy())
|
||||
connections.map((connection) => connection.destroy())
|
||||
}
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
function createExpressApp() {
|
||||
function createExpressApp () {
|
||||
const app: express.Application = express()
|
||||
|
||||
app.get('/get', (req, res) => {
|
||||
@@ -49,12 +49,12 @@ function createExpressApp() {
|
||||
return app
|
||||
}
|
||||
|
||||
function getLocalhostCertKeys() {
|
||||
function getLocalhostCertKeys () {
|
||||
return CA.create()
|
||||
.then(ca => ca.generateServerCertificateKeys('localhost'))
|
||||
.then((ca) => ca.generateServerCertificateKeys('localhost'))
|
||||
}
|
||||
|
||||
function onWsConnection(socket) {
|
||||
function onWsConnection (socket) {
|
||||
socket.send('It worked!')
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ export class Servers {
|
||||
wsServer: any
|
||||
wssServer: any
|
||||
|
||||
start(httpPort: number, httpsPort: number) {
|
||||
start (httpPort: number, httpsPort: number) {
|
||||
return Promise.join(
|
||||
createExpressApp(),
|
||||
getLocalhostCertKeys(),
|
||||
@@ -74,15 +74,17 @@ export class Servers {
|
||||
this.httpServer = Promise.promisifyAll(
|
||||
addDestroy(http.createServer(app))
|
||||
) as http.Server & AsyncServer
|
||||
|
||||
this.wsServer = Io.server(this.httpServer)
|
||||
|
||||
this.https = { cert, key }
|
||||
this.httpsServer = Promise.promisifyAll(
|
||||
addDestroy(https.createServer(this.https, <http.RequestListener>app))
|
||||
) as https.Server & AsyncServer
|
||||
|
||||
this.wssServer = Io.server(this.httpsServer)
|
||||
|
||||
;[this.wsServer, this.wssServer].map(ws => {
|
||||
;[this.wsServer, this.wssServer].map((ws) => {
|
||||
ws.on('connection', onWsConnection)
|
||||
})
|
||||
|
||||
@@ -95,7 +97,7 @@ export class Servers {
|
||||
})
|
||||
}
|
||||
|
||||
stop() {
|
||||
stop () {
|
||||
return Promise.join(
|
||||
this.httpServer.destroyAsync(),
|
||||
this.httpsServer.destroyAsync()
|
||||
|
||||
@@ -11,35 +11,37 @@ import url from 'url'
|
||||
import DebuggingProxy from '@cypress/debugging-proxy'
|
||||
import Io from '@packages/socket'
|
||||
import {
|
||||
buildConnectReqHead, createProxySock, isRequestHttps, isResponseStatusCode200,
|
||||
regenerateRequestHead, CombinedAgent
|
||||
buildConnectReqHead, createProxySock, isRequestHttps, isResponseStatusCode200,
|
||||
regenerateRequestHead, CombinedAgent,
|
||||
} from '../../lib/agent'
|
||||
import { AsyncServer, Servers } from '../support/servers'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
chai.use(sinonChai)
|
||||
|
||||
const PROXY_PORT = 31000
|
||||
const HTTP_PORT = 31080
|
||||
const HTTPS_PORT = 31443
|
||||
|
||||
describe('lib/agent', function() {
|
||||
beforeEach(function() {
|
||||
describe('lib/agent', function () {
|
||||
beforeEach(function () {
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
||||
})
|
||||
|
||||
afterEach(function() {
|
||||
afterEach(function () {
|
||||
process.env.NO_PROXY = process.env.HTTP_PROXY = process.env.HTTPS_PROXY = ''
|
||||
sinon.restore()
|
||||
})
|
||||
|
||||
context('CombinedAgent', function() {
|
||||
before(function() {
|
||||
context('CombinedAgent', function () {
|
||||
before(function () {
|
||||
this.servers = new Servers()
|
||||
|
||||
return this.servers.start(HTTP_PORT, HTTPS_PORT)
|
||||
})
|
||||
|
||||
after(function() {
|
||||
after(function () {
|
||||
return this.servers.stop()
|
||||
})
|
||||
|
||||
@@ -65,11 +67,11 @@ describe('lib/agent', function() {
|
||||
name: 'with an HTTPS upstream requiring auth',
|
||||
proxyUrl: `https://foo:bar@localhost:${PROXY_PORT}`,
|
||||
httpsProxy: true,
|
||||
proxyAuth: true
|
||||
}
|
||||
proxyAuth: true,
|
||||
},
|
||||
].slice().map((testCase) => {
|
||||
context(testCase.name, function() {
|
||||
beforeEach(function() {
|
||||
context(testCase.name, function () {
|
||||
beforeEach(function () {
|
||||
if (testCase.proxyUrl) {
|
||||
process.env.HTTP_PROXY = process.env.HTTPS_PROXY = testCase.proxyUrl
|
||||
process.env.NO_PROXY = ''
|
||||
@@ -79,14 +81,14 @@ describe('lib/agent', function() {
|
||||
|
||||
this.request = request.defaults({
|
||||
proxy: null,
|
||||
agent: this.agent
|
||||
agent: this.agent,
|
||||
})
|
||||
|
||||
if (testCase.proxyUrl) {
|
||||
let options: any = {
|
||||
keepRequests: true,
|
||||
https: false,
|
||||
auth: false
|
||||
auth: false,
|
||||
}
|
||||
|
||||
if (testCase.httpsProxy) {
|
||||
@@ -96,60 +98,62 @@ describe('lib/agent', function() {
|
||||
if (testCase.proxyAuth) {
|
||||
options.auth = {
|
||||
username: 'foo',
|
||||
password: 'bar'
|
||||
password: 'bar',
|
||||
}
|
||||
}
|
||||
|
||||
this.debugProxy = new DebuggingProxy(options)
|
||||
|
||||
return this.debugProxy.start(PROXY_PORT)
|
||||
}
|
||||
})
|
||||
|
||||
afterEach(function() {
|
||||
afterEach(function () {
|
||||
if (testCase.proxyUrl) {
|
||||
this.debugProxy.stop()
|
||||
}
|
||||
})
|
||||
|
||||
it('HTTP pages can be loaded', function() {
|
||||
it('HTTP pages can be loaded', function () {
|
||||
return this.request({
|
||||
url: `http://localhost:${HTTP_PORT}/get`,
|
||||
}).then(body => {
|
||||
}).then((body) => {
|
||||
expect(body).to.eq('It worked!')
|
||||
if (this.debugProxy) {
|
||||
expect(this.debugProxy.requests[0]).to.include({
|
||||
url: `http://localhost:${HTTP_PORT}/get`
|
||||
url: `http://localhost:${HTTP_PORT}/get`,
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('HTTPS pages can be loaded', function() {
|
||||
it('HTTPS pages can be loaded', function () {
|
||||
return this.request({
|
||||
url: `https://localhost:${HTTPS_PORT}/get`
|
||||
}).then(body => {
|
||||
url: `https://localhost:${HTTPS_PORT}/get`,
|
||||
}).then((body) => {
|
||||
expect(body).to.eq('It worked!')
|
||||
if (this.debugProxy) {
|
||||
expect(this.debugProxy.requests[0]).to.include({
|
||||
https: true,
|
||||
url: `localhost:${HTTPS_PORT}`
|
||||
url: `localhost:${HTTPS_PORT}`,
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('HTTP errors are catchable', function() {
|
||||
it('HTTP errors are catchable', function () {
|
||||
return this.request({
|
||||
url: `http://localhost:${HTTP_PORT}/empty-response`,
|
||||
})
|
||||
.then(() => {
|
||||
throw new Error("Shouldn't reach this")
|
||||
throw new Error('Shouldn\'t reach this')
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
if (this.debugProxy) {
|
||||
expect(this.debugProxy.requests[0]).to.include({
|
||||
url: `http://localhost:${HTTP_PORT}/empty-response`
|
||||
url: `http://localhost:${HTTP_PORT}/empty-response`,
|
||||
})
|
||||
|
||||
expect(err.statusCode).to.eq(502)
|
||||
} else {
|
||||
expect(err.message).to.eq('Error: socket hang up')
|
||||
@@ -157,27 +161,27 @@ describe('lib/agent', function() {
|
||||
})
|
||||
})
|
||||
|
||||
it('HTTPS errors are catchable', function() {
|
||||
it('HTTPS errors are catchable', function () {
|
||||
return this.request({
|
||||
url: `https://localhost:${HTTPS_PORT}/empty-response`,
|
||||
})
|
||||
.then(() => {
|
||||
throw new Error("Shouldn't reach this")
|
||||
throw new Error('Shouldn\'t reach this')
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
expect(err.message).to.eq('Error: socket hang up')
|
||||
})
|
||||
})
|
||||
|
||||
it('HTTP websocket connections can be established and used', function() {
|
||||
it('HTTP websocket connections can be established and used', function () {
|
||||
return new Bluebird((resolve) => {
|
||||
Io.client(`http://localhost:${HTTP_PORT}`, {
|
||||
agent: this.agent,
|
||||
transports: ['websocket'],
|
||||
rejectUnauthorized: false
|
||||
rejectUnauthorized: false,
|
||||
}).on('message', resolve)
|
||||
})
|
||||
.then(msg => {
|
||||
.then((msg) => {
|
||||
expect(msg).to.eq('It worked!')
|
||||
if (this.debugProxy) {
|
||||
expect(this.debugProxy.requests[0].ws).to.be.true
|
||||
@@ -186,19 +190,19 @@ describe('lib/agent', function() {
|
||||
})
|
||||
})
|
||||
|
||||
it('HTTPS websocket connections can be established and used', function() {
|
||||
it('HTTPS websocket connections can be established and used', function () {
|
||||
return new Bluebird((resolve) => {
|
||||
Io.client(`https://localhost:${HTTPS_PORT}`, {
|
||||
agent: this.agent,
|
||||
transports: ['websocket'],
|
||||
rejectUnauthorized: false
|
||||
rejectUnauthorized: false,
|
||||
}).on('message', resolve)
|
||||
})
|
||||
.then(msg => {
|
||||
.then((msg) => {
|
||||
expect(msg).to.eq('It worked!')
|
||||
if (this.debugProxy) {
|
||||
expect(this.debugProxy.requests[0]).to.include({
|
||||
url: 'localhost:31443'
|
||||
url: 'localhost:31443',
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -206,17 +210,17 @@ describe('lib/agent', function() {
|
||||
})
|
||||
})
|
||||
|
||||
context('HttpsAgent', function() {
|
||||
beforeEach(function() {
|
||||
context('HttpsAgent', function () {
|
||||
beforeEach(function () {
|
||||
this.agent = new CombinedAgent()
|
||||
|
||||
this.request = request.defaults({
|
||||
agent: <any>this.agent,
|
||||
proxy: null
|
||||
agent: <any> this.agent,
|
||||
proxy: null,
|
||||
})
|
||||
})
|
||||
|
||||
it("#createUpstreamProxyConnection does not go to proxy if domain in NO_PROXY", function () {
|
||||
it('#createUpstreamProxyConnection does not go to proxy if domain in NO_PROXY', function () {
|
||||
const spy = sinon.spy(this.agent.httpsAgent, 'createUpstreamProxyConnection')
|
||||
|
||||
process.env.HTTP_PROXY = process.env.HTTPS_PROXY = 'http://0.0.0.0:0'
|
||||
@@ -229,18 +233,18 @@ describe('lib/agent', function() {
|
||||
expect(spy).to.not.be.called
|
||||
|
||||
return this.request({
|
||||
url: 'https://example.org/'
|
||||
url: 'https://example.org/',
|
||||
})
|
||||
.then(() => {
|
||||
throw new Error('should not be able to connect')
|
||||
})
|
||||
.catch({ message: 'Error: A connection to the upstream proxy could not be established: connect ECONNREFUSED 0.0.0.0'}, () => {
|
||||
.catch({ message: 'Error: A connection to the upstream proxy could not be established: connect ECONNREFUSED 0.0.0.0' }, () => {
|
||||
expect(spy).to.be.calledOnce
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it("#createUpstreamProxyConnection calls to super for caching, TLS-ifying", function() {
|
||||
it('#createUpstreamProxyConnection calls to super for caching, TLS-ifying', function () {
|
||||
const spy = sinon.spy(https.Agent.prototype, 'createConnection')
|
||||
|
||||
const proxy = new DebuggingProxy()
|
||||
@@ -258,6 +262,7 @@ describe('lib/agent', function() {
|
||||
.then(() => {
|
||||
const options = spy.getCall(0).args[0]
|
||||
const session = this.agent.httpsAgent._sessionCache.map[options._agentKey]
|
||||
|
||||
expect(spy).to.be.calledOnce
|
||||
expect(this.agent.httpsAgent._sessionCache.list).to.have.length(1)
|
||||
expect(session).to.not.be.undefined
|
||||
@@ -266,7 +271,7 @@ describe('lib/agent', function() {
|
||||
})
|
||||
})
|
||||
|
||||
it("#createUpstreamProxyConnection throws when connection is accepted then closed", function() {
|
||||
it('#createUpstreamProxyConnection throws when connection is accepted then closed', function () {
|
||||
const proxy = Bluebird.promisifyAll(
|
||||
net.createServer((socket) => {
|
||||
socket.end()
|
||||
@@ -295,17 +300,17 @@ describe('lib/agent', function() {
|
||||
})
|
||||
})
|
||||
|
||||
context('HttpAgent', function() {
|
||||
beforeEach(function() {
|
||||
context('HttpAgent', function () {
|
||||
beforeEach(function () {
|
||||
this.agent = new CombinedAgent()
|
||||
|
||||
this.request = request.defaults({
|
||||
agent: <any>this.agent,
|
||||
proxy: null
|
||||
agent: <any> this.agent,
|
||||
proxy: null,
|
||||
})
|
||||
})
|
||||
|
||||
it("#addRequest does not go to proxy if domain in NO_PROXY", function () {
|
||||
it('#addRequest does not go to proxy if domain in NO_PROXY', function () {
|
||||
const spy = sinon.spy(this.agent.httpAgent, '_addProxiedRequest')
|
||||
|
||||
process.env.HTTP_PROXY = process.env.HTTPS_PROXY = 'http://0.0.0.0:0'
|
||||
@@ -318,12 +323,12 @@ describe('lib/agent', function() {
|
||||
expect(spy).to.not.be.called
|
||||
|
||||
return this.request({
|
||||
url: 'http://example.org/'
|
||||
url: 'http://example.org/',
|
||||
})
|
||||
.then(() => {
|
||||
throw new Error('should not be able to connect')
|
||||
})
|
||||
.catch({ message: 'Error: connect ECONNREFUSED 0.0.0.0'}, () => {
|
||||
.catch({ message: 'Error: connect ECONNREFUSED 0.0.0.0' }, () => {
|
||||
expect(spy).to.be.calledOnce
|
||||
})
|
||||
})
|
||||
@@ -331,82 +336,88 @@ describe('lib/agent', function() {
|
||||
})
|
||||
})
|
||||
|
||||
context(".buildConnectReqHead", function() {
|
||||
it('builds the correct request', function() {
|
||||
context('.buildConnectReqHead', function () {
|
||||
it('builds the correct request', function () {
|
||||
const head = buildConnectReqHead('foo.bar', '1234', {})
|
||||
|
||||
expect(head).to.eq([
|
||||
'CONNECT foo.bar:1234 HTTP/1.1',
|
||||
'Host: foo.bar:1234',
|
||||
'', ''
|
||||
'', '',
|
||||
].join('\r\n'))
|
||||
})
|
||||
|
||||
it('can do Proxy-Authorization', function() {
|
||||
it('can do Proxy-Authorization', function () {
|
||||
const head = buildConnectReqHead('foo.bar', '1234', {
|
||||
auth: 'baz:quux'
|
||||
auth: 'baz:quux',
|
||||
})
|
||||
|
||||
expect(head).to.eq([
|
||||
'CONNECT foo.bar:1234 HTTP/1.1',
|
||||
'Host: foo.bar:1234',
|
||||
'Proxy-Authorization: basic YmF6OnF1dXg=',
|
||||
'', ''
|
||||
'', '',
|
||||
].join('\r\n'))
|
||||
})
|
||||
})
|
||||
|
||||
context(".createProxySock", function() {
|
||||
it("creates a `net` socket for an http url", function(done) {
|
||||
context('.createProxySock', function () {
|
||||
it('creates a `net` socket for an http url', function (done) {
|
||||
sinon.spy(net, 'connect')
|
||||
const proxy = url.parse('http://foo.bar:1234')
|
||||
createProxySock({ proxy }, (err) => {
|
||||
|
||||
createProxySock({ proxy }, () => {
|
||||
expect(net.connect).to.be.calledWith({ host: 'foo.bar', port: 1234 })
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it("creates a `tls` socket for an https url", function(done) {
|
||||
it('creates a `tls` socket for an https url', function (done) {
|
||||
sinon.spy(tls, 'connect')
|
||||
const proxy = url.parse('https://foo.bar:1234')
|
||||
createProxySock({ proxy }, (err) => {
|
||||
|
||||
createProxySock({ proxy }, () => {
|
||||
expect(tls.connect).to.be.calledWith({ host: 'foo.bar', port: 1234 })
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it("throws on unsupported proxy protocol", function(done) {
|
||||
it('throws on unsupported proxy protocol', function (done) {
|
||||
const proxy = url.parse('socksv5://foo.bar:1234')
|
||||
|
||||
createProxySock({ proxy }, (err) => {
|
||||
expect(err.message).to.eq("Unsupported proxy protocol: socksv5:")
|
||||
expect(err.message).to.eq('Unsupported proxy protocol: socksv5:')
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context(".isRequestHttps", function() {
|
||||
context('.isRequestHttps', function () {
|
||||
[
|
||||
{
|
||||
protocol: 'http',
|
||||
agent: http.globalAgent,
|
||||
expect: false
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
protocol: 'https',
|
||||
agent: https.globalAgent,
|
||||
expect: true
|
||||
}
|
||||
expect: true,
|
||||
},
|
||||
].map((testCase) => {
|
||||
it(`detects correctly from ${testCase.protocol} requests`, () => {
|
||||
const spy = sinon.spy(testCase.agent, 'addRequest')
|
||||
|
||||
return request({
|
||||
url: `${testCase.protocol}://foo.bar.baz.invalid`,
|
||||
agent: testCase.agent
|
||||
agent: testCase.agent,
|
||||
})
|
||||
.then(() => {
|
||||
throw new Error('Shouldn\'t succeed')
|
||||
})
|
||||
.catch((e) => {
|
||||
.catch(() => {
|
||||
const requestOptions = spy.getCall(0).args[1]
|
||||
|
||||
expect(isRequestHttps(requestOptions)).to.equal(testCase.expect)
|
||||
})
|
||||
})
|
||||
@@ -419,51 +430,58 @@ describe('lib/agent', function() {
|
||||
agent: <any>testCase.agent,
|
||||
transports: ['websocket'],
|
||||
timeout: 1,
|
||||
rejectUnauthorized: false
|
||||
rejectUnauthorized: false,
|
||||
})
|
||||
.on('message', reject)
|
||||
.on('connect_error', resolve)
|
||||
})
|
||||
.then(() => {
|
||||
const requestOptions = spy.getCall(0).args[1]
|
||||
|
||||
expect(isRequestHttps(requestOptions)).to.equal(testCase.expect)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context(".isResponseStatusCode200", function() {
|
||||
it("matches a 200 OK response correctly", function() {
|
||||
const result = isResponseStatusCode200("HTTP/1.1 200 Connection established")
|
||||
context('.isResponseStatusCode200', function () {
|
||||
it('matches a 200 OK response correctly', function () {
|
||||
const result = isResponseStatusCode200('HTTP/1.1 200 Connection established')
|
||||
|
||||
expect(result).to.be.true
|
||||
})
|
||||
|
||||
it("matches a 500 error response correctly", function() {
|
||||
const result = isResponseStatusCode200("HTTP/1.1 500 Internal Server Error")
|
||||
it('matches a 500 error response correctly', function () {
|
||||
const result = isResponseStatusCode200('HTTP/1.1 500 Internal Server Error')
|
||||
|
||||
expect(result).to.be.false
|
||||
})
|
||||
})
|
||||
|
||||
context(".regenerateRequestHead", function() {
|
||||
it("regenerates changed request head", () => {
|
||||
context('.regenerateRequestHead', function () {
|
||||
it('regenerates changed request head', () => {
|
||||
const spy = sinon.spy(http.globalAgent, 'createSocket')
|
||||
|
||||
return request({
|
||||
url: 'http://foo.bar.baz.invalid',
|
||||
agent: http.globalAgent
|
||||
agent: http.globalAgent,
|
||||
})
|
||||
.then(() => {
|
||||
throw new Error('this should fail')
|
||||
})
|
||||
.catch(() => {
|
||||
const req = spy.getCall(0).args[0]
|
||||
|
||||
expect(req._header).to.equal([
|
||||
'GET / HTTP/1.1',
|
||||
'host: foo.bar.baz.invalid',
|
||||
'Connection: close',
|
||||
'', ''
|
||||
'', '',
|
||||
].join('\r\n'))
|
||||
|
||||
// now change some stuff, regen, and expect it to work
|
||||
delete req._header
|
||||
// @ts-ignore
|
||||
req.path = 'http://quuz.quux.invalid/abc?def=123'
|
||||
req.setHeader('Host', 'foo.fleem.invalid')
|
||||
req.setHeader('bing', 'bang')
|
||||
@@ -473,7 +491,7 @@ describe('lib/agent', function() {
|
||||
'Host: foo.fleem.invalid',
|
||||
'bing: bang',
|
||||
'Connection: close',
|
||||
'', ''
|
||||
'', '',
|
||||
].join('\r\n'))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
"env": {
|
||||
"cypress/globals": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,7 @@ describe('controls', function () {
|
||||
it('shows \'Tests\'', () => {
|
||||
cy.get('.focus-tests span').should('be.visible')
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
describe('< 400px wide', function () {
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -24,6 +24,7 @@ describe('controls', function () {
|
||||
beforeEach(function () {
|
||||
this.suiteTitle = this.runnables.suites[0].title
|
||||
})
|
||||
|
||||
describe('expand and collapse', function () {
|
||||
it('is expanded by default', function () {
|
||||
cy.contains(this.suiteTitle)
|
||||
@@ -45,12 +46,15 @@ describe('controls', function () {
|
||||
it('expands/collapses on click', function () {
|
||||
cy.contains(this.suiteTitle)
|
||||
.click()
|
||||
|
||||
cy.get('@suiteWrapper')
|
||||
.should('not.have.class', 'is-open')
|
||||
.find('.collapsible-content').eq(0)
|
||||
.should('not.be.visible')
|
||||
|
||||
cy.contains(this.suiteTitle)
|
||||
.click()
|
||||
|
||||
cy.get('@suiteWrapper')
|
||||
.should('have.class', 'is-open')
|
||||
.find('.collapsible-content').eq(0)
|
||||
@@ -61,13 +65,16 @@ describe('controls', function () {
|
||||
cy.contains(this.suiteTitle)
|
||||
.parents('.collapsible-header')
|
||||
.focus().type('{enter}')
|
||||
|
||||
cy.get('@suiteWrapper')
|
||||
.should('not.have.class', 'is-open')
|
||||
.find('.collapsible-content').eq(0)
|
||||
.should('not.be.visible')
|
||||
|
||||
cy.contains(this.suiteTitle)
|
||||
.parents('.collapsible-header')
|
||||
.focus().type('{enter}')
|
||||
|
||||
cy.get('@suiteWrapper')
|
||||
.should('have.class', 'is-open')
|
||||
.find('.collapsible-content').eq(0)
|
||||
@@ -78,13 +85,16 @@ describe('controls', function () {
|
||||
cy.contains(this.suiteTitle)
|
||||
.parents('.collapsible-header')
|
||||
.focus().type(' ')
|
||||
|
||||
cy.get('@suiteWrapper')
|
||||
.should('not.have.class', 'is-open')
|
||||
.find('.collapsible-content').eq(0)
|
||||
.should('not.be.visible')
|
||||
|
||||
cy.contains(this.suiteTitle)
|
||||
.parents('.collapsible-header')
|
||||
.focus().type(' ')
|
||||
|
||||
cy.get('@suiteWrapper')
|
||||
.should('have.class', 'is-open')
|
||||
.find('.collapsible-content').eq(0)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user