mirror of
https://github.com/cypress-io/cypress.git
synced 2026-02-21 14:41:00 -06:00
chore(v12): merge develop into release/12.0.0 (#24705)
Co-authored-by: amehta265 <65267668+amehta265@users.noreply.github.com> Co-authored-by: Bill Glesias <bglesias@gmail.com> Co-authored-by: mattvCypress <mattv@cypress.io> Co-authored-by: Ryan Manuel <ryanm@cypress.io> Co-authored-by: Lachlan Miller <lachlan.miller.1990@outlook.com> Co-authored-by: Jordan <jordan@jpdesigning.com> Co-authored-by: Adam Stone <adams@cypress.io>
This commit is contained in:
119
.eslintignore
119
.eslintignore
@@ -1,119 +0,0 @@
|
||||
# unignore hidden files
|
||||
!.*
|
||||
|
||||
**/__snapshots__
|
||||
**/_test-output
|
||||
**/build
|
||||
**/cypress/fixtures
|
||||
**/dist
|
||||
**/dist-*
|
||||
**/node_modules
|
||||
**/support/fixtures/*
|
||||
!**/support/fixtures/projects
|
||||
**/support/fixtures/projects/**/_fixtures/*
|
||||
**/support/fixtures/projects/**/static/*
|
||||
**/support/fixtures/projects/**/*.jsx
|
||||
**/support/fixtures/projects/**/fail.js
|
||||
|
||||
system-tests/fixtures/*
|
||||
!system-tests/projects
|
||||
system-tests/projects/**/_fixtures/*
|
||||
system-tests/projects/**/static/*
|
||||
system-tests/projects/**/*.jsx
|
||||
system-tests/projects/**/fail.js
|
||||
system-tests/lib/scaffold/plugins/index.js
|
||||
system-tests/lib/scaffold/support/e2e.js
|
||||
system-tests/lib/scaffold/support/component.js
|
||||
system-tests/lib/scaffold/support/commands.js
|
||||
system-tests/test/support/projects/e2e/cypress/
|
||||
system-tests/projects/e2e/cypress/e2e/stdout_exit_early_failing.cy.js
|
||||
system-tests/projects/e2e/cypress/e2e/typescript_syntax_error.cy.ts
|
||||
system-tests/projects/config-with-ts-syntax-error/**
|
||||
system-tests/projects/config-with-ts-module-error/**
|
||||
system-tests/projects/no-specs-vue-2/**
|
||||
|
||||
|
||||
**/test/fixtures
|
||||
**/vendor
|
||||
|
||||
# cli/types is linted by tslint/dtslint
|
||||
cli/types
|
||||
|
||||
# cli/react, cli/vue, and cli/mount-utils are all copied from dist'd builds
|
||||
cli/react
|
||||
cli/vue
|
||||
cli/vue2
|
||||
cli/mount-utils
|
||||
|
||||
# packages/example is not linted (think about changing this)
|
||||
packages/example
|
||||
|
||||
packages/extension/test/helpers/background.js
|
||||
e2e/stdout_exit_early_failing_spec.js
|
||||
|
||||
npm/webpack-preprocessor/cypress/tests/e2e/compile-error.js
|
||||
npm/webpack-preprocessor/examples/use-babelrc/cypress/e2e/spec.cy.js
|
||||
|
||||
npm/cypress-schematic/src/**/*.js
|
||||
|
||||
**/.projects
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/.vscode
|
||||
**/.history
|
||||
**/.cy
|
||||
**/.git
|
||||
|
||||
/npm/react/bin/*
|
||||
/npm/react/**/coverage
|
||||
**/.next/**
|
||||
/npm/create-cypress-tests/initial-template
|
||||
/npm/create-cypress-tests/**/*.template.*
|
||||
|
||||
# The global eslint configuration is not set up to parse vue@2 files
|
||||
/npm/vue2/**/*.vue
|
||||
|
||||
npm/grep/cypress
|
||||
|
||||
packages/data-context/test/unit/codegen/files
|
||||
packages/config/test/__fixtures__/**/*
|
||||
packages/config/test/__babel_fixtures__/**/*
|
||||
|
||||
# community templates we test against, no need to lint
|
||||
system-tests/projects/cra-4/**/*
|
||||
system-tests/projects/cra-5/**/*
|
||||
system-tests/projects/cra-ejected/**/*
|
||||
system-tests/projects/create-react-app-configured/**/*
|
||||
system-tests/projects/create-react-app-unconfigured/**/*
|
||||
system-tests/projects/create-react-app-custom-index-html
|
||||
|
||||
system-tests/projects/vueclivue2-unconfigured/**/*
|
||||
system-tests/projects/vueclivue2-configured/**/*
|
||||
system-tests/projects/outdated-deps-vuecli3/**/*
|
||||
|
||||
system-tests/projects/vueclivue3-unconfigured/**/*
|
||||
system-tests/projects/vueclivue3-configured/**/*
|
||||
system-tests/projects/vueclivue3-custom-index-html
|
||||
|
||||
system-tests/projects/vuecli5vue3-unconfigured/**/*
|
||||
system-tests/projects/vuecli5vue3-configured/**/*
|
||||
|
||||
system-tests/projects/vue3-vite-ts-unconfigured/**/*
|
||||
system-tests/projects/vue3-vite-ts-configured/**/*
|
||||
system-tests/projects/vue3-vite-ts-custom-index-html
|
||||
|
||||
system-tests/projects/nextjs-unconfigured/**/*
|
||||
system-tests/projects/nextjs-configured/**/*
|
||||
|
||||
system-tests/projects/nuxtjs-vue2-unconfigured/**/*
|
||||
system-tests/projects/nuxtjs-vue2-configured/**/*
|
||||
|
||||
system-tests/projects/react-app-webpack-5-unconfigured/**/*
|
||||
|
||||
system-tests/project-fixtures/**
|
||||
system-tests/projects/**/*/expected-cypress*/**/*
|
||||
|
||||
# These are generated files that are not linted
|
||||
tooling/electron-mksnapshot/bin/**
|
||||
tooling/v8-snapshot/cache/**
|
||||
4
.github/ISSUE_TEMPLATE/4-flaky-test.yml
vendored
4
.github/ISSUE_TEMPLATE/4-flaky-test.yml
vendored
@@ -10,8 +10,8 @@ body:
|
||||
- type: textarea
|
||||
id: dashboard
|
||||
attributes:
|
||||
label: Link to dashboard or CircleCI failure
|
||||
description: Please include a link to the failure in the Cypress Dashboard or in CircleCI.
|
||||
label: Link to Cypress Cloud or CircleCI failure
|
||||
description: Please include a link to the failure in Cypress Cloud or in CircleCI.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
@@ -238,7 +238,7 @@ If there are errors building the packages, prefix the commands with `DEBUG=cypre
|
||||
|
||||
When running `yarn start` this routes through the CLI and eventually calls `yarn dev` with the proper arguments. This enables Cypress day-to-day development to match the logic of the built binary + CLI integration.
|
||||
|
||||
If you want to bypass the CLI entirely, you can use the `yarn dev` task and pass arguments directly. For example, to headlessly run a project in a given folder, while trying to record to the Dashboard
|
||||
If you want to bypass the CLI entirely, you can use the `yarn dev` task and pass arguments directly. For example, to headlessly run a project in a given folder, while trying to record to Cypress Cloud.
|
||||
|
||||
```text
|
||||
yarn dev --run-project /project/folder --record --key <key>
|
||||
|
||||
14
cli/.eslintignore
Normal file
14
cli/.eslintignore
Normal file
@@ -0,0 +1,14 @@
|
||||
**/__snapshots__
|
||||
/build
|
||||
|
||||
# cli/types is linted by tslint/dtslint
|
||||
/types
|
||||
|
||||
# these are all copied from dist'd builds from the individual libs
|
||||
/angular
|
||||
/react
|
||||
/react18
|
||||
/vue
|
||||
/vue2
|
||||
/svelte
|
||||
/mount-utils
|
||||
@@ -1,37 +1,37 @@
|
||||
exports['package.json build outputs expected properties 1'] = {
|
||||
"name": "test",
|
||||
"engines": "test engines",
|
||||
"version": "x.y.z",
|
||||
"buildInfo": "replaced by normalizePackageJson",
|
||||
"description": "Cypress is a next generation front end testing tool built for the modern web",
|
||||
"homepage": "https://github.com/cypress-io/cypress",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/cypress-io/cypress/issues"
|
||||
'name': 'test',
|
||||
'engines': 'test engines',
|
||||
'version': 'x.y.z',
|
||||
'buildInfo': 'replaced by normalizePackageJson',
|
||||
'description': 'Cypress is a next generation front end testing tool built for the modern web',
|
||||
'homepage': 'https://github.com/cypress-io/cypress',
|
||||
'license': 'MIT',
|
||||
'bugs': {
|
||||
'url': 'https://github.com/cypress-io/cypress/issues',
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cypress-io/cypress.git"
|
||||
'repository': {
|
||||
'type': 'git',
|
||||
'url': 'https://github.com/cypress-io/cypress.git',
|
||||
},
|
||||
"keywords": [
|
||||
"automation",
|
||||
"browser",
|
||||
"cypress",
|
||||
"cypress.io",
|
||||
"e2e",
|
||||
"end-to-end",
|
||||
"integration",
|
||||
"component",
|
||||
"mocks",
|
||||
"runner",
|
||||
"spies",
|
||||
"stubs",
|
||||
"test",
|
||||
"testing"
|
||||
'keywords': [
|
||||
'automation',
|
||||
'browser',
|
||||
'cypress',
|
||||
'cypress.io',
|
||||
'e2e',
|
||||
'end-to-end',
|
||||
'integration',
|
||||
'component',
|
||||
'mocks',
|
||||
'runner',
|
||||
'spies',
|
||||
'stubs',
|
||||
'test',
|
||||
'testing',
|
||||
],
|
||||
"types": "types",
|
||||
"scripts": {
|
||||
"postinstall": "node index.js --exec install",
|
||||
"size": "t=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";"
|
||||
}
|
||||
'types': 'types',
|
||||
'scripts': {
|
||||
'postinstall': 'node index.js --exec install',
|
||||
'size': 't="$(npm pack .)"; wc -c "${t}"; tar tvf "${t}"; rm "${t}";',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ exports['shows help for run --foo 1'] = `
|
||||
-C, --config-file <config-file> path to script file where configuration values are set. defaults to "cypress.config.{js,ts,mjs,cjs}".
|
||||
--e2e runs end to end tests
|
||||
-e, --env <env> sets environment variables. separate multiple values with a comma. overrides any value in cypress.config.{js,ts,mjs,cjs} or cypress.env.json
|
||||
--group <name> a named group for recorded runs in the Cypress Dashboard
|
||||
--group <name> a named group for recorded runs in Cypress Cloud
|
||||
-k, --key <record-key> your secret Record Key. you can omit this if you set a CYPRESS_RECORD_KEY environment variable.
|
||||
--headed displays the browser instead of running headlessly
|
||||
--headless hide the browser instead of running headed (default for cypress run)
|
||||
@@ -83,11 +83,11 @@ exports['shows help for run --foo 1'] = `
|
||||
-p, --port <port> runs Cypress on a specific port. overrides any value in cypress.config.{js,ts,mjs,cjs}.
|
||||
-P, --project <project-path> path to the project
|
||||
-q, --quiet run quietly, using only the configured reporter
|
||||
--record [bool] records the run. sends test results, screenshots and videos to your Cypress Dashboard.
|
||||
--record [bool] records the run. sends test results, screenshots and videos to Cypress Cloud.
|
||||
-r, --reporter <reporter> runs a specific mocha reporter. pass a path to use a custom reporter. defaults to "spec"
|
||||
-o, --reporter-options <reporter-options> options for the mocha reporter. defaults to "null"
|
||||
-s, --spec <spec> runs specific spec file(s). defaults to "all"
|
||||
-t, --tag <tag> named tag(s) for recorded runs in the Cypress Dashboard
|
||||
-t, --tag <tag> named tag(s) for recorded runs in Cypress Cloud
|
||||
--dev runs cypress in development and bypasses binary check
|
||||
-h, --help display help for command
|
||||
-------
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
exports['cypress .run resolves with contents of tmp file 1'] = {
|
||||
"code": 0,
|
||||
"failingTests": []
|
||||
'code': 0,
|
||||
'failingTests': [],
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ Cypress Version: 1.2.3
|
||||
`
|
||||
|
||||
exports['child kill error object'] = {
|
||||
"description": "The Test Runner unexpectedly exited via a [36mexit[39m event with signal [36mSIGKILL[39m",
|
||||
"solution": "Please search Cypress documentation for possible solutions:\n\n [34mhttps://on.cypress.io[39m\n\nCheck if there is a GitHub issue describing this crash:\n\n [34mhttps://github.com/cypress-io/cypress/issues[39m\n\nConsider opening a new issue."
|
||||
'description': 'The Test Runner unexpectedly exited via a [36mexit[39m event with signal [36mSIGKILL[39m',
|
||||
'solution': 'Please search Cypress documentation for possible solutions:\n\n [34mhttps://on.cypress.io[39m\n\nCheck if there is a GitHub issue describing this crash:\n\n [34mhttps://github.com/cypress-io/cypress/issues[39m\n\nConsider opening a new issue.',
|
||||
}
|
||||
|
||||
exports['Error message'] = `
|
||||
@@ -74,29 +74,29 @@ Cypress Version: 1.2.3
|
||||
`
|
||||
|
||||
exports['errors individual has the following errors 1'] = [
|
||||
"CYPRESS_RUN_BINARY",
|
||||
"binaryNotExecutable",
|
||||
"childProcessKilled",
|
||||
"failedDownload",
|
||||
"failedUnzip",
|
||||
"failedUnzipWindowsMaxPathLength",
|
||||
"incompatibleHeadlessFlags",
|
||||
"incompatibleTestTypeFlags",
|
||||
"incompatibleTestingTypeAndFlag",
|
||||
"invalidCacheDirectory",
|
||||
"invalidConfigFile",
|
||||
"invalidCypressEnv",
|
||||
"invalidOS",
|
||||
"invalidRunProjectPath",
|
||||
"invalidSmokeTestDisplayError",
|
||||
"invalidTestingType",
|
||||
"missingApp",
|
||||
"missingDependency",
|
||||
"missingXvfb",
|
||||
"nonZeroExitCodeXvfb",
|
||||
"notInstalledCI",
|
||||
"smokeTestFailure",
|
||||
"unexpected",
|
||||
"unknownError",
|
||||
"versionMismatch"
|
||||
'CYPRESS_RUN_BINARY',
|
||||
'binaryNotExecutable',
|
||||
'childProcessKilled',
|
||||
'failedDownload',
|
||||
'failedUnzip',
|
||||
'failedUnzipWindowsMaxPathLength',
|
||||
'incompatibleHeadlessFlags',
|
||||
'incompatibleTestTypeFlags',
|
||||
'incompatibleTestingTypeAndFlag',
|
||||
'invalidCacheDirectory',
|
||||
'invalidConfigFile',
|
||||
'invalidCypressEnv',
|
||||
'invalidOS',
|
||||
'invalidRunProjectPath',
|
||||
'invalidSmokeTestDisplayError',
|
||||
'invalidTestingType',
|
||||
'missingApp',
|
||||
'missingDependency',
|
||||
'missingXvfb',
|
||||
'nonZeroExitCodeXvfb',
|
||||
'notInstalledCI',
|
||||
'smokeTestFailure',
|
||||
'unexpected',
|
||||
'unknownError',
|
||||
'versionMismatch',
|
||||
]
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
exports['exec run .processRunOptions does not remove --record option when using --browser 1'] = [
|
||||
"--run-project",
|
||||
'--run-project',
|
||||
null,
|
||||
"--browser",
|
||||
"test browser",
|
||||
"--record",
|
||||
"foo"
|
||||
'--browser',
|
||||
'test browser',
|
||||
'--record',
|
||||
'foo',
|
||||
]
|
||||
|
||||
exports['exec run .processRunOptions passes --browser option 1'] = [
|
||||
"--run-project",
|
||||
'--run-project',
|
||||
null,
|
||||
"--browser",
|
||||
"test browser"
|
||||
'--browser',
|
||||
'test browser',
|
||||
]
|
||||
|
||||
exports['exec run .processRunOptions passes --record option 1'] = [
|
||||
"--run-project",
|
||||
'--run-project',
|
||||
null,
|
||||
"--record",
|
||||
"my record id"
|
||||
'--record',
|
||||
'my record id',
|
||||
]
|
||||
|
||||
exports['exec run .processRunOptions defaults to e2e testingType 1'] = [
|
||||
"--run-project",
|
||||
null
|
||||
'--run-project',
|
||||
null,
|
||||
]
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
exports['lib/exec/spawn .start forces colors and streams when supported 1'] = {
|
||||
"FORCE_COLOR": "1",
|
||||
"DEBUG_COLORS": "1",
|
||||
"MOCHA_COLORS": "1",
|
||||
"FORCE_STDIN_TTY": "1",
|
||||
"FORCE_STDOUT_TTY": "1",
|
||||
"FORCE_STDERR_TTY": "1"
|
||||
'FORCE_COLOR': '1',
|
||||
'DEBUG_COLORS': '1',
|
||||
'MOCHA_COLORS': '1',
|
||||
'FORCE_STDIN_TTY': '1',
|
||||
'FORCE_STDOUT_TTY': '1',
|
||||
'FORCE_STDERR_TTY': '1',
|
||||
}
|
||||
|
||||
exports['lib/exec/spawn .start does not force colors and streams when not supported 1'] = {
|
||||
"FORCE_COLOR": "0",
|
||||
"DEBUG_COLORS": "0",
|
||||
"FORCE_STDIN_TTY": "0",
|
||||
"FORCE_STDOUT_TTY": "0",
|
||||
"FORCE_STDERR_TTY": "0"
|
||||
'FORCE_COLOR': '0',
|
||||
'DEBUG_COLORS': '0',
|
||||
'FORCE_STDIN_TTY': '0',
|
||||
'FORCE_STDOUT_TTY': '0',
|
||||
'FORCE_STDERR_TTY': '0',
|
||||
}
|
||||
|
||||
exports['lib/exec/spawn .start detects kill signal exits with error on SIGKILL 1'] = `
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
exports['config_as_object 1'] = {
|
||||
"config": "{\"baseUrl\":\"http://localhost:2000\",\"watchForFileChanges\":false}"
|
||||
'config': '{"baseUrl":"http://localhost:2000","watchForFileChanges":false}',
|
||||
}
|
||||
|
||||
exports['env_as_object 1'] = {
|
||||
"env": "{\"foo\":\"bar\",\"magicNumber\":1234,\"host\":\"kevin.dev.local\"}"
|
||||
'env': '{"foo":"bar","magicNumber":1234,"host":"kevin.dev.local"}',
|
||||
}
|
||||
|
||||
exports['env_as_string 1'] = {
|
||||
"env": "foo=bar"
|
||||
'env': 'foo=bar',
|
||||
}
|
||||
|
||||
exports['others_unchanged 1'] = {
|
||||
"foo": "bar"
|
||||
'foo': 'bar',
|
||||
}
|
||||
|
||||
exports['reporter_options_as_object 1'] = {
|
||||
"reporterOptions": "{\"mochaFile\":\"results/my-test-output.xml\",\"toConsole\":true}"
|
||||
'reporterOptions': '{"mochaFile":"results/my-test-output.xml","toConsole":true}',
|
||||
}
|
||||
|
||||
exports['spec_as_array 1'] = {
|
||||
"spec": "[\"a\",\"b\",\"c\"]"
|
||||
'spec': '["a","b","c"]',
|
||||
}
|
||||
|
||||
exports['spec_as_string 1'] = {
|
||||
"spec": "x,y,z"
|
||||
'spec': 'x,y,z',
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ const descriptions = {
|
||||
exit: 'keep the browser open after tests finish',
|
||||
forceInstall: 'force install the Cypress binary',
|
||||
global: 'force Cypress into global mode as if its globally installed',
|
||||
group: 'a named group for recorded runs in the Cypress Dashboard',
|
||||
group: 'a named group for recorded runs in Cypress Cloud',
|
||||
headed: 'displays the browser instead of running headlessly',
|
||||
headless: 'hide the browser instead of running headed (default for cypress run)',
|
||||
key: 'your secret Record Key. you can omit this if you set a CYPRESS_RECORD_KEY environment variable.',
|
||||
@@ -118,11 +118,11 @@ const descriptions = {
|
||||
port: 'runs Cypress on a specific port. overrides any value in cypress.config.{js,ts,mjs,cjs}.',
|
||||
project: 'path to the project',
|
||||
quiet: 'run quietly, using only the configured reporter',
|
||||
record: 'records the run. sends test results, screenshots and videos to your Cypress Dashboard.',
|
||||
record: 'records the run. sends test results, screenshots and videos to Cypress Cloud.',
|
||||
reporter: 'runs a specific mocha reporter. pass a path to use a custom reporter. defaults to "spec"',
|
||||
reporterOptions: 'options for the mocha reporter. defaults to "null"',
|
||||
spec: 'runs specific spec file(s). defaults to "all"',
|
||||
tag: 'named tag(s) for recorded runs in the Cypress Dashboard',
|
||||
tag: 'named tag(s) for recorded runs in Cypress Cloud',
|
||||
version: 'prints Cypress version',
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"test-unit": "yarn unit",
|
||||
"test-watch": "yarn unit --watch",
|
||||
"types": "yarn dtslint",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json,.vue .",
|
||||
"unit": "cross-env BLUEBIRD_DEBUG=1 NODE_ENV=test mocha --reporter mocha-multi-reporters --reporter-options configFile=../mocha-reporter-config.json"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
3
cli/types/cypress-npm-api.d.ts
vendored
3
cli/types/cypress-npm-api.d.ts
vendored
@@ -229,6 +229,7 @@ declare namespace CypressCommandLine {
|
||||
startedAt: dateTimeISO
|
||||
endedAt: dateTimeISO
|
||||
duration: ms
|
||||
wallClockDuration?: number
|
||||
}
|
||||
/**
|
||||
* Reporter name like "spec"
|
||||
@@ -259,8 +260,10 @@ declare namespace CypressCommandLine {
|
||||
* resolved filename of the spec
|
||||
*/
|
||||
absolute: string
|
||||
relativeToCommonRoot: string
|
||||
}
|
||||
shouldUploadVideo: boolean
|
||||
skippedSpec: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
25
cli/types/cypress.d.ts
vendored
25
cli/types/cypress.d.ts
vendored
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/// <reference path="./cypress-npm-api.d.ts" />
|
||||
/// <reference path="./cypress-eventemitter.d.ts" />
|
||||
/// <reference path="./cypress-type-helpers.d.ts" />
|
||||
@@ -489,7 +490,7 @@ declare namespace Cypress {
|
||||
* @see https://on.cypress.io/api/commands#Validations
|
||||
*/
|
||||
add<T extends keyof Chainable, S extends PrevSubject>(
|
||||
name: T, options: CommandOptions & { prevSubject: S | ['optional'] }, fn: CommandFnWithSubject<T, PrevSubjectMap[S]>,
|
||||
name: T, options: CommandOptions & { prevSubject: S | ['optional'] }, fn: CommandFnWithSubject<T, PrevSubjectMap[S]>,
|
||||
): void
|
||||
|
||||
/**
|
||||
@@ -497,7 +498,7 @@ declare namespace Cypress {
|
||||
* @see https://on.cypress.io/api/commands#Validations#Allow-Multiple-Types
|
||||
*/
|
||||
add<T extends keyof Chainable, S extends PrevSubject>(
|
||||
name: T, options: CommandOptions & { prevSubject: S[] }, fn: CommandFnWithSubject<T, PrevSubjectMap<void>[S]>,
|
||||
name: T, options: CommandOptions & { prevSubject: S[] }, fn: CommandFnWithSubject<T, PrevSubjectMap<void>[S]>,
|
||||
): void
|
||||
|
||||
/**
|
||||
@@ -523,7 +524,7 @@ declare namespace Cypress {
|
||||
* @see https://on.cypress.io/api/commands#Validations
|
||||
*/
|
||||
addAll<T extends keyof Chainable, S extends PrevSubject>(
|
||||
options: CommandOptions & { prevSubject: S | ['optional'] }, fns: CommandFnsWithSubject<PrevSubjectMap[S]>,
|
||||
options: CommandOptions & { prevSubject: S | ['optional'] }, fns: CommandFnsWithSubject<PrevSubjectMap[S]>,
|
||||
): void
|
||||
|
||||
/**
|
||||
@@ -531,7 +532,7 @@ declare namespace Cypress {
|
||||
* @see https://on.cypress.io/api/commands#Allow-Multiple-Types
|
||||
*/
|
||||
addAll<T extends keyof Chainable, S extends PrevSubject>(
|
||||
options: CommandOptions & { prevSubject: S[] }, fns: CommandFnsWithSubject<PrevSubjectMap<void>[S]>,
|
||||
options: CommandOptions & { prevSubject: S[] }, fns: CommandFnsWithSubject<PrevSubjectMap<void>[S]>,
|
||||
): void
|
||||
|
||||
/**
|
||||
@@ -724,8 +725,8 @@ declare namespace Cypress {
|
||||
type CanReturnChainable = void | Chainable | Promise<unknown>
|
||||
type ThenReturn<S, R> =
|
||||
R extends void ? Chainable<S> :
|
||||
R extends R | undefined ? Chainable<S | Exclude<R, undefined>> :
|
||||
Chainable<S>
|
||||
R extends R | undefined ? Chainable<S | Exclude<R, undefined>> :
|
||||
Chainable<S>
|
||||
|
||||
/**
|
||||
* Chainable interface for non-array Subjects
|
||||
@@ -2339,8 +2340,8 @@ declare namespace Cypress {
|
||||
|
||||
type ChainableMethods<Subject = any> = {
|
||||
[P in keyof Chainable<Subject>]: Chainable<Subject>[P] extends ((...args: any[]) => any)
|
||||
? Chainable<Subject>[P]
|
||||
: never
|
||||
? Chainable<Subject>[P]
|
||||
: never
|
||||
}
|
||||
|
||||
interface SinonSpyAgent<A extends sinon.SinonSpy> {
|
||||
@@ -2824,7 +2825,7 @@ declare namespace Cypress {
|
||||
*/
|
||||
video: boolean
|
||||
/**
|
||||
* Whether Cypress will upload the video to the Dashboard even if all tests are passing. This applies only when recording your runs to the Dashboard. Turn this off if you'd like the video uploaded only when there are failing tests.
|
||||
* Whether Cypress will upload the video to Cypress Cloud even if all tests are passing. This applies only when recording your runs to Cypress Cloud. Turn this off if you'd like the video uploaded only when there are failing tests.
|
||||
* @default true
|
||||
*/
|
||||
videoUploadOnPasses: boolean
|
||||
@@ -3066,8 +3067,8 @@ declare namespace Cypress {
|
||||
type PickConfigOpt<T> = T extends keyof DefineDevServerConfig ? DefineDevServerConfig[T] : any
|
||||
|
||||
interface AngularDevServerProjectConfig {
|
||||
root: string,
|
||||
sourceRoot: string,
|
||||
root: string
|
||||
sourceRoot: string
|
||||
buildOptions: Record<string, any>
|
||||
}
|
||||
|
||||
@@ -3116,7 +3117,7 @@ declare namespace Cypress {
|
||||
/**
|
||||
* Hosts mappings to IP addresses.
|
||||
*/
|
||||
hosts?: null | {[key: string]: string}
|
||||
hosts?: null | {[key: string]: string}
|
||||
}
|
||||
|
||||
interface PluginConfigOptions extends ResolvedConfigOptions, RuntimeConfigOptions {
|
||||
|
||||
@@ -118,7 +118,7 @@ There are a number of reasons why a ticket may be closed without any change or P
|
||||
The best place for asking questions is our [Discord server](https://discord.gg/cypress) which has a very active community of folks with a diverse set of knowledge. Other available channels to explore include [Cypress GitHub discussions](https://github.com/cypress-io/cypress/discussions), [community chat](https://on.cypress.io/chat), and [Stack Overflow](https://stackoverflow.com/questions/tagged/cypress).
|
||||
We also offer support via email with our [paid plans](https://www.cypress.io/pricing/).
|
||||
|
||||
- **Feature request for Cypress Dashboard** - Thank you for your support as a Cypress Dashboard user! These issues are routed to our Cypress Dashboard team's ticketing system. Your customer success representative is available for follow-up and will reach out you directly via email if more information is needed.
|
||||
- **Feature request for Cypress Cloud** - Thank you for your support as a Cypress Cloud user! These issues are routed to our Cypress Cloud team's ticketing system. Your customer success representative is available for follow-up and will reach out you directly via email if more information is needed.
|
||||
|
||||
- **The fix or feature is not within our vision for Cypress** - There will inevitably be suggestions that will not fit within the scope of Cypress' vision for our product. We will do our best to explain why we will not be addressing this issue.
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ In the following instructions, "X.Y.Z" is used to denote the [next version of Cy
|
||||
- Go into a project, run a quick test, make sure things look right
|
||||
- Optionally, install the new version into an established project and run the tests there
|
||||
- [cypress-realworld-app](https://github.com/cypress-io/cypress-realworld-app) uses yarn and represents a typical consumer implementation.
|
||||
- Optionally, do more thorough tests, for example test the new version of Cypress against the Cypress Dashboard repo.
|
||||
- Optionally, do more thorough tests, for example test the new version of Cypress against the Cypress Cloud repo.
|
||||
|
||||
5. Log into AWS SSO with `aws sso login --profile <name_of_profile>`. If you have setup your credentials under a different profile than `prod`, be sure to set the `AWS_PROFILE` environment variable to that profile name for the remaining steps. For example, if you are using `production` instead of `prod`, do `export AWS_PROFILE=production`.
|
||||
|
||||
@@ -119,7 +119,7 @@ In the following instructions, "X.Y.Z" is used to denote the [next version of Cy
|
||||
- Go into a project, run a quick test, make sure things look right
|
||||
- Install the new version into an established project and run the tests there
|
||||
- [cypress-realworld-app](https://github.com/cypress-io/cypress-realworld-app) uses yarn and represents a typical consumer implementation.
|
||||
- Optionally, do more thorough tests, for example test the new version of Cypress against the Cypress Dashboard repo.
|
||||
- Optionally, do more thorough tests, for example test the new version of Cypress against the Cypress Cloud repo.
|
||||
|
||||
11. Create or review the release-specific documentation and changelog in [cypress-documentation](https://github.com/cypress-io/cypress-documentation). If there is not already a release-specific PR open, create one. This PR must be merged, built, and deployed before moving to the next step.
|
||||
- Use [`release-automations`](https://github.com/cypress-io/release-automations)'s `issues-in-release` tool to generate a starting point for the changelog, based off of ZenHub:
|
||||
|
||||
5
npm/angular/.eslintignore
Normal file
5
npm/angular/.eslintignore
Normal file
@@ -0,0 +1,5 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
@@ -8,7 +8,8 @@
|
||||
"build": "rollup -c rollup.config.mjs",
|
||||
"postbuild": "node ../../scripts/sync-exported-npm-with-cli.js",
|
||||
"build-prod": "yarn build",
|
||||
"check-ts": "tsc --noEmit"
|
||||
"check-ts": "tsc --noEmit",
|
||||
"lint": "eslint --ext .js,.ts,.json, ."
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
|
||||
9
npm/create-cypress-tests/.eslintignore
Normal file
9
npm/create-cypress-tests/.eslintignore
Normal file
@@ -0,0 +1,9 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
**/test/fixtures
|
||||
**/__snapshots__
|
||||
/initial-template
|
||||
/**/*.template.*
|
||||
@@ -9,7 +9,8 @@
|
||||
"prepare-example": "node scripts/example copy-to ./initial-template",
|
||||
"prepare-copy-templates": "node scripts/copy-templates copy-to ./dist/src",
|
||||
"test": "cross-env TS_NODE_PROJECT=./tsconfig.test.json mocha --config .mocharc.json './src/**/*.test.ts'",
|
||||
"test:watch": "yarn test -w"
|
||||
"test:watch": "yarn test -w",
|
||||
"lint": "eslint --ext .js,.ts,.json, ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.5.4",
|
||||
|
||||
5
npm/cypress-schematic/.eslintignore
Normal file
5
npm/cypress-schematic/.eslintignore
Normal file
@@ -0,0 +1,5 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
@@ -135,9 +135,9 @@ Before running Cypress in `open` mode, ensure that you have started your applica
|
||||
|
||||
Read our docs to learn more about [launching browsers](https://on.cypress.io/launching-browsers) with Cypress.
|
||||
|
||||
### Recording test results to the Cypress Dashboard
|
||||
### Recording test results to Cypress Cloud
|
||||
|
||||
We recommend setting your [Cypress Dashboard](https://on.cypress.io/features-dashboard) recording key as an environment variable and NOT as a builder option when running it in CI.
|
||||
We recommend setting your [Cypress Cloud](https://on.cypress.io/features-dashboard) recording key as an environment variable and NOT as a builder option when running it in CI.
|
||||
|
||||
```json
|
||||
"cypress-run": {
|
||||
@@ -145,7 +145,7 @@ We recommend setting your [Cypress Dashboard](https://on.cypress.io/features-das
|
||||
"options": {
|
||||
"devServerTarget": "{project-name}:serve",
|
||||
"record": true,
|
||||
"key": "your-cypress-dashboard-recording-key"
|
||||
"key": "your-cypress-cloud-recording-key"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
@@ -155,7 +155,7 @@ We recommend setting your [Cypress Dashboard](https://on.cypress.io/features-das
|
||||
}
|
||||
```
|
||||
|
||||
Read our docs to learn more about [recording test results](https://on.cypress.io/recording-project-runs) to the [Cypress Dashboard](https://on.cypress.io/features-dashboard).
|
||||
Read our docs to learn more about [recording test results](https://on.cypress.io/recording-project-runs) to [Cypress Cloud](https://on.cypress.io/features-dashboard).
|
||||
|
||||
### Specifying a custom config file
|
||||
|
||||
@@ -187,7 +187,7 @@ Read our docs to learn more about all the [configuration options](https://on.cyp
|
||||
"devServerTarget": "{project-name}:serve",
|
||||
"parallel": true,
|
||||
"record": true,
|
||||
"key": "your-cypress-dashboard-recording-key"
|
||||
"key": "your-cypress-cloud-recording-key"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"build:watch": "tsc -p tsconfig.json --watch",
|
||||
"test": "mocha -r @packages/ts/register --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json src/**/*.spec.ts"
|
||||
"test": "mocha -r @packages/ts/register --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json src/**/*.spec.ts",
|
||||
"lint": "eslint --ext .ts,.json, ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular-devkit/architect": "^0.1402.1",
|
||||
|
||||
5
npm/mount-utils/.eslintignore
Normal file
5
npm/mount-utils/.eslintignore
Normal file
@@ -0,0 +1,5 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
@@ -8,7 +8,8 @@
|
||||
"postbuild": "node ../../scripts/sync-exported-npm-with-cli.js",
|
||||
"build-prod": "yarn build",
|
||||
"check-ts": "tsc --noEmit",
|
||||
"watch": "tsc -w"
|
||||
"watch": "tsc -w",
|
||||
"lint": "eslint --ext .js,.ts,.json, ."
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
|
||||
5
npm/react/.eslintignore
Normal file
5
npm/react/.eslintignore
Normal file
@@ -0,0 +1,5 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
@@ -12,6 +12,7 @@
|
||||
"cy:run": "node ../../scripts/cypress.js run --component",
|
||||
"cy:run:debug": "node --inspect-brk ../../scripts/start.js --component-testing --run-project ${PWD}",
|
||||
"test": "yarn cy:run",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json, .",
|
||||
"watch": "yarn build --watch --watch.exclude ./dist/**/*"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
5
npm/react18/.eslintignore
Normal file
5
npm/react18/.eslintignore
Normal file
@@ -0,0 +1,5 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
@@ -7,7 +7,8 @@
|
||||
"build": "rimraf dist && rollup -c rollup.config.mjs",
|
||||
"postbuild": "node ../../scripts/sync-exported-npm-with-cli.js",
|
||||
"build-prod": "yarn build",
|
||||
"watch": "yarn build --watch --watch.exclude ./dist/**/*"
|
||||
"watch": "yarn build --watch --watch.exclude ./dist/**/*",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json, ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/mount-utils": "0.0.0-development",
|
||||
|
||||
5
npm/svelte/.eslintignore
Normal file
5
npm/svelte/.eslintignore
Normal file
@@ -0,0 +1,5 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
@@ -8,6 +8,7 @@
|
||||
"build": "rollup -c rollup.config.mjs",
|
||||
"postbuild": "node ../../scripts/sync-exported-npm-with-cli.js",
|
||||
"build-prod": "yarn build",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json, .",
|
||||
"check-ts": "tsc --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
5
npm/vite-dev-server/.eslintignore
Normal file
5
npm/vite-dev-server/.eslintignore
Normal file
@@ -0,0 +1,5 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
@@ -12,7 +12,8 @@
|
||||
"cypress:open": "yarn cypress:run-cypress-in-cypress gulp open --project .",
|
||||
"watch": "tsc -w",
|
||||
"test": "yarn test-unit",
|
||||
"test-unit": "mocha -r ts-node/register/transpile-only --config ./test/.mocharc.js"
|
||||
"test-unit": "mocha -r ts-node/register/transpile-only --config ./test/.mocharc.js",
|
||||
"lint": "eslint --ext .js,.ts,.json, ."
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
|
||||
5
npm/vue/.eslintignore
Normal file
5
npm/vue/.eslintignore
Normal file
@@ -0,0 +1,5 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
@@ -10,6 +10,8 @@
|
||||
"build": "rimraf dist && rollup -c rollup.config.mjs",
|
||||
"postbuild": "node ../../scripts/sync-exported-npm-with-cli.js",
|
||||
"typecheck": "yarn tsd && vue-tsc --noEmit",
|
||||
"check-ts": "yarn tsd && vue-tsc --noEmit",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json,.vue .",
|
||||
"test": "yarn cy:run",
|
||||
"tsd": "yarn build && yarn tsc -p test-tsd/tsconfig.tsd.json",
|
||||
"watch": "yarn build --watch --watch.exclude ./dist/**/*"
|
||||
|
||||
5
npm/vue2/.eslintignore
Normal file
5
npm/vue2/.eslintignore
Normal file
@@ -0,0 +1,5 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
@@ -9,7 +9,9 @@
|
||||
"postbuild": "node ../../scripts/sync-exported-npm-with-cli.js",
|
||||
"build-prod": "yarn build",
|
||||
"test": "echo \"Tests for @cypress/vue2 are run from system-tests\"",
|
||||
"watch": "yarn build --watch --watch.exclude ./dist/**/*"
|
||||
"watch": "yarn build --watch --watch.exclude ./dist/**/*",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json,.vue .",
|
||||
"test-ci": "node ../../scripts/run-ct-examples.js --examplesList=./examples.env"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/mount-utils": "0.0.0-development",
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
"description": "Cypress preprocessor for bundling JavaScript via webpack with dependencies included and support for various ES features, TypeScript, and CoffeeScript",
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"test": "mocha test/e2e/*.spec.* --timeout 4000"
|
||||
"test": "mocha test/e2e/*.spec.* --timeout 4000",
|
||||
"lint": "eslint --ext .js,.ts,.json, ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.11.1",
|
||||
|
||||
7
npm/webpack-dev-server/.eslintignore
Normal file
7
npm/webpack-dev-server/.eslintignore
Normal file
@@ -0,0 +1,7 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
**/test/fixtures
|
||||
**/__snapshots__
|
||||
@@ -14,7 +14,8 @@
|
||||
"cypress:run-cypress-in-cypress": "cross-env HTTP_PROXY_TARGET_FOR_ORIGIN_REQUESTS=http://localhost:4455 CYPRESS_REMOTE_DEBUGGING_PORT=6666 TZ=America/New_York",
|
||||
"cypress:open": "yarn cypress:run-cypress-in-cypress gulp open --project .",
|
||||
"test": "yarn test-unit",
|
||||
"test-unit": "mocha -r ts-node/register/transpile-only --config ./test/.mocharc.js"
|
||||
"test-unit": "mocha -r ts-node/register/transpile-only --config ./test/.mocharc.js",
|
||||
"lint": "eslint --ext .js,.ts,.json, ."
|
||||
},
|
||||
"dependencies": {
|
||||
"find-up": "6.3.0",
|
||||
|
||||
9
npm/webpack-preprocessor/.eslintignore
Normal file
9
npm/webpack-preprocessor/.eslintignore
Normal file
@@ -0,0 +1,9 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
**/test/fixtures
|
||||
**/_test-output
|
||||
/cypress/tests/e2e/compile-error.js
|
||||
/examples/use-babelrc/cypress/e2e/spec.cy.js
|
||||
@@ -17,7 +17,8 @@
|
||||
"test-unit": "mocha test/unit/*.spec.*",
|
||||
"test-watch": "yarn test-unit & chokidar '**/*.(js|ts)' 'test/unit/*.(js|ts)' -c 'yarn test-unit'",
|
||||
"check-ts": "tsc --noEmit",
|
||||
"watch": "rimraf dist && tsc --watch"
|
||||
"watch": "rimraf dist && tsc --watch",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json, ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/parser": "7.13.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cypress",
|
||||
"version": "11.0.0",
|
||||
"version": "11.1.0",
|
||||
"description": "Cypress is a next generation front end testing tool built for the modern web",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -42,7 +42,7 @@
|
||||
"get-next-version": "node scripts/get-next-version.js",
|
||||
"postinstall": "node ./scripts/run-postInstall.js",
|
||||
"jscodeshift": "jscodeshift -t ./node_modules/js-codemod/transforms/arrow-function-arguments.js",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json,.vue .",
|
||||
"lint": "lerna run lint --no-bail",
|
||||
"lint-changed": "lint-changed",
|
||||
"prepare-release-artifacts": "node ./scripts/prepare-release-artifacts.js",
|
||||
"npm-release": "node scripts/npm-release.js",
|
||||
|
||||
7
packages/app/.eslintignore
Normal file
7
packages/app/.eslintignore
Normal file
@@ -0,0 +1,7 @@
|
||||
**/dist
|
||||
**/dist-*
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
/src/store/mobx-runner-store.ts
|
||||
@@ -16,7 +16,7 @@ This is the front-end for the Cypress App.
|
||||
|
||||
Cypress has two modes: `run` and `open`. We want run mode to be as light and fast as possible, since this is the mode used to run on CI machines, etc. Run mode has minimal UI showing only what is necessary. Open mode is the interactive experience.
|
||||
|
||||
- **`open`** mode is driven using GraphQL and urql. It shows the full Cypress app, include the top nav, side nav, spec list, etc. You can change between testing types, check your latest runs on the Cypress Dashboard, update settings, etc.
|
||||
- **`open`** mode is driven using GraphQL and urql. It shows the full Cypress app, include the top nav, side nav, spec list, etc. You can change between testing types, check your latest runs on Cypress Cloud, update settings, etc.
|
||||
- **`run`** mode is does not rely on GraphQL. This is so we can be as performant as possible. It only renders the "runner" part of the UI, which is comprised of the command log, Spec Runner header, and AUT iframe.
|
||||
|
||||
The two modes are composed using the same logic, but have slightly different components. You can see where the differences are in `Runner.vue`(src/pages/Specs/Runner.vue). Notice that `<SpecRunnerOpenMode>` receives a `gql` prop, since it uses GraphQL, and `<SpecRunnerRunMode>` does not.
|
||||
|
||||
@@ -19,10 +19,7 @@ const validateSetupSessionGroup = (isNewSession = true) => {
|
||||
cy.get('@setupSession').find('.command-expander').click()
|
||||
cy.get('@setupSession').find('.command-alias').contains('runSetup')
|
||||
|
||||
return cy.contains(groupText)
|
||||
.closest('.command')
|
||||
.find('.command-name-Clear-page')
|
||||
.should('have.length', 1)
|
||||
return cy.get('@setupSession')
|
||||
}
|
||||
|
||||
describe('runner/cypress sessions.ui.spec', {
|
||||
@@ -200,7 +197,7 @@ describe('runner/cypress sessions.ui.spec', {
|
||||
cy.contains('user1')
|
||||
cy.contains('restored')
|
||||
|
||||
cy.get('.command-name-Clear-page').should('have.length', 1)
|
||||
cy.get('.command-name-Clear-page').should('have.length', 2)
|
||||
|
||||
cy.contains('Restore saved session')
|
||||
|
||||
@@ -258,7 +255,7 @@ describe('runner/cypress sessions.ui.spec', {
|
||||
.find('.command-expander')
|
||||
.should('have.class', 'command-expander-is-open')
|
||||
|
||||
cy.get('.command-name-Clear-page').should('have.length', 2)
|
||||
cy.get('.command-name-Clear-page').should('have.length', 3)
|
||||
|
||||
validateSetupSessionGroup(false)
|
||||
|
||||
@@ -321,8 +318,6 @@ describe('runner/cypress sessions.ui.spec', {
|
||||
cy.get('.command-name-Clear-page').should('have.length', 2)
|
||||
|
||||
validateSetupSessionGroup(false)
|
||||
.parent()
|
||||
.closest('.command')
|
||||
.next()
|
||||
.contains('Validate session')
|
||||
.closest('.command').as('secondValidateSession')
|
||||
|
||||
@@ -279,7 +279,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
|
||||
name: 'Test User A',
|
||||
} })
|
||||
|
||||
cy.contains('button', 'Log in to the Cypress Dashboard').click()
|
||||
cy.contains('button', 'Log in to Cypress Cloud').click()
|
||||
|
||||
cy.findByRole('dialog', { name: 'Log in to Cypress' }).as('logInModal').within(() => {
|
||||
cy.findByRole('button', { name: 'Log in' }).click()
|
||||
@@ -578,7 +578,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
|
||||
})
|
||||
|
||||
context('Runs - No Runs', () => {
|
||||
it('when no runs and not connected, shows connect to dashboard button', () => {
|
||||
it('when no runs and not connected, shows connect to Cypress Cloud button', () => {
|
||||
cy.scaffoldProject('component-tests')
|
||||
cy.openProject('component-tests', ['--config-file', 'cypressWithoutProjectId.config.js'])
|
||||
cy.startAppServer('component')
|
||||
@@ -722,7 +722,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
|
||||
|
||||
moveToRunsPage()
|
||||
|
||||
cy.contains('h2', 'Cannot connect to the Cypress Dashboard')
|
||||
cy.contains('h2', 'Cannot connect to Cypress Cloud')
|
||||
// cy.percySnapshot() // TODO: restore when Percy CSS is fixed. See https://github.com/cypress-io/cypress/issues/23435
|
||||
|
||||
cy.remoteGraphQLIntercept((obj) => {
|
||||
@@ -755,7 +755,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
|
||||
|
||||
cy.get('[data-cy=warning-alert]')
|
||||
.should('contain.text', 'You have no internet connection')
|
||||
.and('contain.text', 'Check your internet connection to pull the latest data from the dashboard')
|
||||
.and('contain.text', 'Check your internet connection to pull the latest data from Cypress Cloud')
|
||||
})
|
||||
|
||||
it('should remove the alert warning if the app reconnects to the internet', () => {
|
||||
@@ -769,7 +769,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
|
||||
|
||||
cy.get('[data-cy=warning-alert]')
|
||||
.should('contain.text', 'You have no internet connection')
|
||||
.and('contain.text', 'Check your internet connection to pull the latest data from the dashboard')
|
||||
.and('contain.text', 'Check your internet connection to pull the latest data from Cypress Cloud')
|
||||
|
||||
cy.goOnline()
|
||||
|
||||
@@ -810,7 +810,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
|
||||
|
||||
cy.get('[data-cy=standard-modal]')
|
||||
.should('contain.text', 'You have no internet connection')
|
||||
.and('contain.text', 'Check your internet connection to pull the latest data from the dashboard')
|
||||
.and('contain.text', 'Check your internet connection to pull the latest data from Cypress Cloud')
|
||||
})
|
||||
|
||||
it('shows correct message on connect project modal', () => {
|
||||
@@ -844,7 +844,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
|
||||
|
||||
cy.get('[data-cy=standard-modal]')
|
||||
.should('contain.text', 'You have no internet connection')
|
||||
.and('contain.text', 'Check your internet connection to pull the latest data from the dashboard')
|
||||
.and('contain.text', 'Check your internet connection to pull the latest data from Cypress Cloud')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ describe('App: Settings', () => {
|
||||
|
||||
cy.findByText('Device settings').should('be.visible')
|
||||
cy.findByText('Project settings').should('be.visible')
|
||||
cy.findByText('Dashboard settings').should('be.visible')
|
||||
cy.findByText('Cypress Cloud settings').should('be.visible')
|
||||
})
|
||||
|
||||
describe('Cloud Settings', () => {
|
||||
@@ -33,7 +33,7 @@ describe('App: Settings', () => {
|
||||
cy.startAppServer('e2e')
|
||||
cy.visitApp()
|
||||
cy.get(SidebarSettingsLinkSelector).click()
|
||||
cy.findByText('Dashboard settings').click()
|
||||
cy.findByText('Cypress Cloud settings').click()
|
||||
cy.findByText('Project ID').should('be.visible')
|
||||
cy.get('[data-cy="code-box"]').should('contain', 'fromCli')
|
||||
cy.findByText('Copy').click()
|
||||
@@ -49,7 +49,7 @@ describe('App: Settings', () => {
|
||||
|
||||
cy.visitApp()
|
||||
cy.get(SidebarSettingsLinkSelector).click()
|
||||
cy.findByText('Dashboard settings').click()
|
||||
cy.findByText('Cypress Cloud settings').click()
|
||||
cy.findByText('Record key').should('be.visible')
|
||||
})
|
||||
|
||||
@@ -59,7 +59,7 @@ describe('App: Settings', () => {
|
||||
|
||||
cy.visitApp()
|
||||
cy.get(SidebarSettingsLinkSelector).click()
|
||||
cy.findByText('Dashboard settings').click()
|
||||
cy.findByText('Cypress Cloud settings').click()
|
||||
cy.get('[data-cy="code-box"]').should('contain', '***')
|
||||
cy.get('[aria-label="Record Key Visibility Toggle"]').click()
|
||||
cy.get('[data-cy="code-box"]').should('contain', '2aaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa')
|
||||
@@ -69,7 +69,7 @@ describe('App: Settings', () => {
|
||||
cy.startAppServer('e2e')
|
||||
cy.loginUser()
|
||||
cy.visitApp('settings')
|
||||
cy.findByText('Dashboard settings').click()
|
||||
cy.findByText('Cypress Cloud settings').click()
|
||||
cy.findByText('Manage keys').click()
|
||||
cy.withRetryableCtx((ctx) => {
|
||||
expect((ctx.actions.electron.openExternal as SinonStub).lastCall.lastArg).to.eq('http:/test.cloud/cloud-project/settings')
|
||||
@@ -97,7 +97,7 @@ describe('App: Settings', () => {
|
||||
// Wait for the test to pass, so the test is completed
|
||||
cy.get('.passed > .num').should('contain', 1)
|
||||
cy.get(SidebarSettingsLinkSelector).click()
|
||||
cy.contains('Dashboard settings').click()
|
||||
cy.contains('Cypress Cloud settings').click()
|
||||
// Assert the data is not there before it arrives
|
||||
cy.contains('Record key').should('not.exist')
|
||||
cy.contains('Record key')
|
||||
@@ -112,7 +112,7 @@ describe('App: Settings', () => {
|
||||
})
|
||||
|
||||
cy.findByTestId('sidebar-link-settings-page').click()
|
||||
cy.contains('Dashboard settings').click()
|
||||
cy.contains('Cypress Cloud settings').click()
|
||||
cy.contains('Record key').should('exist')
|
||||
cy.findByTestId('sidebar-link-runs-page').click()
|
||||
cy.findByTestId('user-avatar-title').click()
|
||||
@@ -123,7 +123,7 @@ describe('App: Settings', () => {
|
||||
})
|
||||
|
||||
cy.findByTestId('sidebar-link-settings-page').click()
|
||||
cy.contains('Dashboard settings').click()
|
||||
cy.contains('Cypress Cloud settings').click()
|
||||
cy.contains('Record key').should('not.exist')
|
||||
})
|
||||
})
|
||||
@@ -396,13 +396,13 @@ describe('App: Settings without cloud', () => {
|
||||
|
||||
cy.visitApp()
|
||||
cy.get(SidebarSettingsLinkSelector).click()
|
||||
cy.findByText('Dashboard settings').click()
|
||||
cy.findByText('Cypress Cloud settings').click()
|
||||
cy.findByText('Project ID').should('not.exist')
|
||||
cy.withCtx((ctx, o) => {
|
||||
o.sinon.spy(ctx._apis.authApi, 'logIn')
|
||||
})
|
||||
|
||||
cy.contains('button', 'Log in to the Cypress Dashboard').click()
|
||||
cy.contains('button', 'Log in to Cypress Cloud').click()
|
||||
cy.findByRole('dialog', { name: 'Log in to Cypress' }).within(() => {
|
||||
cy.contains('button', 'Log in').click()
|
||||
})
|
||||
|
||||
@@ -245,7 +245,8 @@ describe('App: Spec List (E2E)', () => {
|
||||
cy.findByText('No specs matched your search:').should('not.be.visible')
|
||||
})
|
||||
|
||||
it('saves the filter when navigating to a spec and back', function () {
|
||||
// TODO: FIGURE OUT WHY THIS IS NOW FAILING CONSTANTLY
|
||||
it.skip('saves the filter when navigating to a spec and back', function () {
|
||||
const targetSpecFile = 'accounts_list.spec.js'
|
||||
|
||||
clearSearchAndType(targetSpecFile)
|
||||
|
||||
@@ -198,9 +198,9 @@ describe('App/Cloud Integration - Latest runs and Average duration', { viewportW
|
||||
it('shows correct tooltips with log in buttons', () => {
|
||||
cy.findByTestId('latest-runs-header').trigger('mouseenter')
|
||||
cy.get('.v-popper__popper--shown')
|
||||
.should('contain', 'Connect to the Cypress Dashboard to see the status of your latest runs')
|
||||
.should('contain', 'Connect to Cypress Cloud to see the status of your latest runs')
|
||||
.find('button')
|
||||
.should('have.text', 'Log in to the Dashboard')
|
||||
.should('have.text', 'Log in to Cypress Cloud')
|
||||
.click()
|
||||
|
||||
cy.findByRole('dialog', { name: 'Log in to Cypress' }).within(() => {
|
||||
@@ -212,9 +212,9 @@ describe('App/Cloud Integration - Latest runs and Average duration', { viewportW
|
||||
|
||||
cy.findByTestId('average-duration-header').trigger('mouseenter')
|
||||
cy.get('.v-popper__popper--shown')
|
||||
.should('contain', 'Connect to the Cypress Dashboard to see the average spec durations of your latest runs')
|
||||
.should('contain', 'Connect to Cypress Cloud to see the average spec durations of your latest runs')
|
||||
.find('button')
|
||||
.should('have.text', 'Log in to the Dashboard')
|
||||
.should('have.text', 'Log in to Cypress Cloud')
|
||||
.click()
|
||||
|
||||
cy.findByRole('dialog', { name: 'Log in to Cypress' }).within(() => {
|
||||
@@ -267,7 +267,7 @@ describe('App/Cloud Integration - Latest runs and Average duration', { viewportW
|
||||
it('shows correct tooltips with log in buttons', () => {
|
||||
cy.findByTestId('latest-runs-header').trigger('mouseenter')
|
||||
cy.get('.v-popper__popper--shown')
|
||||
.should('contain', 'Connect to the Cypress Dashboard to see the status of your latest runs')
|
||||
.should('contain', 'Connect to Cypress Cloud to see the status of your latest runs')
|
||||
.find('button')
|
||||
.should('have.text', 'Connect your project')
|
||||
.click()
|
||||
@@ -280,7 +280,7 @@ describe('App/Cloud Integration - Latest runs and Average duration', { viewportW
|
||||
|
||||
cy.findByTestId('average-duration-header').trigger('mouseenter')
|
||||
cy.get('.v-popper__popper--shown')
|
||||
.should('contain', 'Connect to the Cypress Dashboard to see the average spec durations of your latest runs')
|
||||
.should('contain', 'Connect to Cypress Cloud to see the average spec durations of your latest runs')
|
||||
.find('button')
|
||||
.should('have.text', 'Connect your project')
|
||||
.click()
|
||||
@@ -323,7 +323,7 @@ describe('App/Cloud Integration - Latest runs and Average duration', { viewportW
|
||||
it('shows correct tooltips', () => {
|
||||
cy.findByTestId('latest-runs-header').trigger('mouseenter')
|
||||
cy.get('.v-popper__popper--shown')
|
||||
.should('contain', 'The status of your latest runs in the Cypress Dashboard')
|
||||
.should('contain', 'The status of your latest runs in Cypress Cloud')
|
||||
.find('button')
|
||||
.should('not.exist')
|
||||
|
||||
@@ -331,7 +331,7 @@ describe('App/Cloud Integration - Latest runs and Average duration', { viewportW
|
||||
|
||||
cy.findByTestId('average-duration-header').trigger('mouseenter')
|
||||
cy.get('.v-popper__popper--shown')
|
||||
.should('contain', 'The average spec durations of your latest runs in the Cypress Dashboard')
|
||||
.should('contain', 'The average spec durations of your latest runs in Cypress Cloud')
|
||||
.find('button')
|
||||
.should('not.exist')
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"cypress:run:e2e": "yarn cypress:run-cypress-in-cypress node ../../scripts/cypress run --project .",
|
||||
"dev": "yarn cypress:run-cypress-in-cypress gulp dev --project .",
|
||||
"start": "echo \"run 'yarn dev' from the root\" && exit 1",
|
||||
"watch": "echo \"run 'yarn dev' from the root\" && exit 1"
|
||||
"watch": "echo \"run 'yarn dev' from the root\" && exit 1",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json, ."
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -25,7 +25,6 @@ export function useSpecFilter (savedFilter?: string) {
|
||||
|
||||
function setSpecFilter (specFilter: string) {
|
||||
if (specStore.specFilter !== specFilter) {
|
||||
specStore.setSpecFilter(specFilter)
|
||||
saveSpecFilter.executeMutation({ value: JSON.stringify({ specFilter }) })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,7 +416,7 @@ export class EventManager {
|
||||
|
||||
if (config.isTextTerminal && !runState.currentId) {
|
||||
// we are in run mode and it's the first load
|
||||
// store runnables in backend and maybe send to dashboard
|
||||
// store runnables in backend and maybe send to Cypress Cloud
|
||||
return this.ws.emit('set:runnables:and:maybe:record:tests', runnables, run)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@ describe('<RunsError />', () => {
|
||||
return (
|
||||
<div class="h-screen">
|
||||
<RunsError
|
||||
message="Cannot connect to the Cypress Dashboard"
|
||||
message="Cannot connect to Cypress Cloud"
|
||||
icon="error"
|
||||
buttonText="Request Access"
|
||||
buttonIcon={PaperAirplaneIcon}
|
||||
>
|
||||
The request timed out when trying to retrieve the recorded runs from the Cypress Dashboard. <br/>
|
||||
The request timed out when trying to retrieve the recorded runs from Cypress Cloud. <br/>
|
||||
Please refresh the page to try again and visit our Status Page if this behavior continues.
|
||||
</RunsError>
|
||||
</div>
|
||||
@@ -40,11 +40,11 @@ describe('<SettingsContainer />', { viewportHeight: 800, viewportWidth: 900 }, (
|
||||
})
|
||||
|
||||
it('expands and collapses cloud settings', () => {
|
||||
cy.contains('Dashboard settings').click()
|
||||
cy.contains('Cypress Cloud settings').click()
|
||||
|
||||
cy.findByText(defaultMessages.settingsPage.projectId.title).scrollIntoView().should('be.visible')
|
||||
cy.percySnapshot()
|
||||
cy.findByText('Dashboard settings').click()
|
||||
cy.findByText('Cypress Cloud settings').click()
|
||||
|
||||
cy.findByText(defaultMessages.settingsPage.projectId.title).should('not.exist')
|
||||
})
|
||||
|
||||
@@ -5,7 +5,7 @@ describe('<SettingsSection />', () => {
|
||||
cy.viewport(800, 200)
|
||||
|
||||
const title = 'Project Id'
|
||||
const description = 'A Cypress config setting used to uniquely identify your project when recording runs to Cypress Dashboard. Learn more.'
|
||||
const description = 'A Cypress config setting used to uniquely identify your project when recording runs to Cypress Cloud. Learn more.'
|
||||
const slots = {
|
||||
description: () => <p>{description}</p>,
|
||||
title: () => <h1>{title}</h1>,
|
||||
|
||||
@@ -29,7 +29,7 @@ import InlineSpecListHeader from './InlineSpecListHeader.vue'
|
||||
import InlineSpecListTree from './InlineSpecListTree.vue'
|
||||
import CreateSpecModal from './CreateSpecModal.vue'
|
||||
import { fuzzySortSpecs, makeFuzzyFoundSpec, useCachedSpecs } from './spec-utils'
|
||||
import type { FuzzyFoundSpec } from './spec-utils'
|
||||
import type { FuzzyFoundSpec } from './tree/useCollapsibleTree'
|
||||
import { useSpecFilter } from '../composables/useSpecFilter'
|
||||
|
||||
gql`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { FuzzyFoundSpec } from './spec-utils'
|
||||
import { ref } from 'vue'
|
||||
import { useSpecStore } from '../store'
|
||||
import InlineSpecListTree from './InlineSpecListTree.vue'
|
||||
import type { FuzzyFoundSpec } from './tree/useCollapsibleTree'
|
||||
|
||||
describe('InlineSpecListTree', () => {
|
||||
let foundSpecs: FuzzyFoundSpec[]
|
||||
|
||||
@@ -60,17 +60,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCollapsibleTree } from '@packages/frontend-shared/src/composables/useCollapsibleTree'
|
||||
import type { UseCollapsibleTreeNode } from '@packages/frontend-shared/src/composables/useCollapsibleTree'
|
||||
import { buildSpecTree } from './spec-utils'
|
||||
import type { SpecTreeNode, FuzzyFoundSpec } from './spec-utils'
|
||||
import { UseCollapsibleTreeNode, useCollapsibleTree, SpecTreeNode, FuzzyFoundSpec, buildSpecTree } from './tree/useCollapsibleTree'
|
||||
import SpecFileItem from './SpecFileItem.vue'
|
||||
import { computed, watch, onMounted } from 'vue'
|
||||
import DirectoryItem from './DirectoryItem.vue'
|
||||
import { RouterLink, useRouter } from 'vue-router'
|
||||
import { useSpecStore } from '../store'
|
||||
import { useVirtualList } from '@packages/frontend-shared/src/composables/useVirtualList'
|
||||
import { useVirtualListNavigation } from '@packages/frontend-shared/src/composables/useVirtualListNavigation'
|
||||
import { useVirtualList } from './tree/useVirtualList'
|
||||
import { useVirtualListNavigation } from './tree/useVirtualListNavigation'
|
||||
import { useStudioStore } from '../store/studio-store'
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
>
|
||||
<component
|
||||
:is="latestRun? ExternalLink : 'div'"
|
||||
:href="dashboardUrl"
|
||||
:href="cloudUrl"
|
||||
>
|
||||
<div
|
||||
v-if="isRunsLoaded"
|
||||
@@ -54,7 +54,7 @@
|
||||
>
|
||||
<ExternalLink
|
||||
v-if="latestRun"
|
||||
:href="dashboardUrl"
|
||||
:href="cloudUrl"
|
||||
:use-default-hocus="false"
|
||||
>
|
||||
<SpecRunSummary
|
||||
@@ -213,7 +213,7 @@ const latestDot = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const dashboardUrl = computed(() => {
|
||||
const cloudUrl = computed(() => {
|
||||
if (latestRun.value?.url) {
|
||||
return getUrlWithParams({
|
||||
url: latestRun.value.url,
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
data-cy="login-button"
|
||||
@click="emits('showLoginConnect')"
|
||||
>
|
||||
{{ t('specPage.dashboardLoginButton') }}
|
||||
{{ t('specPage.cloudLoginButton') }}
|
||||
</Button>
|
||||
<Button
|
||||
v-else-if="userStatusMatches('needsProjectConnect')"
|
||||
|
||||
@@ -183,12 +183,11 @@ import { gql, useSubscription } from '@urql/vue'
|
||||
import { computed, ref, toRef, watch } from 'vue'
|
||||
import { Specs_SpecsListFragment, SpecsList_GitInfoUpdatedDocument, SpecsListFragment } from '../generated/graphql'
|
||||
import { useI18n } from '@cy/i18n'
|
||||
import { buildSpecTree, fuzzySortSpecs, makeFuzzyFoundSpec, useCachedSpecs } from './spec-utils'
|
||||
import type { FuzzyFoundSpec } from './spec-utils'
|
||||
import { useCollapsibleTree } from '@packages/frontend-shared/src/composables/useCollapsibleTree'
|
||||
import { buildSpecTree, FuzzyFoundSpec, useCollapsibleTree } from './tree/useCollapsibleTree'
|
||||
import { fuzzySortSpecs, makeFuzzyFoundSpec, useCachedSpecs } from './spec-utils'
|
||||
import RowDirectory from './RowDirectory.vue'
|
||||
import SpecItem from './SpecItem.vue'
|
||||
import { useVirtualList } from '@packages/frontend-shared/src/composables/useVirtualList'
|
||||
import { useVirtualList } from './tree/useVirtualList'
|
||||
import NoResults from '@cy/components/NoResults.vue'
|
||||
import SpecPatternModal from '../components/SpecPatternModal.vue'
|
||||
import { useOnline, useResizeObserver } from '@vueuse/core'
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
style="width: fit-content"
|
||||
>
|
||||
<ExternalLink
|
||||
:href="dashboardUrl"
|
||||
:href="cloudUrl"
|
||||
class="hocus:no-underline"
|
||||
>
|
||||
<FlakyBadge />
|
||||
@@ -17,7 +17,7 @@
|
||||
<template #popper="{ shown }">
|
||||
<ExternalLink
|
||||
v-if="shown && props.projectGql?.projectId && props.specGql?.relative"
|
||||
:href="dashboardUrl"
|
||||
:href="cloudUrl"
|
||||
class="hocus:no-underline"
|
||||
>
|
||||
<FlakySpecSummaryAdapter
|
||||
@@ -85,7 +85,7 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const isFlaky = computed(() => props.cloudSpecGql?.data?.__typename === 'CloudProjectSpec' && !!props.cloudSpecGql?.data?.isConsideredFlaky)
|
||||
const dashboardUrl = computed(() => {
|
||||
const cloudUrl = computed(() => {
|
||||
const cloudSpec = props.cloudSpecGql?.data?.__typename === 'CloudProjectSpec' ? props.cloudSpecGql.data : null
|
||||
const flakyStatus = cloudSpec?.flakyStatus?.__typename === 'CloudProjectSpecFlakyStatus' ? cloudSpec.flakyStatus : null
|
||||
|
||||
|
||||
@@ -58,8 +58,8 @@
|
||||
import { gql, useMutation } from '@urql/vue'
|
||||
import { ScaffoldGeneratorStepOne_ScaffoldIntegrationDocument } from '../../../generated/graphql'
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { buildSpecTree } from '../../spec-utils'
|
||||
import { useCollapsibleTree } from '@packages/frontend-shared/src/composables/useCollapsibleTree'
|
||||
import { buildSpecTree } from '../../../specs/tree/useCollapsibleTree'
|
||||
import { useCollapsibleTree } from '../../tree/useCollapsibleTree'
|
||||
import StandardModalFooter from '@cy/components/StandardModalFooter.vue'
|
||||
import Button from '@cy/components/Button.vue'
|
||||
import { useI18n } from '@cy/i18n'
|
||||
|
||||
@@ -2,127 +2,7 @@ import fuzzySort from 'fuzzysort'
|
||||
import type { FoundSpec } from '@packages/types'
|
||||
import { ComputedRef, Ref, ref, watch } from 'vue'
|
||||
import _ from 'lodash'
|
||||
import { getRunnerConfigFromWindow } from '../runner'
|
||||
|
||||
// Platform may not be available when this file is loaded (e.g. during component our component tests) so
|
||||
// we defer loading it until it's used
|
||||
let platform
|
||||
const getPlatform = (): string => {
|
||||
if (!platform) {
|
||||
platform = getRunnerConfigFromWindow().platform
|
||||
}
|
||||
|
||||
return platform
|
||||
}
|
||||
const getRegexSeparator = () => getPlatform() === 'win32' ? /\\/ : /\//
|
||||
const getSeparator = () => getPlatform() === 'win32' ? '\\' : '/'
|
||||
|
||||
export type FuzzyFoundSpec<T = FoundSpec> = T & {
|
||||
fuzzyIndexes: {
|
||||
relative: number[]
|
||||
baseName: number[]
|
||||
}
|
||||
}
|
||||
|
||||
export type SpecTreeNode<T extends FoundSpec = FoundSpec> = {
|
||||
id: string
|
||||
name: string
|
||||
children: SpecTreeNode<T>[]
|
||||
isLeaf: boolean
|
||||
parent?: SpecTreeNode<T>
|
||||
data?: T
|
||||
highlightIndexes: number[]
|
||||
}
|
||||
|
||||
export function buildSpecTree<T extends FoundSpec> (specs: FoundSpec[], root: SpecTreeNode<T> = { name: '', isLeaf: false, children: [], id: '', highlightIndexes: [] }): SpecTreeNode<T> {
|
||||
specs.forEach((spec) => buildSpecTreeRecursive(spec.relative, root, spec))
|
||||
collapseEmptyChildren(root)
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
export function buildSpecTreeRecursive<T extends FoundSpec> (path: string, tree: SpecTreeNode<T>, data?: T) {
|
||||
const [firstFile, ...rest] = path.split(getRegexSeparator())
|
||||
const id = tree.id ? [tree.id, firstFile].join(getSeparator()) : firstFile
|
||||
|
||||
const newNode: SpecTreeNode<T> = { name: firstFile, isLeaf: false, children: [], parent: tree, data, id, highlightIndexes: [] }
|
||||
|
||||
if (rest.length < 1) {
|
||||
newNode.isLeaf = true
|
||||
newNode.highlightIndexes = getHighlightIndexes(newNode)
|
||||
|
||||
tree.children.push(newNode)
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
const foundChild = tree.children.find((child) => child.name === firstFile)
|
||||
|
||||
if (foundChild) {
|
||||
buildSpecTreeRecursive(rest.join(getSeparator()), foundChild, data)
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
newNode.highlightIndexes = getHighlightIndexes(newNode)
|
||||
const newTree = buildSpecTreeRecursive(rest.join(getSeparator()), newNode, data)
|
||||
|
||||
tree.children.push(newTree)
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
function collapseEmptyChildren<T extends FoundSpec> (node: SpecTreeNode<T>) {
|
||||
for (const child of node.children) {
|
||||
collapseEmptyChildren(child)
|
||||
}
|
||||
if (node.isLeaf) {
|
||||
return
|
||||
}
|
||||
|
||||
// Root name of our tree is '/'. We don't want to collapse into the root node
|
||||
// so we check node.parent.parent
|
||||
if (node.parent && node.parent.parent && (node.parent.children.length === 1)) {
|
||||
node.parent.name = [node.parent.name, node.name].join(getSeparator())
|
||||
node.parent.id = [node.parent.id, node.name].join(getSeparator())
|
||||
node.parent.children = node.children
|
||||
node.parent.highlightIndexes = getHighlightIndexes(node.parent)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Given a node, return the indexes of the characters that should be highlighted
|
||||
// The indexes are matched to the `relative` and `baseName` keys of FoundSpec, and
|
||||
// depending on whether the node is a leaf or not, the indexes are normalized to the position
|
||||
// of the node's location in the tree.
|
||||
// If a search of "src/comp" is given with indexes [0,1,2,3,4,5,6,7], the indexes will be split
|
||||
// into [0,1,2] and [4,5,6,7] corresponding with a
|
||||
// - src
|
||||
// - components
|
||||
// - index.ts
|
||||
// tree (given that src/comp is not collapsed)
|
||||
function getHighlightIndexes <T extends FoundSpec> (node: SpecTreeNode<T>) {
|
||||
if (!(node.data as any)?.fuzzyIndexes) {
|
||||
return []
|
||||
}
|
||||
|
||||
const { relative: relativeIndexes, baseName: baseNameIndexes } = (node.data as FuzzyFoundSpec<T>).fuzzyIndexes
|
||||
|
||||
// When there is a full (or close to) relative match, baseName will no longer match.
|
||||
// If we have indexes for baseName we show them, otherwise we pull from relative to derive
|
||||
// baseName indexes
|
||||
if (node.isLeaf && baseNameIndexes.length > 0) {
|
||||
return baseNameIndexes
|
||||
}
|
||||
|
||||
const maxIndex = node.id.length - 1
|
||||
const minIndex = maxIndex - node.name.length + 1
|
||||
|
||||
const res = relativeIndexes.filter((index) => index >= minIndex && index <= maxIndex)
|
||||
|
||||
return res.map((idx) => idx - minIndex)
|
||||
}
|
||||
import { FuzzyFoundSpec, getPlatform } from './tree/useCollapsibleTree'
|
||||
|
||||
export function fuzzySortSpecs <T extends FuzzyFoundSpec> (specs: T[], searchValue: string) {
|
||||
const normalizedSearchValue = getPlatform() === 'win32' ? searchValue.replaceAll('/', '\\') : searchValue
|
||||
|
||||
266
packages/app/src/specs/tree/useCollapsibleTree.ts
Normal file
266
packages/app/src/specs/tree/useCollapsibleTree.ts
Normal file
@@ -0,0 +1,266 @@
|
||||
import type { ComputedRef, Ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { useToggle } from '@vueuse/core'
|
||||
import type { FoundSpec } from '@packages/types/src'
|
||||
import { getRunnerConfigFromWindow } from '../../runner'
|
||||
|
||||
export type RawNode <T> = {
|
||||
id: string
|
||||
name: string
|
||||
children: RawNode<T>[]
|
||||
}
|
||||
|
||||
export type FuzzyFoundSpec<T = FoundSpec> = T & {
|
||||
fuzzyIndexes: {
|
||||
relative: number[]
|
||||
baseName: number[]
|
||||
}
|
||||
}
|
||||
|
||||
export type SpecTreeNode<T extends FoundSpec = FoundSpec> = {
|
||||
id: string
|
||||
name: string
|
||||
children: SpecTreeNode<T>[]
|
||||
isLeaf: boolean
|
||||
parent?: SpecTreeNode<T>
|
||||
data?: T
|
||||
highlightIndexes: number[]
|
||||
}
|
||||
|
||||
// Platform may not be available when this file is loaded (e.g. during component our component tests) so
|
||||
// we defer loading it until it's used
|
||||
let platform: string
|
||||
|
||||
export const getPlatform = (): string => {
|
||||
if (!platform) {
|
||||
platform = getRunnerConfigFromWindow().platform
|
||||
}
|
||||
|
||||
return platform
|
||||
}
|
||||
|
||||
const getRegexSeparator = () => getPlatform() === 'win32' ? /\\/ : /\//
|
||||
const getSeparator = () => getPlatform() === 'win32' ? '\\' : '/'
|
||||
|
||||
export function buildSpecTree<T extends FoundSpec> (specs: FoundSpec[], root: SpecTreeNode<T> = { name: '', isLeaf: false, children: [], id: '', highlightIndexes: [] }): SpecTreeNode<T> {
|
||||
specs.forEach((spec) => buildSpecTreeRecursive(spec.relative, root, spec))
|
||||
collapseEmptyChildren(root)
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
// Given a node, return the indexes of the characters that should be highlighted
|
||||
// The indexes are matched to the `relative` and `baseName` keys of FoundSpec, and
|
||||
// depending on whether the node is a leaf or not, the indexes are normalized to the position
|
||||
// of the node's location in the tree.
|
||||
// If a search of "src/comp" is given with indexes [0,1,2,3,4,5,6,7], the indexes will be split
|
||||
// into [0,1,2] and [4,5,6,7] corresponding with a
|
||||
// - src
|
||||
// - components
|
||||
// - index.ts
|
||||
// tree (given that src/comp is not collapsed)
|
||||
function getHighlightIndexes <T extends FoundSpec> (node: SpecTreeNode<T>) {
|
||||
if (!(node.data as any)?.fuzzyIndexes) {
|
||||
return []
|
||||
}
|
||||
|
||||
const { relative: relativeIndexes, baseName: baseNameIndexes } = (node.data as FuzzyFoundSpec<T>).fuzzyIndexes
|
||||
|
||||
// When there is a full (or close to) relative match, baseName will no longer match.
|
||||
// If we have indexes for baseName we show them, otherwise we pull from relative to derive
|
||||
// baseName indexes
|
||||
if (node.isLeaf && baseNameIndexes.length > 0) {
|
||||
return baseNameIndexes
|
||||
}
|
||||
|
||||
const maxIndex = node.id.length - 1
|
||||
const minIndex = maxIndex - node.name.length + 1
|
||||
|
||||
const res = relativeIndexes.filter((index) => index >= minIndex && index <= maxIndex)
|
||||
|
||||
return res.map((idx) => idx - minIndex)
|
||||
}
|
||||
|
||||
export function buildSpecTreeRecursive<T extends FoundSpec> (path: string, tree: SpecTreeNode<T>, data?: T) {
|
||||
const [firstFile, ...rest] = path.split(getRegexSeparator())
|
||||
const id = tree.id ? [tree.id, firstFile].join(getSeparator()) : firstFile
|
||||
|
||||
const newNode: SpecTreeNode<T> = { name: firstFile, isLeaf: false, children: [], parent: tree, data, id, highlightIndexes: [] }
|
||||
|
||||
if (rest.length < 1) {
|
||||
newNode.isLeaf = true
|
||||
newNode.highlightIndexes = getHighlightIndexes(newNode)
|
||||
|
||||
tree.children.push(newNode)
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
const foundChild = tree.children.find((child) => child.name === firstFile)
|
||||
|
||||
if (foundChild) {
|
||||
buildSpecTreeRecursive(rest.join(getSeparator()), foundChild, data)
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
newNode.highlightIndexes = getHighlightIndexes(newNode)
|
||||
const newTree = buildSpecTreeRecursive(rest.join(getSeparator()), newNode, data)
|
||||
|
||||
tree.children.push(newTree)
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
function collapseEmptyChildren<T extends FoundSpec> (node: SpecTreeNode<T>) {
|
||||
for (const child of node.children) {
|
||||
collapseEmptyChildren(child)
|
||||
}
|
||||
if (node.isLeaf) {
|
||||
return
|
||||
}
|
||||
|
||||
// Root name of our tree is '/'. We don't want to collapse into the root node
|
||||
// so we check node.parent.parent
|
||||
if (node.parent && node.parent.parent && (node.parent.children.length === 1)) {
|
||||
node.parent.name = [node.parent.name, node.name].join(getSeparator())
|
||||
node.parent.id = [node.parent.id, node.name].join(getSeparator())
|
||||
node.parent.children = node.children
|
||||
node.parent.highlightIndexes = getHighlightIndexes(node.parent)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
export type UseCollapsibleTreeNode <T extends RawNode<T>> = {
|
||||
// control open/close state
|
||||
hidden: ComputedRef<boolean>
|
||||
expanded: Ref<boolean>
|
||||
toggle: () => void
|
||||
|
||||
// Depth of a particular node -- 1 indexed
|
||||
depth: number
|
||||
|
||||
parent?: UseCollapsibleTreeNode<T>
|
||||
children: UseCollapsibleTreeNode<T>[]
|
||||
} & { [K in keyof T]: T[K]}
|
||||
|
||||
export interface UseCollapsibleTreeOptions {
|
||||
expandInitially?: boolean
|
||||
dropRoot?: boolean
|
||||
/**
|
||||
* Provide a long-lived cache to preserve directory collapse state across tree re-builds.
|
||||
* This can be useful when row data is updating but doesn't represent a change to the
|
||||
* structure of the tree.
|
||||
*/
|
||||
cache?: Map<string, boolean>
|
||||
}
|
||||
|
||||
function collectRoots<T extends RawNode<T>> (node: UseCollapsibleTreeNode<T> | null, acc: UseCollapsibleTreeNode<T>[] = []) {
|
||||
if (!node || !node.parent) {
|
||||
return acc
|
||||
}
|
||||
|
||||
acc.push(node)
|
||||
|
||||
collectRoots<T>(node.parent, acc)
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
export const useCollapsibleTreeNode = <T extends RawNode<T>>(rawNode: T, options: UseCollapsibleTreeOptions, depth: number, parent: UseCollapsibleTreeNode<T> | null): UseCollapsibleTreeNode<T> => {
|
||||
const { cache, expandInitially } = options
|
||||
const treeNode = rawNode as UseCollapsibleTreeNode<T>
|
||||
const roots = parent ? collectRoots<T>(parent) : []
|
||||
const [expanded, toggle] = useToggle(cache?.get(rawNode.id) ?? !!expandInitially)
|
||||
|
||||
const hidden = computed(() => {
|
||||
return !!roots.find((r) => r.expanded.value === false)
|
||||
})
|
||||
|
||||
const wrappedToggle = (value?: boolean): boolean => {
|
||||
const originalState = expanded.value
|
||||
const newValue = toggle(value)
|
||||
|
||||
// If this is a non-hidden directory then watch for expansion changes and register them into the cache if one was provided
|
||||
if (!!cache && !hidden.value && rawNode.children?.length) {
|
||||
cache.set(rawNode.id, !originalState)
|
||||
}
|
||||
|
||||
return newValue
|
||||
}
|
||||
|
||||
return {
|
||||
...treeNode,
|
||||
depth,
|
||||
parent,
|
||||
hidden,
|
||||
expanded,
|
||||
toggle: wrappedToggle,
|
||||
}
|
||||
}
|
||||
|
||||
function buildTree<T extends RawNode<T>> (
|
||||
rawNode: T,
|
||||
options: UseCollapsibleTreeOptions,
|
||||
acc: UseCollapsibleTreeNode<T>[] = [],
|
||||
depth = 1,
|
||||
parent: UseCollapsibleTreeNode<T> | null = null,
|
||||
) {
|
||||
// console.log(arguments)
|
||||
const node = useCollapsibleTreeNode<T>(rawNode, options, depth, parent)
|
||||
|
||||
acc.push(node)
|
||||
|
||||
if (node.children?.length) {
|
||||
for (const child of node.children) {
|
||||
buildTree(child, options, acc, depth + 1, node)
|
||||
}
|
||||
}
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
function sortTree<T extends RawNode<T>> (tree: T) {
|
||||
if (tree.children.length > 0) {
|
||||
tree.children = tree.children.sort((a, b) => {
|
||||
if (a.children.length === 0 && b.children.length === 0) {
|
||||
return a.name > b.name ? 1 : -1
|
||||
}
|
||||
|
||||
if (a.children.length === 0) {
|
||||
return 1
|
||||
}
|
||||
|
||||
if (b.children.length === 0) {
|
||||
return -1
|
||||
}
|
||||
|
||||
return a.name > b.name ? 1 : -1
|
||||
})
|
||||
|
||||
tree.children.forEach(sortTree)
|
||||
}
|
||||
}
|
||||
|
||||
export function useCollapsibleTree <T extends RawNode<T>> (tree: T, options: UseCollapsibleTreeOptions = {}) {
|
||||
options.expandInitially = options.expandInitially ?? true
|
||||
sortTree(tree)
|
||||
const collapsibleTree = buildTree<T>(tree, options)
|
||||
|
||||
collapsibleTree.sort((a, b) => {
|
||||
if (a.parent === b.parent) {
|
||||
if (a.children.length && !b.children.length) {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
return 0
|
||||
})
|
||||
|
||||
return {
|
||||
tree: options.dropRoot ? collapsibleTree.slice(1) : collapsibleTree,
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ export const useSpecStore = defineStore({
|
||||
state (): SpecState {
|
||||
return {
|
||||
activeSpec: undefined,
|
||||
specFilter: undefined,
|
||||
}
|
||||
},
|
||||
|
||||
@@ -20,8 +19,5 @@ export const useSpecStore = defineStore({
|
||||
setActiveSpec (activeSpec: SpecFile | null) {
|
||||
this.activeSpec = activeSpec
|
||||
},
|
||||
setSpecFilter (filter: string) {
|
||||
this.specFilter = filter
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
8
packages/config/.eslintignore
Normal file
8
packages/config/.eslintignore
Normal file
@@ -0,0 +1,8 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
/test/__fixtures__/**/*
|
||||
/test/__babel_fixtures__/**/*
|
||||
**/__snapshots__
|
||||
@@ -13,7 +13,8 @@
|
||||
"test": "yarn test-unit",
|
||||
"test:clean": "find ./test/__fixtures__ -depth -name 'output.*' -type f -exec rm {} \\;",
|
||||
"test-debug": "yarn test-unit --inspect-brk=5566",
|
||||
"test-unit": "mocha --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json -r @packages/ts/register 'test/**/*.spec.ts' --exit --timeout 5000"
|
||||
"test-unit": "mocha --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json -r @packages/ts/register 'test/**/*.spec.ts' --exit --timeout 5000",
|
||||
"lint": "eslint --ext .js,.ts,.json, ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7",
|
||||
|
||||
@@ -27,6 +27,10 @@ import path from 'node:path'
|
||||
const debug = Debug('test')
|
||||
|
||||
describe('config/src/project/utils', () => {
|
||||
beforeEach(function () {
|
||||
delete process.env.CYPRESS_COMMERCIAL_RECOMMENDATIONS
|
||||
})
|
||||
|
||||
before(function () {
|
||||
this.env = process.env;
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ import {
|
||||
} from '../src/project/utils'
|
||||
|
||||
describe('config/src/utils', () => {
|
||||
beforeEach(function () {
|
||||
delete process.env.CYPRESS_COMMERCIAL_RECOMMENDATIONS
|
||||
})
|
||||
|
||||
describe('hideKeys', () => {
|
||||
it('removes middle part of the string', () => {
|
||||
const hidden = hideKeys('12345-xxxx-abcde')
|
||||
|
||||
9
packages/data-context/.eslintignore
Normal file
9
packages/data-context/.eslintignore
Normal file
@@ -0,0 +1,9 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
/test/unit/codegen/files
|
||||
/test/unit/codegen/tmp
|
||||
/test/fixtures/**
|
||||
**/__snapshots__
|
||||
16
packages/data-context/.eslintrc.json
Normal file
16
packages/data-context/.eslintrc.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": [
|
||||
"../../.eslintrc.js"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -11,7 +11,8 @@
|
||||
"tslint": "tslint --config ../ts/tslint.json --project .",
|
||||
"clean": "rimraf --glob \"./{src,test}/**/*.js\"",
|
||||
"test": "yarn test-unit",
|
||||
"test-unit": "mocha -r @packages/ts/register --config ./test/.mocharc.js --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json"
|
||||
"test-unit": "mocha -r @packages/ts/register --config ./test/.mocharc.js --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json",
|
||||
"lint": "eslint --ext .js,.ts,.json, ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "7.8.3",
|
||||
|
||||
@@ -25,10 +25,10 @@ export class EventCollectorActions {
|
||||
|
||||
async recordEvent (event: CollectableEvent): Promise<boolean> {
|
||||
try {
|
||||
const dashboardUrl = this.ctx.cloud.getDashboardUrl(cloudEnv)
|
||||
const cloudUrl = this.ctx.cloud.getCloudUrl(cloudEnv)
|
||||
|
||||
await this.ctx.util.fetch(
|
||||
`${dashboardUrl}/anon-collect`,
|
||||
`${cloudUrl}/anon-collect`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
||||
@@ -119,7 +119,7 @@ export class ProjectConfigIpc extends EventEmitter {
|
||||
loadConfig (): Promise<LoadConfigReply> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (this._childProcess.stdout && this._childProcess.stderr) {
|
||||
// manually pipe plugin stdout and stderr for dashboard capture
|
||||
// manually pipe plugin stdout and stderr for Cypress Cloud capture
|
||||
// @see https://github.com/cypress-io/cypress/issues/7434
|
||||
this._childProcess.stdout.on('data', (data) => process.stdout.write(data))
|
||||
this._childProcess.stderr.on('data', (data) => process.stderr.write(data))
|
||||
|
||||
@@ -465,7 +465,7 @@ export class ProjectConfigManager {
|
||||
/*
|
||||
Used to detect the correct file path when a test fails.
|
||||
It is derived and assigned in the packages/driver in stack_utils.
|
||||
It's needed to show the correct link to files in repo mgmt tools like GitHub in the dashboard.
|
||||
It's needed to show the correct link to files in repo mgmt tools like GitHub in Cypress Cloud.
|
||||
Right now we assume the repoRoot is where the `.git` dir is located.
|
||||
*/
|
||||
return this.options.ctx.git?.gitBaseDir
|
||||
|
||||
@@ -129,7 +129,7 @@ export interface CoreDataShape {
|
||||
gqlSocketServer?: Maybe<SocketIONamespace>
|
||||
}
|
||||
hasInitializedMode: 'run' | 'open' | null
|
||||
dashboardGraphQLError: ErrorWrapperSource | null
|
||||
cloudGraphQLError: ErrorWrapperSource | null
|
||||
dev: DevStateShape
|
||||
localSettings: LocalSettingsDataShape
|
||||
app: AppDataShape
|
||||
@@ -162,7 +162,7 @@ export function makeCoreData (modeOptions: Partial<AllModeOptions> = {}): CoreDa
|
||||
machineBrowsers: null,
|
||||
allBrowsers: null,
|
||||
hasInitializedMode: null,
|
||||
dashboardGraphQLError: null,
|
||||
cloudGraphQLError: null,
|
||||
dev: {
|
||||
refreshState: null,
|
||||
},
|
||||
|
||||
@@ -31,9 +31,9 @@ const debug = debugLib('cypress:data-context:sources:CloudDataSource')
|
||||
const cloudEnv = getenv('CYPRESS_INTERNAL_CLOUD_ENV', process.env.CYPRESS_INTERNAL_ENV || 'development') as keyof typeof REMOTE_SCHEMA_URLS
|
||||
|
||||
const REMOTE_SCHEMA_URLS = {
|
||||
staging: 'https://dashboard-staging.cypress.io',
|
||||
staging: 'https://cloud-staging.cypress.io',
|
||||
development: 'http://localhost:3000',
|
||||
production: 'https://dashboard.cypress.io',
|
||||
production: 'https://cloud.cypress.io',
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
@@ -99,7 +99,7 @@ export class CloudDataSource {
|
||||
|
||||
reset () {
|
||||
return this.#cloudUrqlClient = createClient({
|
||||
url: `${this.getDashboardUrl(cloudEnv)}/test-runner-graphql`,
|
||||
url: `${this.getCloudUrl(cloudEnv)}/test-runner-graphql`,
|
||||
exchanges: [
|
||||
dedupExchange,
|
||||
cacheExchange({
|
||||
@@ -182,7 +182,7 @@ export class CloudDataSource {
|
||||
}
|
||||
|
||||
#formatWithErrors = async (data: OperationResult<any, any>) => {
|
||||
// If we receive a 401 from the dashboard, we need to logout the user
|
||||
// If we receive a 401 from Cypress Cloud, we need to logout the user
|
||||
if (data.error?.response?.status === 401) {
|
||||
await this.params.logout()
|
||||
}
|
||||
@@ -333,7 +333,7 @@ export class CloudDataSource {
|
||||
return JSON.parse(this.#lastCache ?? '')
|
||||
}
|
||||
|
||||
getDashboardUrl (env: keyof typeof REMOTE_SCHEMA_URLS) {
|
||||
getCloudUrl (env: keyof typeof REMOTE_SCHEMA_URLS) {
|
||||
return REMOTE_SCHEMA_URLS[env]
|
||||
}
|
||||
}
|
||||
|
||||
5
packages/driver/.eslintignore
Normal file
5
packages/driver/.eslintignore
Normal file
@@ -0,0 +1,5 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
@@ -24,27 +24,6 @@ const clearAllSavedSessions = () => {
|
||||
})
|
||||
}
|
||||
|
||||
// In webkit, the clear page and clear cookies, etc log messages may be reversed. This isn't an issue, but we just want to test we have both messages.
|
||||
const validateClearLogs = (logs, sessionGroupId) => {
|
||||
let clearPageLogIndex = 0
|
||||
let clearCookiesIndex = 1
|
||||
|
||||
if (logs[1].get('name') === 'Clear page') {
|
||||
clearPageLogIndex = 1
|
||||
clearCookiesIndex = 0
|
||||
}
|
||||
|
||||
expect(logs[clearPageLogIndex].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
expect(logs[clearCookiesIndex].get()).to.contain({
|
||||
displayName: 'Clear cookies, localStorage and sessionStorage',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
}
|
||||
|
||||
describe('cy.session', { retries: 0 }, () => {
|
||||
describe('args', () => {
|
||||
it('accepts string as id', () => {
|
||||
@@ -147,9 +126,6 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
|
||||
const handleValidate = () => {
|
||||
// both create & restore session clears page after running
|
||||
cy.contains('Default blank page')
|
||||
cy.contains('This page was cleared by navigating to about:blank.')
|
||||
|
||||
cy.visit('/fixtures/auth/index.html')
|
||||
cy.contains('Welcome tester')
|
||||
}
|
||||
@@ -205,7 +181,7 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
})
|
||||
|
||||
// test must be first to run before blank page visit between each test
|
||||
it('clears page after setup runs', () => {
|
||||
it('clears page after command runs', () => {
|
||||
cy.url().should('eq', 'about:blank')
|
||||
})
|
||||
|
||||
@@ -217,6 +193,7 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
it('groups session logs correctly', () => {
|
||||
expect(logs[0].get()).to.deep.contain({
|
||||
name: 'session',
|
||||
state: 'passed',
|
||||
id: sessionGroupId,
|
||||
sessionInfo: {
|
||||
id: 'session-1',
|
||||
@@ -225,7 +202,15 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
},
|
||||
})
|
||||
|
||||
validateClearLogs([logs[1], logs[2]], sessionGroupId)
|
||||
expect(logs[1].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
expect(logs[2].get()).to.contain({
|
||||
displayName: 'Clear cookies, localStorage and sessionStorage',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
const createNewSessionGroup = logs[3].get()
|
||||
|
||||
@@ -242,7 +227,7 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
|
||||
expect(logs[5].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: createNewSessionGroup.id,
|
||||
group: sessionGroupId,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -285,8 +270,8 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
})
|
||||
|
||||
// test must be first to run before blank page visit between each test
|
||||
it('does not clear page visit from validate function', () => {
|
||||
cy.url().should('contain', '/fixtures/auth/index.html')
|
||||
it('clears page after command runs', () => {
|
||||
cy.url().should('eq', 'about:blank')
|
||||
})
|
||||
|
||||
it('successfully creates new session and validates it', () => {
|
||||
@@ -298,6 +283,7 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
it('groups session logs correctly', () => {
|
||||
expect(logs[0].get()).to.deep.contain({
|
||||
name: 'session',
|
||||
state: 'passed',
|
||||
id: sessionGroupId,
|
||||
sessionInfo: {
|
||||
id: sessionId,
|
||||
@@ -306,7 +292,15 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
},
|
||||
})
|
||||
|
||||
validateClearLogs([logs[1], logs[2]], sessionGroupId)
|
||||
expect(logs[1].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
expect(logs[2].get()).to.contain({
|
||||
displayName: 'Clear cookies, localStorage and sessionStorage',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
const createNewSessionGroup = logs[3].get()
|
||||
|
||||
@@ -321,22 +315,22 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
group: createNewSessionGroup.id,
|
||||
})
|
||||
|
||||
expect(logs[5].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: createNewSessionGroup.id,
|
||||
})
|
||||
|
||||
const validateSessionGroup = logs[6].get()
|
||||
const validateSessionGroup = logs[5].get()
|
||||
|
||||
expect(validateSessionGroup).to.contain({
|
||||
displayName: 'Validate session',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
expect(logs[7].get()).to.deep.contain({
|
||||
expect(logs[6].get()).to.deep.contain({
|
||||
alias: ['validateSession'],
|
||||
group: validateSessionGroup.id,
|
||||
})
|
||||
|
||||
expect(logs[7].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -348,10 +342,11 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
cy.once('fail', (err) => {
|
||||
expect(setup).to.be.calledOnce
|
||||
expect(validate).to.be.calledOnce
|
||||
expect(clearPageCount, 'total times session cleared the page').to.eq(2)
|
||||
expect(clearPageCount, 'total times session cleared the page').to.eq(1)
|
||||
expect(err.message).to.contain('This error occurred while validating the created session')
|
||||
expect(logs[0].get()).to.deep.contain({
|
||||
name: 'session',
|
||||
state: 'failed',
|
||||
id: sessionGroupId,
|
||||
sessionInfo: {
|
||||
id: `session-${Cypress.state('test').id}`,
|
||||
@@ -360,7 +355,15 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
},
|
||||
})
|
||||
|
||||
validateClearLogs([logs[1], logs[2]], sessionGroupId)
|
||||
expect(logs[1].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
expect(logs[2].get()).to.contain({
|
||||
displayName: 'Clear cookies, localStorage and sessionStorage',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
const createNewSessionGroup = logs[3].get()
|
||||
|
||||
@@ -375,19 +378,14 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
group: createNewSessionGroup.id,
|
||||
})
|
||||
|
||||
expect(logs[5].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: createNewSessionGroup.id,
|
||||
})
|
||||
|
||||
const validateSessionGroup = logs[6].get()
|
||||
const validateSessionGroup = logs[5].get()
|
||||
|
||||
expect(validateSessionGroup).to.contain({
|
||||
displayName: 'Validate session',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
expect(logs[7].get()).to.deep.contain({
|
||||
expect(logs[6].get()).to.deep.contain({
|
||||
alias: ['validateSession'],
|
||||
group: validateSessionGroup.id,
|
||||
})
|
||||
@@ -426,12 +424,13 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
it('successfully restores saved session', () => {
|
||||
expect(setup).to.not.be.called
|
||||
expect(validate).to.not.be.called
|
||||
expect(clearPageCount, 'total times session cleared the page').to.eq(1)
|
||||
expect(clearPageCount, 'total times session cleared the page').to.eq(2)
|
||||
})
|
||||
|
||||
it('groups session logs correctly', () => {
|
||||
expect(logs[0].get()).to.contain({
|
||||
name: 'session',
|
||||
state: 'passed',
|
||||
id: sessionGroupId,
|
||||
})
|
||||
|
||||
@@ -445,7 +444,15 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
},
|
||||
})
|
||||
|
||||
validateClearLogs([logs[1], logs[2]], sessionGroupId)
|
||||
expect(logs[1].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
expect(logs[2].get()).to.contain({
|
||||
displayName: 'Clear cookies, localStorage and sessionStorage',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
const restoreSavedSessionGroup = logs[3].get()
|
||||
|
||||
@@ -474,19 +481,20 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
})
|
||||
|
||||
// test must be first to run before blank page visit between each test
|
||||
it('does not clear page visit from validate function', () => {
|
||||
cy.url().should('contain', '/fixtures/auth/index.html')
|
||||
it('clears page after command runs', () => {
|
||||
cy.url().should('eq', 'about:blank')
|
||||
})
|
||||
|
||||
it('successfully restores saved session', () => {
|
||||
expect(setup).to.not.be.called
|
||||
expect(validate).to.be.calledOnce
|
||||
expect(clearPageCount, 'total times session cleared the page').to.eq(1)
|
||||
expect(clearPageCount, 'total times session cleared the page').to.eq(2)
|
||||
})
|
||||
|
||||
it('groups session logs correctly', () => {
|
||||
expect(logs[0].get()).to.contain({
|
||||
name: 'session',
|
||||
state: 'passed',
|
||||
id: sessionGroupId,
|
||||
})
|
||||
|
||||
@@ -500,7 +508,15 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
},
|
||||
})
|
||||
|
||||
validateClearLogs([logs[1], logs[2]], sessionGroupId)
|
||||
expect(logs[1].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
expect(logs[2].get()).to.contain({
|
||||
displayName: 'Clear cookies, localStorage and sessionStorage',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
const restoreSavedSessionGroup = logs[3].get()
|
||||
|
||||
@@ -548,8 +564,8 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
})
|
||||
|
||||
// test must be first to run before blank page visit between each test
|
||||
it('does not clear page visit from validate function', () => {
|
||||
cy.url().should('contain', '/fixtures/auth/index.html')
|
||||
it('clears page after command runs', () => {
|
||||
cy.url().should('eq', 'about:blank')
|
||||
})
|
||||
|
||||
it('successfully recreates session', () => {
|
||||
@@ -561,6 +577,7 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
it('groups session logs correctly', () => {
|
||||
expect(logs[0].get()).to.contain({
|
||||
name: 'session',
|
||||
state: 'warned',
|
||||
id: sessionGroupId,
|
||||
})
|
||||
|
||||
@@ -574,7 +591,15 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
},
|
||||
})
|
||||
|
||||
validateClearLogs([logs[1], logs[2]], sessionGroupId)
|
||||
expect(logs[1].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
expect(logs[2].get()).to.contain({
|
||||
displayName: 'Clear cookies, localStorage and sessionStorage',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
const restoreSavedSessionGroup = logs[3].get()
|
||||
|
||||
@@ -598,7 +623,15 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
// this error is associated with the group since the validation rejected
|
||||
expect(logs[4].get('error').message).to.contain('This error occurred while validating the restored session')
|
||||
|
||||
validateClearLogs([logs[6], logs[7]], sessionGroupId)
|
||||
expect(logs[6].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
expect(logs[7].get()).to.contain({
|
||||
displayName: 'Clear cookies, localStorage and sessionStorage',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
const createNewSessionGroup = logs[8].get()
|
||||
|
||||
@@ -613,22 +646,22 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
group: createNewSessionGroup.id,
|
||||
})
|
||||
|
||||
expect(logs[10].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: createNewSessionGroup.id,
|
||||
})
|
||||
|
||||
const secondValidateSessionGroup = logs[11].get()
|
||||
const secondValidateSessionGroup = logs[10].get()
|
||||
|
||||
expect(secondValidateSessionGroup).to.contain({
|
||||
displayName: 'Validate session',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
expect(logs[12].get()).to.deep.contain({
|
||||
expect(logs[11].get()).to.deep.contain({
|
||||
alias: ['validateSession'],
|
||||
group: secondValidateSessionGroup.id,
|
||||
})
|
||||
|
||||
expect(logs[12].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -638,7 +671,7 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
cy.log('Creating new session for test')
|
||||
cy.session(`session-${Cypress.state('test').id}`, setup, { validate })
|
||||
.then(() => {
|
||||
// reset and only test restored session
|
||||
// reset and only test restored session
|
||||
resetMocks()
|
||||
validate.callsFake(() => Promise.reject(false))
|
||||
})
|
||||
@@ -647,10 +680,11 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
expect(err.message).to.contain('Your `cy.session` **validate** promise rejected with false')
|
||||
expect(setup).to.be.calledOnce
|
||||
expect(validate).to.be.calledTwice
|
||||
expect(clearPageCount, 'total times session cleared the page').to.eq(3)
|
||||
expect(clearPageCount, 'total times session cleared the page').to.eq(2)
|
||||
|
||||
expect(logs[0].get()).to.contain({
|
||||
name: 'session',
|
||||
state: 'failed',
|
||||
id: sessionGroupId,
|
||||
})
|
||||
|
||||
@@ -664,7 +698,15 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
},
|
||||
})
|
||||
|
||||
validateClearLogs([logs[1], logs[2]], sessionGroupId)
|
||||
expect(logs[1].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
expect(logs[2].get()).to.contain({
|
||||
displayName: 'Clear cookies, localStorage and sessionStorage',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
const restoreSavedSessionGroup = logs[3].get()
|
||||
|
||||
@@ -688,7 +730,15 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
// this error is associated with the group since the validation rejected
|
||||
expect(logs[4].get('error').message).to.contain('Your `cy.session` **validate** promise rejected with false.')
|
||||
|
||||
validateClearLogs([logs[6], logs[7]], sessionGroupId)
|
||||
expect(logs[6].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
expect(logs[7].get()).to.contain({
|
||||
displayName: 'Clear cookies, localStorage and sessionStorage',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
const createNewSessionGroup = logs[8].get()
|
||||
|
||||
@@ -703,19 +753,14 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
group: createNewSessionGroup.id,
|
||||
})
|
||||
|
||||
expect(logs[10].get()).to.contain({
|
||||
name: 'Clear page',
|
||||
group: createNewSessionGroup.id,
|
||||
})
|
||||
|
||||
const secondValidateSessionGroup = logs[11].get()
|
||||
const secondValidateSessionGroup = logs[10].get()
|
||||
|
||||
expect(secondValidateSessionGroup).to.contain({
|
||||
displayName: 'Validate session',
|
||||
group: sessionGroupId,
|
||||
})
|
||||
|
||||
expect(logs[12].get()).to.deep.contain({
|
||||
expect(logs[11].get()).to.deep.contain({
|
||||
alias: ['validateSession'],
|
||||
group: secondValidateSessionGroup.id,
|
||||
})
|
||||
@@ -876,6 +921,7 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
it('groups session logs correctly', () => {
|
||||
expect(logs[0].get()).to.deep.contain({
|
||||
name: 'session',
|
||||
state: 'passed',
|
||||
id: sessionGroupId,
|
||||
sessionInfo: {
|
||||
id: 'session-1',
|
||||
@@ -954,6 +1000,7 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
it('groups session logs correctly', () => {
|
||||
expect(logs[0].get()).to.deep.contain({
|
||||
name: 'session',
|
||||
state: 'passed',
|
||||
id: sessionGroupId,
|
||||
sessionInfo: {
|
||||
id: sessionId,
|
||||
@@ -1006,6 +1053,7 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
expect(err.message).to.contain('Your `cy.session` **validate** promise rejected with false')
|
||||
expect(logs[0].get()).to.deep.contain({
|
||||
name: 'session',
|
||||
state: 'failed',
|
||||
id: sessionGroupId,
|
||||
sessionInfo: {
|
||||
id: `session-${Cypress.state('test').id}`,
|
||||
@@ -1083,6 +1131,7 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
it('groups session logs correctly', () => {
|
||||
expect(logs[0].get()).to.contain({
|
||||
name: 'session',
|
||||
state: 'passed',
|
||||
id: sessionGroupId,
|
||||
})
|
||||
|
||||
@@ -1140,6 +1189,7 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
it('groups session logs correctly', () => {
|
||||
expect(logs[0].get()).to.contain({
|
||||
name: 'session',
|
||||
state: 'passed',
|
||||
id: sessionGroupId,
|
||||
})
|
||||
|
||||
@@ -1216,6 +1266,7 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
it('groups session logs correctly', () => {
|
||||
expect(logs[0].get()).to.contain({
|
||||
name: 'session',
|
||||
state: 'warned',
|
||||
id: sessionGroupId,
|
||||
})
|
||||
|
||||
@@ -1307,6 +1358,7 @@ describe('cy.session', { retries: 0 }, () => {
|
||||
|
||||
expect(logs[0].get()).to.contain({
|
||||
name: 'session',
|
||||
state: 'failed',
|
||||
id: sessionGroupId,
|
||||
})
|
||||
|
||||
|
||||
@@ -104,9 +104,7 @@ describe('basic login', { browser: '!webkit' }, () => {
|
||||
}, {
|
||||
validate: () => {
|
||||
cy.window().then((win) => {
|
||||
const cypressAuthToken = win.sessionStorage.getItem('cypressAuthToken')
|
||||
|
||||
return !!cypressAuthToken
|
||||
expect(win.sessionStorage.getItem('cypressAuthToken')).to.exist
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"cypress:open": "node ../../scripts/cypress open",
|
||||
"cypress:run": "node ../../scripts/cypress run --spec \"cypress/e2e/*/*\",\"cypress/e2e/*/!(origin|sessions)/**/*\"",
|
||||
"postinstall": "patch-package",
|
||||
"start": "node -e 'console.log(require(`chalk`).red(`\nError:\n\tRunning \\`yarn start\\` is no longer needed for driver/cypress tests.\n\tWe now automatically spawn the server in e2e.setupNodeEvents config.\n\tChanges to the server will be watched and reloaded automatically.`))'"
|
||||
"start": "node -e 'console.log(require(`chalk`).red(`\nError:\n\tRunning \\`yarn start\\` is no longer needed for driver/cypress tests.\n\tWe now automatically spawn the server in e2e.setupNodeEvents config.\n\tChanges to the server will be watched and reloaded automatically.`))'",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json, ."
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -8,6 +8,7 @@ import SessionsManager from './manager'
|
||||
import {
|
||||
getConsoleProps,
|
||||
navigateAboutBlank,
|
||||
SESSION_STEPS,
|
||||
statusMap,
|
||||
} from './utils'
|
||||
|
||||
@@ -27,8 +28,6 @@ export default function (Commands, Cypress, cy) {
|
||||
const sessionsManager = new SessionsManager(Cypress, cy)
|
||||
const sessions = sessionsManager.sessions
|
||||
|
||||
type SESSION_STEPS = 'create' | 'restore' | 'recreate' | 'validate'
|
||||
|
||||
Cypress.on('run:start', () => {
|
||||
// @ts-ignore
|
||||
Object.values(Cypress.state('activeSessions') || {}).forEach((sessionData: ServerSessionData) => {
|
||||
@@ -42,10 +41,7 @@ export default function (Commands, Cypress, cy) {
|
||||
return
|
||||
}
|
||||
|
||||
// Component testing does not support navigation and handles clearing the page via mount utils
|
||||
const clearPage = Cypress.testingType === 'e2e' ? navigateAboutBlank(false) : new Cypress.Promise.resolve()
|
||||
|
||||
return clearPage
|
||||
return navigateAboutBlank(false)
|
||||
.then(() => sessions.clearCurrentSessionData())
|
||||
.then(() => Cypress.backend('reset:rendered:html:origins'))
|
||||
})
|
||||
@@ -134,6 +130,7 @@ export default function (Commands, Cypress, cy) {
|
||||
|
||||
function setSessionLogStatus (status: string) {
|
||||
_log.set({
|
||||
state: statusMap.commandState(status),
|
||||
sessionInfo: {
|
||||
id: session.id,
|
||||
isGlobalSession: session.cacheAcrossSpecs,
|
||||
@@ -182,7 +179,6 @@ export default function (Commands, Cypress, cy) {
|
||||
})
|
||||
.then(async () => {
|
||||
cy.state('onQueueFailed', null)
|
||||
await navigateAboutBlank()
|
||||
const data = await sessions.getCurrentSessionData()
|
||||
|
||||
_.extend(existingSession, data)
|
||||
@@ -222,7 +218,7 @@ export default function (Commands, Cypress, cy) {
|
||||
return sessions.setSessionData(testSession)
|
||||
}
|
||||
|
||||
function validateSession (existingSession, step: SESSION_STEPS) {
|
||||
function validateSession (existingSession, step: keyof typeof SESSION_STEPS) {
|
||||
const isValidSession = true
|
||||
|
||||
if (!existingSession.validate) {
|
||||
@@ -311,11 +307,7 @@ export default function (Commands, Cypress, cy) {
|
||||
|
||||
// skip all commands between this command which errored and _commandToRunAfterValidation
|
||||
for (let i = cy.queue.index; i < index; i++) {
|
||||
const cmd = commands[i]
|
||||
|
||||
if (!cmd.get('restore-within')) {
|
||||
commands[i].skip()
|
||||
}
|
||||
commands[i].skip()
|
||||
}
|
||||
|
||||
// restore within subject back to the original subject used when
|
||||
@@ -359,7 +351,7 @@ export default function (Commands, Cypress, cy) {
|
||||
}
|
||||
|
||||
const failValidation = (err) => {
|
||||
if (step === 'restore') {
|
||||
if (step === SESSION_STEPS.restore) {
|
||||
enhanceErr(err)
|
||||
|
||||
// move to recreate session flow
|
||||
@@ -427,18 +419,18 @@ export default function (Commands, Cypress, cy) {
|
||||
await navigateAboutBlank()
|
||||
await sessions.clearCurrentSessionData()
|
||||
|
||||
return createSession(existingSession, step)
|
||||
return cy.whenStable(() => createSession(existingSession, step))
|
||||
})
|
||||
.then(() => validateSession(existingSession, step))
|
||||
.then(async (isValidSession: boolean) => {
|
||||
if (!isValidSession) {
|
||||
throw new Error('not a valid session :(')
|
||||
return 'failed'
|
||||
}
|
||||
|
||||
sessionsManager.registeredSessions.set(existingSession.id, true)
|
||||
await sessions.saveSessionData(existingSession)
|
||||
|
||||
setSessionLogStatus(statusMap.complete(step))
|
||||
return statusMap.complete(step)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -450,19 +442,19 @@ export default function (Commands, Cypress, cy) {
|
||||
*/
|
||||
const restoreSessionWorkflow = (existingSession: SessionData) => {
|
||||
return cy.then(async () => {
|
||||
setSessionLogStatus('restoring')
|
||||
setSessionLogStatus(statusMap.inProgress(SESSION_STEPS.restore))
|
||||
await navigateAboutBlank()
|
||||
await sessions.clearCurrentSessionData()
|
||||
|
||||
return restoreSession(existingSession)
|
||||
})
|
||||
.then(() => validateSession(existingSession, 'restore'))
|
||||
.then(() => validateSession(existingSession, SESSION_STEPS.restore))
|
||||
.then((isValidSession: boolean) => {
|
||||
if (!isValidSession) {
|
||||
return createSessionWorkflow(existingSession, 'recreate')
|
||||
return createSessionWorkflow(existingSession, SESSION_STEPS.recreate)
|
||||
}
|
||||
|
||||
setSessionLogStatus('restored')
|
||||
return statusMap.complete(SESSION_STEPS.restore)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -493,13 +485,16 @@ export default function (Commands, Cypress, cy) {
|
||||
_.extend(session, _.omit(serverStoredSession, 'setup', 'validate'))
|
||||
session.hydrated = true
|
||||
} else {
|
||||
return createSessionWorkflow(session, 'create')
|
||||
return createSessionWorkflow(session, SESSION_STEPS.create)
|
||||
}
|
||||
}
|
||||
|
||||
return restoreSessionWorkflow(session)
|
||||
}).then(() => {
|
||||
_log.set({ state: 'passed' })
|
||||
}).then((status: 'created' | 'restored' | 'recreated' | 'failed') => {
|
||||
return navigateAboutBlank()
|
||||
.then(() => {
|
||||
setSessionLogStatus(status)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
@@ -194,16 +194,42 @@ const getPostMessageLocalStorage = (specWindow, origins): Promise<any[]> => {
|
||||
}
|
||||
|
||||
function navigateAboutBlank (session: boolean = true) {
|
||||
if (Cypress.config('testIsolation') === 'off') {
|
||||
return
|
||||
// Component testing does not support navigation and handles clearing the page via mount utils
|
||||
if (Cypress.testingType === 'component' || Cypress.config('testIsolation') === 'off') {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
Cypress.action('cy:url:changed', '')
|
||||
return new Promise((resolve) => {
|
||||
cy.once('window:load', resolve)
|
||||
|
||||
return Cypress.action('cy:visit:blank', { type: session ? 'session' : 'session-lifecycle' }) as unknown as Promise<void>
|
||||
Cypress.action('cy:url:changed', '')
|
||||
|
||||
return Cypress.action('cy:visit:blank', { type: session ? 'session' : 'session-lifecycle' }) as unknown as Promise<void>
|
||||
})
|
||||
}
|
||||
|
||||
const enum SESSION_STEPS {
|
||||
create = 'create',
|
||||
restore = 'restore',
|
||||
recreate = 'recreate',
|
||||
validate = 'validate',
|
||||
}
|
||||
|
||||
const statusMap = {
|
||||
commandState: (status: string) => {
|
||||
switch (status) {
|
||||
case 'failed':
|
||||
return 'failed'
|
||||
case 'recreating':
|
||||
case 'recreated':
|
||||
return 'warned'
|
||||
case 'created':
|
||||
case 'restored':
|
||||
return 'passed'
|
||||
default:
|
||||
return 'pending'
|
||||
}
|
||||
},
|
||||
inProgress: (step) => {
|
||||
switch (step) {
|
||||
case 'create':
|
||||
@@ -250,5 +276,6 @@ export {
|
||||
getConsoleProps,
|
||||
getPostMessageLocalStorage,
|
||||
navigateAboutBlank,
|
||||
SESSION_STEPS,
|
||||
statusMap,
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ function mutateConfiguration (testConfig: ResolvedTestConfigOverride, config, en
|
||||
|
||||
// this is called during test onRunnable time
|
||||
// in order to resolve the test config upfront before test runs
|
||||
// note: must return as an object to meet the dashboard recording API
|
||||
// note: must return as an object to meet the Cypress Cloud recording API
|
||||
export function getResolvedTestConfigOverride (test): ResolvedTestConfigOverride {
|
||||
let curr = test
|
||||
let testConfigList: TestConfig[] = []
|
||||
@@ -147,7 +147,7 @@ export function getResolvedTestConfigOverride (test): ResolvedTestConfigOverride
|
||||
|
||||
const testConfig = {
|
||||
testConfigList: testConfigList.filter(({ overrides }) => overrides !== undefined),
|
||||
// collect test overrides to send to the dashboard api when @packages/server is ran in record mode
|
||||
// collect test overrides to send to the Cypress Cloud api when @packages/server is ran in record mode
|
||||
unverifiedTestConfig: _.reduce(testConfigList, (acc, { overrides }) => _.extend(acc, overrides), {}),
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ const wrap = (runnable): Record<string, any> | null => {
|
||||
|
||||
// Reduce runnable down to its props and collections.
|
||||
// Sent to the Reporter to populate command log
|
||||
// and send to the Dashboard when in record mode.
|
||||
// and send to Cypress Cloud when in record mode.
|
||||
const wrapAll = (runnable): Record<string, any> => {
|
||||
return _.extend(
|
||||
{},
|
||||
|
||||
5
packages/electron/.eslintignore
Normal file
5
packages/electron/.eslintignore
Normal file
@@ -0,0 +1,5 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
@@ -47,5 +47,5 @@ Upgrading `electron` involves more than just bumping this package's `package.jso
|
||||
- Update the Docker `image`s to the new matching `browsers` image.
|
||||
- Update the `xcode` version to one with the same major Node.js version bundled. There is usually not an exact match, this is ok as long as the major version number as the same.
|
||||
- [ ] Do a global search for the old Node.js version to identify any new areas that may need updating/unification, and update those locations (and this document!)
|
||||
- [ ] **Manually smoke test `cypress open`.** Upgrading Electron can break the `desktop-gui` in unexpected ways. Since testing in this area is weak, double-check that things like launching `cypress open`, signing into the Dashboard, and launching Electron tests still work.
|
||||
- [ ] **Manually smoke test `cypress open`.** Upgrading Electron can break the `desktop-gui` in unexpected ways. Since testing in this area is weak, double-check that things like launching `cypress open`, signing into Cypress Cloud, and launching Electron tests still work.
|
||||
- [ ] **Fix failing tests.** Usually, these are due to breaking changes in either Node.js or Electron. Check the changelogs of both to find relevant changes.
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
"test": "yarn test-unit",
|
||||
"test-debug": "yarn test-unit --inspect-brk=5566",
|
||||
"test-unit": "mocha --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json",
|
||||
"test-watch": "yarn test-unit --watch"
|
||||
"test-watch": "yarn test-unit --watch",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json, ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@packages/icons": "0.0.0-development",
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The run you are attempting to access is already complete and will not accept new groups.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">The existing run is: <span style="color:#4ec4ff">https://dashboard.cypress.io/project/abcd/runs/1<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">The existing run is: <span style="color:#4ec4ff">https://cloud.cypress.io/project/abcd/runs/1<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">When a run finishes all of its groups, it waits for a configurable set of time before finally completing. You must add more groups during that time period.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user