mirror of
https://github.com/cypress-io/cypress.git
synced 2026-01-04 05:29:45 -06:00
misc: Remove migration UI, warnings, and errors for changes pre-Cypress 10 (v15) (#31629)
* begin removing migration code * remove migration query * add back actions * remove more migration references * more migration removals * remove call to migration * remove gqp-Migration file * updates to remove migration * update type * remove a lot more migration code - especially errors * Remove other errors/warnins for versions before 10.x * update error snapshots * fix some tests * index on remove-migration:49fa75ab78Merge branch 'remove-migration' of https://github.com/cypress-io/cypress into remove-migration * index on remove-migration:49fa75ab78Merge branch 'remove-migration' of https://github.com/cypress-io/cypress into remove-migration * index on remove-migration:49fa75ab78Merge branch 'remove-migration' of https://github.com/cypress-io/cypress into remove-migration * remove more system tests and references * fix call to refreshMetaState which was lost at initialization * rearrange some system tests to not be dependent on migration * update welcome version test * fix wording of messaging * skip irrelevant test * fix failing assertion * remove tests around cypress-plugin-retries * Remove test from config_spec * Remove screenshot from snapshot * fix tests + remove more migration projects * remove + update system tests * remove + update system tests * remove some invalid dev-server: start errors * remove references and tests around pluginsFile which was removed * remove some more invalid config examples * Add changelog entry * fix changelog link * fix unit test * index on remove-migration:490ddb134cMerge branch 'release/15.0.0' into remove-migration * index on remove-migration:490ddb134cMerge branch 'release/15.0.0' into remove-migration * index on remove-migration:490ddb134cMerge branch 'release/15.0.0' into remove-migration * run all binary/windows tests on this branch * Update packages/scaffold-config/test/unit/detect.spec.ts Co-authored-by: Bill Glesias <bglesias@gmail.com> * Update packages/scaffold-config/test/unit/detect.spec.ts Co-authored-by: Bill Glesias <bglesias@gmail.com> --------- Co-authored-by: cypress-bot[bot] <+cypress-bot[bot]@users.noreply.github.com> Co-authored-by: Bill Glesias <bglesias@gmail.com>
This commit is contained in:
@@ -38,7 +38,7 @@ mainBuildFilters: &mainBuildFilters
|
||||
- /^release\/\d+\.\d+\.\d+$/
|
||||
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
|
||||
- 'update-v8-snapshot-cache-on-develop'
|
||||
- 'breaking/remove_webpack_4'
|
||||
- 'remove-migration'
|
||||
|
||||
# usually we don't build Mac app - it takes a long time
|
||||
# but sometimes we want to really confirm we are doing the right thing
|
||||
@@ -49,7 +49,7 @@ macWorkflowFilters: &darwin-workflow-filters
|
||||
- equal: [ develop, << pipeline.git.branch >> ]
|
||||
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
|
||||
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
|
||||
- equal: [ 'breaking/remove_webpack_4', << pipeline.git.branch >> ]
|
||||
- equal: [ 'remove-migration', << pipeline.git.branch >> ]
|
||||
- matches:
|
||||
pattern: /^release\/\d+\.\d+\.\d+$/
|
||||
value: << pipeline.git.branch >>
|
||||
@@ -60,7 +60,7 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters
|
||||
- equal: [ develop, << pipeline.git.branch >> ]
|
||||
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
|
||||
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
|
||||
- equal: [ 'breaking/remove_webpack_4', << pipeline.git.branch >> ]
|
||||
- equal: [ 'remove-migration', << pipeline.git.branch >> ]
|
||||
- matches:
|
||||
pattern: /^release\/\d+\.\d+\.\d+$/
|
||||
value: << pipeline.git.branch >>
|
||||
@@ -83,7 +83,7 @@ windowsWorkflowFilters: &windows-workflow-filters
|
||||
- equal: [ develop, << pipeline.git.branch >> ]
|
||||
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
|
||||
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
|
||||
- equal: [ 'breaking/remove_webpack_4', << pipeline.git.branch >> ]
|
||||
- equal: [ 'remove-migration', << pipeline.git.branch >> ]
|
||||
- matches:
|
||||
pattern: /^release\/\d+\.\d+\.\d+$/
|
||||
value: << pipeline.git.branch >>
|
||||
@@ -157,7 +157,7 @@ commands:
|
||||
name: Set environment variable to determine whether or not to persist artifacts
|
||||
command: |
|
||||
echo "Setting SHOULD_PERSIST_ARTIFACTS variable"
|
||||
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "breaking/remove_webpack_4" ]]; then
|
||||
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "remove-migration" ]]; then
|
||||
export SHOULD_PERSIST_ARTIFACTS=true
|
||||
fi' >> "$BASH_ENV"
|
||||
# You must run `setup_should_persist_artifacts` command and be using bash before running this command
|
||||
@@ -1160,23 +1160,6 @@ commands:
|
||||
CYPRESS_INSTALL_BINARY=~/cypress/cypress.zip npm install --legacy-peer-deps ~/cypress/cypress.tgz
|
||||
fi
|
||||
working_directory: /tmp/<<parameters.repo>>
|
||||
- run:
|
||||
name: Scaffold new config file
|
||||
working_directory: /tmp/<<parameters.repo>>
|
||||
environment:
|
||||
CYPRESS_INTERNAL_FORCE_SCAFFOLD: "1"
|
||||
command: |
|
||||
if [[ -f cypress.json ]]; then
|
||||
rm -rf cypress.json
|
||||
echo 'module.exports = { e2e: {} }' > cypress.config.js
|
||||
fi
|
||||
- run:
|
||||
name: Rename support file
|
||||
working_directory: /tmp/<<parameters.repo>>
|
||||
command: |
|
||||
if [[ -f cypress/support/index.js ]]; then
|
||||
mv cypress/support/index.js cypress/support/e2e.js
|
||||
fi
|
||||
- run:
|
||||
name: Print Cypress version
|
||||
working_directory: /tmp/<<parameters.repo>>
|
||||
|
||||
@@ -18,6 +18,10 @@ _Released 07/01/2025 (PENDING)_
|
||||
|
||||
- [`tsx`](https://tsx.is/) is now used in all cases to run the Cypress config, replacing [ts-node](https://github.com/TypeStrong/ts-node) for TypeScript and Node for commonjs/ESM. This should allow for more interoperability for users who are using any variant of ES Modules. Addresses [#8090](https://github.com/cypress-io/cypress/issues/8090), [#15724](https://github.com/cypress-io/cypress/issues/15724), [#21805](https://github.com/cypress-io/cypress/issues/21805), [#22273](https://github.com/cypress-io/cypress/issues/22273), [#22747](https://github.com/cypress-io/cypress/issues/22747), [#23141](https://github.com/cypress-io/cypress/issues/23141), [#25958](https://github.com/cypress-io/cypress/issues/25958), [#25959](https://github.com/cypress-io/cypress/issues/25959), [#26606](https://github.com/cypress-io/cypress/issues/26606), [#27359](https://github.com/cypress-io/cypress/issues/27359), [#27450](https://github.com/cypress-io/cypress/issues/27450), [#28442](https://github.com/cypress-io/cypress/issues/28442), [#30318](https://github.com/cypress-io/cypress/issues/30318), [#30718](https://github.com/cypress-io/cypress/issues/30718), [#30907](https://github.com/cypress-io/cypress/issues/30907), [#30915](https://github.com/cypress-io/cypress/issues/30915), [#30925](https://github.com/cypress-io/cypress/issues/30925), [#30954](https://github.com/cypress-io/cypress/issues/30954) and [#31185](https://github.com/cypress-io/cypress/issues/31185).
|
||||
|
||||
**Misc:**
|
||||
|
||||
- Migration helpers and related errors are no longer shown when upgrading from Cypress versions earlier than 10.0.0. To migrate from a pre-10.0.0 version, upgrade one major version at a time to receive the appropriate guidance. Addresses [#31345](https://github.com/cypress-io/cypress/issues/31345). Addressed in [https://github.com/cypress-io/cypress/pull/31629/](https://github.com/cypress-io/cypress/pull/31629/).
|
||||
|
||||
## 14.3.3
|
||||
|
||||
_Released 5/6/2025_
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// checking types passed to cypress/plugins/index.js file
|
||||
// checking types passed through setupNodeEvents
|
||||
|
||||
// does nothing
|
||||
const pluginConfig: Cypress.PluginConfig = (on, config) => {}
|
||||
|
||||
@@ -4,7 +4,7 @@ Clear, consistent, errors are one of the important parts of the Cypress experien
|
||||
|
||||
### @packages/errors
|
||||
|
||||
All error related logic for the server should be added to `@packages/errors`. This logic has been separated out from the `@packages/server` to enable strict type checking & use in other packages we have added in the `10.0-release` branch.
|
||||
All error related logic for the server should be added to `@packages/errors`.
|
||||
|
||||
### Errors Development Workflow
|
||||
|
||||
@@ -78,15 +78,15 @@ In this case, `arg1` will be highlighted in yellow when printed to the terminal.
|
||||
|
||||
|
||||
```ts
|
||||
PLUGINS_FILE_ERROR: (arg1: string, arg2: Error) => {
|
||||
FAKE_ERROR: (arg1: string, arg2: Error) => {
|
||||
return errTemplate`\
|
||||
The plugins file is missing or invalid.
|
||||
The fake file is missing or invalid.
|
||||
|
||||
Your \`pluginsFile\` is set to ${arg1}, but either the file is missing, it contains a syntax error, or threw an error when required. The \`pluginsFile\` must be a \`.js\`, \`.ts\`, or \`.coffee\` file.
|
||||
Your \`fakeFile\` is set to ${arg1}, but either the file is missing, it contains a syntax error, or threw an error when required. The \`fakeFile\` must be a \`.js\`, \`.ts\`, or \`.coffee\` file.
|
||||
|
||||
Or you might have renamed the extension of your \`pluginsFile\`. If that's the case, restart the test runner.
|
||||
Or you might have renamed the extension of your \`fakeFile\`. If that's the case, restart the test runner.
|
||||
|
||||
Please fix this, or set \`pluginsFile\` to \`false\` if a plugins file is not necessary for your project.
|
||||
Please fix this, or set \`fakeFile\` to \`false\` if a plugins file is not necessary for your project.
|
||||
|
||||
${details(arg2)}
|
||||
`
|
||||
|
||||
@@ -143,14 +143,16 @@ $ npx cypress run --env grepTags=@smoke,grepFilterSpecs=true
|
||||
$ npx cypress run --env grepUntagged=true
|
||||
```
|
||||
|
||||
You can use any way to modify the environment values `grep` and `grepTags`, except the run-time `Cypress.env('grep')` (because it is too late at run-time). You can set the `grep` value in the `cypress.json` file to run only tests with the substring `viewport` in their names
|
||||
You can use any way to modify the environment values `grep` and `grepTags`, except the run-time `Cypress.env('grep')` (because it is too late at run-time). You can set the `grep` value in the `cypress.config.js` file to run only tests with the substring `viewport` in their names
|
||||
|
||||
```json
|
||||
{
|
||||
"env": {
|
||||
"grep": "viewport"
|
||||
}
|
||||
}
|
||||
```js
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
env: {
|
||||
grep: "viewport"
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
You can also set the `env.grep` object in the plugin file, but remember to return the changed config object:
|
||||
|
||||
@@ -1,20 +1,7 @@
|
||||
exports['config/src/index .getBreakingKeys returns list of breaking config keys 1'] = [
|
||||
'blacklistHosts',
|
||||
'componentFolder',
|
||||
'experimentalComponentTesting',
|
||||
'experimentalGetCookiesSameSite',
|
||||
'experimentalJustInTimeCompile',
|
||||
'experimentalNetworkStubbing',
|
||||
'experimentalRunEvents',
|
||||
'experimentalSessionSupport',
|
||||
'experimentalSessionAndOrigin',
|
||||
'experimentalShadowDomSupport',
|
||||
'experimentalSkipDomainInjection',
|
||||
'firefoxGcInterval',
|
||||
'ignoreTestFiles',
|
||||
'integrationFolder',
|
||||
'pluginsFile',
|
||||
'testFiles',
|
||||
'videoUploadOnPasses',
|
||||
]
|
||||
|
||||
|
||||
@@ -9,26 +9,15 @@ import type { TestingType } from '@packages/types'
|
||||
import * as validate from './validation'
|
||||
|
||||
const BREAKING_OPTION_ERROR_KEY: Readonly<AllCypressErrorNames[]> = [
|
||||
'COMPONENT_FOLDER_REMOVED',
|
||||
'INTEGRATION_FOLDER_REMOVED',
|
||||
'CONFIG_FILE_INVALID_ROOT_CONFIG',
|
||||
'CONFIG_FILE_INVALID_ROOT_CONFIG_E2E',
|
||||
'CONFIG_FILE_INVALID_ROOT_CONFIG_COMPONENT',
|
||||
'CONFIG_FILE_INVALID_TESTING_TYPE_CONFIG_COMPONENT',
|
||||
'CONFIG_FILE_INVALID_TESTING_TYPE_CONFIG_E2E',
|
||||
'EXPERIMENTAL_COMPONENT_TESTING_REMOVED',
|
||||
'EXPERIMENTAL_SAMESITE_REMOVED',
|
||||
'EXPERIMENTAL_NETWORK_STUBBING_REMOVED',
|
||||
'EXPERIMENTAL_RUN_EVENTS_REMOVED',
|
||||
'EXPERIMENTAL_SESSION_SUPPORT_REMOVED',
|
||||
'EXPERIMENTAL_SESSION_AND_ORIGIN_REMOVED',
|
||||
'EXPERIMENTAL_SINGLE_TAB_RUN_MODE',
|
||||
'EXPERIMENTAL_SHADOW_DOM_REMOVED',
|
||||
'FIREFOX_GC_INTERVAL_REMOVED',
|
||||
'PLUGINS_FILE_CONFIG_OPTION_REMOVED',
|
||||
'VIDEO_UPLOAD_ON_PASSES_REMOVED',
|
||||
'RENAMED_CONFIG_OPTION',
|
||||
'TEST_FILES_RENAMED',
|
||||
] as const
|
||||
|
||||
type ValidationOptions = {
|
||||
@@ -617,74 +606,17 @@ export const options: Array<DriverConfigOption | RuntimeConfigOption> = [
|
||||
*/
|
||||
export const breakingOptions: Readonly<BreakingOption[]> = [
|
||||
{
|
||||
name: 'blacklistHosts',
|
||||
errorKey: 'RENAMED_CONFIG_OPTION',
|
||||
newName: 'blockHosts',
|
||||
isWarning: false,
|
||||
}, {
|
||||
name: 'componentFolder',
|
||||
errorKey: 'COMPONENT_FOLDER_REMOVED',
|
||||
isWarning: false,
|
||||
}, {
|
||||
name: 'experimentalComponentTesting',
|
||||
errorKey: 'EXPERIMENTAL_COMPONENT_TESTING_REMOVED',
|
||||
isWarning: false,
|
||||
}, {
|
||||
name: 'experimentalGetCookiesSameSite',
|
||||
errorKey: 'EXPERIMENTAL_SAMESITE_REMOVED',
|
||||
isWarning: true,
|
||||
}, {
|
||||
name: 'experimentalJustInTimeCompile',
|
||||
errorKey: 'EXPERIMENTAL_JIT_COMPILE_REMOVED',
|
||||
isWarning: true,
|
||||
},
|
||||
{
|
||||
name: 'experimentalNetworkStubbing',
|
||||
errorKey: 'EXPERIMENTAL_NETWORK_STUBBING_REMOVED',
|
||||
isWarning: true,
|
||||
}, {
|
||||
name: 'experimentalRunEvents',
|
||||
errorKey: 'EXPERIMENTAL_RUN_EVENTS_REMOVED',
|
||||
isWarning: true,
|
||||
}, {
|
||||
name: 'experimentalSessionSupport',
|
||||
errorKey: 'EXPERIMENTAL_SESSION_SUPPORT_REMOVED',
|
||||
isWarning: true,
|
||||
}, {
|
||||
name: 'experimentalSessionAndOrigin',
|
||||
errorKey: 'EXPERIMENTAL_SESSION_AND_ORIGIN_REMOVED',
|
||||
isWarning: true,
|
||||
}, {
|
||||
name: 'experimentalShadowDomSupport',
|
||||
errorKey: 'EXPERIMENTAL_SHADOW_DOM_REMOVED',
|
||||
isWarning: true,
|
||||
}, {
|
||||
name: 'experimentalSkipDomainInjection',
|
||||
errorKey: 'EXPERIMENTAL_SKIP_DOMAIN_INJECTION_REMOVED',
|
||||
isWarning: false,
|
||||
}, {
|
||||
name: 'firefoxGcInterval',
|
||||
errorKey: 'FIREFOX_GC_INTERVAL_REMOVED',
|
||||
isWarning: true,
|
||||
}, {
|
||||
name: 'ignoreTestFiles',
|
||||
errorKey: 'TEST_FILES_RENAMED',
|
||||
newName: 'excludeSpecPattern',
|
||||
isWarning: false,
|
||||
}, {
|
||||
name: 'integrationFolder',
|
||||
errorKey: 'INTEGRATION_FOLDER_REMOVED',
|
||||
isWarning: false,
|
||||
}, {
|
||||
name: 'pluginsFile',
|
||||
errorKey: 'PLUGINS_FILE_CONFIG_OPTION_REMOVED',
|
||||
isWarning: false,
|
||||
},
|
||||
{
|
||||
name: 'testFiles',
|
||||
errorKey: 'TEST_FILES_RENAMED',
|
||||
newName: 'specPattern',
|
||||
isWarning: false,
|
||||
}, {
|
||||
name: 'videoUploadOnPasses',
|
||||
errorKey: 'VIDEO_UPLOAD_ON_PASSES_REMOVED',
|
||||
|
||||
@@ -14,14 +14,14 @@ describe('config/src/index', () => {
|
||||
it('returns filter config only containing allowed keys', () => {
|
||||
const keys = configUtil.allowed({
|
||||
'baseUrl': 'https://url.com',
|
||||
'blacklistHosts': 'breaking option',
|
||||
'videoUploadOnPasses': true,
|
||||
'devServerPublicPathRoute': 'internal key',
|
||||
'random': 'not a config option',
|
||||
})
|
||||
|
||||
expect(keys).to.deep.eq({
|
||||
'baseUrl': 'https://url.com',
|
||||
'blacklistHosts': 'breaking option',
|
||||
'videoUploadOnPasses': true,
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -30,7 +30,7 @@ describe('config/src/index', () => {
|
||||
it('returns list of breaking config keys', () => {
|
||||
const breakingKeys = configUtil.getBreakingKeys()
|
||||
|
||||
expect(breakingKeys).to.include('blacklistHosts')
|
||||
expect(breakingKeys).to.include('videoUploadOnPasses')
|
||||
snapshot(breakingKeys)
|
||||
})
|
||||
})
|
||||
@@ -154,12 +154,12 @@ describe('config/src/index', () => {
|
||||
const errorFn = sinon.spy()
|
||||
|
||||
configUtil.validateNoBreakingConfig({
|
||||
'experimentalNetworkStubbing': 'should break',
|
||||
'experimentalSessionAndOrigin': 'should break',
|
||||
configFile: 'config.js',
|
||||
}, warningFn, errorFn, 'e2e')
|
||||
|
||||
expect(warningFn).to.have.been.calledOnceWith('EXPERIMENTAL_NETWORK_STUBBING_REMOVED', {
|
||||
name: 'experimentalNetworkStubbing',
|
||||
expect(warningFn).to.have.been.calledOnceWith('EXPERIMENTAL_SESSION_AND_ORIGIN_REMOVED', {
|
||||
name: 'experimentalSessionAndOrigin',
|
||||
newName: undefined,
|
||||
value: undefined,
|
||||
testingType: 'e2e',
|
||||
@@ -174,14 +174,14 @@ describe('config/src/index', () => {
|
||||
const errorFn = sinon.spy()
|
||||
|
||||
configUtil.validateNoBreakingConfig({
|
||||
'blacklistHosts': 'should break',
|
||||
experimentalSkipDomainInjection: true,
|
||||
configFile: 'config.js',
|
||||
}, warningFn, errorFn, 'e2e')
|
||||
|
||||
expect(warningFn).to.have.been.callCount(0)
|
||||
expect(errorFn).to.have.been.calledOnceWith('RENAMED_CONFIG_OPTION', {
|
||||
name: 'blacklistHosts',
|
||||
newName: 'blockHosts',
|
||||
expect(errorFn).to.have.been.calledOnceWith('EXPERIMENTAL_SKIP_DOMAIN_INJECTION_REMOVED', {
|
||||
name: 'experimentalSkipDomainInjection',
|
||||
newName: undefined,
|
||||
value: undefined,
|
||||
testingType: 'e2e',
|
||||
configFile: 'config.js',
|
||||
|
||||
@@ -958,17 +958,6 @@ describe('config/src/project/utils', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// @see https://github.com/cypress-io/cypress/issues/6892
|
||||
it('warns if experimentalGetCookiesSameSite is passed', async function () {
|
||||
const warning = sinon.spy(errors, 'warning')
|
||||
|
||||
await this.defaults('experimentalGetCookiesSameSite', true, {
|
||||
experimentalGetCookiesSameSite: true,
|
||||
})
|
||||
|
||||
expect(warning).to.be.calledWith('EXPERIMENTAL_SAMESITE_REMOVED')
|
||||
})
|
||||
|
||||
it('warns if experimentalJustInTimeCompile is passed', async function () {
|
||||
const warning = sinon.spy(errors, 'warning')
|
||||
|
||||
@@ -979,16 +968,6 @@ describe('config/src/project/utils', () => {
|
||||
expect(warning).to.be.calledWith('EXPERIMENTAL_JIT_COMPILE_REMOVED')
|
||||
})
|
||||
|
||||
it('warns if experimentalSessionSupport is passed', async function () {
|
||||
const warning = sinon.spy(errors, 'warning')
|
||||
|
||||
await this.defaults('experimentalSessionSupport', true, {
|
||||
experimentalSessionSupport: true,
|
||||
})
|
||||
|
||||
expect(warning).to.be.calledWith('EXPERIMENTAL_SESSION_SUPPORT_REMOVED')
|
||||
})
|
||||
|
||||
it('warns if experimentalSessionAndOrigin is passed', async function () {
|
||||
const warning = sinon.spy(errors, 'warning')
|
||||
|
||||
@@ -999,47 +978,6 @@ describe('config/src/project/utils', () => {
|
||||
expect(warning).to.be.calledWith('EXPERIMENTAL_SESSION_AND_ORIGIN_REMOVED')
|
||||
})
|
||||
|
||||
it('warns if experimentalShadowDomSupport is passed', async function () {
|
||||
const warning = sinon.spy(errors, 'warning')
|
||||
|
||||
await this.defaults('experimentalShadowDomSupport', true, {
|
||||
experimentalShadowDomSupport: true,
|
||||
})
|
||||
|
||||
expect(warning).to.be.calledWith('EXPERIMENTAL_SHADOW_DOM_REMOVED')
|
||||
})
|
||||
|
||||
it('warns if experimentalRunEvents is passed', async function () {
|
||||
const warning = sinon.spy(errors, 'warning')
|
||||
|
||||
await this.defaults('experimentalRunEvents', true, {
|
||||
experimentalRunEvents: true,
|
||||
})
|
||||
|
||||
expect(warning).to.be.calledWith('EXPERIMENTAL_RUN_EVENTS_REMOVED')
|
||||
})
|
||||
|
||||
// @see https://github.com/cypress-io/cypress/pull/9185
|
||||
it('warns if experimentalNetworkStubbing is passed', async function () {
|
||||
const warning = sinon.spy(errors, 'warning')
|
||||
|
||||
await this.defaults('experimentalNetworkStubbing', true, {
|
||||
experimentalNetworkStubbing: true,
|
||||
})
|
||||
|
||||
expect(warning).to.be.calledWith('EXPERIMENTAL_NETWORK_STUBBING_REMOVED')
|
||||
})
|
||||
|
||||
it('warns if firefoxGcInterval is passed', async function () {
|
||||
const warning = sinon.spy(errors, 'warning')
|
||||
|
||||
await this.defaults('firefoxGcInterval', true, {
|
||||
firefoxGcInterval: true,
|
||||
})
|
||||
|
||||
expect(warning).to.be.calledWith('FIREFOX_GC_INTERVAL_REMOVED')
|
||||
})
|
||||
|
||||
describe('.resolved', () => {
|
||||
it('sets reporter and port to cli', () => {
|
||||
const obj = {
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
exports['cypress.config.js generation should create a string when passed only a global option 1'] = `
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
viewportWidth: 300,
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require('./cypress/plugins/index.js')(on, config)
|
||||
},
|
||||
},
|
||||
component: {
|
||||
setupNodeEvents(on, config) {},
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation should create a string when passed only a e2e options 1'] = `
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require('./cypress/plugins/index.js')(on, config)
|
||||
},
|
||||
baseUrl: 'localhost:3000',
|
||||
},
|
||||
component: {
|
||||
setupNodeEvents(on, config) {},
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation should create a string when passed only a component options 1'] = `
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require('./cypress/plugins/index.js')(on, config)
|
||||
},
|
||||
},
|
||||
component: {
|
||||
setupNodeEvents(on, config) {},
|
||||
retries: 2,
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation should create a string for a config with global, component, and e2e options 1'] = `
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
viewportWidth: 300,
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require('./cypress/plugins/index.js')(on, config)
|
||||
},
|
||||
retries: 2,
|
||||
baseUrl: 'localhost:300',
|
||||
slowTestThreshold: 500,
|
||||
},
|
||||
component: {
|
||||
setupNodeEvents(on, config) {},
|
||||
retries: 1,
|
||||
slowTestThreshold: 500,
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation should create a string when passed an empty object 1'] = `
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require('./cypress/plugins/index.js')(on, config)
|
||||
},
|
||||
},
|
||||
component: {
|
||||
setupNodeEvents(on, config) {},
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation should handle export default in plugins file 1'] = `
|
||||
import { defineConfig } from 'cypress'
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require('./cypress/plugins/index.ts').default(on, config)
|
||||
},
|
||||
},
|
||||
component: {
|
||||
setupNodeEvents(on, config) {},
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation should exclude fields that are no longer valid 1'] = `
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require('./cypress/plugins/index.js')(on, config)
|
||||
},
|
||||
},
|
||||
component: {
|
||||
setupNodeEvents(on, config) {},
|
||||
specPattern: 'path/to/component/folder/**/*.cy.{js,jsx,ts,tsx}',
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation should create only a component entry when no e2e specs are detected 1'] = `
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
component: {
|
||||
setupNodeEvents(on, config) {},
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation should create only an e2e entry when no component specs are detected 1'] = `
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require('./cypress/plugins/index.js')(on, config)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation should maintain both root level and nested non-breaking options during migration 1'] = `
|
||||
import { defineConfig } from 'cypress'
|
||||
|
||||
export default defineConfig({
|
||||
viewportWidth: 1200,
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require('./cypress/plugins/index.js')(on, config)
|
||||
},
|
||||
viewportWidth: 1600,
|
||||
},
|
||||
component: {
|
||||
setupNodeEvents(on, config) {},
|
||||
viewportWidth: 400,
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation should add custom specPattern if project has projectId 1'] = `
|
||||
import { defineConfig } from 'cypress'
|
||||
|
||||
export default defineConfig({
|
||||
projectId: 'abc1234',
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require('./cypress/plugins/index.js')(on, config)
|
||||
},
|
||||
baseUrl: 'http://localhost:3000',
|
||||
specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}',
|
||||
},
|
||||
component: {
|
||||
setupNodeEvents(on, config) {},
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation should not add custom specPattern if project has projectId and integrationFolder 1'] = `
|
||||
import { defineConfig } from 'cypress'
|
||||
|
||||
export default defineConfig({
|
||||
projectId: 'abc1234',
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require('./cypress/plugins/index.js')(on, config)
|
||||
},
|
||||
baseUrl: 'http://localhost:3000',
|
||||
specPattern: 'cypress/custom/e2e/**/*.{js,jsx,ts,tsx}',
|
||||
},
|
||||
component: {
|
||||
setupNodeEvents(on, config) {},
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation generates correct config for component testing migration with custom testFiles glob 1'] = `
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
component: {
|
||||
setupNodeEvents(on, config) {},
|
||||
specPattern: './**/*.spec.cy.{js,ts,jsx,tsx}',
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation should create a string when passed an empty object for an ECMA Script project 1'] = `
|
||||
import { defineConfig } from 'cypress'
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require('./cypress/plugins/index.js')(on, config)
|
||||
},
|
||||
},
|
||||
component: {
|
||||
setupNodeEvents(on, config) {},
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation generates correct config for component testing migration with custom testFiles array of glob 1'] = `
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
e2e: {
|
||||
setupNodeEvents(on, config) {},
|
||||
specPattern: ['cypress/e2e/**/*.spec.js', 'cypress/e2e/**/*.test.js'],
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
FileActions,
|
||||
ProjectActions,
|
||||
WizardActions,
|
||||
MigrationActions,
|
||||
BrowserActions,
|
||||
DevActions,
|
||||
AuthActions,
|
||||
@@ -30,7 +29,6 @@ export class DataActions {
|
||||
private _wizard: WizardActions
|
||||
private _project: ProjectActions
|
||||
private _electron: ElectronActions
|
||||
private _migration: MigrationActions
|
||||
private _browser: BrowserActions
|
||||
private _servers: ServersActions
|
||||
private _versions: VersionsActions
|
||||
@@ -50,7 +48,6 @@ export class DataActions {
|
||||
this._wizard = new WizardActions(this.ctx)
|
||||
this._project = new ProjectActions(this.ctx)
|
||||
this._electron = new ElectronActions(this.ctx)
|
||||
this._migration = new MigrationActions(this.ctx)
|
||||
this._browser = new BrowserActions(this.ctx)
|
||||
this._servers = new ServersActions(this.ctx)
|
||||
this._versions = new VersionsActions(this.ctx)
|
||||
@@ -97,10 +94,6 @@ export class DataActions {
|
||||
return this._electron
|
||||
}
|
||||
|
||||
get migration () {
|
||||
return this._migration
|
||||
}
|
||||
|
||||
get browser () {
|
||||
return this._browser
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
HtmlDataSource,
|
||||
UtilDataSource,
|
||||
BrowserApiShape,
|
||||
MigrationDataSource,
|
||||
RelevantRunsDataSource,
|
||||
RelevantRunSpecsDataSource,
|
||||
VersionsDataSource,
|
||||
@@ -101,7 +100,6 @@ export class DataContext {
|
||||
private _html: HtmlDataSource
|
||||
private _error: ErrorDataSource
|
||||
private _util: UtilDataSource
|
||||
private _migration: MigrationDataSource
|
||||
|
||||
readonly lifecycleManager: ProjectLifecycleManager
|
||||
|
||||
@@ -136,7 +134,6 @@ export class DataContext {
|
||||
this._html = new HtmlDataSource(this)
|
||||
this._error = new ErrorDataSource(this)
|
||||
this._util = new UtilDataSource(this)
|
||||
this._migration = new MigrationDataSource(this)
|
||||
// the lifecycle manager needs to be initialized last as it needs properties instantiated on the DataContext object
|
||||
this.lifecycleManager = new ProjectLifecycleManager(this)
|
||||
}
|
||||
@@ -236,10 +233,6 @@ export class DataContext {
|
||||
return this._util
|
||||
}
|
||||
|
||||
get migration () {
|
||||
return this._migration
|
||||
}
|
||||
|
||||
/**
|
||||
* This will be replaced with Immer, for immutable state updates.
|
||||
*/
|
||||
|
||||
@@ -1,446 +0,0 @@
|
||||
/* eslint-disable no-dupe-class-members */
|
||||
import path from 'path'
|
||||
import debugLib from 'debug'
|
||||
import { fork } from 'child_process'
|
||||
import fs from 'fs-extra'
|
||||
import os from 'os'
|
||||
import semver from 'semver'
|
||||
import type { ForkOptions } from 'child_process'
|
||||
import assert from 'assert'
|
||||
import _ from 'lodash'
|
||||
import type { DataContext } from '..'
|
||||
import { getError } from '@packages/errors'
|
||||
import {
|
||||
cleanUpIntegrationFolder,
|
||||
formatConfig,
|
||||
LegacyCypressConfigJson,
|
||||
moveSpecFiles,
|
||||
NonStandardMigrationError,
|
||||
SpecToMove,
|
||||
} from '../sources'
|
||||
import {
|
||||
tryGetDefaultLegacyPluginsFile,
|
||||
supportFilesForMigration,
|
||||
hasSpecFile,
|
||||
getStepsForMigration,
|
||||
getIntegrationFolder,
|
||||
isDefaultTestFiles,
|
||||
getComponentTestFilesGlobs,
|
||||
getComponentFolder,
|
||||
getIntegrationTestFilesGlobs,
|
||||
getSpecPattern,
|
||||
legacyOptions,
|
||||
legacyIntegrationFolder,
|
||||
getLegacyPluginsCustomFilePath,
|
||||
} from '../sources/migration'
|
||||
import { makeCoreData } from '../data'
|
||||
import { LegacyPluginsIpc } from '../data/LegacyPluginsIpc'
|
||||
import { hasTypeScriptInstalled, toPosix } from '../util'
|
||||
|
||||
const debug = debugLib('cypress:data-context:MigrationActions')
|
||||
|
||||
// NOTE: need the file:// prefix to avoid https://nodejs.org/api/errors.html#err_unsupported_esm_url_scheme on windows
|
||||
const tsxCjs = os.platform() === 'win32' ? `file://${toPosix(require.resolve('tsx/cjs'))}` : toPosix(require.resolve('tsx/cjs'))
|
||||
|
||||
export function getConfigWithDefaults (legacyConfig: any) {
|
||||
const newConfig = _.cloneDeep(legacyConfig)
|
||||
|
||||
legacyOptions.forEach(({ defaultValue, name }) => {
|
||||
if (defaultValue !== undefined && legacyConfig[name] === undefined) {
|
||||
newConfig[name] = typeof defaultValue === 'function' ? defaultValue() : defaultValue
|
||||
}
|
||||
})
|
||||
|
||||
return newConfig
|
||||
}
|
||||
|
||||
export function getDiff (oldConfig: any, newConfig: any) {
|
||||
// get all the values updated
|
||||
const result: any = _.reduce(oldConfig, (acc: any, value, key) => {
|
||||
// ignore values that have been removed
|
||||
if (newConfig[key] && !_.isEqual(value, newConfig[key])) {
|
||||
acc[key] = newConfig[key]
|
||||
}
|
||||
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
// get all the values added
|
||||
return _.reduce(newConfig, (acc: any, value, key) => {
|
||||
// their key is in the new config but not in the old config
|
||||
if (!oldConfig.hasOwnProperty(key)) {
|
||||
acc[key] = value
|
||||
}
|
||||
|
||||
return acc
|
||||
}, result)
|
||||
}
|
||||
|
||||
export async function processConfigViaLegacyPlugins (projectRoot: string, legacyConfig: LegacyCypressConfigJson, nodeVersion: string | undefined | null): Promise<LegacyCypressConfigJson> {
|
||||
const pluginFile = legacyConfig.pluginsFile
|
||||
? await getLegacyPluginsCustomFilePath(projectRoot, legacyConfig.pluginsFile)
|
||||
: await tryGetDefaultLegacyPluginsFile(projectRoot)
|
||||
|
||||
debug('found legacy pluginsFile at %s', pluginFile)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// couldn't find a pluginsFile
|
||||
// just bail with initial config
|
||||
if (!pluginFile) {
|
||||
return resolve(legacyConfig)
|
||||
}
|
||||
|
||||
const cwd = path.join(projectRoot, pluginFile)
|
||||
|
||||
const childOptions: ForkOptions = {
|
||||
stdio: 'inherit',
|
||||
cwd: path.dirname(cwd),
|
||||
env: _.omit(process.env, 'CYPRESS_INTERNAL_E2E_TESTING_SELF'),
|
||||
}
|
||||
|
||||
const configProcessArgs = ['--projectRoot', projectRoot, '--file', cwd]
|
||||
const CHILD_PROCESS_FILE_PATH = require.resolve('@packages/server/lib/plugins/child/require_async_child')
|
||||
|
||||
// use tsx if they've got typescript installed
|
||||
// this matches the 9.x behavior, which is what we want for
|
||||
// processing legacy pluginsFile (we never supported `"type": "module") in 9.x.
|
||||
if (hasTypeScriptInstalled(projectRoot)) {
|
||||
let tsxLoader = nodeVersion && semver.lt(nodeVersion, '20.6.0') ? `--loader ${tsxCjs}` : `--import ${tsxCjs}`
|
||||
|
||||
debug(`using generic ${tsxLoader} for esm and cjs with TypeScript for legacy migration.`)
|
||||
|
||||
if (!childOptions.env) {
|
||||
childOptions.env = {}
|
||||
}
|
||||
|
||||
if (childOptions.env.NODE_OPTIONS) {
|
||||
childOptions.env.NODE_OPTIONS += ` ${tsxLoader}`
|
||||
} else {
|
||||
childOptions.env.NODE_OPTIONS = tsxLoader
|
||||
}
|
||||
}
|
||||
|
||||
const childProcess = fork(CHILD_PROCESS_FILE_PATH, configProcessArgs, childOptions)
|
||||
const ipc = new LegacyPluginsIpc(childProcess)
|
||||
|
||||
childProcess.on('error', (error) => {
|
||||
error = getError('LEGACY_CONFIG_ERROR_DURING_MIGRATION', cwd, error)
|
||||
|
||||
reject(error)
|
||||
ipc.killChildProcess()
|
||||
})
|
||||
|
||||
const legacyConfigWithDefaults = getConfigWithDefaults(legacyConfig)
|
||||
|
||||
ipc.on('ready', () => {
|
||||
debug('legacyConfigIpc:ready')
|
||||
ipc.send('loadLegacyPlugins', legacyConfigWithDefaults)
|
||||
})
|
||||
|
||||
ipc.on('loadLegacyPlugins:reply', (modifiedLegacyConfig) => {
|
||||
debug('loadLegacyPlugins:reply')
|
||||
const diff = getDiff(legacyConfigWithDefaults, modifiedLegacyConfig)
|
||||
|
||||
// if env is updated by plugins, avoid adding it to the config file
|
||||
if (diff.env) {
|
||||
delete diff.env
|
||||
}
|
||||
|
||||
const legacyConfigWithChanges = _.merge(legacyConfig, diff)
|
||||
|
||||
resolve(legacyConfigWithChanges)
|
||||
ipc.killChildProcess()
|
||||
})
|
||||
|
||||
ipc.on('loadLegacyPlugins:error', (error) => {
|
||||
debug('loadLegacyPlugins:error')
|
||||
error = getError('LEGACY_CONFIG_ERROR_DURING_MIGRATION', cwd, error)
|
||||
|
||||
reject(error)
|
||||
ipc.killChildProcess()
|
||||
})
|
||||
|
||||
ipc.on('childProcess:unhandledError', (error) => {
|
||||
debug('childProcess:unhandledError')
|
||||
reject(error)
|
||||
ipc.killChildProcess()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export class MigrationActions {
|
||||
constructor (private ctx: DataContext) { }
|
||||
|
||||
async initialize (config: LegacyCypressConfigJson) {
|
||||
const legacyConfigForMigration = await this.setLegacyConfigForMigration(config)
|
||||
|
||||
this.reset(legacyConfigForMigration)
|
||||
|
||||
if (!this.ctx.currentProject || !legacyConfigForMigration) {
|
||||
throw Error('cannot do migration without currentProject!')
|
||||
}
|
||||
|
||||
if (this.ctx.coreData.app.isGlobalMode) {
|
||||
const version = await this.locallyInstalledCypressVersion(this.ctx.currentProject)
|
||||
|
||||
if (!version) {
|
||||
// Could not resolve Cypress. Unlikely, but they are using a
|
||||
// project with Cypress that is nested more deeply than
|
||||
// another project, which has a `cypress.json` but has not had
|
||||
// it's node_modules installed, or it relies on a global version
|
||||
// of Cypress that is missing for whatever reason.
|
||||
return this.ctx.onError(getError('MIGRATION_CYPRESS_NOT_FOUND'))
|
||||
}
|
||||
|
||||
const currentVersion = (await this.ctx.versions.versionData()).current.version
|
||||
|
||||
// Validate that the project being migrated has a version of Cypress compatible with the version being executed.
|
||||
// This handles situations where Cypress is launched in global mode to migrate a project with an older version of
|
||||
// Cypress as a dependency which could break the project when launched directly.
|
||||
// For example:
|
||||
// Local: 9.6.0 Global: 10.0.0 FAIL
|
||||
// Local: 10.0.1 Global: 10.0.0 PASS
|
||||
// Local: 12.0.0 Global: 12.0.1 FAIL
|
||||
if (!semver.satisfies(version, `^${currentVersion}`)) {
|
||||
return this.ctx.onError(getError('MIGRATION_MISMATCHED_CYPRESS_VERSIONS', version, currentVersion))
|
||||
}
|
||||
}
|
||||
|
||||
await this.initializeFlags()
|
||||
|
||||
const legacyConfigFileExist = this.ctx.migration.legacyConfigFileExists()
|
||||
const filteredSteps = await getStepsForMigration(this.ctx.currentProject, legacyConfigForMigration, Boolean(legacyConfigFileExist))
|
||||
|
||||
this.ctx.update((coreData) => {
|
||||
if (!filteredSteps[0]) {
|
||||
throw Error(`Impossible to initialize a migration. No steps fit the configuration of this project.`)
|
||||
}
|
||||
|
||||
coreData.migration.filteredSteps = filteredSteps
|
||||
coreData.migration.step = filteredSteps[0]
|
||||
})
|
||||
}
|
||||
|
||||
async locallyInstalledCypressVersion (currentProject: string) {
|
||||
try {
|
||||
const localCypressPkgJsonPath = require.resolve(path.join('cypress', 'package.json'), {
|
||||
paths: [currentProject],
|
||||
})
|
||||
const localCypressPkgJson = await fs.readJson(path.join(localCypressPkgJsonPath)) as { version: string }
|
||||
|
||||
return localCypressPkgJson?.version ?? undefined
|
||||
} catch (e) {
|
||||
// node_modules was not found, or some other unexpected error
|
||||
// return undefined and surface the correct error.
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Figure out all the data required for the migration UI.
|
||||
* This drives which migration steps need be shown and performed.
|
||||
*/
|
||||
private async initializeFlags () {
|
||||
const legacyConfigForMigration = this.ctx.coreData.migration.legacyConfigForMigration
|
||||
|
||||
if (!this.ctx.currentProject || !legacyConfigForMigration) {
|
||||
throw Error('Need currentProject to do migration')
|
||||
}
|
||||
|
||||
const integrationFolder = getIntegrationFolder(legacyConfigForMigration)
|
||||
const integrationTestFiles = getIntegrationTestFilesGlobs(legacyConfigForMigration)
|
||||
|
||||
const hasCustomIntegrationFolder = getIntegrationFolder(legacyConfigForMigration) !== legacyIntegrationFolder
|
||||
const hasCustomIntegrationTestFiles = !isDefaultTestFiles(legacyConfigForMigration, 'integration')
|
||||
|
||||
const shouldAddCustomE2ESpecPattern = Boolean(this.ctx.migration.legacyConfigProjectId)
|
||||
|
||||
let hasE2ESpec = integrationFolder
|
||||
? await hasSpecFile(this.ctx.currentProject, integrationFolder, integrationTestFiles)
|
||||
: false
|
||||
|
||||
// if we don't find specs in the 9.X scope,
|
||||
// let's check already migrated files.
|
||||
// this allows users to stop migration halfway,
|
||||
// then to pick up where they left migration off
|
||||
if (!hasE2ESpec && (!hasCustomIntegrationTestFiles || !hasCustomIntegrationFolder)) {
|
||||
const newE2eSpecPattern = getSpecPattern(legacyConfigForMigration, 'e2e', shouldAddCustomE2ESpecPattern)
|
||||
|
||||
hasE2ESpec = await hasSpecFile(this.ctx.currentProject, '', newE2eSpecPattern)
|
||||
}
|
||||
|
||||
const componentFolder = getComponentFolder(legacyConfigForMigration)
|
||||
const componentTestFiles = getComponentTestFilesGlobs(legacyConfigForMigration)
|
||||
|
||||
const hasCustomComponentFolder = componentFolder !== 'cypress/component'
|
||||
const hasCustomComponentTestFiles = !isDefaultTestFiles(legacyConfigForMigration, 'component')
|
||||
|
||||
// A user is considered to "have" component testing if either
|
||||
// 1. they have a default component folder (cypress/component) with at least 1 spec file
|
||||
// OR
|
||||
// 2. they have configured a non-default componentFolder (even if it doesn't have any specs.)
|
||||
const hasSpecInDefaultComponentFolder = await hasSpecFile(this.ctx.currentProject, componentFolder, componentTestFiles)
|
||||
const hasComponentTesting = (hasCustomComponentFolder || hasSpecInDefaultComponentFolder) ?? false
|
||||
|
||||
this.ctx.update((coreData) => {
|
||||
coreData.migration.flags = {
|
||||
hasCustomIntegrationFolder,
|
||||
hasCustomIntegrationTestFiles,
|
||||
hasCustomComponentFolder,
|
||||
hasCustomComponentTestFiles,
|
||||
hasCustomSupportFile: false,
|
||||
hasComponentTesting,
|
||||
hasE2ESpec,
|
||||
hasPluginsFile: true,
|
||||
shouldAddCustomE2ESpecPattern,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
get configFileNameAfterMigration () {
|
||||
return this.ctx.migration.legacyConfigFile.replace('.json', `.config.${this.ctx.lifecycleManager.fileExtensionToUse}`)
|
||||
}
|
||||
|
||||
async createConfigFile () {
|
||||
const config = await this.ctx.migration.createConfigString()
|
||||
|
||||
this.ctx.lifecycleManager.setConfigFilePath(this.configFileNameAfterMigration)
|
||||
|
||||
await this.ctx.fs.writeFile(this.ctx.lifecycleManager.configFilePath, config).catch((error) => {
|
||||
throw error
|
||||
})
|
||||
|
||||
await this.ctx.actions.file.removeFileInProject(this.ctx.migration.legacyConfigFile).catch((error) => {
|
||||
throw error
|
||||
})
|
||||
|
||||
if (this.ctx.modeOptions.configFile) {
|
||||
// @ts-ignore configFile needs to be updated with the new one, so it finds the correct one
|
||||
// with the new file, instead of the deleted one which is not supported anymore
|
||||
this.ctx.modeOptions.configFile = this.ctx.migration.configFileNameAfterMigration
|
||||
}
|
||||
}
|
||||
|
||||
async setLegacyConfigForMigration (config: LegacyCypressConfigJson) {
|
||||
assert(this.ctx.currentProject)
|
||||
const legacyConfigForMigration = await processConfigViaLegacyPlugins(this.ctx.currentProject, config, this.ctx.coreData.app.nodeVersion)
|
||||
|
||||
this.ctx.update((coreData) => {
|
||||
coreData.migration.legacyConfigForMigration = legacyConfigForMigration
|
||||
})
|
||||
|
||||
return legacyConfigForMigration
|
||||
}
|
||||
|
||||
async renameSpecsFolder () {
|
||||
if (!this.ctx.currentProject) {
|
||||
throw Error('Need to set currentProject before you can rename specs folder')
|
||||
}
|
||||
|
||||
const projectRoot = this.ctx.path.join(this.ctx.currentProject)
|
||||
const from = path.join(projectRoot, 'cypress', 'integration')
|
||||
const to = path.join(projectRoot, 'cypress', 'e2e')
|
||||
|
||||
this.ctx.update((coreData) => {
|
||||
coreData.migration.flags = {
|
||||
...coreData.migration.flags,
|
||||
shouldAddCustomE2ESpecPattern: true,
|
||||
}
|
||||
})
|
||||
|
||||
await this.ctx.fs.move(from, to)
|
||||
}
|
||||
|
||||
async renameSpecFiles (beforeSpecs: string[], afterSpecs: string[]) {
|
||||
if (!this.ctx.currentProject) {
|
||||
throw Error('Need to set currentProject before you can rename files')
|
||||
}
|
||||
|
||||
const specsToMove: SpecToMove[] = []
|
||||
|
||||
for (let i = 0; i < beforeSpecs.length; i++) {
|
||||
const from = beforeSpecs[i]
|
||||
const to = afterSpecs[i]
|
||||
|
||||
if (!from || !to) {
|
||||
throw Error(`Must have matching to and from. Got from: ${from} and to: ${to}`)
|
||||
}
|
||||
|
||||
specsToMove.push({ from, to })
|
||||
}
|
||||
|
||||
const projectRoot = this.ctx.path.join(this.ctx.currentProject)
|
||||
|
||||
await moveSpecFiles(projectRoot, specsToMove)
|
||||
await cleanUpIntegrationFolder(this.ctx.currentProject)
|
||||
}
|
||||
|
||||
async renameSupportFile () {
|
||||
if (!this.ctx.currentProject) {
|
||||
throw Error(`Need current project before starting migration!`)
|
||||
}
|
||||
|
||||
const result = await supportFilesForMigration(this.ctx.currentProject)
|
||||
|
||||
const beforeRelative = result.before.relative
|
||||
const afterRelative = result.after.relative
|
||||
|
||||
if (!beforeRelative || !afterRelative) {
|
||||
throw new NonStandardMigrationError('support')
|
||||
}
|
||||
|
||||
await this.ctx.fs.rename(
|
||||
path.join(this.ctx.currentProject, beforeRelative),
|
||||
path.join(this.ctx.currentProject, afterRelative),
|
||||
)
|
||||
}
|
||||
|
||||
async finishReconfigurationWizard () {
|
||||
this.ctx.lifecycleManager.refreshMetaState()
|
||||
await this.ctx.lifecycleManager.refreshLifecycle()
|
||||
}
|
||||
|
||||
async nextStep () {
|
||||
const filteredSteps = this.ctx.coreData.migration.filteredSteps
|
||||
const index = filteredSteps.indexOf(this.ctx.coreData.migration.step)
|
||||
|
||||
if (index === -1) {
|
||||
throw new Error('Invalid step')
|
||||
}
|
||||
|
||||
const nextIndex = index + 1
|
||||
|
||||
if (nextIndex < filteredSteps.length) {
|
||||
const nextStep = filteredSteps[nextIndex]
|
||||
|
||||
if (nextStep) {
|
||||
this.ctx.update((coreData) => {
|
||||
coreData.migration.step = nextStep
|
||||
})
|
||||
}
|
||||
} else {
|
||||
await this.finishReconfigurationWizard()
|
||||
}
|
||||
}
|
||||
|
||||
async closeManualRenameWatcher () {
|
||||
await this.ctx.migration.closeManualRenameWatcher()
|
||||
}
|
||||
|
||||
async assertSuccessfulConfigMigration (migratedConfigFile: string = 'cypress.config.js') {
|
||||
const actual = formatConfig(await this.ctx.file.readFileInProject(migratedConfigFile))
|
||||
|
||||
const configExtension = path.extname(migratedConfigFile)
|
||||
const expected = formatConfig(await this.ctx.file.readFileInProject(`expected-cypress.config${configExtension}`))
|
||||
|
||||
if (actual !== expected) {
|
||||
throw Error(`Expected ${actual} to equal ${expected}`)
|
||||
}
|
||||
}
|
||||
|
||||
reset (config?: LegacyCypressConfigJson) {
|
||||
this.ctx.update((coreData) => {
|
||||
coreData.migration = { ...makeCoreData().migration, legacyConfigForMigration: config }
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,6 @@ export class ProjectActions {
|
||||
// Also clear any data associated with the linked cloud project
|
||||
this.ctx.actions.cloudProject.clearCloudProject()
|
||||
|
||||
this.ctx.actions.migration.reset()
|
||||
await this.ctx.lifecycleManager.clearCurrentProject()
|
||||
resetIssuedWarnings()
|
||||
await this.api.closeActiveProject()
|
||||
|
||||
@@ -14,7 +14,6 @@ export * from './ErrorActions'
|
||||
export * from './EventCollectorActions'
|
||||
export * from './FileActions'
|
||||
export * from './LocalSettingsActions'
|
||||
export * from './MigrationActions'
|
||||
export * from './NotificationActions'
|
||||
export * from './ProjectActions'
|
||||
export * from './ServersActions'
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { CodeGenType } from '@packages/graphql/src/gen/nxs.gen'
|
||||
import fs from 'fs-extra'
|
||||
import { uniq, upperFirst } from 'lodash'
|
||||
import path from 'path'
|
||||
import { FileExtension, getDefaultSpecFileName } from '../sources/migration/utils'
|
||||
import { FileExtension, getDefaultSpecFileName } from '../util/files'
|
||||
import { toPosix } from '../util'
|
||||
import type { FoundSpec } from '@packages/types'
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/* eslint-disable no-dupe-class-members */
|
||||
import type { ChildProcess } from 'child_process'
|
||||
import EventEmitter from 'events'
|
||||
import type { CypressError } from '@packages/errors'
|
||||
import type { LegacyCypressConfigJson } from '../sources'
|
||||
|
||||
export class LegacyPluginsIpc extends EventEmitter {
|
||||
constructor (readonly childProcess: ChildProcess) {
|
||||
super()
|
||||
childProcess.on('message', (msg: { event: string, args: any[] }) => {
|
||||
this.emit(msg.event, ...msg.args)
|
||||
})
|
||||
|
||||
childProcess.once('disconnect', () => {
|
||||
this.emit('disconnect')
|
||||
})
|
||||
}
|
||||
|
||||
send(event: 'loadLegacyPlugins', legacyConfig: LegacyCypressConfigJson): boolean
|
||||
send (event: string, ...args: any[]) {
|
||||
if (this.childProcess.killed || !this.childProcess.connected) {
|
||||
return false
|
||||
}
|
||||
|
||||
return this.childProcess.send({ event, args })
|
||||
}
|
||||
|
||||
on(event: 'ready', listener: () => void): this
|
||||
on(event: 'loadLegacyPlugins:error', listener: (error: CypressError) => void): this
|
||||
on(event: 'childProcess:unhandledError', listener: (legacyConfig: LegacyCypressConfigJson) => void): this
|
||||
on(event: 'loadLegacyPlugins:reply', listener: (legacyConfig: LegacyCypressConfigJson) => void): this
|
||||
on (evt: string, listener: (...args: any[]) => void) {
|
||||
return super.on(evt, listener)
|
||||
}
|
||||
|
||||
killChildProcess () {
|
||||
this.childProcess.kill()
|
||||
this.childProcess.stdout?.removeAllListeners()
|
||||
this.childProcess.stderr?.removeAllListeners()
|
||||
this.childProcess.removeAllListeners()
|
||||
|
||||
this.removeAllListeners()
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@
|
||||
*/
|
||||
import path from 'path'
|
||||
import _ from 'lodash'
|
||||
import resolve from 'resolve'
|
||||
import fs from 'fs'
|
||||
|
||||
import { getError, CypressError, ConfigValidationFailureInfo } from '@packages/errors'
|
||||
@@ -16,7 +15,7 @@ import type { DataContext } from '..'
|
||||
import assert from 'assert'
|
||||
import type { AllModeOptions, FoundBrowser, FullConfig, TestingType } from '@packages/types'
|
||||
import { autoBindDebug } from '../util/autoBindDebug'
|
||||
import { EventCollectorSource, GitDataSource, LegacyCypressConfigJson } from '../sources'
|
||||
import { EventCollectorSource, GitDataSource } from '../sources'
|
||||
import { OnFinalConfigLoadedOptions, ProjectConfigManager } from './ProjectConfigManager'
|
||||
import pDefer from 'p-defer'
|
||||
import { EventRegistrar } from './EventRegistrar'
|
||||
@@ -56,23 +55,19 @@ export interface InjectedConfigApi {
|
||||
|
||||
export interface ProjectMetaState {
|
||||
isUsingTypeScript: boolean
|
||||
hasLegacyCypressJson: boolean
|
||||
hasCypressEnvFile: boolean
|
||||
hasValidConfigFile: boolean
|
||||
hasSpecifiedConfigViaCLI: false | string
|
||||
allFoundConfigFiles: string[]
|
||||
needsCypressJsonMigration: boolean
|
||||
isProjectUsingESModules: boolean
|
||||
}
|
||||
|
||||
const PROJECT_META_STATE: ProjectMetaState = {
|
||||
isUsingTypeScript: false,
|
||||
hasLegacyCypressJson: false,
|
||||
allFoundConfigFiles: [],
|
||||
hasCypressEnvFile: false,
|
||||
hasSpecifiedConfigViaCLI: false,
|
||||
hasValidConfigFile: false,
|
||||
needsCypressJsonMigration: false,
|
||||
isProjectUsingESModules: false,
|
||||
}
|
||||
|
||||
@@ -108,11 +103,6 @@ export class ProjectLifecycleManager {
|
||||
|
||||
async getProjectId (): Promise<string | null> {
|
||||
try {
|
||||
// No need to kick off config initialization if we need to migrate
|
||||
if (this.ctx.migration.needsCypressJsonMigration()) {
|
||||
return null
|
||||
}
|
||||
|
||||
const contents = await this.ctx.project.getConfig()
|
||||
|
||||
return contents.projectId ?? null
|
||||
@@ -514,37 +504,13 @@ export class ProjectLifecycleManager {
|
||||
* @returns true if we can initialize and false if not
|
||||
*/
|
||||
private readyToInitialize (projectRoot: string): boolean {
|
||||
const { needsCypressJsonMigration } = this.refreshMetaState()
|
||||
|
||||
const legacyConfigPath = path.join(projectRoot, this.ctx.migration.legacyConfigFile)
|
||||
|
||||
if (needsCypressJsonMigration && !this.ctx.isRunMode && this.ctx.fs.existsSync(legacyConfigPath)) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.legacyPluginGuard()
|
||||
|
||||
// This calls a lot of methods that are necessary to check config-wise upfront
|
||||
this.refreshMetaState()
|
||||
this.configFileWarningCheck()
|
||||
|
||||
return this.metaState.hasValidConfigFile
|
||||
}
|
||||
|
||||
async legacyMigration () {
|
||||
try {
|
||||
const legacyConfigPath = path.join(this.projectRoot, this.ctx.migration.legacyConfigFile)
|
||||
// we run the legacy plugins/index.js in a child process
|
||||
// and mutate the config based on the return value for migration
|
||||
// only used in open mode (cannot migrate via terminal)
|
||||
const legacyConfig = await this.ctx.fs.readJson(legacyConfigPath) as LegacyCypressConfigJson
|
||||
|
||||
// should never throw, unless there existing pluginsFile errors out,
|
||||
// in which case they are attempting to migrate an already broken project.
|
||||
await this.ctx.actions.migration.initialize(legacyConfig)
|
||||
} catch (error) {
|
||||
this.onLoadError(error)
|
||||
}
|
||||
}
|
||||
|
||||
get runModeExitEarly () {
|
||||
return this._runModeExitEarly
|
||||
}
|
||||
@@ -658,19 +624,6 @@ export class ProjectLifecycleManager {
|
||||
return this._eventRegistrar.executeNodeEvent(event, args)
|
||||
}
|
||||
|
||||
private legacyPluginGuard () {
|
||||
// test and warn for incompatible plugin
|
||||
try {
|
||||
const retriesPluginPath = path.dirname(resolve.sync('cypress-plugin-retries/package.json', {
|
||||
basedir: this.projectRoot,
|
||||
}))
|
||||
|
||||
this.ctx.onWarning(getError('INCOMPATIBLE_PLUGIN_RETRIES', path.relative(this.projectRoot, retriesPluginPath)))
|
||||
} catch (e) {
|
||||
// noop, incompatible plugin not installed
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all information about the project we need to know to prompt different
|
||||
* onboarding screens, suggestions in the onboarding wizard, etc.
|
||||
@@ -679,7 +632,6 @@ export class ProjectLifecycleManager {
|
||||
const configFile = this.ctx.modeOptions.configFile
|
||||
const metaState: ProjectMetaState = {
|
||||
...PROJECT_META_STATE,
|
||||
hasLegacyCypressJson: this.ctx.migration.legacyConfigFileExists(),
|
||||
hasCypressEnvFile: fs.existsSync(this._pathToFile('cypress.env.json')),
|
||||
}
|
||||
|
||||
@@ -696,7 +648,6 @@ export class ProjectLifecycleManager {
|
||||
projectRoot: this.projectRoot,
|
||||
customConfigFile: configFile,
|
||||
pkgJson,
|
||||
isMigrating: metaState.hasLegacyCypressJson,
|
||||
}) === 'ts'
|
||||
} catch {
|
||||
// No need to handle
|
||||
@@ -704,23 +655,10 @@ export class ProjectLifecycleManager {
|
||||
|
||||
if (configFile) {
|
||||
metaState.hasSpecifiedConfigViaCLI = this._pathToFile(configFile)
|
||||
if (configFile.endsWith('.json')) {
|
||||
metaState.needsCypressJsonMigration = true
|
||||
|
||||
const configFileNameAfterMigration = configFile.replace('.json', `.config.${metaState.isUsingTypeScript ? 'ts' : 'js'}`)
|
||||
|
||||
if (this.ctx.fs.existsSync(this._pathToFile(configFileNameAfterMigration))) {
|
||||
if (this.ctx.fs.existsSync(this._pathToFile(configFile))) {
|
||||
this.ctx.onError(getError('LEGACY_CONFIG_FILE', configFileNameAfterMigration, this.projectRoot, configFile))
|
||||
} else {
|
||||
this.ctx.onError(getError('MIGRATION_ALREADY_OCURRED', configFileNameAfterMigration, configFile))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.setConfigFilePath(configFile)
|
||||
if (fs.existsSync(this.configFilePath)) {
|
||||
metaState.hasValidConfigFile = true
|
||||
}
|
||||
this.setConfigFilePath(configFile)
|
||||
if (fs.existsSync(this.configFilePath)) {
|
||||
metaState.hasValidConfigFile = true
|
||||
}
|
||||
|
||||
this._projectMetaState = metaState
|
||||
@@ -758,10 +696,6 @@ export class ProjectLifecycleManager {
|
||||
configFilePathSet = true
|
||||
}
|
||||
|
||||
if (metaState.hasLegacyCypressJson && !metaState.hasValidConfigFile) {
|
||||
metaState.needsCypressJsonMigration = true
|
||||
}
|
||||
|
||||
this._projectMetaState = metaState
|
||||
|
||||
return metaState
|
||||
@@ -824,7 +758,7 @@ export class ProjectLifecycleManager {
|
||||
return
|
||||
}
|
||||
|
||||
if (testingType === 'e2e' && !this.ctx.migration.needsCypressJsonMigration()) {
|
||||
if (testingType === 'e2e') {
|
||||
// E2E doesn't have a wizard, so if we have a testing type on load we just create/update their cypress.config.js.
|
||||
await this.ctx.actions.wizard.scaffoldTestingType()
|
||||
} else if (testingType === 'component') {
|
||||
@@ -864,17 +798,9 @@ export class ProjectLifecycleManager {
|
||||
this.onLoadError(getError('CONFIG_FILE_NOT_FOUND', path.basename(this.metaState.hasSpecifiedConfigViaCLI), path.dirname(this.metaState.hasSpecifiedConfigViaCLI)))
|
||||
}
|
||||
|
||||
if (this.metaState.hasLegacyCypressJson && !this.metaState.hasValidConfigFile && this.ctx.isRunMode) {
|
||||
this.onLoadError(getError('CONFIG_FILE_MIGRATION_NEEDED', this.projectRoot))
|
||||
}
|
||||
|
||||
if (this.metaState.allFoundConfigFiles.length > 1) {
|
||||
this.onLoadError(getError('CONFIG_FILES_LANGUAGE_CONFLICT', this.projectRoot, this.metaState.allFoundConfigFiles))
|
||||
}
|
||||
|
||||
if (this.metaState.hasValidConfigFile && this.metaState.hasLegacyCypressJson) {
|
||||
this.onLoadError(getError('LEGACY_CONFIG_FILE', path.basename(this.configFilePath), this.projectRoot))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FoundBrowser, Editor, AllowedState, AllModeOptions, TestingType, BrowserStatus, PACKAGE_MANAGERS, AuthStateName, MIGRATION_STEPS, MigrationStep, StudioLifecycleManagerShape } from '@packages/types'
|
||||
import type { FoundBrowser, Editor, AllowedState, AllModeOptions, TestingType, BrowserStatus, PACKAGE_MANAGERS, AuthStateName, StudioLifecycleManagerShape } from '@packages/types'
|
||||
import { WizardBundler, CT_FRAMEWORKS, resolveComponentFrameworkDefinition, ErroredFramework } from '@packages/scaffold-config'
|
||||
import type { NexusGenObjects } from '@packages/graphql/src/gen/nxs.gen'
|
||||
// tslint:disable-next-line no-implicit-dependencies - electron dep needs to be defined
|
||||
@@ -7,7 +7,7 @@ import type { ChildProcess } from 'child_process'
|
||||
import type { SocketIONamespace, SocketIOServer } from '@packages/socket'
|
||||
import type { Server } from 'http'
|
||||
import type { ErrorWrapperSource } from '@packages/errors'
|
||||
import type { EventCollectorSource, GitDataSource, LegacyCypressConfigJson } from '../sources'
|
||||
import type { EventCollectorSource, GitDataSource } from '../sources'
|
||||
import { machineId as getMachineId } from 'node-machine-id'
|
||||
import type { CDPSocketServer } from '@packages/socket/lib/cdp-socket'
|
||||
|
||||
@@ -83,26 +83,6 @@ export interface WizardDataShape {
|
||||
erroredFrameworks: ErroredFramework[]
|
||||
}
|
||||
|
||||
export interface MigrationDataShape {
|
||||
// TODO: have the model of migration here
|
||||
step: MigrationStep
|
||||
legacyConfigForMigration?: LegacyCypressConfigJson | null
|
||||
filteredSteps: MigrationStep[]
|
||||
flags: {
|
||||
hasCustomIntegrationFolder: boolean
|
||||
hasCustomIntegrationTestFiles: boolean
|
||||
|
||||
hasCustomComponentFolder: boolean
|
||||
hasCustomComponentTestFiles: boolean
|
||||
|
||||
hasCustomSupportFile: boolean
|
||||
hasComponentTesting: boolean
|
||||
hasE2ESpec: boolean
|
||||
hasPluginsFile: boolean
|
||||
shouldAddCustomE2ESpecPattern: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface ElectronShape {
|
||||
app: App | null
|
||||
browserWindow: BrowserWindow | null
|
||||
@@ -150,7 +130,6 @@ export interface CoreDataShape {
|
||||
currentTestingType: TestingType | null
|
||||
diagnostics: Diagnostics
|
||||
wizard: WizardDataShape
|
||||
migration: MigrationDataShape
|
||||
user: AuthenticatedUserShape | null
|
||||
electron: ElectronShape
|
||||
authState: AuthStateShape
|
||||
@@ -215,22 +194,6 @@ export function makeCoreData (modeOptions: Partial<AllModeOptions> = {}): CoreDa
|
||||
frameworks: CT_FRAMEWORKS.map((framework) => resolveComponentFrameworkDefinition(framework)),
|
||||
erroredFrameworks: [],
|
||||
},
|
||||
migration: {
|
||||
step: 'renameAuto',
|
||||
legacyConfigForMigration: null,
|
||||
filteredSteps: [...MIGRATION_STEPS],
|
||||
flags: {
|
||||
hasCustomIntegrationFolder: false,
|
||||
hasCustomIntegrationTestFiles: false,
|
||||
hasCustomComponentFolder: false,
|
||||
hasCustomComponentTestFiles: false,
|
||||
hasCustomSupportFile: false,
|
||||
hasComponentTesting: true,
|
||||
hasE2ESpec: true,
|
||||
hasPluginsFile: true,
|
||||
shouldAddCustomE2ESpecPattern: false,
|
||||
},
|
||||
},
|
||||
activeBrowser: null,
|
||||
user: null,
|
||||
electron: {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
export * from './CypressEnv'
|
||||
export * from './EventRegistrar'
|
||||
export * from './LegacyPluginsIpc'
|
||||
export * from './ProjectConfigIpc'
|
||||
export * from './ProjectConfigManager'
|
||||
export * from './ProjectLifecycleManager'
|
||||
|
||||
@@ -1,299 +0,0 @@
|
||||
import type { TestingType } from '@packages/types'
|
||||
import type chokidar from 'chokidar'
|
||||
import type { DataContext } from '..'
|
||||
import {
|
||||
createConfigString,
|
||||
initComponentTestingMigration,
|
||||
ComponentTestingMigrationStatus,
|
||||
supportFilesForMigration,
|
||||
getSpecs,
|
||||
applyMigrationTransform,
|
||||
shouldShowRenameSupport,
|
||||
getIntegrationFolder,
|
||||
isDefaultTestFiles,
|
||||
getComponentTestFilesGlobs,
|
||||
getComponentFolder,
|
||||
} from './migration'
|
||||
import _ from 'lodash'
|
||||
|
||||
import type { FilePart } from './migration/format'
|
||||
import Debug from 'debug'
|
||||
import path from 'path'
|
||||
|
||||
const debug = Debug('cypress:data-context:sources:MigrationDataSource')
|
||||
|
||||
export type LegacyCypressConfigJson = Partial<{
|
||||
component: Omit<LegacyCypressConfigJson, 'component' | 'e2e'>
|
||||
e2e: Omit<LegacyCypressConfigJson, 'component' | 'e2e'>
|
||||
pluginsFile: string | false
|
||||
supportFile: string | false
|
||||
slowTestThreshold: number
|
||||
componentFolder: string | false
|
||||
integrationFolder: string
|
||||
testFiles: string | string[]
|
||||
ignoreTestFiles: string | string[]
|
||||
env: { [key: string]: any }
|
||||
[index: string]: any
|
||||
}>
|
||||
|
||||
export interface MigrationFile {
|
||||
testingType: TestingType
|
||||
before: {
|
||||
relative: string
|
||||
parts: FilePart[]
|
||||
}
|
||||
after: {
|
||||
relative: string
|
||||
parts: FilePart[]
|
||||
}
|
||||
}
|
||||
|
||||
export class MigrationDataSource {
|
||||
private componentTestingMigrationWatcher: chokidar.FSWatcher | null = null
|
||||
componentTestingMigrationStatus?: ComponentTestingMigrationStatus
|
||||
|
||||
constructor (private ctx: DataContext) { }
|
||||
|
||||
get legacyConfig () {
|
||||
if (!this.ctx.coreData.migration.legacyConfigForMigration) {
|
||||
throw Error(`Expected _legacyConfig to be set. Did you forget to call MigrationDataSource#initialize?`)
|
||||
}
|
||||
|
||||
return this.ctx.coreData.migration.legacyConfigForMigration
|
||||
}
|
||||
|
||||
get legacyConfigProjectId () {
|
||||
return this.legacyConfig.projectId || this.legacyConfig.e2e?.projectId
|
||||
}
|
||||
|
||||
get shouldMigratePreExtension () {
|
||||
return !this.legacyConfigProjectId
|
||||
}
|
||||
|
||||
get legacyConfigFile () {
|
||||
if (this.ctx.modeOptions.configFile && this.ctx.modeOptions.configFile.endsWith('.json')) {
|
||||
return this.ctx.modeOptions.configFile
|
||||
}
|
||||
|
||||
return 'cypress.json'
|
||||
}
|
||||
|
||||
legacyConfigFileExists (): boolean {
|
||||
// If we aren't in a current project we definitely don't have a legacy config file
|
||||
if (!this.ctx.currentProject) {
|
||||
return false
|
||||
}
|
||||
|
||||
const configFilePath = path.isAbsolute(this.legacyConfigFile) ? this.legacyConfigFile : path.join(this.ctx.currentProject, this.legacyConfigFile)
|
||||
const legacyConfigFileExists = this.ctx.fs.existsSync(configFilePath)
|
||||
|
||||
return Boolean(legacyConfigFileExists)
|
||||
}
|
||||
|
||||
needsCypressJsonMigration (): boolean {
|
||||
const legacyConfigFileExists = this.legacyConfigFileExists()
|
||||
|
||||
return this.ctx.lifecycleManager.metaState.needsCypressJsonMigration && Boolean(legacyConfigFileExists)
|
||||
}
|
||||
|
||||
async getComponentTestingMigrationStatus () {
|
||||
debug('getComponentTestingMigrationStatus: start')
|
||||
if (!this.legacyConfig || !this.ctx.currentProject) {
|
||||
throw Error('Need currentProject and config to continue')
|
||||
}
|
||||
|
||||
const componentFolder = getComponentFolder(this.legacyConfig)
|
||||
|
||||
// no component folder, so no specs to migrate
|
||||
// this should never happen since we never show the
|
||||
// component specs migration step ("renameManual")
|
||||
if (componentFolder === false) {
|
||||
return null
|
||||
}
|
||||
|
||||
debug('getComponentTestingMigrationStatus: componentFolder', componentFolder)
|
||||
|
||||
if (!this.componentTestingMigrationWatcher) {
|
||||
debug('getComponentTestingMigrationStatus: initializing watcher')
|
||||
const onFileMoved = async (status: ComponentTestingMigrationStatus) => {
|
||||
this.componentTestingMigrationStatus = status
|
||||
debug('getComponentTestingMigrationStatus: file moved %O', status)
|
||||
|
||||
if (status.completed) {
|
||||
await this.componentTestingMigrationWatcher?.close()
|
||||
this.componentTestingMigrationWatcher = null
|
||||
}
|
||||
|
||||
// TODO(lachlan): is this the right place to use the emitter?
|
||||
this.ctx.emitter.toLaunchpad()
|
||||
}
|
||||
|
||||
const { status, watcher } = await initComponentTestingMigration(
|
||||
this.ctx.currentProject,
|
||||
componentFolder,
|
||||
getComponentTestFilesGlobs(this.legacyConfig),
|
||||
onFileMoved,
|
||||
)
|
||||
|
||||
this.componentTestingMigrationStatus = status
|
||||
this.componentTestingMigrationWatcher = watcher
|
||||
debug('getComponentTestingMigrationStatus: watcher initialized. Status: %o', status)
|
||||
}
|
||||
|
||||
if (!this.componentTestingMigrationStatus) {
|
||||
throw Error(`Status should have been assigned by the watcher. Something is wrong`)
|
||||
}
|
||||
|
||||
return this.componentTestingMigrationStatus
|
||||
}
|
||||
|
||||
async supportFilesForMigrationGuide (): Promise<MigrationFile | null> {
|
||||
if (!this.ctx.currentProject) {
|
||||
throw Error('Need this.ctx.currentProject')
|
||||
}
|
||||
|
||||
debug('supportFilesForMigrationGuide: config %O', this.legacyConfig)
|
||||
if (!await shouldShowRenameSupport(this.ctx.currentProject, this.legacyConfig)) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!this.ctx.currentProject) {
|
||||
throw Error(`Need this.ctx.projectRoot!`)
|
||||
}
|
||||
|
||||
try {
|
||||
const supportFiles = await supportFilesForMigration(this.ctx.currentProject)
|
||||
|
||||
debug('supportFilesForMigrationGuide: supportFiles %O', supportFiles)
|
||||
|
||||
return supportFiles
|
||||
} catch (err) {
|
||||
debug('supportFilesForMigrationGuide: err %O', err)
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async getSpecsForMigrationGuide (): Promise<MigrationFile[]> {
|
||||
if (!this.ctx.currentProject) {
|
||||
throw Error(`Need this.ctx.projectRoot!`)
|
||||
}
|
||||
|
||||
const specs = await getSpecs(this.ctx.currentProject, this.legacyConfig)
|
||||
|
||||
const e2eMigrationOptions = {
|
||||
// If the configFile has projectId, we do not want to change the preExtension
|
||||
// so, we can keep the cloud history
|
||||
shouldMigratePreExtension: this.shouldMigratePreExtension,
|
||||
}
|
||||
|
||||
const canBeAutomaticallyMigrated: MigrationFile[] = specs.integration.map((s) => applyMigrationTransform(s, e2eMigrationOptions)).filter((spec) => spec.before.relative !== spec.after.relative)
|
||||
|
||||
const defaultComponentPattern = isDefaultTestFiles(this.legacyConfig, 'component')
|
||||
|
||||
// Can only migration component specs if they use the default testFiles pattern.
|
||||
if (defaultComponentPattern) {
|
||||
canBeAutomaticallyMigrated.push(...specs.component.map((s) => applyMigrationTransform(s)).filter((spec) => spec.before.relative !== spec.after.relative))
|
||||
}
|
||||
|
||||
return this.checkAndUpdateDuplicatedSpecs(canBeAutomaticallyMigrated)
|
||||
}
|
||||
|
||||
async createConfigString () {
|
||||
if (!this.ctx.currentProject) {
|
||||
throw Error('Need currentProject!')
|
||||
}
|
||||
|
||||
const { isUsingTypeScript } = this.ctx.lifecycleManager.metaState
|
||||
|
||||
return createConfigString(this.legacyConfig, {
|
||||
hasComponentTesting: this.ctx.coreData.migration.flags.hasComponentTesting,
|
||||
hasE2ESpec: this.ctx.coreData.migration.flags.hasE2ESpec,
|
||||
hasPluginsFile: this.ctx.coreData.migration.flags.hasPluginsFile,
|
||||
projectRoot: this.ctx.currentProject,
|
||||
isUsingTypeScript,
|
||||
isProjectUsingESModules: this.ctx.lifecycleManager.metaState.isProjectUsingESModules,
|
||||
shouldAddCustomE2ESpecPattern: this.ctx.coreData.migration.flags.shouldAddCustomE2ESpecPattern,
|
||||
})
|
||||
}
|
||||
|
||||
async integrationFolder () {
|
||||
return getIntegrationFolder(this.legacyConfig)
|
||||
}
|
||||
|
||||
async componentFolder () {
|
||||
return getComponentFolder(this.legacyConfig)
|
||||
}
|
||||
|
||||
async closeManualRenameWatcher () {
|
||||
if (this.componentTestingMigrationWatcher) {
|
||||
await this.componentTestingMigrationWatcher.close()
|
||||
this.componentTestingMigrationWatcher = null
|
||||
}
|
||||
}
|
||||
|
||||
get configFileNameAfterMigration () {
|
||||
return this.legacyConfigFile.replace('.json', `.config.${this.ctx.lifecycleManager.fileExtensionToUse}`)
|
||||
}
|
||||
|
||||
private checkAndUpdateDuplicatedSpecs (specs: MigrationFile[]) {
|
||||
const updatedSpecs: MigrationFile[] = []
|
||||
|
||||
const sortedSpecs = this.sortSpecsByExtension(specs)
|
||||
|
||||
sortedSpecs.forEach((spec) => {
|
||||
const specExist = _.find(updatedSpecs, (x) => x.after.relative === spec.after.relative)
|
||||
|
||||
if (specExist) {
|
||||
const beforeParts: FilePart[] = JSON.parse(JSON.stringify(spec.before.parts))
|
||||
const preExtensionBefore = beforeParts.find((part) => part.group === 'preExtension')
|
||||
|
||||
if (preExtensionBefore) {
|
||||
preExtensionBefore.highlight = false
|
||||
}
|
||||
|
||||
const afterParts: FilePart[] = JSON.parse(JSON.stringify(spec.after.parts))
|
||||
const fileNameAfter = afterParts.find((part) => part.group === 'fileName')
|
||||
|
||||
if (fileNameAfter && preExtensionBefore) {
|
||||
const beforePreExtension = preExtensionBefore?.text?.replace('.', '')
|
||||
|
||||
fileNameAfter.text = `${fileNameAfter.text}${beforePreExtension}`
|
||||
}
|
||||
|
||||
spec.before.parts = beforeParts
|
||||
spec.after.parts = afterParts
|
||||
spec.after.relative = afterParts.map((x) => x.text).join('')
|
||||
}
|
||||
|
||||
updatedSpecs.push(spec)
|
||||
})
|
||||
|
||||
return updatedSpecs
|
||||
}
|
||||
|
||||
private sortSpecsByExtension (specs: MigrationFile[]) {
|
||||
const sortedExtensions = ['.spec.', '.Spec.', '_spec.', '_Spec.', '-spec.', '-Spec.', '.test.', '.Test.', '_test.', '_Test.', '-test.', '-Test.']
|
||||
|
||||
return specs.sort(function (a, b) {
|
||||
function getExtIndex (spec: string) {
|
||||
let index = -1
|
||||
|
||||
// Sort the specs based on the extension, giving priority to .spec
|
||||
sortedExtensions.some((c, i) => {
|
||||
if (~spec.indexOf(c)) {
|
||||
index = i
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
return index
|
||||
}
|
||||
|
||||
return getExtIndex(a.before.relative) - getExtIndex(b.before.relative)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ import { toPosix } from '../util/file'
|
||||
import type { FilePartsShape } from '@packages/graphql/src/schemaTypes/objectTypes/gql-FileParts'
|
||||
import type { ProjectShape } from '../data'
|
||||
import type { FindSpecs } from '../actions'
|
||||
import { FileExtension, getDefaultSpecFileName } from './migration/utils'
|
||||
import { FileExtension, getDefaultSpecFileName } from '../util/files'
|
||||
|
||||
type SpecPatterns = {
|
||||
specPattern?: string[]
|
||||
|
||||
@@ -10,7 +10,6 @@ export * from './FileDataSource'
|
||||
export * from './GitDataSource'
|
||||
export * from './GraphQLDataSource'
|
||||
export * from './HtmlDataSource'
|
||||
export * from './MigrationDataSource'
|
||||
export * from './ProjectDataSource'
|
||||
export * from './RelevantRunSpecsDataSource'
|
||||
export * from './RelevantRunsDataSource'
|
||||
@@ -18,4 +17,3 @@ export * from './RemoteRequestDataSource'
|
||||
export * from './UtilDataSource'
|
||||
export * from './VersionsDataSource'
|
||||
export * from './WizardDataSource'
|
||||
export * from './migration/'
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
import globby from 'globby'
|
||||
import type { TestingType } from '@packages/types'
|
||||
import {
|
||||
defaultTestFilesGlob,
|
||||
FilePart,
|
||||
formatMigrationFile,
|
||||
getComponentFolder,
|
||||
getComponentTestFilesGlobs,
|
||||
getIntegrationFolder,
|
||||
getIntegrationTestFilesGlobs,
|
||||
isDefaultTestFiles,
|
||||
legacyIntegrationFolder,
|
||||
regexps,
|
||||
} from '.'
|
||||
import type { MigrationFile } from '../MigrationDataSource'
|
||||
import type { LegacyCypressConfigJson } from '..'
|
||||
|
||||
export interface MigrationSpec {
|
||||
relative: string
|
||||
usesDefaultFolder: boolean
|
||||
usesDefaultTestFiles: boolean
|
||||
testingType: TestingType
|
||||
}
|
||||
|
||||
interface GetSpecs {
|
||||
component: MigrationSpec[]
|
||||
integration: MigrationSpec[]
|
||||
}
|
||||
|
||||
export type MigrationTransformOptions = {
|
||||
shouldMigratePreExtension: boolean
|
||||
}
|
||||
|
||||
export const defaultMigrationTransformOptions = {
|
||||
shouldMigratePreExtension: true,
|
||||
}
|
||||
|
||||
export function substitute (part: FilePart, options: MigrationTransformOptions = defaultMigrationTransformOptions): FilePart {
|
||||
// nothing to substitute, just a regular
|
||||
// part of the file
|
||||
if (!('group' in part)) {
|
||||
return part
|
||||
}
|
||||
|
||||
// cypress/integration -> cypress/e2e
|
||||
if (part.group === 'folder' && part.text === 'integration') {
|
||||
return { ...part, text: 'e2e' }
|
||||
}
|
||||
|
||||
// basic.spec.js -> basic.cy.js
|
||||
if (part.group === 'preExtension' && options.shouldMigratePreExtension) {
|
||||
return { ...part, text: '.cy.' }
|
||||
}
|
||||
|
||||
// support/index.js -> support/e2e.js
|
||||
if (part.group === 'supportFileName' && part.text === 'index') {
|
||||
return { ...part, text: 'e2e' }
|
||||
}
|
||||
|
||||
return part
|
||||
}
|
||||
|
||||
export function applyMigrationTransform (
|
||||
spec: MigrationSpec,
|
||||
options: MigrationTransformOptions = defaultMigrationTransformOptions,
|
||||
): MigrationFile {
|
||||
let regexp: RegExp
|
||||
|
||||
if (spec.testingType === 'e2e' && spec.usesDefaultFolder && spec.usesDefaultTestFiles) {
|
||||
// e2e, cypress/integration, **/* (default testFiles)
|
||||
regexp = new RegExp(regexps.e2e.before.defaultFolderDefaultTestFiles)
|
||||
} else if (spec.testingType === 'e2e' && !spec.usesDefaultFolder && spec.usesDefaultTestFiles) {
|
||||
// e2e, custom-folder, **/* (default testFiles)
|
||||
regexp = new RegExp(regexps.e2e.before.customFolderDefaultTestFiles)
|
||||
} else if (spec.testingType === 'e2e' && spec.usesDefaultFolder && !spec.usesDefaultTestFiles) {
|
||||
// e2e, cypress/integration , **/*.spec.ts (custom testFiles)
|
||||
regexp = new RegExp(regexps.e2e.before.defaultFolderCustomTestFiles)
|
||||
} else if (spec.testingType === 'component' && spec.usesDefaultFolder && spec.usesDefaultTestFiles) {
|
||||
// component, cypress/component , (default testFiles)
|
||||
regexp = new RegExp(regexps.component.before.defaultFolderDefaultTestFiles)
|
||||
} else if (spec.testingType === 'component' && !spec.usesDefaultFolder && spec.usesDefaultTestFiles) {
|
||||
// component, cypress/custom-component , (default testFiles)
|
||||
regexp = new RegExp(regexps.component.before.customFolderDefaultTestFiles)
|
||||
} else {
|
||||
// custom folder AND test files pattern
|
||||
// should be impossible, we should not call this function in the first place.
|
||||
throw Error(`Cannot use applyMigrationTransform on a project with a custom folder and custom testFiles.`)
|
||||
}
|
||||
|
||||
const partsBeforeMigration = formatMigrationFile(spec.relative, regexp, options)
|
||||
const partsAfterMigration = partsBeforeMigration.map((part) => {
|
||||
// avoid re-renaming files with the right preExtension
|
||||
// it would make a myFile.cy.cy.js file
|
||||
if (part.highlight
|
||||
&& part.group === 'preExtension'
|
||||
&& /\.cy\.([j|t]s[x]?|coffee)$/.test(spec.relative)) {
|
||||
return part
|
||||
}
|
||||
|
||||
return substitute(part, options)
|
||||
})
|
||||
|
||||
return {
|
||||
testingType: spec.testingType,
|
||||
before: {
|
||||
relative: spec.relative,
|
||||
parts: partsBeforeMigration,
|
||||
},
|
||||
after: {
|
||||
relative: partsAfterMigration.map((x) => x.text).join(''),
|
||||
parts: partsAfterMigration,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSpecs (projectRoot: string, config: LegacyCypressConfigJson): Promise<GetSpecs> {
|
||||
const integrationFolder = getIntegrationFolder(config)
|
||||
const integrationTestFiles = getIntegrationTestFilesGlobs(config)
|
||||
|
||||
const componentFolder = getComponentFolder(config)
|
||||
const componentTestFiles = getComponentTestFilesGlobs(config)
|
||||
|
||||
let integrationSpecs: MigrationSpec[] = []
|
||||
let componentSpecs: MigrationSpec[] = []
|
||||
|
||||
const globs = integrationFolder
|
||||
? integrationFolder === legacyIntegrationFolder
|
||||
? [defaultTestFilesGlob].map((glob) => `${integrationFolder}/${glob}`)
|
||||
: integrationTestFiles.map((glob) => `${integrationFolder}/${glob}`)
|
||||
: []
|
||||
|
||||
let specs = integrationFolder
|
||||
? (await globby(globs, { onlyFiles: true, cwd: projectRoot }))
|
||||
: []
|
||||
|
||||
const fullyCustom = integrationFolder !== legacyIntegrationFolder && !isDefaultTestFiles(config, 'integration')
|
||||
|
||||
// we cannot do a migration if either integrationFolder is false,
|
||||
// or if both the integrationFolder and testFiles are custom.
|
||||
if (fullyCustom) {
|
||||
integrationSpecs = []
|
||||
} else {
|
||||
integrationSpecs = specs.map((relative) => {
|
||||
return {
|
||||
relative,
|
||||
usesDefaultFolder: integrationFolder === legacyIntegrationFolder,
|
||||
usesDefaultTestFiles: isDefaultTestFiles(config, 'integration'),
|
||||
testingType: 'e2e',
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (componentFolder === false || !isDefaultTestFiles(config, 'component')) {
|
||||
componentSpecs = []
|
||||
} else {
|
||||
const globs = componentTestFiles.map((glob) => {
|
||||
return `${componentFolder}/${glob}`
|
||||
})
|
||||
|
||||
componentSpecs = (await globby(globs, { onlyFiles: true, cwd: projectRoot })).map((relative) => {
|
||||
return {
|
||||
relative,
|
||||
usesDefaultFolder: componentFolder === 'cypress/component',
|
||||
usesDefaultTestFiles: isDefaultTestFiles(config, 'component'),
|
||||
testingType: 'component',
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
component: componentSpecs,
|
||||
integration: integrationSpecs,
|
||||
}
|
||||
}
|
||||
@@ -1,623 +0,0 @@
|
||||
import chokidar from 'chokidar'
|
||||
import fs from 'fs-extra'
|
||||
import path from 'path'
|
||||
import globby from 'globby'
|
||||
import type { TestingType } from '@packages/types'
|
||||
import { formatMigrationFile } from './format'
|
||||
import { substitute } from './autoRename'
|
||||
import { supportFileRegexps } from './regexps'
|
||||
import type { MigrationFile } from '../MigrationDataSource'
|
||||
import { toPosix } from '../../util'
|
||||
import Debug from 'debug'
|
||||
import dedent from 'dedent'
|
||||
import { hasDefaultExport } from './parserUtils'
|
||||
import { isDefaultSupportFile, LegacyCypressConfigJson, legacyIntegrationFolder } from '..'
|
||||
import { parse } from '@babel/parser'
|
||||
import generate from '@babel/generator'
|
||||
import _ from 'lodash'
|
||||
import { defineConfigAvailable, getBreakingKeys } from '@packages/config'
|
||||
|
||||
const debug = Debug('cypress:data-context:sources:migration:codegen')
|
||||
|
||||
type ConfigOptions = {
|
||||
global: Record<string, unknown>
|
||||
e2e: Record<string, unknown>
|
||||
component: Record<string, unknown>
|
||||
}
|
||||
|
||||
type ResolvedConfigOptions = Cypress.ResolvedConfigOptions & {
|
||||
testFiles: string | string[]
|
||||
ignoreTestFiles: string | string[]
|
||||
}
|
||||
|
||||
export class NonStandardMigrationError extends Error {
|
||||
constructor (fileType: 'support' | 'config') {
|
||||
super()
|
||||
this.message = `Failed to find default ${fileType}. Bailing automation migration.`
|
||||
}
|
||||
}
|
||||
|
||||
export interface CreateConfigOptions {
|
||||
hasE2ESpec: boolean
|
||||
hasPluginsFile: boolean
|
||||
hasComponentTesting: boolean
|
||||
projectRoot: string
|
||||
isUsingTypeScript: boolean
|
||||
isProjectUsingESModules: boolean
|
||||
shouldAddCustomE2ESpecPattern: boolean
|
||||
}
|
||||
|
||||
export async function createConfigString (cfg: LegacyCypressConfigJson, options: CreateConfigOptions) {
|
||||
const newConfig = reduceConfig(cfg, options)
|
||||
const relativePluginPath = await getPluginRelativePath(cfg, options.projectRoot)
|
||||
|
||||
debug('creating cypress.config from newConfig %o relativePluginPath %s options %o', newConfig, relativePluginPath, options)
|
||||
|
||||
return createCypressConfig(newConfig, relativePluginPath, options)
|
||||
}
|
||||
|
||||
interface FileToBeMigratedManually {
|
||||
relative: string
|
||||
moved: boolean
|
||||
}
|
||||
|
||||
export interface ComponentTestingMigrationStatus {
|
||||
files: Map<string, FileToBeMigratedManually>
|
||||
completed: boolean
|
||||
}
|
||||
|
||||
export async function initComponentTestingMigration (
|
||||
projectRoot: string,
|
||||
componentFolder: string,
|
||||
testFiles: string[],
|
||||
onFileMoved: (status: ComponentTestingMigrationStatus) => void,
|
||||
): Promise<{
|
||||
status: ComponentTestingMigrationStatus
|
||||
watcher: chokidar.FSWatcher | null
|
||||
}> {
|
||||
debug('initComponentTestingMigration %O', { projectRoot, componentFolder, testFiles })
|
||||
const watchPaths = testFiles.map((glob) => {
|
||||
return `${componentFolder}/${glob}`
|
||||
})
|
||||
|
||||
const watcher = chokidar.watch(
|
||||
watchPaths, {
|
||||
cwd: projectRoot,
|
||||
ignorePermissionErrors: true,
|
||||
},
|
||||
)
|
||||
|
||||
debug('watchPaths %o', watchPaths)
|
||||
|
||||
let filesToBeMoved: Map<string, FileToBeMigratedManually> = (await globby(watchPaths, {
|
||||
cwd: projectRoot,
|
||||
})).reduce<Map<string, FileToBeMigratedManually>>((acc, relative) => {
|
||||
acc.set(relative, { relative, moved: false })
|
||||
|
||||
return acc
|
||||
}, new Map())
|
||||
|
||||
debug('files to be moved manually %o', filesToBeMoved)
|
||||
if (filesToBeMoved.size === 0) {
|
||||
// this should not happen as the step should be hidden in this case
|
||||
// but files can have been moved manually before clicking next
|
||||
return {
|
||||
status: {
|
||||
files: filesToBeMoved,
|
||||
completed: true,
|
||||
},
|
||||
watcher: null,
|
||||
}
|
||||
}
|
||||
|
||||
watcher.on('unlink', (unlinkedPath) => {
|
||||
const posixUnlinkedPath = toPosix(unlinkedPath)
|
||||
const file = filesToBeMoved.get(posixUnlinkedPath)
|
||||
|
||||
if (!file) {
|
||||
throw Error(`Watcher incorrectly triggered ${posixUnlinkedPath}
|
||||
while watching ${Array.from(filesToBeMoved.keys()).join(', ')}
|
||||
projectRoot: ${projectRoot}`)
|
||||
}
|
||||
|
||||
file.moved = true
|
||||
|
||||
const completed = Array.from(filesToBeMoved.values()).every((value) => value.moved === true)
|
||||
|
||||
onFileMoved({
|
||||
files: filesToBeMoved,
|
||||
completed,
|
||||
})
|
||||
})
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
watcher.on('ready', () => {
|
||||
debug('watcher ready')
|
||||
resolve({
|
||||
status: {
|
||||
files: filesToBeMoved,
|
||||
completed: false,
|
||||
},
|
||||
watcher,
|
||||
})
|
||||
}).on('error', (err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function getPluginRelativePath (cfg: LegacyCypressConfigJson, projectRoot: string): Promise<string | undefined> {
|
||||
return cfg.pluginsFile ? cfg.pluginsFile : await tryGetDefaultLegacyPluginsFile(projectRoot)
|
||||
}
|
||||
|
||||
async function createCypressConfig (config: ConfigOptions, pluginPath: string | undefined, options: CreateConfigOptions): Promise<string> {
|
||||
const globalString = Object.keys(config.global).length > 0 ? `${formatObjectForConfig(config.global)},` : ''
|
||||
const componentString = options.hasComponentTesting ? createComponentTemplate(config.component) : ''
|
||||
const e2eString = options.hasE2ESpec
|
||||
? await createE2ETemplate(pluginPath, options, config.e2e)
|
||||
: ''
|
||||
|
||||
if (defineConfigAvailable(options.projectRoot)) {
|
||||
if (options.isUsingTypeScript || options.isProjectUsingESModules) {
|
||||
return formatConfig(dedent`
|
||||
import { defineConfig } from 'cypress'
|
||||
|
||||
export default defineConfig({
|
||||
${globalString}
|
||||
${e2eString}
|
||||
${componentString}
|
||||
})`)
|
||||
}
|
||||
|
||||
return formatConfig(dedent`
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
${globalString}
|
||||
${e2eString}
|
||||
${componentString}
|
||||
})`)
|
||||
}
|
||||
|
||||
if (options.isUsingTypeScript || options.isProjectUsingESModules) {
|
||||
return formatConfig(`export default {${globalString}${e2eString}${componentString}}`)
|
||||
}
|
||||
|
||||
return formatConfig(`module.exports = {${globalString}${e2eString}${componentString}}`)
|
||||
}
|
||||
|
||||
function formatObjectForConfig (obj: Record<string, unknown>) {
|
||||
return JSON.stringify(obj, null, 2).replace(/^[{]|[}]$/g, '') // remove opening and closing {}
|
||||
}
|
||||
|
||||
// Returns path of `pluginsFile` relative to projectRoot
|
||||
// Considers cases of:
|
||||
// 1. `pluginsFile` pointing to a directory containing an index file
|
||||
// 2. `pluginsFile` pointing to a file
|
||||
//
|
||||
// Example:
|
||||
// - projectRoot
|
||||
// --- cypress
|
||||
// ----- plugins
|
||||
// -------- index.js
|
||||
// Both { "pluginsFile": "cypress/plugins"} and { "pluginsFile": "cypress/plugins/index.js" } are valid.
|
||||
//
|
||||
// Will return `cypress/plugins/index.js` for both cases.
|
||||
export async function getLegacyPluginsCustomFilePath (projectRoot: string, pluginPath: string): Promise<string> {
|
||||
debug('looking for pluginPath %s in projectRoot %s', pluginPath, projectRoot)
|
||||
|
||||
const pluginLoc = path.join(projectRoot, pluginPath)
|
||||
|
||||
debug('fs.stats on %s', pluginLoc)
|
||||
|
||||
let stats: fs.Stats
|
||||
|
||||
try {
|
||||
stats = await fs.stat(pluginLoc)
|
||||
} catch (e) {
|
||||
throw Error(`Looked for pluginsFile at ${pluginPath}, but it was not found.`)
|
||||
}
|
||||
|
||||
if (stats.isFile()) {
|
||||
debug('found pluginsFile %s', pluginLoc)
|
||||
|
||||
return pluginPath
|
||||
}
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
// Although you are supposed to pass a file to `pluginsFile`, we also supported
|
||||
// passing a directory containing an `index` file.
|
||||
// If pluginsFile is a directory, see if there is an index.{js,ts} and grab that.
|
||||
// {
|
||||
// "pluginsFile": "plugins"
|
||||
// }
|
||||
// Where cypress/plugins contains an `index.{js,ts,coffee...}` but NOT `index.d.ts`.
|
||||
const ls = await fs.readdir(pluginLoc)
|
||||
const indexFile = ls.find((file) => file.startsWith('index.') && !file.endsWith('.d.ts'))
|
||||
|
||||
debug('pluginsFile was a directory containing %o, looks like we want %s', ls, indexFile)
|
||||
|
||||
if (indexFile) {
|
||||
const pathToIndex = path.join(pluginPath, indexFile)
|
||||
|
||||
debug('found pluginsFile %s', pathToIndex)
|
||||
|
||||
return pathToIndex
|
||||
}
|
||||
}
|
||||
|
||||
debug('error, could not find path to pluginsFile!')
|
||||
|
||||
throw Error(`Could not find pluginsFile. Received projectRoot ${projectRoot} and pluginPath: ${pluginPath}`)
|
||||
}
|
||||
|
||||
async function createE2ETemplate (pluginPath: string | undefined, createConfigOptions: CreateConfigOptions, options: Record<string, unknown>) {
|
||||
if (createConfigOptions.shouldAddCustomE2ESpecPattern && !options.specPattern) {
|
||||
options.specPattern = 'cypress/e2e/**/*.{js,jsx,ts,tsx}'
|
||||
}
|
||||
|
||||
if (!createConfigOptions.hasPluginsFile || !pluginPath) {
|
||||
return dedent`
|
||||
e2e: {
|
||||
setupNodeEvents(on, config) {},${formatObjectForConfig(options)}
|
||||
},
|
||||
`
|
||||
}
|
||||
|
||||
let relPluginsPath: string
|
||||
|
||||
const startsWithDotSlash = new RegExp(/^.\//)
|
||||
|
||||
if (startsWithDotSlash.test(pluginPath)) {
|
||||
relPluginsPath = `'${pluginPath}'`
|
||||
} else {
|
||||
relPluginsPath = `'./${pluginPath}'`
|
||||
}
|
||||
|
||||
const legacyPluginFileLoc = await getLegacyPluginsCustomFilePath(createConfigOptions.projectRoot, pluginPath)
|
||||
const pluginFile = await fs.readFile(path.join(createConfigOptions.projectRoot, legacyPluginFileLoc), 'utf8')
|
||||
|
||||
const requirePlugins = hasDefaultExport(pluginFile)
|
||||
? `return require(${relPluginsPath}).default(on, config)`
|
||||
: `return require(${relPluginsPath})(on, config)`
|
||||
|
||||
const setupNodeEvents = dedent`
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
${requirePlugins}
|
||||
}`
|
||||
|
||||
return dedent`
|
||||
e2e: {
|
||||
${setupNodeEvents},${formatObjectForConfig(options)}
|
||||
},`
|
||||
}
|
||||
|
||||
function createComponentTemplate (options: Record<string, unknown>) {
|
||||
return `component: {
|
||||
setupNodeEvents(on, config) {},${formatObjectForConfig(options)}
|
||||
},`
|
||||
}
|
||||
|
||||
export interface RelativeSpec {
|
||||
relative: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that at least one spec file exist for testing type
|
||||
*
|
||||
* NOTE: this is what we use to see if CT/E2E is set up
|
||||
*/
|
||||
export async function hasSpecFile (projectRoot: string, folder: string | false, glob: string | string[]): Promise<boolean> {
|
||||
if (!folder) {
|
||||
return false
|
||||
}
|
||||
|
||||
return (await globby(glob, {
|
||||
cwd: path.join(projectRoot, folder),
|
||||
onlyFiles: true,
|
||||
})).length > 0
|
||||
}
|
||||
|
||||
export async function tryGetDefaultLegacyPluginsFile (projectRoot: string) {
|
||||
const files = await globby('cypress/plugins/index.*', { cwd: projectRoot, ignore: ['cypress/plugins/index.d.ts'] })
|
||||
|
||||
return files[0]
|
||||
}
|
||||
|
||||
export async function tryGetDefaultLegacySupportFile (projectRoot: string) {
|
||||
const files = await globby('cypress/support/index.*', { cwd: projectRoot, ignore: ['cypress/support/index.d.ts'] })
|
||||
|
||||
debug('tryGetDefaultLegacySupportFile: files %O', files)
|
||||
|
||||
return files[0]
|
||||
}
|
||||
|
||||
export async function getDefaultLegacySupportFile (projectRoot: string) {
|
||||
const defaultSupportFile = await tryGetDefaultLegacySupportFile(projectRoot)
|
||||
|
||||
if (!defaultSupportFile) {
|
||||
throw new NonStandardMigrationError('support')
|
||||
}
|
||||
|
||||
return defaultSupportFile
|
||||
}
|
||||
|
||||
export async function supportFilesForMigration (projectRoot: string): Promise<MigrationFile> {
|
||||
debug('Checking for support files in %s', projectRoot)
|
||||
const defaultOldSupportFile = await getDefaultLegacySupportFile(projectRoot)
|
||||
const defaultNewSupportFile = renameSupportFilePath(defaultOldSupportFile)
|
||||
|
||||
const afterParts = formatMigrationFile(
|
||||
defaultOldSupportFile,
|
||||
new RegExp(supportFileRegexps.e2e.beforeRegexp),
|
||||
).map((part) => substitute(part))
|
||||
|
||||
return {
|
||||
testingType: 'e2e',
|
||||
before: {
|
||||
relative: defaultOldSupportFile,
|
||||
parts: formatMigrationFile(defaultOldSupportFile, new RegExp(supportFileRegexps.e2e.beforeRegexp)),
|
||||
},
|
||||
after: {
|
||||
relative: defaultNewSupportFile,
|
||||
parts: afterParts,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export interface SpecToMove {
|
||||
from: string
|
||||
to: string
|
||||
}
|
||||
|
||||
export async function moveSpecFiles (projectRoot: string, specs: SpecToMove[]) {
|
||||
await Promise.all(specs.map((spec) => {
|
||||
const from = path.join(projectRoot, spec.from)
|
||||
const to = path.join(projectRoot, spec.to)
|
||||
|
||||
if (from === to) {
|
||||
return
|
||||
}
|
||||
|
||||
return fs.move(from, to)
|
||||
}))
|
||||
}
|
||||
|
||||
export async function cleanUpIntegrationFolder (projectRoot: string) {
|
||||
const integrationPath = path.join(projectRoot, 'cypress', 'integration')
|
||||
const e2ePath = path.join(projectRoot, 'cypress', 'e2e')
|
||||
|
||||
try {
|
||||
await fs.copy(integrationPath, e2ePath, { recursive: true })
|
||||
await fs.remove(integrationPath)
|
||||
} catch (e: any) {
|
||||
// only throw if the folder exists
|
||||
if (e.code !== 'ENOENT') {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function renameSupportFilePath (relative: string) {
|
||||
const res = new RegExp(supportFileRegexps.e2e.beforeRegexp).exec(relative)
|
||||
|
||||
if (!res?.groups?.supportFileName) {
|
||||
throw new NonStandardMigrationError('support')
|
||||
}
|
||||
|
||||
return relative.slice(0, res.index) + relative.slice(res.index).replace(res.groups.supportFileName, 'e2e')
|
||||
}
|
||||
|
||||
export function reduceConfig (cfg: LegacyCypressConfigJson, options: CreateConfigOptions): ConfigOptions {
|
||||
return Object.entries(cfg).reduce((acc, [key, val]) => {
|
||||
switch (key) {
|
||||
case 'pluginsFile':
|
||||
case '$schema':
|
||||
return acc
|
||||
|
||||
case 'e2e':
|
||||
case 'component': {
|
||||
const value = val as ResolvedConfigOptions
|
||||
|
||||
if (!value) {
|
||||
return acc
|
||||
}
|
||||
|
||||
const { testFiles, ignoreTestFiles, ...rest } = value
|
||||
|
||||
// don't include if it's the default! No need.
|
||||
const specPattern = getSpecPattern(cfg, key, options.shouldAddCustomE2ESpecPattern)
|
||||
const ext = '**/*.cy.{js,jsx,ts,tsx}'
|
||||
const isDefaultE2E = key === 'e2e' && specPattern === `cypress/e2e/${ext}`
|
||||
const isDefaultCT = key === 'component' && specPattern === ext
|
||||
|
||||
const breakingKeys = getBreakingKeys()
|
||||
const restWithoutBreakingKeys = _.omit(rest, breakingKeys)
|
||||
const existingWithoutBreakingKeys = _.omit(acc[key], breakingKeys)
|
||||
|
||||
if (isDefaultE2E || isDefaultCT) {
|
||||
return {
|
||||
...acc, [key]: {
|
||||
...restWithoutBreakingKeys,
|
||||
...existingWithoutBreakingKeys,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...acc, [key]: {
|
||||
...restWithoutBreakingKeys,
|
||||
...existingWithoutBreakingKeys,
|
||||
specPattern,
|
||||
},
|
||||
}
|
||||
}
|
||||
case 'integrationFolder':
|
||||
// If the integration folder is set, but the value is the same as the default legacy one
|
||||
// we do not want to update the config value, we keep using the new default.
|
||||
if (val === legacyIntegrationFolder) {
|
||||
return acc
|
||||
}
|
||||
|
||||
return {
|
||||
...acc,
|
||||
e2e: { ...acc.e2e, specPattern: getSpecPattern(cfg, 'e2e', options.shouldAddCustomE2ESpecPattern) },
|
||||
}
|
||||
case 'componentFolder':
|
||||
return {
|
||||
...acc,
|
||||
component: { ...acc.component, specPattern: getSpecPattern(cfg, 'component') },
|
||||
}
|
||||
case 'testFiles':
|
||||
return {
|
||||
...acc,
|
||||
e2e: { ...acc.e2e, specPattern: getSpecPattern(cfg, 'e2e', options.shouldAddCustomE2ESpecPattern) },
|
||||
component: { ...acc.component, specPattern: getSpecPattern(cfg, 'component') },
|
||||
}
|
||||
case 'ignoreTestFiles':
|
||||
return {
|
||||
...acc,
|
||||
e2e: { ...acc.e2e, excludeSpecPattern: val },
|
||||
component: { ...acc.component, excludeSpecPattern: val },
|
||||
}
|
||||
case 'supportFile':
|
||||
// If the supportFile is set, but is the same value as the default one; where
|
||||
// we migrate it, we do not want to put the legacy value in the migrated config.
|
||||
// It can be .ts or .js
|
||||
if (isDefaultSupportFile(val)) {
|
||||
return acc
|
||||
}
|
||||
|
||||
return {
|
||||
...acc,
|
||||
e2e: { ...acc.e2e, supportFile: val },
|
||||
}
|
||||
case 'baseUrl':
|
||||
return {
|
||||
...acc,
|
||||
e2e: { ...acc.e2e, [key]: val },
|
||||
}
|
||||
case 'slowTestThreshold':
|
||||
return {
|
||||
...acc,
|
||||
component: { ...acc.component, [key]: val },
|
||||
e2e: { ...acc.e2e, [key]: val },
|
||||
}
|
||||
default:
|
||||
return { ...acc, global: { ...acc.global, [key]: val } }
|
||||
}
|
||||
}, { global: {}, e2e: {}, component: {} })
|
||||
}
|
||||
|
||||
function propOrArrayProp<T> (val: T[]): T | T[] {
|
||||
if (val[0] && val.length === 1) {
|
||||
return val[0]
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
export function getSpecPattern (cfg: LegacyCypressConfigJson, testingType: TestingType, shouldAddCustomE2ESpecPattern: boolean = false) {
|
||||
let _specPattern = cfg[testingType]?.testFiles ?? cfg.testFiles ?? (testingType === 'e2e' && shouldAddCustomE2ESpecPattern ? '**/*.{js,jsx,ts,tsx}' : '**/*.cy.{js,jsx,ts,tsx}')
|
||||
const specPattern = _.castArray(_specPattern)
|
||||
|
||||
const customComponentFolder = cfg.component?.componentFolder ?? cfg.componentFolder ?? null
|
||||
|
||||
if (testingType === 'component' && customComponentFolder) {
|
||||
return propOrArrayProp(specPattern.map((pattern) => `${customComponentFolder}/${pattern}`))
|
||||
}
|
||||
|
||||
if (testingType === 'e2e') {
|
||||
const customIntegrationFolder = cfg.e2e?.integrationFolder ?? cfg.integrationFolder ?? null
|
||||
|
||||
if (customIntegrationFolder && customIntegrationFolder !== legacyIntegrationFolder) {
|
||||
return propOrArrayProp(specPattern.map((pattern) => `${customIntegrationFolder}/${pattern}`))
|
||||
}
|
||||
|
||||
return propOrArrayProp(specPattern.map((pattern) => `cypress/e2e/${pattern}`))
|
||||
}
|
||||
|
||||
return propOrArrayProp(specPattern)
|
||||
}
|
||||
|
||||
function formatWithBundledBabel (config: string) {
|
||||
const ast = parse(config)
|
||||
|
||||
// @ts-ignore - transitive babel types have a minor conflict - readonly vs non readonly.
|
||||
let { code } = generate(ast, {}, config)
|
||||
// By default babel generates imports like this:
|
||||
// const {
|
||||
// defineConfig
|
||||
// } = require('cypress');
|
||||
// So we replace them with a one-liner, since we know this will never
|
||||
// be more than one import.
|
||||
//
|
||||
// Babel also adds empty lines, for example:
|
||||
//
|
||||
// export default defineConfig({
|
||||
// component: {
|
||||
// },
|
||||
// <===== empty line
|
||||
// e2e: {
|
||||
//
|
||||
// }
|
||||
// })
|
||||
// Which we don't want, so we change those to single carriage returns.
|
||||
const replacers = [
|
||||
{
|
||||
from: dedent`
|
||||
const {
|
||||
defineConfig
|
||||
} = require('cypress');
|
||||
`,
|
||||
to: dedent`
|
||||
const { defineConfig } = require('cypress');
|
||||
`,
|
||||
},
|
||||
{
|
||||
|
||||
from: dedent`
|
||||
import {
|
||||
defineConfig
|
||||
} from 'cypress';
|
||||
`,
|
||||
to: dedent`
|
||||
import { defineConfig } from 'cypress';
|
||||
`,
|
||||
},
|
||||
{
|
||||
from: `,\n\n`,
|
||||
to: `,\n`,
|
||||
},
|
||||
]
|
||||
|
||||
for (const rep of replacers) {
|
||||
if (code.includes(rep.from)) {
|
||||
code = code.replaceAll(rep.from, rep.to)
|
||||
}
|
||||
}
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
export function formatConfig (config: string): string {
|
||||
try {
|
||||
const prettier = require('prettier') as typeof import('prettier')
|
||||
|
||||
return prettier.format(config, {
|
||||
semi: false,
|
||||
singleQuote: true,
|
||||
endOfLine: 'lf',
|
||||
parser: 'babel',
|
||||
})
|
||||
} catch (e) {
|
||||
// If they do not have prettier
|
||||
// We do a basic format using babel, which we
|
||||
// bundle as part of the binary.
|
||||
// We don't ship a fully fledged formatter like
|
||||
// prettier, since it's massively bloats the bundle.
|
||||
return formatWithBundledBabel(config)
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import dedent from 'dedent'
|
||||
import { MigrationTransformOptions, defaultMigrationTransformOptions } from './autoRename'
|
||||
|
||||
export type FilePart = {
|
||||
text: string
|
||||
group?: 'folder' | 'preExtension' | 'supportFileName' | 'fileName'
|
||||
highlight: boolean
|
||||
}
|
||||
|
||||
export function formatMigrationFile (file: string, regexp: RegExp, options: MigrationTransformOptions = defaultMigrationTransformOptions): FilePart[] {
|
||||
const match = regexp.exec(file)
|
||||
|
||||
if (!match?.groups) {
|
||||
throw new Error(dedent`
|
||||
Expected groups main,ext or file in ${file} using ${regexp} when matching ${file}
|
||||
Perhaps this isn't a spec file, or it is an unexpected format?`)
|
||||
}
|
||||
|
||||
const { folder, fileName, preExtension, extension, supportFileName } = match.groups
|
||||
|
||||
if (supportFileName && extension) {
|
||||
return [{
|
||||
text: `${file.slice(0, match.index)}cypress/support/`, // user/cypress/support/index.js -> user/cypress/support/
|
||||
highlight: false,
|
||||
}, {
|
||||
text: supportFileName, // user/cypress/support/index.js -> index
|
||||
highlight: true,
|
||||
group: 'supportFileName',
|
||||
},
|
||||
{
|
||||
text: extension, // user/cypress/support/index.js -> .js
|
||||
highlight: false,
|
||||
}]
|
||||
}
|
||||
|
||||
return [{
|
||||
text: file.slice(0, match.index), // user/cypress/integration/file.spec.tsx -> user/
|
||||
highlight: false,
|
||||
},
|
||||
{
|
||||
text: folder ? 'cypress/' : '', // empty when using a custom integration folder or in component
|
||||
highlight: false,
|
||||
},
|
||||
{
|
||||
text: folder || '', // user/cypress/integration/file.spec.tsx -> integration
|
||||
highlight: true,
|
||||
group: 'folder',
|
||||
},
|
||||
{
|
||||
text: (folder ? '/' : '') + fileName, // user/cypress/integration/file.spec.tsx -> /file
|
||||
highlight: false,
|
||||
group: 'fileName',
|
||||
},
|
||||
{
|
||||
text: preExtension || '', // user/cypress/integration/file.spec.tsx -> .spec.
|
||||
highlight: options.shouldMigratePreExtension,
|
||||
group: 'preExtension',
|
||||
}, {
|
||||
text: extension || '', // user/cypress/integration/file.spec.tsx -> tsx
|
||||
highlight: false,
|
||||
}].filter((f) => f.text.length) as FilePart[]
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/* eslint-disable padding-line-between-statements */
|
||||
// created by autobarrel, do not modify directly
|
||||
|
||||
export * from './autoRename'
|
||||
export * from './codegen'
|
||||
export * from './format'
|
||||
export * from './legacyOptions'
|
||||
export * from './parserUtils'
|
||||
export * from './regexps'
|
||||
export * from './shouldShowSteps'
|
||||
export * from './utils'
|
||||
@@ -1,296 +0,0 @@
|
||||
interface ResolvedConfigOption {
|
||||
name: string
|
||||
defaultValue?: any
|
||||
isFolder?: boolean
|
||||
isExperimental?: boolean
|
||||
/**
|
||||
* Can be mutated with Cypress.config() or test-specific configuration overrides
|
||||
*/
|
||||
canUpdateDuringTestTime?: boolean
|
||||
}
|
||||
|
||||
interface RuntimeConfigOption {
|
||||
name: string
|
||||
defaultValue: any
|
||||
isInternal?: boolean
|
||||
/**
|
||||
* Can be mutated with Cypress.config() or test-specific configuration overrides
|
||||
*/
|
||||
canUpdateDuringTestTime?: boolean
|
||||
}
|
||||
|
||||
export const legacyIntegrationFolder = 'cypress/integration'
|
||||
// NOTE:
|
||||
// If you add/remove/change a config value, make sure to update the following
|
||||
// - cli/types/index.d.ts (including allowed config options on TestOptions)
|
||||
// - cypress.schema.json
|
||||
//
|
||||
// Add options in alphabetical order for better readability
|
||||
|
||||
// TODO - add boolean attribute to indicate read-only / static vs mutable options
|
||||
// that can be updated during test executions
|
||||
const resolvedOptions: Array<ResolvedConfigOption> = [
|
||||
{
|
||||
name: 'animationDistanceThreshold',
|
||||
defaultValue: 5,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'baseUrl',
|
||||
defaultValue: null,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'blockHosts',
|
||||
defaultValue: null,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'chromeWebSecurity',
|
||||
defaultValue: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'clientCertificates',
|
||||
defaultValue: [],
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'component',
|
||||
// runner-ct overrides
|
||||
defaultValue: {},
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'componentFolder',
|
||||
defaultValue: 'cypress/component',
|
||||
isFolder: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'defaultCommandTimeout',
|
||||
defaultValue: 4000,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'downloadsFolder',
|
||||
defaultValue: 'cypress/downloads',
|
||||
isFolder: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'e2e',
|
||||
// e2e runner overrides
|
||||
defaultValue: {},
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'env',
|
||||
defaultValue: {},
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'execTimeout',
|
||||
defaultValue: 60000,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'exit',
|
||||
defaultValue: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'experimentalInteractiveRunEvents',
|
||||
defaultValue: false,
|
||||
isExperimental: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'experimentalSourceRewriting',
|
||||
defaultValue: false,
|
||||
isExperimental: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'experimentalStudio',
|
||||
defaultValue: false,
|
||||
isExperimental: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'fileServerFolder',
|
||||
defaultValue: '',
|
||||
isFolder: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'fixturesFolder',
|
||||
defaultValue: 'cypress/fixtures',
|
||||
isFolder: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'ignoreTestFiles',
|
||||
defaultValue: '*.hot-update.js',
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'includeShadowDom',
|
||||
defaultValue: false,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'integrationFolder',
|
||||
defaultValue: legacyIntegrationFolder,
|
||||
isFolder: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'keystrokeDelay',
|
||||
defaultValue: 0,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'modifyObstructiveCode',
|
||||
defaultValue: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'nodeVersion',
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'numTestsKeptInMemory',
|
||||
defaultValue: 50,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'pageLoadTimeout',
|
||||
defaultValue: 60000,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'pluginsFile',
|
||||
defaultValue: 'cypress/plugins',
|
||||
isFolder: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'port',
|
||||
defaultValue: null,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'projectId',
|
||||
defaultValue: null,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'redirectionLimit',
|
||||
defaultValue: 20,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'reporter',
|
||||
defaultValue: 'spec',
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'reporterOptions',
|
||||
defaultValue: null,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'requestTimeout',
|
||||
defaultValue: 5000,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'resolvedNodePath',
|
||||
defaultValue: null,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'resolvedNodeVersion',
|
||||
defaultValue: null,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'responseTimeout',
|
||||
defaultValue: 30000,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'retries',
|
||||
defaultValue: {
|
||||
runMode: 0,
|
||||
openMode: 0,
|
||||
},
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'screenshotOnRunFailure',
|
||||
defaultValue: true,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'screenshotsFolder',
|
||||
defaultValue: 'cypress/screenshots',
|
||||
isFolder: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'slowTestThreshold',
|
||||
defaultValue: (options: Record<string, any> = {}) => options.testingType === 'component' ? 250 : 10000,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'scrollBehavior',
|
||||
defaultValue: 'top',
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'supportFile',
|
||||
defaultValue: 'cypress/support',
|
||||
isFolder: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'supportFolder',
|
||||
defaultValue: false,
|
||||
isFolder: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'taskTimeout',
|
||||
defaultValue: 60000,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'testFiles',
|
||||
defaultValue: '**/*.*',
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'trashAssetsBeforeRuns',
|
||||
defaultValue: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'userAgent',
|
||||
defaultValue: null,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'video',
|
||||
defaultValue: false,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'videoCompression',
|
||||
defaultValue: 32,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'videosFolder',
|
||||
defaultValue: 'cypress/videos',
|
||||
isFolder: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'videoUploadOnPasses',
|
||||
defaultValue: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'viewportHeight',
|
||||
defaultValue: 660,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'viewportWidth',
|
||||
defaultValue: 1000,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'waitForAnimations',
|
||||
defaultValue: true,
|
||||
canUpdateDuringTestTime: true,
|
||||
}, {
|
||||
name: 'watchForFileChanges',
|
||||
defaultValue: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
},
|
||||
]
|
||||
|
||||
const runtimeOptions: Array<RuntimeConfigOption> = [
|
||||
{
|
||||
name: 'browsers',
|
||||
defaultValue: [],
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'hosts',
|
||||
defaultValue: null,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'isInteractive',
|
||||
defaultValue: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
}, {
|
||||
name: 'modifyObstructiveCode',
|
||||
defaultValue: true,
|
||||
canUpdateDuringTestTime: false,
|
||||
},
|
||||
]
|
||||
|
||||
export const legacyOptions: Array<ResolvedConfigOption|RuntimeConfigOption> = [
|
||||
...resolvedOptions,
|
||||
...runtimeOptions,
|
||||
]
|
||||
@@ -1,47 +0,0 @@
|
||||
import { parse, ParserOptions } from '@babel/parser'
|
||||
import { visit } from 'recast'
|
||||
import type * as bt from '@babel/types'
|
||||
|
||||
const babelParserOptions: ParserOptions = {
|
||||
sourceType: 'module',
|
||||
strictMode: false,
|
||||
tokens: true,
|
||||
plugins: [
|
||||
'decorators-legacy',
|
||||
'doExpressions',
|
||||
'objectRestSpread',
|
||||
'classProperties',
|
||||
'classPrivateProperties',
|
||||
'classPrivateMethods',
|
||||
'exportDefaultFrom',
|
||||
'exportNamespaceFrom',
|
||||
'asyncGenerators',
|
||||
'functionBind',
|
||||
'functionSent',
|
||||
'dynamicImport',
|
||||
'numericSeparator',
|
||||
'optionalChaining',
|
||||
'importMeta',
|
||||
'bigInt',
|
||||
'optionalCatchBinding',
|
||||
'throwExpressions',
|
||||
'nullishCoalescingOperator',
|
||||
'typescript',
|
||||
],
|
||||
}
|
||||
|
||||
export function hasDefaultExport (src: string): boolean {
|
||||
const ast = parse(src, babelParserOptions) as bt.File
|
||||
|
||||
let hasDefault = false
|
||||
|
||||
visit(ast, {
|
||||
visitExportDefaultDeclaration () {
|
||||
hasDefault = true
|
||||
|
||||
return false
|
||||
},
|
||||
})
|
||||
|
||||
return hasDefault
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* This partial regular expression is used to extract
|
||||
* the extension from a spec file name:
|
||||
*
|
||||
* matches
|
||||
* - file.spec.tsx -> ext=".spec."
|
||||
* - file_Spec.jsx -> ext="_Spec."
|
||||
* - file-spec.js -> ext="-spec."
|
||||
* - spec.jsx -> ext="."
|
||||
*
|
||||
* The final objective being to be able to replace "ext" with ".cy."
|
||||
*/
|
||||
const specExtRe = '(?:[._-]?(?:[s|S]pec|[T|t]est))?[.])(?<extension>(?:[j|t]s[x]?|coffee|cjsx)'
|
||||
|
||||
export const regexps = {
|
||||
e2e: {
|
||||
before: {
|
||||
defaultFolderDefaultTestFiles: `cypress\/(?<folder>integration)\/(?<fileName>.+?)(?<preExtension>${specExtRe})$`,
|
||||
defaultFolderCustomTestFiles: `cypress\/(?<folder>integration)\/(?<fileName>.+)$`,
|
||||
customFolderDefaultTestFiles: `(?<fileName>.+?)(?<preExtension>${specExtRe})$`,
|
||||
},
|
||||
},
|
||||
component: {
|
||||
before: {
|
||||
defaultFolderDefaultTestFiles: `(?<fileName>cypress\/component\/.+?)(?<preExtension>${specExtRe})`,
|
||||
customFolderDefaultTestFiles: `(?<fileName>.+?)(?<preExtension>${specExtRe})`,
|
||||
},
|
||||
},
|
||||
} as const
|
||||
|
||||
export const supportFileRegexps = {
|
||||
e2e: {
|
||||
beforeRegexp: 'cypress[\\\\/]support[\\\\/](?<supportFileName>index)(?<extension>\.(?:[j|t]sx?|coffee))',
|
||||
afterRegexp: 'cypress[\\\\/]support[\\\\/](?<supportFileName>e2e)(?<extension>\.(?:[j|t]sx?|coffee))',
|
||||
},
|
||||
} as const
|
||||
@@ -1,194 +0,0 @@
|
||||
import globby from 'globby'
|
||||
import path from 'path'
|
||||
import { MIGRATION_STEPS } from '@packages/types'
|
||||
import { applyMigrationTransform, getSpecs, isDefaultSupportFile, legacyIntegrationFolder, tryGetDefaultLegacySupportFile } from '.'
|
||||
import type { LegacyCypressConfigJson } from '..'
|
||||
|
||||
export const defaultTestFilesGlob = '**/*.{js,ts,jsx,tsx,coffee,cjsx}'
|
||||
|
||||
function getTestFilesGlobs (config: LegacyCypressConfigJson, type: 'component' | 'integration'): string[] {
|
||||
// super awkward how we call it integration tests, but the key to override
|
||||
// the config is `e2e`
|
||||
const k = type === 'component' ? 'component' : 'e2e'
|
||||
|
||||
const glob = config[k]?.testFiles ?? config.testFiles
|
||||
|
||||
if (glob) {
|
||||
return ([] as string[]).concat(glob)
|
||||
}
|
||||
|
||||
return [defaultTestFilesGlob]
|
||||
}
|
||||
|
||||
export function getIntegrationTestFilesGlobs (config: LegacyCypressConfigJson): string[] {
|
||||
return getTestFilesGlobs(config, 'integration')
|
||||
}
|
||||
|
||||
export function getComponentTestFilesGlobs (config: LegacyCypressConfigJson): string[] {
|
||||
return getTestFilesGlobs(config, 'component')
|
||||
}
|
||||
|
||||
export function isDefaultTestFiles (config: LegacyCypressConfigJson, type: 'component' | 'integration') {
|
||||
const testFiles = type === 'component'
|
||||
? getComponentTestFilesGlobs(config)
|
||||
: getIntegrationTestFilesGlobs(config)
|
||||
|
||||
return testFiles.length === 1 && testFiles[0] === defaultTestFilesGlob
|
||||
}
|
||||
|
||||
export function getPluginsFile (config: LegacyCypressConfigJson) {
|
||||
if (config.e2e?.pluginsFile === false || config.pluginsFile === false) {
|
||||
return false
|
||||
}
|
||||
|
||||
return config.e2e?.pluginsFile ?? config.pluginsFile ?? 'cypress/plugins/index.js'
|
||||
}
|
||||
|
||||
export function getIntegrationFolder (config: LegacyCypressConfigJson) {
|
||||
return config.e2e?.integrationFolder ?? config.integrationFolder ?? legacyIntegrationFolder
|
||||
}
|
||||
|
||||
export function getComponentFolder (config: LegacyCypressConfigJson): false | string {
|
||||
if (config.component?.componentFolder === false || config.componentFolder === false) {
|
||||
return false
|
||||
}
|
||||
|
||||
return config.component?.componentFolder ?? config.componentFolder ?? 'cypress/component'
|
||||
}
|
||||
|
||||
async function hasSpecFiles (projectRoot: string, dir: string, testFilesGlob: string[]): Promise<boolean> {
|
||||
const f = await globby(testFilesGlob, { cwd: path.join(projectRoot, dir) })
|
||||
|
||||
return f.length > 0
|
||||
}
|
||||
|
||||
export async function shouldShowAutoRenameStep (projectRoot: string, config: LegacyCypressConfigJson) {
|
||||
const specsToAutoMigrate = await getSpecs(projectRoot, config)
|
||||
|
||||
const e2eMigrationOptions = {
|
||||
// If the configFile has projectId, we do not want to change the preExtension
|
||||
// so, we can keep the cloud history
|
||||
shouldMigratePreExtension: !config.projectId && !config.e2e?.projectId,
|
||||
}
|
||||
|
||||
const integrationCleaned = specsToAutoMigrate.integration.filter((spec) => {
|
||||
const transformed = applyMigrationTransform(spec, e2eMigrationOptions)
|
||||
|
||||
return transformed.before.relative !== transformed.after.relative
|
||||
})
|
||||
|
||||
const componentCleaned = specsToAutoMigrate.component.filter((spec) => {
|
||||
const transformed = applyMigrationTransform(spec)
|
||||
|
||||
return transformed.before.relative !== transformed.after.relative
|
||||
})
|
||||
|
||||
// if we have at least one spec to auto migrate in either Ct or E2E, we return true.
|
||||
return integrationCleaned.length > 0 || componentCleaned.length > 0
|
||||
}
|
||||
|
||||
async function anyComponentSpecsExist (projectRoot: string, config: LegacyCypressConfigJson) {
|
||||
const componentFolder = getComponentFolder(config)
|
||||
|
||||
if (componentFolder === false) {
|
||||
return false
|
||||
}
|
||||
|
||||
const componentTestFiles = getComponentTestFilesGlobs(config)
|
||||
|
||||
return hasSpecFiles(projectRoot, componentFolder, componentTestFiles)
|
||||
}
|
||||
|
||||
async function anyIntegrationSpecsExist (projectRoot: string, config: LegacyCypressConfigJson) {
|
||||
const integrationFolder = getIntegrationFolder(config)
|
||||
|
||||
const integrationTestFiles = getIntegrationTestFilesGlobs(config)
|
||||
|
||||
return hasSpecFiles(projectRoot, integrationFolder, integrationTestFiles)
|
||||
}
|
||||
|
||||
// we only show rename support file if they are using the default
|
||||
// if they have anything set in their config, we will not try to rename it.
|
||||
// Also, if there are no **no** integration specs, we are doing a CT only migration,
|
||||
// in which case we don't migrate the supportFile - they'll make a new support/component.js
|
||||
// when they set CT up.
|
||||
export async function shouldShowRenameSupport (projectRoot: string, config: LegacyCypressConfigJson) {
|
||||
if (!await anyIntegrationSpecsExist(projectRoot, config)) {
|
||||
return false
|
||||
}
|
||||
|
||||
let supportFile = config.e2e?.supportFile ?? config.supportFile
|
||||
|
||||
if (supportFile === undefined) {
|
||||
const foundDefaultSupportFile = await tryGetDefaultLegacySupportFile(projectRoot)
|
||||
|
||||
if (foundDefaultSupportFile) {
|
||||
supportFile = foundDefaultSupportFile
|
||||
}
|
||||
}
|
||||
|
||||
// if the support file is set to false, we don't show the rename step
|
||||
// if the support file does not exist (value is undefined), we don't show the rename step
|
||||
if (!supportFile) {
|
||||
return false
|
||||
}
|
||||
|
||||
// if the support file is custom, we don't show the rename step
|
||||
// only if the support file matches the default do we show the rename step
|
||||
return isDefaultSupportFile(supportFile)
|
||||
}
|
||||
|
||||
// if they have component testing configured using the defaults, they will need to
|
||||
// rename/move their specs.
|
||||
async function shouldShowRenameManual (projectRoot: string, config: LegacyCypressConfigJson) {
|
||||
const componentFolder = getComponentFolder(config)
|
||||
|
||||
const usingAllDefaults = componentFolder === 'cypress/component' && isDefaultTestFiles(config, 'component')
|
||||
|
||||
if (componentFolder === false || !usingAllDefaults) {
|
||||
return false
|
||||
}
|
||||
|
||||
return anyComponentSpecsExist(projectRoot, config)
|
||||
}
|
||||
|
||||
// All projects must move from cypress.json to cypress.config.js!
|
||||
export function shouldShowConfigFileStep (config: LegacyCypressConfigJson) {
|
||||
return true
|
||||
}
|
||||
|
||||
export type Step = typeof MIGRATION_STEPS[number]
|
||||
|
||||
export async function getStepsForMigration (
|
||||
projectRoot: string,
|
||||
config: LegacyCypressConfigJson,
|
||||
configFileExists: boolean,
|
||||
): Promise<Step[]> {
|
||||
const steps: Step[] = []
|
||||
|
||||
for (const step of MIGRATION_STEPS) {
|
||||
if (step === 'renameAuto' && await shouldShowAutoRenameStep(projectRoot, config)) {
|
||||
steps.push(step)
|
||||
}
|
||||
|
||||
if (step === 'renameManual' && await shouldShowRenameManual(projectRoot, config)) {
|
||||
steps.push(step)
|
||||
}
|
||||
|
||||
if (step === 'renameSupport' && await shouldShowRenameSupport(projectRoot, config)) {
|
||||
steps.push(step)
|
||||
}
|
||||
|
||||
if (step === 'configFile' && configFileExists) {
|
||||
steps.push(step)
|
||||
}
|
||||
|
||||
// if we are showing rename manual, this implies
|
||||
// component testing is configured.
|
||||
if (step === 'setupComponent' && await anyComponentSpecsExist(projectRoot, config)) {
|
||||
steps.push(step)
|
||||
}
|
||||
}
|
||||
|
||||
return steps
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import type { TestingType, FoundSpec } from '@packages/types'
|
||||
import Debug from 'debug'
|
||||
import _ from 'lodash'
|
||||
import path from 'path'
|
||||
import { getPathFromSpecPattern, getLongestCommonPrefixFromPaths } from '../ProjectDataSource'
|
||||
import { getPathFromSpecPattern, getLongestCommonPrefixFromPaths } from '../sources/ProjectDataSource'
|
||||
|
||||
export const isDefaultSupportFile = (supportFile: string) => {
|
||||
if (_.isNil(supportFile) || !_.isBoolean(supportFile) && supportFile.match(/(^|\.+\/)cypress\/support($|\/index($|\.(ts|js|coffee)$))/)) {
|
||||
@@ -19,7 +19,7 @@ export async function getDefaultSpecFileName (
|
||||
{ currentProject, testingType, fileExtensionToUse, specPattern, specs = [], name }:
|
||||
{ currentProject: string | null, testingType: TestingType | null, fileExtensionToUse: FileExtension, specPattern: string[], specs?: FoundSpec[], name?: string },
|
||||
): Promise<string> {
|
||||
const debug = Debug('cypress:data-context:sources:migration:utils')
|
||||
const debug = Debug('cypress:data-context:util:files')
|
||||
|
||||
const defaultFilename = `${name ? name : testingType === 'e2e' ? 'spec' : 'ComponentName'}.cy.${fileExtensionToUse}`
|
||||
const defaultPathname = path.join('cypress', testingType ?? 'e2e', defaultFilename)
|
||||
@@ -5,6 +5,7 @@ export * from './DocumentNodeBuilder'
|
||||
export * from './autoBindDebug'
|
||||
export * from './config-file-updater'
|
||||
export * from './file'
|
||||
export * from './files'
|
||||
export * from './hasTypescript'
|
||||
export * from './pluginHandlers'
|
||||
export * from './testCounts'
|
||||
|
||||
@@ -22,11 +22,8 @@ export const urqlCacheKeys: Partial<UrqlCacheKeys> = {
|
||||
keys: {
|
||||
DevState: (data) => data.__typename,
|
||||
Wizard: (data) => data.__typename,
|
||||
Migration: (data) => data.__typename,
|
||||
CloudRunCommitInfo: () => null,
|
||||
GitInfo: () => null,
|
||||
MigrationFile: () => null,
|
||||
MigrationFilePart: () => null,
|
||||
CodeFrame: () => null,
|
||||
ProjectPreferences: (data) => data.__typename,
|
||||
VersionData: () => null,
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
import chai, { expect } from 'chai'
|
||||
import chaiAsPromised from 'chai-as-promised'
|
||||
import { getConfigWithDefaults, getDiff } from '../../../src/actions/MigrationActions'
|
||||
import fs from 'fs-extra'
|
||||
import Fixtures from '@tooling/system-tests'
|
||||
import { createTestDataContext, scaffoldMigrationProject } from '../helper'
|
||||
import path from 'path'
|
||||
|
||||
chai.use(chaiAsPromised)
|
||||
|
||||
describe('MigrationActions', () => {
|
||||
context('getConfigWithDefaults', () => {
|
||||
it('returns a config with defaults without touching the original', () => {
|
||||
const config = {
|
||||
foo: 'bar',
|
||||
}
|
||||
|
||||
expect(getConfigWithDefaults(config)).to.have.property('env')
|
||||
expect(getConfigWithDefaults(config)).to.have.property('browsers')
|
||||
expect(config).not.to.have.property('env')
|
||||
expect(config).not.to.have.property('browsers')
|
||||
})
|
||||
})
|
||||
|
||||
context('getDiff', () => {
|
||||
it('returns all the updated values', () => {
|
||||
const oldConfig = {
|
||||
foo: 'bar',
|
||||
other: 'config',
|
||||
removed: 'value',
|
||||
updated: 'oldValue',
|
||||
}
|
||||
|
||||
const newConfig = {
|
||||
foo: 'hello',
|
||||
other: 'config',
|
||||
updated: 'newValue',
|
||||
}
|
||||
|
||||
const diff = getDiff(oldConfig, newConfig)
|
||||
|
||||
expect(diff).to.have.property('foo', 'hello')
|
||||
expect(diff).to.have.property('updated', 'newValue')
|
||||
expect(diff).not.to.have.property('removed')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#initialize', () => {
|
||||
let currentProject: string
|
||||
|
||||
beforeEach(async () => {
|
||||
Fixtures.clearFixtureNodeModules('migration')
|
||||
currentProject = await scaffoldMigrationProject('migration')
|
||||
})
|
||||
|
||||
// simulate having a specific version of cypress installed
|
||||
// in a project's local node_modules
|
||||
function mockLocallyInstalledCypress (projectRoot: string, version: string) {
|
||||
const mockPkgJson = {
|
||||
version,
|
||||
main: 'index.js',
|
||||
}
|
||||
const mockCypressDir = path.join(projectRoot, 'node_modules', 'cypress')
|
||||
|
||||
fs.mkdirSync(mockCypressDir, { recursive: true })
|
||||
fs.createFileSync(path.join(mockCypressDir, 'index.js'))
|
||||
fs.writeJsonSync(path.join(mockCypressDir, 'package.json'), mockPkgJson)
|
||||
}
|
||||
|
||||
it('errors when local cypress version is <10', async () => {
|
||||
mockLocallyInstalledCypress(currentProject, '9.5.0')
|
||||
const ctx = createTestDataContext()
|
||||
|
||||
ctx.update((coreData) => {
|
||||
coreData.currentProject = currentProject
|
||||
coreData.currentTestingType = 'e2e'
|
||||
coreData.app.isGlobalMode = true
|
||||
})
|
||||
|
||||
const currentVersion = (await ctx.versions.versionData()).current.version
|
||||
|
||||
return (
|
||||
expect(ctx.actions.migration.initialize({})).to.eventually.be.rejectedWith(
|
||||
`You are running Cypress version ${currentVersion} in global mode, but you are attempting to migrate a project where Cypress version 9.5.0 is installed`,
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
it('does not error when local cypress version is 10', () => {
|
||||
mockLocallyInstalledCypress(currentProject, '10.0.0')
|
||||
const ctx = createTestDataContext()
|
||||
|
||||
ctx.update((coreData) => {
|
||||
coreData.currentProject = currentProject
|
||||
coreData.currentTestingType = 'e2e'
|
||||
})
|
||||
|
||||
return (
|
||||
expect(ctx.actions.migration.initialize({})).to.eventually.not.be.rejected
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,577 +0,0 @@
|
||||
import {
|
||||
getSpecs,
|
||||
applyMigrationTransform,
|
||||
MigrationSpec,
|
||||
} from '../../../../src/sources/migration/autoRename'
|
||||
import { expect } from 'chai'
|
||||
import path from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import { MigrationFile } from '../../../../src/sources'
|
||||
import { scaffoldMigrationProject } from '../../helper'
|
||||
|
||||
describe('getSpecs', () => {
|
||||
it('handles custom folders', async () => {
|
||||
// CASE 1: E2E + CT, custom folders, default test files
|
||||
// We want to rename specs, but keep current folders.
|
||||
const cwd = await scaffoldMigrationProject('migration-e2e-component-default-test-files')
|
||||
const json = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
|
||||
const actual = await getSpecs(cwd, json)
|
||||
|
||||
expect(actual.integration).to.eql([
|
||||
{
|
||||
relative: 'cypress/custom-integration/foo.spec.ts',
|
||||
usesDefaultFolder: false,
|
||||
usesDefaultTestFiles: true,
|
||||
testingType: 'e2e',
|
||||
},
|
||||
])
|
||||
|
||||
expect(actual.component).to.eql([
|
||||
{
|
||||
relative: 'cypress/custom-component/button.spec.js',
|
||||
usesDefaultFolder: false,
|
||||
usesDefaultTestFiles: true,
|
||||
testingType: 'component',
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('handles default folder and custom testFiles', async () => {
|
||||
// CASE 1: E2E + CT, custom folders, default test files
|
||||
// We want to rename specs, but keep current folders.
|
||||
const cwd = await scaffoldMigrationProject('migration')
|
||||
const json = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
|
||||
const actual = await getSpecs(cwd, json)
|
||||
|
||||
expect(actual.integration).to.eql([
|
||||
{
|
||||
'relative': 'cypress/integration/app_spec.js',
|
||||
'testingType': 'e2e',
|
||||
'usesDefaultFolder': true,
|
||||
'usesDefaultTestFiles': false,
|
||||
},
|
||||
{
|
||||
relative: 'cypress/integration/bar.spec.js',
|
||||
usesDefaultFolder: true,
|
||||
usesDefaultTestFiles: false,
|
||||
testingType: 'e2e',
|
||||
},
|
||||
{
|
||||
'relative': 'cypress/integration/blog-post-spec.ts',
|
||||
'testingType': 'e2e',
|
||||
'usesDefaultFolder': true,
|
||||
'usesDefaultTestFiles': false,
|
||||
},
|
||||
{
|
||||
'relative': 'cypress/integration/company.js',
|
||||
'testingType': 'e2e',
|
||||
'usesDefaultFolder': true,
|
||||
'usesDefaultTestFiles': false,
|
||||
},
|
||||
{
|
||||
'relative': 'cypress/integration/homeSpec.js',
|
||||
'testingType': 'e2e',
|
||||
'usesDefaultFolder': true,
|
||||
'usesDefaultTestFiles': false,
|
||||
},
|
||||
{
|
||||
'relative': 'cypress/integration/sign-up.js',
|
||||
'testingType': 'e2e',
|
||||
'usesDefaultFolder': true,
|
||||
'usesDefaultTestFiles': false,
|
||||
},
|
||||
{
|
||||
'relative': 'cypress/integration/spectacleBrowser.ts',
|
||||
'testingType': 'e2e',
|
||||
'usesDefaultFolder': true,
|
||||
'usesDefaultTestFiles': false,
|
||||
},
|
||||
{
|
||||
'relative': 'cypress/integration/someDir/someFile.js',
|
||||
'testingType': 'e2e',
|
||||
'usesDefaultFolder': true,
|
||||
'usesDefaultTestFiles': false,
|
||||
},
|
||||
])
|
||||
|
||||
// expect(actual.component).to.eql([
|
||||
// {
|
||||
// relative: 'src/Radio.spec.js',
|
||||
// usesDefaultFolder: false,
|
||||
// usesDefaultTestFiles: false,
|
||||
// testingType: 'component',
|
||||
// },
|
||||
// ])
|
||||
})
|
||||
|
||||
it('handles default folders', async () => {
|
||||
// CASE 1: E2E + CT, custom folders, default test files
|
||||
// We want to rename specs, but keep current folders.
|
||||
const cwd = await scaffoldMigrationProject('migration-e2e-component-default-everything')
|
||||
const json = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
|
||||
const actual = await getSpecs(cwd, json)
|
||||
|
||||
expect(actual.integration).to.eql([
|
||||
{
|
||||
relative: 'cypress/integration/foo.spec.ts',
|
||||
usesDefaultFolder: true,
|
||||
usesDefaultTestFiles: true,
|
||||
testingType: 'e2e',
|
||||
},
|
||||
{
|
||||
relative: 'cypress/integration/spec.ts',
|
||||
usesDefaultFolder: true,
|
||||
usesDefaultTestFiles: true,
|
||||
testingType: 'e2e',
|
||||
},
|
||||
])
|
||||
|
||||
expect(actual.component).to.eql([
|
||||
{
|
||||
relative: 'cypress/component/button.spec.js',
|
||||
usesDefaultFolder: true,
|
||||
usesDefaultTestFiles: true,
|
||||
testingType: 'component',
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('applyMigrationTransform', () => {
|
||||
describe('e2e spec', () => {
|
||||
it('handles default folders and extensions', async () => {
|
||||
const input: MigrationSpec = {
|
||||
relative: 'cypress/integration/button.spec.js',
|
||||
usesDefaultFolder: true,
|
||||
usesDefaultTestFiles: true,
|
||||
testingType: 'e2e',
|
||||
}
|
||||
|
||||
const expected: MigrationFile = {
|
||||
testingType: 'e2e',
|
||||
before: {
|
||||
relative: 'cypress/integration/button.spec.js',
|
||||
parts: [
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'cypress/',
|
||||
},
|
||||
{
|
||||
group: 'folder',
|
||||
'highlight': true,
|
||||
'text': 'integration',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': '/button',
|
||||
'group': 'fileName',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'preExtension',
|
||||
'text': '.spec.',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'js',
|
||||
},
|
||||
],
|
||||
},
|
||||
after: {
|
||||
relative: 'cypress/e2e/button.cy.js',
|
||||
parts: [
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'cypress/',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'folder',
|
||||
'text': 'e2e',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': '/button',
|
||||
'group': 'fileName',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'preExtension',
|
||||
'text': '.cy.',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'js',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
const result = applyMigrationTransform(input)
|
||||
|
||||
expect(result.before).to.eql(expected.before)
|
||||
expect(result.after).to.eql(expected.after)
|
||||
})
|
||||
|
||||
it('handles custom folder, default extension', async () => {
|
||||
const input: MigrationSpec = {
|
||||
relative: 'custom-folder/button.spec.js',
|
||||
usesDefaultFolder: false,
|
||||
usesDefaultTestFiles: true,
|
||||
testingType: 'e2e',
|
||||
}
|
||||
|
||||
const expected: MigrationFile = {
|
||||
testingType: 'e2e',
|
||||
before: {
|
||||
relative: 'custom-folder/button.spec.js',
|
||||
parts: [
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'custom-folder/button',
|
||||
'group': 'fileName',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'preExtension',
|
||||
'text': '.spec.',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'js',
|
||||
},
|
||||
],
|
||||
},
|
||||
after: {
|
||||
relative: 'custom-folder/button.cy.js',
|
||||
parts: [
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'custom-folder/button',
|
||||
'group': 'fileName',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'preExtension',
|
||||
'text': '.cy.',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'js',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
const result = applyMigrationTransform(input)
|
||||
|
||||
expect(result.before).to.eql(expected.before)
|
||||
expect(result.after).to.eql(expected.after)
|
||||
})
|
||||
|
||||
it('handles default folder, custom extension', async () => {
|
||||
const input: MigrationSpec = {
|
||||
relative: 'cypress/integration/foo.bar',
|
||||
usesDefaultFolder: true,
|
||||
usesDefaultTestFiles: false,
|
||||
testingType: 'e2e',
|
||||
}
|
||||
|
||||
const expected: MigrationFile = {
|
||||
testingType: 'e2e',
|
||||
before: {
|
||||
relative: 'cypress/integration/foo.bar',
|
||||
parts: [
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'cypress/',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'folder',
|
||||
'text': 'integration',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': '/foo.bar',
|
||||
'group': 'fileName',
|
||||
},
|
||||
],
|
||||
},
|
||||
after: {
|
||||
relative: 'cypress/e2e/foo.bar',
|
||||
parts: [
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'cypress/',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'folder',
|
||||
'text': 'e2e',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': '/foo.bar',
|
||||
'group': 'fileName',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
const result = applyMigrationTransform(input)
|
||||
|
||||
expect(result.before).to.eql(expected.before)
|
||||
expect(result.after).to.eql(expected.after)
|
||||
})
|
||||
|
||||
it('handles a spec named spec', () => {
|
||||
const input: MigrationSpec = {
|
||||
relative: 'cypress/integration/spec.js',
|
||||
usesDefaultFolder: true,
|
||||
usesDefaultTestFiles: true,
|
||||
testingType: 'e2e',
|
||||
}
|
||||
|
||||
const expected: MigrationFile = {
|
||||
testingType: 'e2e',
|
||||
before: {
|
||||
relative: 'cypress/integration/spec.js',
|
||||
parts: [
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'cypress/',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'folder',
|
||||
'text': 'integration',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': '/spec',
|
||||
'group': 'fileName',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'preExtension',
|
||||
'text': '.',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'js',
|
||||
},
|
||||
],
|
||||
},
|
||||
after: {
|
||||
relative: 'cypress/e2e/spec.cy.js',
|
||||
parts: [
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'cypress/',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'folder',
|
||||
'text': 'e2e',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': '/spec',
|
||||
'group': 'fileName',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'preExtension',
|
||||
'text': '.cy.',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'js',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
const result = applyMigrationTransform(input)
|
||||
|
||||
expect(result.before).to.eql(expected.before)
|
||||
expect(result.after).to.eql(expected.after)
|
||||
})
|
||||
|
||||
it('handles .test files', () => {
|
||||
const result = applyMigrationTransform(
|
||||
{
|
||||
relative: 'cypress/tests/api-bankaccounts.test.js',
|
||||
usesDefaultFolder: false,
|
||||
usesDefaultTestFiles: true,
|
||||
testingType: 'e2e',
|
||||
},
|
||||
)
|
||||
|
||||
const expected: MigrationFile = {
|
||||
testingType: 'e2e',
|
||||
before: {
|
||||
relative: 'cypress/tests/api-bankaccounts.test.js',
|
||||
parts: [
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'cypress/tests/api-bankaccounts',
|
||||
'group': 'fileName',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'preExtension',
|
||||
'text': '.test.',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'js',
|
||||
},
|
||||
],
|
||||
},
|
||||
after: {
|
||||
relative: 'cypress/tests/api-bankaccounts.cy.js',
|
||||
parts: [
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'cypress/tests/api-bankaccounts',
|
||||
'group': 'fileName',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'preExtension',
|
||||
'text': '.cy.',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'js',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
expect(result.before).to.eql(expected.before)
|
||||
expect(result.after).to.eql(expected.after)
|
||||
})
|
||||
})
|
||||
|
||||
describe('component spec', () => {
|
||||
it('handles default folders and extensions', async () => {
|
||||
const input: MigrationSpec = {
|
||||
relative: 'cypress/component/button.spec.tsx',
|
||||
usesDefaultFolder: true,
|
||||
usesDefaultTestFiles: true,
|
||||
testingType: 'component',
|
||||
}
|
||||
|
||||
const expected: MigrationFile = {
|
||||
testingType: 'component',
|
||||
before: {
|
||||
relative: 'cypress/component/button.spec.tsx',
|
||||
parts: [
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'cypress/component/button',
|
||||
'group': 'fileName',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'preExtension',
|
||||
'text': '.spec.',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'tsx',
|
||||
},
|
||||
],
|
||||
},
|
||||
after: {
|
||||
relative: 'cypress/component/button.cy.tsx',
|
||||
parts: [
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'cypress/component/button',
|
||||
'group': 'fileName',
|
||||
},
|
||||
{
|
||||
'highlight': true,
|
||||
group: 'preExtension',
|
||||
'text': '.cy.',
|
||||
},
|
||||
{
|
||||
'highlight': false,
|
||||
'text': 'tsx',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
const result = applyMigrationTransform(input)
|
||||
|
||||
expect(result.before).to.eql(expected.before)
|
||||
expect(result.after).to.eql(expected.after)
|
||||
})
|
||||
})
|
||||
|
||||
describe('component with custom folder, default testFiles', () => {
|
||||
it('handles custom folders and default extensions', async () => {
|
||||
const input: MigrationSpec = {
|
||||
relative: 'cypress/custom-component/button.spec.js',
|
||||
usesDefaultFolder: false,
|
||||
usesDefaultTestFiles: true,
|
||||
testingType: 'component',
|
||||
}
|
||||
|
||||
const expected: MigrationFile = {
|
||||
'testingType': 'component',
|
||||
'before': {
|
||||
'relative': 'cypress/custom-component/button.spec.js',
|
||||
'parts': [
|
||||
{
|
||||
'text': 'cypress/custom-component/button',
|
||||
'highlight': false,
|
||||
'group': 'fileName',
|
||||
},
|
||||
{
|
||||
'text': '.spec.',
|
||||
'highlight': true,
|
||||
'group': 'preExtension',
|
||||
},
|
||||
{
|
||||
'text': 'js',
|
||||
'highlight': false,
|
||||
},
|
||||
],
|
||||
},
|
||||
'after': {
|
||||
'relative': 'cypress/custom-component/button.cy.js',
|
||||
'parts': [
|
||||
{
|
||||
'text': 'cypress/custom-component/button',
|
||||
'highlight': false,
|
||||
'group': 'fileName',
|
||||
},
|
||||
{
|
||||
'text': '.cy.',
|
||||
'highlight': true,
|
||||
'group': 'preExtension',
|
||||
},
|
||||
{
|
||||
'text': 'js',
|
||||
'highlight': false,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
const actual = applyMigrationTransform(input)
|
||||
|
||||
expect(actual.before).to.eql(expected.before)
|
||||
expect(actual.after).to.eql(expected.after)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,561 +0,0 @@
|
||||
import snapshot from 'snap-shot-it'
|
||||
import path from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import {
|
||||
createConfigString,
|
||||
initComponentTestingMigration,
|
||||
ComponentTestingMigrationStatus,
|
||||
NonStandardMigrationError,
|
||||
supportFilesForMigration,
|
||||
reduceConfig,
|
||||
renameSupportFilePath,
|
||||
} from '../../../../src/sources/migration'
|
||||
import { expect } from 'chai'
|
||||
import { MigrationFile } from '../../../../src/sources'
|
||||
import { scaffoldMigrationProject, getSystemTestProject } from '../../helper'
|
||||
|
||||
const projectRoot = getSystemTestProject('migration-e2e-defaults')
|
||||
|
||||
describe('cypress.config.js generation', () => {
|
||||
it('generates correct config for component testing migration with custom testFiles glob', async () => {
|
||||
const config = {
|
||||
component: {
|
||||
testFiles: '**/*.spec.cy.{js,ts,jsx,tsx}',
|
||||
componentFolder: '.',
|
||||
},
|
||||
}
|
||||
|
||||
const generatedConfig = await createConfigString(config, {
|
||||
hasE2ESpec: false,
|
||||
hasComponentTesting: true,
|
||||
hasPluginsFile: false,
|
||||
projectRoot,
|
||||
isUsingTypeScript: false,
|
||||
shouldAddCustomE2ESpecPattern: false,
|
||||
isProjectUsingESModules: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('generates correct config for component testing migration with custom testFiles array of glob', async () => {
|
||||
const config = {
|
||||
e2e: {
|
||||
testFiles: ['**/*.spec.js', '**/*.test.js'],
|
||||
},
|
||||
}
|
||||
|
||||
const generatedConfig = await createConfigString(config, {
|
||||
hasE2ESpec: true,
|
||||
hasComponentTesting: false,
|
||||
hasPluginsFile: false,
|
||||
projectRoot,
|
||||
isUsingTypeScript: false,
|
||||
shouldAddCustomE2ESpecPattern: true,
|
||||
isProjectUsingESModules: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('should create a string when passed only a global option', async () => {
|
||||
const config: Partial<Cypress.Config> = {
|
||||
viewportWidth: 300,
|
||||
}
|
||||
|
||||
const generatedConfig = await createConfigString(config, {
|
||||
hasE2ESpec: true,
|
||||
hasComponentTesting: true,
|
||||
hasPluginsFile: true,
|
||||
projectRoot,
|
||||
isUsingTypeScript: false,
|
||||
shouldAddCustomE2ESpecPattern: false,
|
||||
isProjectUsingESModules: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('should create a string when passed only a e2e options', async () => {
|
||||
const config: Partial<Cypress.Config> = {
|
||||
e2e: {
|
||||
baseUrl: 'localhost:3000',
|
||||
},
|
||||
}
|
||||
|
||||
const generatedConfig = await createConfigString(config, {
|
||||
hasE2ESpec: true,
|
||||
hasComponentTesting: true,
|
||||
hasPluginsFile: true,
|
||||
projectRoot,
|
||||
isUsingTypeScript: false,
|
||||
shouldAddCustomE2ESpecPattern: false,
|
||||
isProjectUsingESModules: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('should create a string when passed only a component options', async () => {
|
||||
const generatedConfig = await createConfigString({
|
||||
component: {
|
||||
retries: 2,
|
||||
},
|
||||
}, {
|
||||
hasE2ESpec: true,
|
||||
hasComponentTesting: true,
|
||||
hasPluginsFile: true,
|
||||
projectRoot,
|
||||
isUsingTypeScript: false,
|
||||
shouldAddCustomE2ESpecPattern: false,
|
||||
isProjectUsingESModules: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('should create only a component entry when no e2e specs are detected', async () => {
|
||||
const generatedConfig = await createConfigString({}, {
|
||||
hasE2ESpec: false,
|
||||
hasComponentTesting: true,
|
||||
hasPluginsFile: true,
|
||||
projectRoot,
|
||||
isUsingTypeScript: false,
|
||||
shouldAddCustomE2ESpecPattern: false,
|
||||
isProjectUsingESModules: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('should create only an e2e entry when no component specs are detected', async () => {
|
||||
const generatedConfig = await createConfigString({}, {
|
||||
hasE2ESpec: true,
|
||||
hasComponentTesting: false,
|
||||
hasPluginsFile: true,
|
||||
projectRoot,
|
||||
isUsingTypeScript: false,
|
||||
shouldAddCustomE2ESpecPattern: false,
|
||||
isProjectUsingESModules: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('should create a string for a config with global, component, and e2e options', async () => {
|
||||
const config = {
|
||||
viewportWidth: 300,
|
||||
baseUrl: 'localhost:300',
|
||||
slowTestThreshold: 500,
|
||||
e2e: {
|
||||
retries: 2,
|
||||
},
|
||||
component: {
|
||||
retries: 1,
|
||||
},
|
||||
}
|
||||
|
||||
const generatedConfig = await createConfigString(config, {
|
||||
hasE2ESpec: true,
|
||||
hasComponentTesting: true,
|
||||
hasPluginsFile: true,
|
||||
projectRoot,
|
||||
isUsingTypeScript: false,
|
||||
shouldAddCustomE2ESpecPattern: false,
|
||||
isProjectUsingESModules: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('should create a string when passed an empty object', async () => {
|
||||
const config = {}
|
||||
|
||||
const generatedConfig = await createConfigString(config, {
|
||||
hasE2ESpec: true,
|
||||
hasComponentTesting: true,
|
||||
hasPluginsFile: true,
|
||||
projectRoot,
|
||||
isUsingTypeScript: false,
|
||||
shouldAddCustomE2ESpecPattern: false,
|
||||
isProjectUsingESModules: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('should create a string when passed an empty object for an ECMA Script project', async () => {
|
||||
const config = {}
|
||||
|
||||
const generatedConfig = await createConfigString(config, {
|
||||
hasE2ESpec: true,
|
||||
hasComponentTesting: true,
|
||||
hasPluginsFile: true,
|
||||
projectRoot,
|
||||
isUsingTypeScript: false,
|
||||
isProjectUsingESModules: true,
|
||||
shouldAddCustomE2ESpecPattern: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('should exclude fields that are no longer valid', async () => {
|
||||
const config = {
|
||||
'$schema': 'http://someschema.com',
|
||||
pluginsFile: './cypress/plugins/index.js',
|
||||
componentFolder: 'path/to/component/folder',
|
||||
}
|
||||
|
||||
const generatedConfig = await createConfigString(config, {
|
||||
hasE2ESpec: true,
|
||||
hasComponentTesting: true,
|
||||
hasPluginsFile: true,
|
||||
projectRoot,
|
||||
isUsingTypeScript: false,
|
||||
shouldAddCustomE2ESpecPattern: false,
|
||||
isProjectUsingESModules: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('should handle export default in plugins file', async () => {
|
||||
const projectRoot = getSystemTestProject('migration-e2e-export-default')
|
||||
const config = fs.readJsonSync(path.join(projectRoot, 'cypress.json'))
|
||||
|
||||
const generatedConfig = await createConfigString(config, {
|
||||
hasE2ESpec: true,
|
||||
hasComponentTesting: true,
|
||||
hasPluginsFile: true,
|
||||
projectRoot,
|
||||
isUsingTypeScript: true,
|
||||
shouldAddCustomE2ESpecPattern: false,
|
||||
isProjectUsingESModules: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('should maintain both root level and nested non-breaking options during migration', async () => {
|
||||
const projectRoot = getSystemTestProject('migration-e2e-component-default-everything')
|
||||
const config = await fs.readJson(path.join(projectRoot, 'cypress.json'))
|
||||
|
||||
const generatedConfig = await createConfigString(config, {
|
||||
hasE2ESpec: true,
|
||||
hasComponentTesting: true,
|
||||
hasPluginsFile: true,
|
||||
projectRoot,
|
||||
isUsingTypeScript: true,
|
||||
shouldAddCustomE2ESpecPattern: false,
|
||||
isProjectUsingESModules: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('should add custom specPattern if project has projectId', async () => {
|
||||
const projectRoot = getSystemTestProject('migration-e2e-defaults-with-projectId')
|
||||
const config = await fs.readJson(path.join(projectRoot, 'cypress.json'))
|
||||
|
||||
const generatedConfig = await createConfigString(config, {
|
||||
hasE2ESpec: true,
|
||||
hasComponentTesting: true,
|
||||
hasPluginsFile: true,
|
||||
projectRoot,
|
||||
isUsingTypeScript: true,
|
||||
shouldAddCustomE2ESpecPattern: true,
|
||||
isProjectUsingESModules: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('should not add custom specPattern if project has projectId and integrationFolder', async () => {
|
||||
const projectRoot = getSystemTestProject('migration-e2e-defaults-with-projectId')
|
||||
const config = await fs.readJson(path.join(projectRoot, 'cypress.json'))
|
||||
|
||||
config['integrationFolder'] = 'cypress/custom/e2e'
|
||||
|
||||
const generatedConfig = await createConfigString(config, {
|
||||
hasE2ESpec: true,
|
||||
hasComponentTesting: true,
|
||||
hasPluginsFile: true,
|
||||
projectRoot,
|
||||
isUsingTypeScript: true,
|
||||
shouldAddCustomE2ESpecPattern: true,
|
||||
isProjectUsingESModules: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
})
|
||||
|
||||
describe('supportFilesForMigrationGuide', () => {
|
||||
it('finds and represents correct supportFile migration guide', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration')
|
||||
const actual = await supportFilesForMigration(cwd)
|
||||
|
||||
const expected: MigrationFile = {
|
||||
testingType: 'e2e',
|
||||
before: {
|
||||
relative: 'cypress/support/index.js',
|
||||
parts: [
|
||||
{
|
||||
'text': 'cypress/support/',
|
||||
'highlight': false,
|
||||
},
|
||||
{
|
||||
'text': 'index',
|
||||
'highlight': true,
|
||||
group: 'supportFileName',
|
||||
},
|
||||
{
|
||||
'text': '.js',
|
||||
'highlight': false,
|
||||
},
|
||||
],
|
||||
},
|
||||
after: {
|
||||
relative: 'cypress/support/e2e.js',
|
||||
parts: [
|
||||
{
|
||||
'text': 'cypress/support/',
|
||||
'highlight': false,
|
||||
},
|
||||
{
|
||||
'text': 'e2e',
|
||||
'highlight': true,
|
||||
group: 'supportFileName',
|
||||
},
|
||||
{
|
||||
'text': '.js',
|
||||
'highlight': false,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
// expect(actual.before).to.eql(expected.before)
|
||||
expect(actual.after).to.eql(expected.after)
|
||||
})
|
||||
})
|
||||
|
||||
describe('renameSupportFilePath', () => {
|
||||
it('renames and keeps correct js extension', () => {
|
||||
const p = 'cypress/support/index.js'
|
||||
const actual = renameSupportFilePath(p)
|
||||
|
||||
expect(actual).to.eq('cypress/support/e2e.js')
|
||||
})
|
||||
|
||||
it('renames and keeps correct tsx extension', () => {
|
||||
const p = 'cypress/support/index.tsx'
|
||||
const actual = renameSupportFilePath(p)
|
||||
|
||||
expect(actual).to.eq('cypress/support/e2e.tsx')
|
||||
})
|
||||
|
||||
it('errors on non standard path', () => {
|
||||
const p = 'cypress/support/something-else.tsx'
|
||||
|
||||
expect(() => renameSupportFilePath(p)).to.throw(NonStandardMigrationError)
|
||||
})
|
||||
})
|
||||
|
||||
describe('initComponentTestingMigration', () => {
|
||||
it('calls callback with status each time file is removed', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration-component-testing-customized')
|
||||
|
||||
const delay = () => new Promise((res) => setTimeout(res, 250))
|
||||
|
||||
let updatedStatus: ComponentTestingMigrationStatus
|
||||
|
||||
const onFileMoved = (_status: ComponentTestingMigrationStatus) => {
|
||||
updatedStatus = _status
|
||||
}
|
||||
|
||||
const { status, watcher } = await initComponentTestingMigration(
|
||||
cwd,
|
||||
'src',
|
||||
['**/*.{js,tsx}'],
|
||||
onFileMoved,
|
||||
)
|
||||
|
||||
expect(status.completed).to.be.false
|
||||
expect(status.files).to.eql(new Map([
|
||||
['src/button.spec.js', { moved: false,
|
||||
relative: 'src/button.spec.js',
|
||||
}],
|
||||
['src/input-spec.tsx', {
|
||||
moved: false,
|
||||
relative: 'src/input-spec.tsx',
|
||||
}],
|
||||
]))
|
||||
|
||||
fs.moveSync(
|
||||
path.join(cwd, 'src', 'input-spec.tsx'),
|
||||
path.join(cwd, 'src', 'input.cy.tsx'),
|
||||
)
|
||||
|
||||
// give watcher time to trigger
|
||||
await delay()
|
||||
|
||||
expect(updatedStatus).to.eql({
|
||||
files: new Map([
|
||||
['src/button.spec.js', { moved: false, relative: 'src/button.spec.js' }],
|
||||
['src/input-spec.tsx', { moved: true, relative: 'src/input-spec.tsx' }],
|
||||
]),
|
||||
completed: false,
|
||||
})
|
||||
|
||||
fs.moveSync(
|
||||
path.join(cwd, 'src', 'button.spec.js'),
|
||||
path.join(cwd, 'src', 'button.cy.js'),
|
||||
)
|
||||
|
||||
// give watcher time to trigger
|
||||
await delay()
|
||||
|
||||
expect(updatedStatus).to.eql({
|
||||
files: new Map([
|
||||
['src/button.spec.js', { moved: true, relative: 'src/button.spec.js' }],
|
||||
['src/input-spec.tsx', { moved: true, relative: 'src/input-spec.tsx' }],
|
||||
]),
|
||||
completed: true,
|
||||
})
|
||||
|
||||
await watcher.close()
|
||||
})
|
||||
})
|
||||
|
||||
describe('reduceConfig', () => {
|
||||
const options = {
|
||||
hasComponentTesting: false,
|
||||
hasE2ESpec: false,
|
||||
hasPluginsFile: false,
|
||||
projectRoot: '',
|
||||
isUsingTypeScript: false,
|
||||
isProjectUsingESModules: false,
|
||||
shouldAddCustomE2ESpecPattern: false,
|
||||
}
|
||||
|
||||
it('should move the testFiles field to e2e and component', () => {
|
||||
const config = { testFiles: '**/**.cy.js' }
|
||||
const newConfig = reduceConfig(config, options)
|
||||
|
||||
expect(newConfig.e2e.specPattern).to.eq('cypress/e2e/**/**.cy.js')
|
||||
expect(newConfig.component.specPattern).to.eq('**/**.cy.js')
|
||||
})
|
||||
|
||||
it('should update integration folder for e2e when is set to default', () => {
|
||||
const config = { testFiles: '*.spec.js', integrationFolder: 'cypress/integration' }
|
||||
const newConfig = reduceConfig(config, options)
|
||||
|
||||
expect(newConfig.e2e.specPattern).to.eq(`cypress/e2e/${config.testFiles}`)
|
||||
})
|
||||
|
||||
it('should combine componentFolder and integrationFolder with testFiles field in component', () => {
|
||||
const config = { testFiles: '**/**.cy.js', componentFolder: 'src', integrationFolder: 'cypress/src' }
|
||||
const newConfig = reduceConfig(config, options)
|
||||
|
||||
expect(newConfig.component.specPattern).to.eq('src/**/**.cy.js')
|
||||
expect(newConfig.e2e.specPattern).to.eq(`${config.integrationFolder}/${config.testFiles}`)
|
||||
})
|
||||
|
||||
it('should combine nested componentFolder and integrationFolder with testFiles field in component', () => {
|
||||
const config = {
|
||||
testFiles: '**/**.cy.js',
|
||||
component: {
|
||||
componentFolder: 'src',
|
||||
},
|
||||
e2e: {
|
||||
integrationFolder: 'cypress/src',
|
||||
},
|
||||
}
|
||||
const newConfig = reduceConfig(config, options)
|
||||
|
||||
expect(newConfig.component.componentFolder).to.not.exist
|
||||
expect(newConfig.component.specPattern).to.eq('src/**/**.cy.js')
|
||||
expect(newConfig.e2e.specPattern).to.eq(`${config.e2e.integrationFolder}/${config.testFiles}`)
|
||||
})
|
||||
|
||||
it('should add custom integrationFolder to default testFiles if testFiles is not present', () => {
|
||||
const config = { integrationFolder: 'cypress/custom-integration' }
|
||||
const newConfig = reduceConfig(config, options)
|
||||
|
||||
expect(newConfig.e2e.specPattern).to.eq(`${config.integrationFolder}/**/*.cy.{js,jsx,ts,tsx}`)
|
||||
})
|
||||
|
||||
it('should add custom integrationFolder to default testFiles if testFiles is not present and shouldAddCustomE2ESpecPattern is true', () => {
|
||||
const config = { integrationFolder: 'cypress/custom-integration' }
|
||||
const newConfig = reduceConfig(config, { ...options, shouldAddCustomE2ESpecPattern: true })
|
||||
|
||||
expect(newConfig.e2e.specPattern).to.eq(`${config.integrationFolder}/**/*.{js,jsx,ts,tsx}`)
|
||||
})
|
||||
|
||||
it('should combine testFiles with highest specificity', () => {
|
||||
const config = {
|
||||
testFiles: '**/**.cy.js',
|
||||
componentFolder: 'lower/specificity',
|
||||
integrationFolder: 'lower/specificity',
|
||||
component: {
|
||||
componentFolder: 'higher/specificity',
|
||||
},
|
||||
e2e: {
|
||||
integrationFolder: 'higher/specificity',
|
||||
},
|
||||
}
|
||||
const newConfig = reduceConfig(config, options)
|
||||
|
||||
expect(newConfig.component.specPattern).to.eq(`higher/specificity/**/**.cy.js`)
|
||||
expect(newConfig.e2e.specPattern).to.eq(`${config.e2e.integrationFolder}/${config.testFiles}`)
|
||||
})
|
||||
|
||||
it('should exclude integrationFolder and componentFolder', () => {
|
||||
const config = {
|
||||
componentFolder: 'src',
|
||||
integrationFolder: 'cypress/integration',
|
||||
}
|
||||
|
||||
const newConfig = reduceConfig(config, options)
|
||||
|
||||
// @ts-ignore field not on ConfigOptions type
|
||||
expect(newConfig.global.componentFolder).to.not.exist
|
||||
// @ts-ignore field not on ConfigOptions type
|
||||
expect(newConfig.global.integrationFolder).to.not.exist
|
||||
})
|
||||
|
||||
it('should rename ignoreTestFiles to excludeSpecPattern', () => {
|
||||
const config = { ignoreTestFiles: 'path/to/**/*.js' }
|
||||
const newConfig = reduceConfig(config, options)
|
||||
|
||||
expect(newConfig.e2e.excludeSpecPattern).to.eq(config.ignoreTestFiles)
|
||||
expect(newConfig.component.excludeSpecPattern).to.eq(config.ignoreTestFiles)
|
||||
})
|
||||
|
||||
it('should nest supportFile under component and e2e', () => {
|
||||
const config = { supportFile: 'cypress/support/mySupportFile.js' }
|
||||
const newConfig = reduceConfig(config, options)
|
||||
|
||||
expect(newConfig.e2e.supportFile).to.eq(config.supportFile)
|
||||
})
|
||||
|
||||
it('should not add supportFile if it is the default one', () => {
|
||||
expect(reduceConfig({ supportFile: null }, options).e2e.supportFile).to.not.exist
|
||||
expect(reduceConfig({ supportFile: undefined }, options).e2e.supportFile).to.not.exist
|
||||
expect(reduceConfig({ supportFile: 'cypress/support' }, options).e2e.supportFile).to.not.exist
|
||||
expect(reduceConfig({ supportFile: 'cypress/support/index' }, options).e2e.supportFile).to.not.exist
|
||||
expect(reduceConfig({ supportFile: 'cypress/support/index.js' }, options).e2e.supportFile).to.not.exist
|
||||
expect(reduceConfig({ supportFile: './cypress/support/index.js' }, options).e2e.supportFile).to.not.exist
|
||||
expect(reduceConfig({ supportFile: '../cypress/support/index.js' }, options).e2e.supportFile).to.not.exist
|
||||
})
|
||||
|
||||
it('should exclude the pluginsFile', () => {
|
||||
const config = { pluginsFile: 'cypress/plugins/index.js' }
|
||||
const newConfig = reduceConfig(config, options)
|
||||
|
||||
// @ts-ignore field not on ConfigOptions type
|
||||
expect(newConfig.global.pluginsFile).to.not.exist
|
||||
})
|
||||
})
|
||||
@@ -1,63 +0,0 @@
|
||||
import { expect } from 'chai'
|
||||
import {
|
||||
formatMigrationFile,
|
||||
} from '../../../../src/sources/migration/format'
|
||||
import { regexps, supportFileRegexps } from '../../../../src/sources/migration/regexps'
|
||||
|
||||
describe('formatMigrationFile', () => {
|
||||
describe('e2e - defaultFolderDefaultTestFiles', () => {
|
||||
it('breaks pre-migration spec into parts', () => {
|
||||
const spec = 'cypress/integration/app.spec.js'
|
||||
const re = new RegExp(regexps.e2e.before.defaultFolderDefaultTestFiles)
|
||||
const actual = formatMigrationFile(spec, re, { shouldMigratePreExtension: true })
|
||||
|
||||
expect(actual).to.eql([
|
||||
{ text: 'cypress/', highlight: false },
|
||||
{ text: 'integration', highlight: true, group: 'folder' },
|
||||
{ text: '/app', highlight: false, group: 'fileName' },
|
||||
{ text: '.spec.', highlight: true, group: 'preExtension' },
|
||||
{ text: 'js', highlight: false },
|
||||
])
|
||||
})
|
||||
|
||||
it('do not highlight the preExtension when migratePreExtension is false', () => {
|
||||
const spec = 'cypress/integration/app.spec.js'
|
||||
const re = new RegExp(regexps.e2e.before.defaultFolderDefaultTestFiles)
|
||||
const actual = formatMigrationFile(spec, re, { shouldMigratePreExtension: false })
|
||||
|
||||
expect(actual).to.eql([
|
||||
{ text: 'cypress/', highlight: false },
|
||||
{ text: 'integration', highlight: true, group: 'folder' },
|
||||
{ text: '/app', highlight: false, group: 'fileName' },
|
||||
{ text: '.spec.', highlight: false, group: 'preExtension' },
|
||||
{ text: 'js', highlight: false },
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
;['js', 'ts'].forEach((ext) => {
|
||||
it(`handles e2e support pre file migration [${ext}]`, () => {
|
||||
const file = `cypress/support/index.${ext}`
|
||||
const re = new RegExp(supportFileRegexps.e2e.beforeRegexp)
|
||||
const actual = formatMigrationFile(file, re, { shouldMigratePreExtension: true })
|
||||
|
||||
expect(actual).to.eql([
|
||||
{ text: 'cypress/support/', highlight: false },
|
||||
{ text: 'index', highlight: true, group: 'supportFileName' },
|
||||
{ text: `.${ext}`, highlight: false },
|
||||
])
|
||||
})
|
||||
|
||||
it(`handles e2e support post file migration [${ext}]`, () => {
|
||||
const file = `cypress/support/e2e.${ext}`
|
||||
const re = new RegExp(supportFileRegexps.e2e.afterRegexp)
|
||||
const actual = formatMigrationFile(file, re, { shouldMigratePreExtension: true })
|
||||
|
||||
expect(actual).to.eql([
|
||||
{ text: 'cypress/support/', highlight: false },
|
||||
{ text: 'e2e', highlight: true, group: 'supportFileName' },
|
||||
{ text: `.${ext}`, highlight: false },
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,71 +0,0 @@
|
||||
import { expect } from 'chai'
|
||||
import fs from 'fs-extra'
|
||||
import path from 'path'
|
||||
import { processConfigViaLegacyPlugins } from '../../../../src/actions'
|
||||
import { getSystemTestProject } from '../../helper'
|
||||
|
||||
describe('processConfigViaLegacyPlugins', () => {
|
||||
it('executes legacy plugins and returns modified config', async () => {
|
||||
const projectRoot = getSystemTestProject('migration-e2e-plugins-modify-config')
|
||||
const result = await processConfigViaLegacyPlugins(projectRoot, {})
|
||||
|
||||
expect(result).to.eql({
|
||||
'component': {
|
||||
'testFiles': '**/*.spec.ts',
|
||||
},
|
||||
'e2e': {
|
||||
'testFiles': '**/*.js',
|
||||
},
|
||||
'integrationFolder': 'tests/e2e',
|
||||
'retries': {
|
||||
'openMode': 0,
|
||||
'runMode': 1,
|
||||
},
|
||||
'testFiles': '**/*.spec.js',
|
||||
})
|
||||
})
|
||||
|
||||
it('executes legacy plugins and returns without change if pluginsFile returns nothing', async () => {
|
||||
const projectRoot = getSystemTestProject('migration-e2e-defaults')
|
||||
const configFile = fs.readJsonSync(path.join(projectRoot, 'cypress.json'))
|
||||
const result = await processConfigViaLegacyPlugins(projectRoot, configFile)
|
||||
|
||||
expect(result).to.eql(configFile)
|
||||
})
|
||||
|
||||
it('works with cypress/plugins/index.ts and export default', async () => {
|
||||
const projectRoot = getSystemTestProject('migration-e2e-export-default')
|
||||
const result = await processConfigViaLegacyPlugins(projectRoot, {
|
||||
retries: 10,
|
||||
viewportWidth: 8888,
|
||||
})
|
||||
|
||||
expect(result).to.eql({
|
||||
retries: 10,
|
||||
viewportWidth: 1111, // mutated in plugins file
|
||||
})
|
||||
})
|
||||
|
||||
it('catches error', (done) => {
|
||||
const projectRoot = getSystemTestProject('migration-e2e-legacy-plugins-throws-error')
|
||||
|
||||
processConfigViaLegacyPlugins(projectRoot, {})
|
||||
.catch((e) => {
|
||||
expect(e.originalError.message).to.eq('Uh oh, there was an error!')
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('handles pluginsFile: false', async () => {
|
||||
const projectRoot = getSystemTestProject('launchpad')
|
||||
const result = await processConfigViaLegacyPlugins(projectRoot, {
|
||||
retries: 10,
|
||||
viewportWidth: 8888,
|
||||
})
|
||||
|
||||
expect(result).to.eql({
|
||||
retries: 10,
|
||||
viewportWidth: 8888,
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,129 +0,0 @@
|
||||
import { scaffoldMigrationProject } from '../../helper'
|
||||
import path from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import {
|
||||
getStepsForMigration,
|
||||
shouldShowAutoRenameStep,
|
||||
Step,
|
||||
} from '../../../../src/sources/migration/shouldShowSteps'
|
||||
import { expect } from 'chai'
|
||||
|
||||
describe('shouldShowAutoRenameStep', () => {
|
||||
it('true when testFiles is custom, but default integration folder', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration')
|
||||
const config = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
const actual = await shouldShowAutoRenameStep(cwd, config)
|
||||
|
||||
expect(actual).to.be.true
|
||||
})
|
||||
|
||||
it('true when testFiles is custom, but default integration folder', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration-e2e-component-default-test-files')
|
||||
const config = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
const actual = await shouldShowAutoRenameStep(cwd, config)
|
||||
|
||||
expect(actual).to.be.true
|
||||
})
|
||||
|
||||
it('false when integrationFolder and testFiles are custom', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration-e2e-fully-custom')
|
||||
const config = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
const actual = await shouldShowAutoRenameStep(cwd, config)
|
||||
|
||||
expect(actual).to.be.false
|
||||
})
|
||||
|
||||
it('true when integrationFolder custom and testFiles default', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration-e2e-custom-integration')
|
||||
const config = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
const actual = await shouldShowAutoRenameStep(cwd, config)
|
||||
|
||||
expect(actual).to.be.true
|
||||
})
|
||||
|
||||
it('true when integrationFolder default and testFiles custom', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration-e2e-custom-test-files')
|
||||
const config = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
const actual = await shouldShowAutoRenameStep(cwd, config)
|
||||
|
||||
expect(actual).to.be.true
|
||||
})
|
||||
|
||||
it('true when integrationFolder and testFiles default and spec exists', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration-e2e-defaults')
|
||||
const config = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
const actual = await shouldShowAutoRenameStep(cwd, config)
|
||||
|
||||
expect(actual).to.be.true
|
||||
})
|
||||
|
||||
it('false when integrationFolder and testFiles default by no spec to migrate', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration-e2e-defaults-no-specs')
|
||||
const config = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
const actual = await shouldShowAutoRenameStep(cwd, config)
|
||||
|
||||
expect(actual).to.be.false
|
||||
})
|
||||
})
|
||||
|
||||
describe('getStepsForMigration', () => {
|
||||
it('only returns configFile step for highly custom project', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration-e2e-fully-custom')
|
||||
const config = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
|
||||
const actual = await getStepsForMigration(cwd, config, true)
|
||||
const expected: Step[] = ['configFile']
|
||||
|
||||
expect(actual).to.eql(expected)
|
||||
})
|
||||
|
||||
it('returns all e2e steps for project with all defaults', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration-e2e-defaults')
|
||||
const config = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
|
||||
const actual = await getStepsForMigration(cwd, config, true)
|
||||
const expected: Step[] = ['renameAuto', 'renameSupport', 'configFile']
|
||||
|
||||
expect(actual).to.eql(expected)
|
||||
})
|
||||
|
||||
it('returns all e2e steps for project with all defaults + custom testFiles', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration-e2e-custom-test-files')
|
||||
const config = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
|
||||
const actual = await getStepsForMigration(cwd, config, true)
|
||||
const expected: Step[] = ['renameAuto', 'renameSupport', 'configFile']
|
||||
|
||||
expect(actual).to.eql(expected)
|
||||
})
|
||||
|
||||
it('returns all steps for default integrationFolder, custom testFiles', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration')
|
||||
const config = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
|
||||
const actual = await getStepsForMigration(cwd, config, true)
|
||||
const expected: Step[] = ['renameAuto', 'renameSupport', 'configFile', 'setupComponent']
|
||||
|
||||
expect(actual).to.eql(expected)
|
||||
})
|
||||
|
||||
it('returns all steps except supportFile for default CT project', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration-component-testing-defaults')
|
||||
const config = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
|
||||
const actual = await getStepsForMigration(cwd, config, true)
|
||||
const expected: Step[] = ['renameAuto', 'renameManual', 'configFile', 'setupComponent']
|
||||
|
||||
expect(actual).to.eql(expected)
|
||||
})
|
||||
|
||||
it('returns component steps for component testing project (no e2e)', async () => {
|
||||
const cwd = await scaffoldMigrationProject('migration-component-testing-customized')
|
||||
const config = fs.readJsonSync(path.join(cwd, 'cypress.json'))
|
||||
|
||||
const actual = await getStepsForMigration(cwd, config, true)
|
||||
const expected: Step[] = ['configFile', 'setupComponent']
|
||||
|
||||
expect(actual).to.eql(expected)
|
||||
})
|
||||
})
|
||||
@@ -777,17 +777,6 @@ describe('network stubbing', { retries: 15 }, function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('errors on matchUrlAgainstPath usage', function (done) {
|
||||
testFail((err) => {
|
||||
expect(err.message).to.include('`matchUrlAgainstPath` was removed in Cypress 7.0.0')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
// @ts-ignore
|
||||
cy.intercept({ matchUrlAgainstPath: true })
|
||||
})
|
||||
|
||||
it('errors on unknown prop', function (done) {
|
||||
testFail((err) => {
|
||||
expect(err.message).to.include('An unknown \`RouteMatcher\` property was passed: `wrong`')
|
||||
@@ -1023,7 +1012,7 @@ describe('network stubbing', { retries: 15 }, function () {
|
||||
context('cors preflight', function () {
|
||||
// a different domain from the page own domain
|
||||
// NOTE: this domain is redirected back to the local host test server
|
||||
// using "hosts" setting in the "cypress.json" file
|
||||
// using "hosts" setting in the "cypress.config.js" file
|
||||
let corsUrl = 'http://diff.foobar.com:3501/no-cors'
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -158,11 +158,6 @@ function validateRouteMatcherOptions (routeMatcher: RouteMatcherOptions): { isVa
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
if (routeMatcher.matchUrlAgainstPath) {
|
||||
return err(`\`matchUrlAgainstPath\` was removed in Cypress 7.0.0 and should be removed from your tests. Your tests will run the same. For more information, visit https://on.cypress.io/migration-guide`)
|
||||
}
|
||||
|
||||
for (const prop in routeMatcher) {
|
||||
if (!allRouteMatcherFields.includes(prop)) {
|
||||
return err(`An unknown \`RouteMatcher\` property was passed: \`${String(prop)}\`\n\nValid \`RouteMatcher\` properties are: ${allRouteMatcherFields.join(', ')}`)
|
||||
|
||||
@@ -60,9 +60,5 @@
|
||||
<span style="color:#e05561"><span style="color:#4f5666"> - <span style="color:#e05561"><span style="color:#4ec4ff">edge<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4f5666"> - <span style="color:#e05561"><span style="color:#4ec4ff">edge:beta<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4f5666"> - <span style="color:#e05561"><span style="color:#4ec4ff">edge:canary<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4f5666"> - <span style="color:#e05561"><span style="color:#4ec4ff">edge:dev<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Note: In Cypress version 4.0.0, Canary must be launched as <span style="color:#de73ff">chrome:canary<span style="color:#e05561">, not <span style="color:#de73ff">canary<span style="color:#e05561">.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">See https://on.cypress.io/migration-guide for more information on breaking changes in 4.0.0.<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
<span style="color:#e05561"><span style="color:#4f5666"> - <span style="color:#e05561"><span style="color:#4ec4ff">edge:dev<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -36,7 +36,7 @@
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">You passed the <span style="color:#de73ff">--record<span style="color:#e05561"> flag but this project has not been setup to record.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">This project is missing the <span style="color:#e5e510">projectId<span style="color:#e05561"> inside of: <span style="color:#4ec4ff">/path/to/cypress.json<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">This project is missing the <span style="color:#e5e510">projectId<span style="color:#e05561"> inside of: <span style="color:#4ec4ff">/path/to/cypress.config.js<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">We cannot uniquely identify this project without this id.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">We could not find a Cypress Cloud project with the projectId: <span style="color:#e5e510">project-id-123<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">This <span style="color:#de73ff">projectId<span style="color:#e05561"> came from your <span style="color:#4ec4ff">/path/to/cypress.json<span style="color:#e05561"> file or an environment variable.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">This <span style="color:#de73ff">projectId<span style="color:#e05561"> came from your <span style="color:#4ec4ff">/path/to/cypress.config.js<span style="color:#e05561"> file or an environment variable.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Please log into Cypress Cloud and find your project.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">componentFolder<span style="color:#e05561"> configuration option is now invalid when set on the config object in Cypress version 10.0.0.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">It is now renamed to <span style="color:#e5e510">specPattern<span style="color:#e05561"> and configured separately as a component testing property: <span style="color:#de73ff">component.specPattern<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">{<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> component: {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> specPattern: '...',<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> },<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/migration-guide<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,49 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">To run component tests, Cypress needs you to configure the <span style="color:#e5e510">dev-server:start<span style="color:#e05561"> event.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Please update this file: <span style="color:#4ec4ff">/path/to/plugins/file.js<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">module.exports = (on, config) => {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> on('dev-server:start', () => {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> <span style="color:#4f5666">// start dev server here<span style="color:#4ec4ff"><span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> return startDevServer(...)<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> }<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/component-testing<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -34,9 +34,9 @@
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">specPattern<span style="color:#e05561"> configuration option is now invalid when set from the root of the config object in Cypress version 10.0.0.<span style="color:#e6e6e6">
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">specPattern<span style="color:#e05561"> configuration option is invalid when set from the root of the config object.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">It is now configured separately as a testing type property: <span style="color:#de73ff">e2e.specPattern<span style="color:#e05561"> and <span style="color:#de73ff">component.specPattern<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Set it within a testing type property: <span style="color:#de73ff">e2e.specPattern<span style="color:#e05561"> and <span style="color:#de73ff">component.specPattern<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">{<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> e2e: {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
@@ -45,7 +45,5 @@
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> component: {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> specPattern: '...',<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> },<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/migration-guide<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -34,15 +34,13 @@
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">indexHtmlFile<span style="color:#e05561"> configuration option is now invalid when set from the root of the config object in Cypress version 10.0.0.<span style="color:#e6e6e6">
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">indexHtmlFile<span style="color:#e05561"> configuration option is invalid when set from the root of the config object.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">It is now configured separately as a testing type property: <span style="color:#de73ff">component.indexHtmlFile<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Set it within a testing type property: <span style="color:#de73ff">component.indexHtmlFile<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">{<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> component: {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> indexHtmlFile: '...',<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> }<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/migration-guide<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -34,15 +34,13 @@
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">baseUrl<span style="color:#e05561"> configuration option is now invalid when set from the root of the config object in Cypress version 10.0.0.<span style="color:#e6e6e6">
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">baseUrl<span style="color:#e05561"> configuration option is invalid when set from the root of the config object.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">It is now configured separately as a testing type property: <span style="color:#de73ff">e2e.baseUrl<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Set it within a testing type property: <span style="color:#de73ff">e2e.baseUrl<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">{<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> e2e: {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> baseUrl: '...',<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> }<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/migration-guide<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -42,7 +42,5 @@
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> e2e: {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> baseUrl: '...',<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> }<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/migration-guide<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -42,7 +42,5 @@
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> e2e: {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> indexHtmlFile: '...',<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> }<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/migration-guide<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,45 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">There is a <span style="color:#e5e510">cypress.json<span style="color:#e05561"> file at the path: <span style="color:#4ec4ff">/path/to/projectRoot<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Cypress version 10.0.0 no longer supports <span style="color:#e5e510">cypress.json<span style="color:#e05561">.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Please run <span style="color:#4ec4ff">cypress open<span style="color:#e05561"> to launch the migration tool to migrate to <span style="color:#de73ff">cypress.config.{js,ts,mjs,cjs}<span style="color:#e05561">.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/migration-guide<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -36,5 +36,5 @@
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">Could not find a Cypress configuration file.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">We looked but did not find a <span style="color:#e5e510">cypress.json<span style="color:#e05561"> file in this folder: <span style="color:#4ec4ff">/path/to/project/root<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span>
|
||||
<span style="color:#e05561">We looked but did not find a <span style="color:#e5e510">cypress.config.js<span style="color:#e05561"> file in this folder: <span style="color:#4ec4ff">/path/to/project/root<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -34,7 +34,7 @@
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">Your <span style="color:#e5e510">configFile<span style="color:#e05561"> at <span style="color:#4ec4ff">cypress.json<span style="color:#e05561"> set an invalid value:<span style="color:#e6e6e6">
|
||||
<body><pre><span style="color:#e05561">Your <span style="color:#e5e510">configFile<span style="color:#e05561"> at <span style="color:#4ec4ff">cypress.config.js<span style="color:#e05561"> set an invalid value:<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Expected <span style="color:#e5e510">defaultCommandTimeout<span style="color:#e05561"> to be a number.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">Your <span style="color:#e5e510">configFile<span style="color:#e05561"> at <span style="color:#4ec4ff">cypress.json<span style="color:#e05561"> set an invalid value:<span style="color:#e6e6e6">
|
||||
<body><pre><span style="color:#e05561">Your <span style="color:#e5e510">configFile<span style="color:#e05561"> at <span style="color:#4ec4ff">cypress.config.js<span style="color:#e05561"> set an invalid value:<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Expected <span style="color:#e5e510">defaultCommandTimeout<span style="color:#e05561"> to be a number.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">Your <span style="color:#e5e510">configFile<span style="color:#e05561"> at <span style="color:#4ec4ff">cypress.json<span style="color:#e05561"> set an invalid value:<span style="color:#e6e6e6">
|
||||
<body><pre><span style="color:#e05561">Your <span style="color:#e5e510">configFile<span style="color:#e05561"> at <span style="color:#4ec4ff">cypress.config.js<span style="color:#e05561"> set an invalid value:<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Expected <span style="color:#e5e510">defaultCommandTimeout<span style="color:#e05561"> to be a number.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">Your <span style="color:#e5e510">configFile<span style="color:#e05561"> at <span style="color:#4ec4ff">cypress.json<span style="color:#e05561"> set an invalid value:<span style="color:#e6e6e6">
|
||||
<body><pre><span style="color:#e05561">Your <span style="color:#e5e510">configFile<span style="color:#e05561"> at <span style="color:#4ec4ff">cypress.config.js<span style="color:#e05561"> set an invalid value:<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">The error occurred while validating the <span style="color:#de73ff">browsers<span style="color:#e05561"> list.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">Your <span style="color:#e5e510">configFile<span style="color:#e05561"> at <span style="color:#4ec4ff">cypress.json<span style="color:#e05561"> set an invalid value:<span style="color:#e6e6e6">
|
||||
<body><pre><span style="color:#e05561">Your <span style="color:#e5e510">configFile<span style="color:#e05561"> at <span style="color:#4ec4ff">cypress.config.js<span style="color:#e05561"> set an invalid value:<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Expected <span style="color:#e5e510">defaultCommandTimeout<span style="color:#e05561"> to be a number.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">Your <span style="color:#e5e510">configFile<span style="color:#e05561"> as <span style="color:#4ec4ff">cypress.json<span style="color:#e05561"> set an invalid value:<span style="color:#e6e6e6">
|
||||
<body><pre><span style="color:#e05561">Your <span style="color:#e5e510">configFile<span style="color:#e05561"> as <span style="color:#4ec4ff">cypress.config.js<span style="color:#e05561"> set an invalid value:<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e5e510">`something` was not right<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,46 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">experimentalComponentTesting<span style="color:#e05561"> configuration option was removed in Cypress version 7.0.0.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Please remove this flag from: <span style="color:#4ec4ff">/path/to/cypress.config.js<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Component Testing is now a supported testing type. You can run your component tests with:<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"> <span style="color:#4f5666">$<span style="color:#e05561"> <span style="color:#4ec4ff">cypress open --component<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/migration-guide<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,40 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">experimentalNetworkStubbing<span style="color:#e05561"> configuration option was removed in Cypress version 6.0.0.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">It is no longer necessary for using <span style="color:#de73ff">cy.intercept()<span style="color:#e05561">. You can safely remove this option from your config.<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,40 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">experimentalRunEvents<span style="color:#e05561"> configuration option was removed in Cypress version 6.7.0. It is no longer necessary when listening to run events in the plugins file.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">You can safely remove this option from your config.<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,42 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">experimentalGetCookiesSameSite<span style="color:#e05561"> configuration option was removed in Cypress version 5.0.0.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Returning the <span style="color:#de73ff">sameSite<span style="color:#e05561"> property is now the default behavior of the <span style="color:#de73ff">cy.cookie<span style="color:#e05561"> commands.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">You can safely remove this option from your config.<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,42 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">experimentalSessionSupport<span style="color:#e05561"> configuration option was removed in Cypress version 9.6.0.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">You can safely remove this option from your config.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/session<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,40 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">experimentalShadowDomSupport<span style="color:#e05561"> configuration option was removed in Cypress version 5.2.0. It is no longer necessary when utilizing the <span style="color:#de73ff">includeShadowDom<span style="color:#e05561"> option.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">You can safely remove this option from your config.<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,44 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">We're ending the experimental phase of Cypress Studio in Cypress version 10.0.0.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">If you don't think you can live without Studio or you'd like to learn about how to work around its removal, please join the discussion here: http://on.cypress.io/studio-removal<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Your feedback will help us factor in product decisions that may see Studio return in a future release.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">You can safely remove the <span style="color:#e5e510">experimentalStudio<span style="color:#e05561"> configuration option from your config.<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,42 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">firefoxGcInterval<span style="color:#e05561"> configuration option was removed in Cypress version 8.0.0. It was introduced to work around a bug in Firefox 79 and below.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Since Cypress no longer supports Firefox 85 and below in Cypress Cypress version 8.0.0, this option was removed.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">You can safely remove this option from your config.<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,45 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">We've detected that the incompatible plugin <span style="color:#e5e510">cypress-plugin-retries<span style="color:#e05561"> is installed at: <span style="color:#4ec4ff">./path/to/cypress-plugin-retries<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Test retries is now natively supported in Cypress version 5.0.0.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Remove the plugin from your dependencies to silence this warning.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/test-retries<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,48 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">integrationFolder<span style="color:#e05561"> configuration option is now invalid when set on the config object in Cypress version 10.0.0.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">It is now renamed to <span style="color:#e5e510">specPattern<span style="color:#e05561"> and configured separately as a end to end testing property: <span style="color:#de73ff">e2e.specPattern<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">{<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> e2e: {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> specPattern: '...',<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> },<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/migration-guide<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,45 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">Your <span style="color:#e5e510">cypress/plugins/index.js<span style="color:#e05561"> file threw an error. <span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Please ensure your pluginsFile is valid and relaunch the migration tool to migrate to Cypress version 10.0.0.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#c062de"><span style="color:#e6e6e6">
|
||||
<span style="color:#c062de">Error: fail whale<span style="color:#e6e6e6">
|
||||
<span style="color:#c062de"> at makeErr (cypress/packages/errors/test/unit/visualSnapshotErrors_spec.ts)<span style="color:#e6e6e6">
|
||||
<span style="color:#c062de"> at LEGACY_CONFIG_ERROR_DURING_MIGRATION (cypress/packages/errors/test/unit/visualSnapshotErrors_spec.ts)<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,43 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">There is both a <span style="color:#e5e510">cypress.json<span style="color:#e05561"> and a <span style="color:#e5e510">cypress.json<span style="color:#e05561"> file at the location below:<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">/path/to/projectRoot<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Cypress no longer supports cypress.json, please remove it from your project.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,45 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">You are attempting to use Cypress with an older config file: <span style="color:#e5e510">custom.json<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">When you upgraded to Cypress v10.0 the config file was updated and moved to a new location: <span style="color:#e5e510">custom.config.js<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">You may need to update any CLI scripts to ensure that they are referring the new version. This would typically look something like:<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">"<span style="color:#e5e510">cypress open --config-file=custom.config.js<span style="color:#e05561">"<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/migration-guide<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,43 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">You are running Cypress 10+ in global mode and attempting to open or migrate a project where an install of <span style="color:#4ec4ff">cypress<span style="color:#e05561"> cannot be found.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Ensure that <span style="color:#4ec4ff">cypress@10<span style="color:#e05561"> or greater is installed in the project you are attempting to open or migrate.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/migration-guide<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,43 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">You are running Cypress version 10.0.0 in global mode, but you are attempting to migrate a project where Cypress version 9.6.0 is installed.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Ensure the project you are migrating has Cypress version Cypress version 10.0.0 installed.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/migration-guide<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -34,5 +34,5 @@
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">Can't find <span style="color:#e5e510">projectId<span style="color:#e05561"> in the config file: <span style="color:#4ec4ff">/path/to/project/cypress.json<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span>
|
||||
<body><pre><span style="color:#e05561">Can't find <span style="color:#e5e510">projectId<span style="color:#e05561"> in the config file: <span style="color:#4ec4ff">/path/to/project/cypress.config.js<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,51 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">pluginsFile<span style="color:#e05561"> configuration option you have supplied has been replaced with <span style="color:#de73ff">setupNodeEvents<span style="color:#e05561">.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">This new option is not a one-to-one correlation and it must be configured separately as a testing type property: <span style="color:#de73ff">e2e.setupNodeEvents<span style="color:#e05561"> and <span style="color:#de73ff">component.setupNodeEvents<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">{<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> e2e: {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> setupNodeEvents()<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> },<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> component: {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> setupNodeEvents()<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> },<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/migration-guide<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,52 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">Your <span style="color:#de73ff">configFile<span style="color:#e05561"> is invalid: <span style="color:#4ec4ff">/path/to/project/cypress.config.js<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Binding to the <span style="color:#de73ff">on('dev-server:start')<span style="color:#e05561"> event is no longer necessary.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Please update your code to use the <span style="color:#e5e510">component.devServer()<span style="color:#e05561"> function.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">{<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> component: {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> devServer (cypressDevServerConfig, devServerConfig) {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> <span style="color:#4f5666">// start dev server here<span style="color:#4ec4ff"><span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> }<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">Learn more: https://on.cypress.io/dev-server<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -1,51 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body {
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
padding: 0 1em;
|
||||
line-height: 1.4;
|
||||
color: #eee;
|
||||
background-color: #111;
|
||||
}
|
||||
pre {
|
||||
padding: 0 0;
|
||||
margin: 0 0;
|
||||
font-family: "Courier Prime", Courier, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body><pre><span style="color:#e05561">The <span style="color:#e5e510">testFiles<span style="color:#e05561"> configuration option is now invalid when set on the config object in Cypress version 10.0.0.<span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">It is now renamed to <span style="color:#e5e510">specPattern<span style="color:#e05561"> and configured separately as a testing type property: <span style="color:#de73ff">e2e.specPattern<span style="color:#e05561"> or <span style="color:#de73ff">component.specPattern<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">{<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> e2e: {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> specPattern: '...',<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> },<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> component: {<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> specPattern: '...',<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff"> },<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#4ec4ff">}<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561"><span style="color:#e6e6e6">
|
||||
<span style="color:#e05561">https://on.cypress.io/migration-guide<span style="color:#e6e6e6"></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
|
||||
</pre></body></html>
|
||||
@@ -7,7 +7,7 @@ import path from 'path'
|
||||
import stripAnsi from 'strip-ansi'
|
||||
import type { BreakingErrResult, TestingType } from '@packages/types'
|
||||
import { humanTime, logError, parseResolvedPattern, pluralize } from './errorUtils'
|
||||
import { errPartial, errTemplate, fmt, theme, PartialErr } from './errTemplate'
|
||||
import { errPartial, errTemplate, fmt, theme } from './errTemplate'
|
||||
import { stackWithoutMessage } from './stackUtils'
|
||||
import type { ClonedError, ConfigValidationFailureInfo, CypressError, ErrTemplateResult, ErrorLike } from './errorTypes'
|
||||
import { normalizeNetworkErrorMessage } from './normalizeNetworkErrorMessage'
|
||||
@@ -105,16 +105,6 @@ export const AllCypressErrors = {
|
||||
${fmt.listItems(options)}`
|
||||
},
|
||||
BROWSER_NOT_FOUND_BY_NAME: (browser: string, foundBrowsersStr: string[]) => {
|
||||
let canarySuffix: PartialErr | null = null
|
||||
|
||||
if (browser === 'canary') {
|
||||
canarySuffix = errPartial`\
|
||||
${fmt.off('\n\n')}
|
||||
Note: In ${fmt.cypressVersion(`4.0.0`)}, Canary must be launched as ${fmt.highlightSecondary(`chrome:canary`)}, not ${fmt.highlightSecondary(`canary`)}.
|
||||
|
||||
See https://on.cypress.io/migration-guide for more information on breaking changes in 4.0.0.`
|
||||
}
|
||||
|
||||
return errTemplate`\
|
||||
Can't run because you've entered an invalid browser name.
|
||||
|
||||
@@ -126,7 +116,7 @@ export const AllCypressErrors = {
|
||||
You can also use a custom browser: https://on.cypress.io/customize-browsers
|
||||
|
||||
Available browsers found on your system are:
|
||||
${fmt.listItems(foundBrowsersStr)}${canarySuffix}`
|
||||
${fmt.listItems(foundBrowsersStr)}`
|
||||
},
|
||||
BROWSER_NOT_FOUND_BY_PATH: (arg1: string, arg2: string) => {
|
||||
return errTemplate`\
|
||||
@@ -895,7 +885,7 @@ export const AllCypressErrors = {
|
||||
|
||||
Fix the error in your code and re-run your tests.`
|
||||
},
|
||||
// happens when there is an error in configuration file like "cypress.json"
|
||||
// happens when there is an error in configuration file like "cypress.config.js"
|
||||
// TODO: make this relative path, not absolute
|
||||
CONFIG_VALIDATION_MSG_ERROR: (fileType: 'configFile' | null, fileName: string | null, validationMsg: string) => {
|
||||
if (!fileType) {
|
||||
@@ -1216,42 +1206,12 @@ export const AllCypressErrors = {
|
||||
|
||||
If you don't require screenshots or videos to be stored you can safely ignore this warning.`
|
||||
},
|
||||
EXPERIMENTAL_SAMESITE_REMOVED: () => {
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(`experimentalGetCookiesSameSite`)} configuration option was removed in ${fmt.cypressVersion(`5.0.0`)}.
|
||||
|
||||
Returning the ${fmt.highlightSecondary(`sameSite`)} property is now the default behavior of the ${fmt.highlightSecondary(`cy.cookie`)} commands.
|
||||
|
||||
You can safely remove this option from your config.`
|
||||
},
|
||||
EXPERIMENTAL_JIT_COMPILE_REMOVED: () => {
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(`experimentalJustInTimeCompile`)} configuration option was removed in ${fmt.cypressVersion(`14.0.0`)}.
|
||||
A new ${fmt.highlightSecondary(`justInTimeCompile`)} configuration option is available and is now ${fmt.highlightSecondary(`true`)} by default.
|
||||
You can safely remove this option from your config.`
|
||||
},
|
||||
// TODO: verify configFile is absolute path
|
||||
// TODO: make this relative path, not absolute
|
||||
EXPERIMENTAL_COMPONENT_TESTING_REMOVED: (arg1: {configFile: string}) => {
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight('experimentalComponentTesting')} configuration option was removed in ${fmt.cypressVersion(`7.0.0`)}.
|
||||
|
||||
Please remove this flag from: ${fmt.path(arg1.configFile)}
|
||||
|
||||
Component Testing is now a supported testing type. You can run your component tests with:
|
||||
|
||||
${fmt.terminal(`cypress open --component`)}
|
||||
|
||||
https://on.cypress.io/migration-guide`
|
||||
},
|
||||
EXPERIMENTAL_SESSION_SUPPORT_REMOVED: () => {
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(`experimentalSessionSupport`)} configuration option was removed in ${fmt.cypressVersion(`9.6.0`)}.
|
||||
|
||||
You can safely remove this option from your config.
|
||||
|
||||
https://on.cypress.io/session`
|
||||
},
|
||||
EXPERIMENTAL_SESSION_AND_ORIGIN_REMOVED: () => {
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(`experimentalSessionAndOrigin`)} configuration option was removed in ${fmt.cypressVersion(`12.0.0`)}.
|
||||
@@ -1261,34 +1221,6 @@ export const AllCypressErrors = {
|
||||
https://on.cypress.io/session
|
||||
https://on.cypress.io/origin`
|
||||
},
|
||||
EXPERIMENTAL_SHADOW_DOM_REMOVED: () => {
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(`experimentalShadowDomSupport`)} configuration option was removed in ${fmt.cypressVersion(`5.2.0`)}. It is no longer necessary when utilizing the ${fmt.highlightSecondary(`includeShadowDom`)} option.
|
||||
|
||||
You can safely remove this option from your config.`
|
||||
},
|
||||
EXPERIMENTAL_NETWORK_STUBBING_REMOVED: () => {
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(`experimentalNetworkStubbing`)} configuration option was removed in ${fmt.cypressVersion(`6.0.0`)}.
|
||||
|
||||
It is no longer necessary for using ${fmt.highlightSecondary(`cy.intercept()`)}. You can safely remove this option from your config.`
|
||||
},
|
||||
EXPERIMENTAL_RUN_EVENTS_REMOVED: () => {
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(`experimentalRunEvents`)} configuration option was removed in ${fmt.cypressVersion(`6.7.0`)}. It is no longer necessary when listening to run events in the plugins file.
|
||||
|
||||
You can safely remove this option from your config.`
|
||||
},
|
||||
EXPERIMENTAL_STUDIO_REMOVED: () => {
|
||||
return errTemplate`\
|
||||
We're ending the experimental phase of Cypress Studio in ${fmt.cypressVersion(`10.0.0`)}.
|
||||
|
||||
If you don't think you can live without Studio or you'd like to learn about how to work around its removal, please join the discussion here: http://on.cypress.io/studio-removal
|
||||
|
||||
Your feedback will help us factor in product decisions that may see Studio return in a future release.
|
||||
|
||||
You can safely remove the ${fmt.highlight(`experimentalStudio`)} configuration option from your config.`
|
||||
},
|
||||
EXPERIMENTAL_SINGLE_TAB_RUN_MODE: () => {
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(`experimentalSingleTabRunMode`)} experiment is currently only supported for Component Testing.
|
||||
@@ -1356,26 +1288,6 @@ export const AllCypressErrors = {
|
||||
Read the documentation for the injectDocumentDomain configuration option: https://on.cypress.io/inject-document-domain-configuration
|
||||
`
|
||||
},
|
||||
FIREFOX_GC_INTERVAL_REMOVED: () => {
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(`firefoxGcInterval`)} configuration option was removed in ${fmt.cypressVersion(`8.0.0`)}. It was introduced to work around a bug in Firefox 79 and below.
|
||||
|
||||
Since Cypress no longer supports Firefox 85 and below in Cypress ${fmt.cypressVersion(`8.0.0`)}, this option was removed.
|
||||
|
||||
You can safely remove this option from your config.`
|
||||
},
|
||||
// TODO: make this relative path, not absolute
|
||||
INCOMPATIBLE_PLUGIN_RETRIES: (arg1: string) => {
|
||||
return errTemplate`\
|
||||
We've detected that the incompatible plugin ${fmt.highlight(`cypress-plugin-retries`)} is installed at: ${fmt.path(arg1)}
|
||||
|
||||
Test retries is now natively supported in ${fmt.cypressVersion(`5.0.0`)}.
|
||||
|
||||
Remove the plugin from your dependencies to silence this warning.
|
||||
|
||||
https://on.cypress.io/test-retries
|
||||
`
|
||||
},
|
||||
INVALID_CONFIG_OPTION: (arg1: string[]) => {
|
||||
const phrase = arg1.length > 1 ? 'options are' : 'option is'
|
||||
|
||||
@@ -1395,31 +1307,11 @@ export const AllCypressErrors = {
|
||||
|
||||
${fmt.stackTrace(arg2)}`
|
||||
},
|
||||
CONFIG_FILE_INVALID_DEV_START_EVENT: (pluginsFilePath: string) => {
|
||||
const code = errPartial`
|
||||
module.exports = (on, config) => {
|
||||
on('dev-server:start', () => {
|
||||
${fmt.comment('// start dev server here')}
|
||||
return startDevServer(...)
|
||||
}
|
||||
}`
|
||||
|
||||
return errTemplate`\
|
||||
To run component tests, Cypress needs you to configure the ${fmt.highlight(`dev-server:start`)} event.
|
||||
|
||||
Please update this file: ${fmt.path(pluginsFilePath)}
|
||||
|
||||
${fmt.code(code)}
|
||||
|
||||
https://on.cypress.io/component-testing`
|
||||
},
|
||||
|
||||
UNSUPPORTED_BROWSER_VERSION: (errorMsg: string) => {
|
||||
return errTemplate`${fmt.off(errorMsg)}`
|
||||
},
|
||||
|
||||
// V10 Added:
|
||||
|
||||
MULTIPLE_SUPPORT_FILES_FOUND: (arg1: string, arg2: string[]) => {
|
||||
return errTemplate`\
|
||||
There were multiple support files found matching your ${fmt.highlightSecondary(`supportFile`)} pattern.
|
||||
@@ -1433,80 +1325,6 @@ export const AllCypressErrors = {
|
||||
Please remove or combine the support files into a single file.`
|
||||
},
|
||||
|
||||
CONFIG_FILE_MIGRATION_NEEDED: (projectRoot: string) => {
|
||||
return errTemplate`
|
||||
There is a ${fmt.highlight(`cypress.json`)} file at the path: ${fmt.path(projectRoot)}
|
||||
|
||||
${fmt.cypressVersion('10.0.0')} no longer supports ${fmt.highlight(`cypress.json`)}.
|
||||
|
||||
Please run ${fmt.highlightTertiary('cypress open')} to launch the migration tool to migrate to ${fmt.highlightSecondary('cypress.config.{js,ts,mjs,cjs}')}.
|
||||
|
||||
https://on.cypress.io/migration-guide
|
||||
`
|
||||
},
|
||||
|
||||
LEGACY_CONFIG_ERROR_DURING_MIGRATION: (file: string, error: Error) => {
|
||||
return errTemplate`
|
||||
Your ${fmt.highlight(file)} file threw an error. ${fmt.stackTrace(error)}
|
||||
|
||||
Please ensure your pluginsFile is valid and relaunch the migration tool to migrate to ${fmt.cypressVersion('10.0.0')}.
|
||||
`
|
||||
},
|
||||
|
||||
LEGACY_CONFIG_FILE: (baseFileName: string, projectRoot: string, legacyConfigFile: string = 'cypress.json') => {
|
||||
return errTemplate`
|
||||
There is both a ${fmt.highlight(baseFileName)} and a ${fmt.highlight(legacyConfigFile)} file at the location below:
|
||||
|
||||
${fmt.path(projectRoot)}
|
||||
|
||||
Cypress no longer supports ${fmt.off(legacyConfigFile)}, please remove it from your project.
|
||||
`
|
||||
},
|
||||
|
||||
SETUP_NODE_EVENTS_DO_NOT_SUPPORT_DEV_SERVER: (configFilePath: string) => {
|
||||
const code = errPartial`
|
||||
{
|
||||
component: {
|
||||
devServer (cypressDevServerConfig, devServerConfig) {
|
||||
${fmt.comment(`// start dev server here`)
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
return errTemplate`\
|
||||
Your ${fmt.highlightSecondary(`configFile`)} is invalid: ${fmt.path(configFilePath)}
|
||||
|
||||
Binding to the ${fmt.highlightSecondary(`on('dev-server:start')`)} event is no longer necessary.
|
||||
|
||||
Please update your code to use the ${fmt.highlight(`component.devServer()`)} function.
|
||||
|
||||
${fmt.code(code)}
|
||||
|
||||
Learn more: https://on.cypress.io/dev-server
|
||||
`
|
||||
},
|
||||
|
||||
PLUGINS_FILE_CONFIG_OPTION_REMOVED: (_errShape: BreakingErrResult) => {
|
||||
const code = errPartial`
|
||||
{
|
||||
e2e: {
|
||||
setupNodeEvents()
|
||||
},
|
||||
component: {
|
||||
setupNodeEvents()
|
||||
},
|
||||
}`
|
||||
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight('pluginsFile')} configuration option you have supplied has been replaced with ${fmt.highlightSecondary('setupNodeEvents')}.
|
||||
|
||||
This new option is not a one-to-one correlation and it must be configured separately as a testing type property: ${fmt.highlightSecondary('e2e.setupNodeEvents')} and ${fmt.highlightSecondary('component.setupNodeEvents')}
|
||||
|
||||
${fmt.code(code)}
|
||||
|
||||
https://on.cypress.io/migration-guide`
|
||||
},
|
||||
|
||||
VIDEO_UPLOAD_ON_PASSES_REMOVED: (_errShape: BreakingErrResult) => {
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(`videoUploadOnPasses`)} configuration option was removed in ${fmt.cypressVersion(`13.0.0`)}.
|
||||
@@ -1528,13 +1346,11 @@ export const AllCypressErrors = {
|
||||
}`
|
||||
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(errShape.name)} configuration option is now invalid when set from the root of the config object in ${fmt.cypressVersion(`10.0.0`)}.
|
||||
The ${fmt.highlight(errShape.name)} configuration option is invalid when set from the root of the config object.
|
||||
|
||||
It is now configured separately as a testing type property: ${fmt.highlightSecondary(`e2e.${errShape.name}`)} and ${fmt.highlightSecondary(`component.${errShape.name}`)}
|
||||
Set it within a testing type property: ${fmt.highlightSecondary(`e2e.${errShape.name}`)} and ${fmt.highlightSecondary(`component.${errShape.name}`)}
|
||||
|
||||
${fmt.code(code)}
|
||||
|
||||
https://on.cypress.io/migration-guide`
|
||||
${fmt.code(code)}`
|
||||
},
|
||||
|
||||
CONFIG_FILE_INVALID_ROOT_CONFIG_E2E: (errShape: BreakingErrResult) => {
|
||||
@@ -1546,13 +1362,11 @@ export const AllCypressErrors = {
|
||||
}`
|
||||
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(errShape.name)} configuration option is now invalid when set from the root of the config object in ${fmt.cypressVersion(`10.0.0`)}.
|
||||
The ${fmt.highlight(errShape.name)} configuration option is invalid when set from the root of the config object.
|
||||
|
||||
It is now configured separately as a testing type property: ${fmt.highlightSecondary(`e2e.${errShape.name}`)}
|
||||
Set it within a testing type property: ${fmt.highlightSecondary(`e2e.${errShape.name}`)}
|
||||
|
||||
${fmt.code(code)}
|
||||
|
||||
https://on.cypress.io/migration-guide`
|
||||
${fmt.code(code)}`
|
||||
},
|
||||
|
||||
CONFIG_FILE_INVALID_ROOT_CONFIG_COMPONENT: (errShape: BreakingErrResult) => {
|
||||
@@ -1564,13 +1378,11 @@ export const AllCypressErrors = {
|
||||
}`
|
||||
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(errShape.name)} configuration option is now invalid when set from the root of the config object in ${fmt.cypressVersion(`10.0.0`)}.
|
||||
The ${fmt.highlight(errShape.name)} configuration option is invalid when set from the root of the config object.
|
||||
|
||||
It is now configured separately as a testing type property: ${fmt.highlightSecondary(`component.${errShape.name}`)}
|
||||
Set it within a testing type property: ${fmt.highlightSecondary(`component.${errShape.name}`)}
|
||||
|
||||
${fmt.code(code)}
|
||||
|
||||
https://on.cypress.io/migration-guide`
|
||||
${fmt.code(code)}`
|
||||
},
|
||||
|
||||
// TODO: add path to config file
|
||||
@@ -1587,9 +1399,7 @@ export const AllCypressErrors = {
|
||||
|
||||
Please remove this option or add this as an e2e testing type property: ${fmt.highlightSecondary(`e2e.${errShape.name}`)}
|
||||
|
||||
${fmt.code(code)}
|
||||
|
||||
https://on.cypress.io/migration-guide`
|
||||
${fmt.code(code)}`
|
||||
},
|
||||
|
||||
CONFIG_FILE_INVALID_TESTING_TYPE_CONFIG_E2E: (errShape: BreakingErrResult) => {
|
||||
@@ -1605,9 +1415,7 @@ export const AllCypressErrors = {
|
||||
|
||||
Please remove this option or add this as a component testing type property: ${fmt.highlightSecondary(`component.${errShape.name}`)}
|
||||
|
||||
${fmt.code(code)}
|
||||
|
||||
https://on.cypress.io/migration-guide`
|
||||
${fmt.code(code)}`
|
||||
},
|
||||
|
||||
CONFIG_FILE_DEV_SERVER_IS_NOT_VALID: (configFilePath: string, setupNodeEvents: any) => {
|
||||
@@ -1681,120 +1489,6 @@ export const AllCypressErrors = {
|
||||
`
|
||||
},
|
||||
|
||||
MIGRATION_ALREADY_OCURRED: (configFile: string, legacyConfigFile: string) => {
|
||||
return errTemplate`
|
||||
You are attempting to use Cypress with an older config file: ${fmt.highlight(legacyConfigFile)}
|
||||
When you upgraded to Cypress v10.0 the config file was updated and moved to a new location: ${fmt.highlight(configFile)}
|
||||
|
||||
You may need to update any CLI scripts to ensure that they are referring the new version. This would typically look something like:
|
||||
"${fmt.highlight(`cypress open --config-file=${configFile}`)}"
|
||||
|
||||
https://on.cypress.io/migration-guide
|
||||
`
|
||||
},
|
||||
|
||||
TEST_FILES_RENAMED: (errShape: BreakingErrResult, err?: Error) => {
|
||||
const stackTrace = err ? fmt.stackTrace(err) : null
|
||||
|
||||
const newName = errShape.newName || '<unknown>'
|
||||
|
||||
const testingTypedHelpMessage = errShape.testingType
|
||||
? errPartial`${fmt.highlightSecondary(`${errShape.testingType}.${newName}`)}`
|
||||
: errPartial`${fmt.highlightSecondary(`e2e.${newName}`)} or ${fmt.highlightSecondary(`component.${newName}`)}`
|
||||
|
||||
const code = errShape.testingType
|
||||
? errPartial`
|
||||
{
|
||||
${fmt.off(errShape.testingType)}: {
|
||||
specPattern: '...',
|
||||
},
|
||||
}`
|
||||
: errPartial`
|
||||
{
|
||||
e2e: {
|
||||
specPattern: '...',
|
||||
},
|
||||
component: {
|
||||
specPattern: '...',
|
||||
},
|
||||
}`
|
||||
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(errShape.name)} configuration option is now invalid when set on the config object in ${fmt.cypressVersion(`10.0.0`)}.
|
||||
|
||||
It is now renamed to ${fmt.highlight(newName)} and configured separately as a testing type property: ${testingTypedHelpMessage}
|
||||
${fmt.code(code)}
|
||||
|
||||
https://on.cypress.io/migration-guide
|
||||
|
||||
${stackTrace}
|
||||
`
|
||||
},
|
||||
|
||||
COMPONENT_FOLDER_REMOVED: (errShape: BreakingErrResult, err?: Error) => {
|
||||
const stackTrace = err ? fmt.stackTrace(err) : null
|
||||
|
||||
const code = errPartial`
|
||||
{
|
||||
component: {
|
||||
specPattern: '...',
|
||||
},
|
||||
}`
|
||||
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(errShape.name)} configuration option is now invalid when set on the config object in ${fmt.cypressVersion(`10.0.0`)}.
|
||||
|
||||
It is now renamed to ${fmt.highlight('specPattern')} and configured separately as a component testing property: ${fmt.highlightSecondary('component.specPattern')}
|
||||
${fmt.code(code)}
|
||||
|
||||
https://on.cypress.io/migration-guide
|
||||
|
||||
${stackTrace}
|
||||
`
|
||||
},
|
||||
|
||||
INTEGRATION_FOLDER_REMOVED: (errShape: BreakingErrResult, err?: Error) => {
|
||||
const stackTrace = err ? fmt.stackTrace(err) : null
|
||||
|
||||
const code = errPartial`
|
||||
{
|
||||
e2e: {
|
||||
specPattern: '...',
|
||||
},
|
||||
}`
|
||||
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(errShape.name)} configuration option is now invalid when set on the config object in ${fmt.cypressVersion(`10.0.0`)}.
|
||||
|
||||
It is now renamed to ${fmt.highlight('specPattern')} and configured separately as a end to end testing property: ${fmt.highlightSecondary('e2e.specPattern')}
|
||||
${fmt.code(code)}
|
||||
|
||||
https://on.cypress.io/migration-guide
|
||||
|
||||
${stackTrace}
|
||||
`
|
||||
},
|
||||
|
||||
MIGRATION_MISMATCHED_CYPRESS_VERSIONS: (version: string, currentVersion: string) => {
|
||||
return errTemplate`
|
||||
You are running ${fmt.cypressVersion(currentVersion)} in global mode, but you are attempting to migrate a project where ${fmt.cypressVersion(version)} is installed.
|
||||
|
||||
Ensure the project you are migrating has Cypress version ${fmt.cypressVersion(currentVersion)} installed.
|
||||
|
||||
https://on.cypress.io/migration-guide
|
||||
`
|
||||
},
|
||||
|
||||
MIGRATION_CYPRESS_NOT_FOUND: () => {
|
||||
return errTemplate`
|
||||
You are running Cypress 10+ in global mode and attempting to open or migrate a project where an install of ${fmt.code('cypress')} cannot be found.
|
||||
|
||||
Ensure that ${fmt.code('cypress@10')} or greater is installed in the project you are attempting to open or migrate.
|
||||
|
||||
https://on.cypress.io/migration-guide
|
||||
`
|
||||
},
|
||||
|
||||
DEV_SERVER_CONFIG_FILE_NOT_FOUND: (devServer: 'vite' | 'webpack', root: string, searchedFor: string[]) => {
|
||||
const devServerConfigFile = `${devServer}Config`
|
||||
|
||||
|
||||
@@ -49,13 +49,13 @@ describe('lib/errors', () => {
|
||||
})
|
||||
|
||||
it('logs err.message', () => {
|
||||
const err = errors.getError('NO_PROJECT_ID', '/path/to/project/cypress.json')
|
||||
const err = errors.getError('NO_PROJECT_ID', '/path/to/project/cypress.config.js')
|
||||
|
||||
const ret = errors.log(err)
|
||||
|
||||
expect(ret).to.be.undefined
|
||||
|
||||
expect(console.log).to.be.calledWithMatch('/path/to/project/cypress.json')
|
||||
expect(console.log).to.be.calledWithMatch('/path/to/project/cypress.config.js')
|
||||
})
|
||||
|
||||
it('logs err.details', () => {
|
||||
|
||||
@@ -304,13 +304,6 @@ describe('visual error templates', () => {
|
||||
|
||||
// testVisualErrors('CANNOT_RECORD_NO_PROJECT_ID', {
|
||||
testVisualErrors(errorType, {
|
||||
LEGACY_CONFIG_ERROR_DURING_MIGRATION: () => {
|
||||
const err = makeErr()
|
||||
|
||||
return {
|
||||
default: ['cypress/plugins/index.js', err],
|
||||
}
|
||||
},
|
||||
CANNOT_TRASH_ASSETS: () => {
|
||||
const err = makeErr()
|
||||
|
||||
@@ -598,7 +591,7 @@ describe('visual error templates', () => {
|
||||
},
|
||||
CANNOT_RECORD_NO_PROJECT_ID: () => {
|
||||
return {
|
||||
default: ['/path/to/cypress.json'],
|
||||
default: ['/path/to/cypress.config.js'],
|
||||
}
|
||||
},
|
||||
PROJECT_ID_AND_KEY_BUT_MISSING_RECORD_OPTION: () => {
|
||||
@@ -739,12 +732,12 @@ describe('visual error templates', () => {
|
||||
},
|
||||
CLOUD_PROJECT_NOT_FOUND: () => {
|
||||
return {
|
||||
default: ['project-id-123', '/path/to/cypress.json'],
|
||||
default: ['project-id-123', '/path/to/cypress.config.js'],
|
||||
}
|
||||
},
|
||||
NO_PROJECT_ID: () => {
|
||||
return {
|
||||
default: ['/path/to/project/cypress.json'],
|
||||
default: ['/path/to/project/cypress.config.js'],
|
||||
}
|
||||
},
|
||||
NO_PROJECT_FOUND_AT_PROJECT_ROOT: () => {
|
||||
@@ -864,28 +857,28 @@ describe('visual error templates', () => {
|
||||
},
|
||||
CONFIG_VALIDATION_ERROR: () => {
|
||||
return {
|
||||
default: ['configFile', 'cypress.json', {
|
||||
default: ['configFile', 'cypress.config.js', {
|
||||
key: 'defaultCommandTimeout',
|
||||
type: 'a number',
|
||||
value: false,
|
||||
}],
|
||||
list: ['configFile', 'cypress.json', {
|
||||
list: ['configFile', 'cypress.config.js', {
|
||||
key: 'displayName',
|
||||
type: 'a non-empty string',
|
||||
value: { name: 'chrome', version: '1.2.3', displayName: null },
|
||||
list: 'browsers',
|
||||
}],
|
||||
invalidString: ['configFile', 'cypress.json', {
|
||||
invalidString: ['configFile', 'cypress.config.js', {
|
||||
key: 'defaultCommandTimeout',
|
||||
type: 'a number',
|
||||
value: '1234',
|
||||
}],
|
||||
invalidObject: ['configFile', 'cypress.json', {
|
||||
invalidObject: ['configFile', 'cypress.config.js', {
|
||||
key: 'defaultCommandTimeout',
|
||||
type: 'a number',
|
||||
value: { foo: 'bar' },
|
||||
}],
|
||||
invalidArray: ['configFile', 'cypress.json', {
|
||||
invalidArray: ['configFile', 'cypress.config.js', {
|
||||
key: 'defaultCommandTimeout',
|
||||
type: 'a number',
|
||||
value: [1, 2, 3],
|
||||
@@ -899,7 +892,7 @@ describe('visual error templates', () => {
|
||||
},
|
||||
CONFIG_VALIDATION_MSG_ERROR: () => {
|
||||
return {
|
||||
default: ['configFile', 'cypress.json', '`something` was not right'],
|
||||
default: ['configFile', 'cypress.config.js', '`something` was not right'],
|
||||
noFileType: [null, null, '`something` was not right'],
|
||||
}
|
||||
},
|
||||
@@ -958,7 +951,7 @@ describe('visual error templates', () => {
|
||||
},
|
||||
CONFIG_FILE_NOT_FOUND: () => {
|
||||
return {
|
||||
default: ['cypress.json', '/path/to/project/root'],
|
||||
default: ['cypress.config.js', '/path/to/project/root'],
|
||||
}
|
||||
},
|
||||
INVOKED_BINARY_OUTSIDE_NPM_MODULE: () => {
|
||||
@@ -1113,81 +1106,16 @@ describe('visual error templates', () => {
|
||||
default: ['/path/to/folder'],
|
||||
}
|
||||
},
|
||||
EXPERIMENTAL_SAMESITE_REMOVED: () => {
|
||||
return {
|
||||
default: [],
|
||||
}
|
||||
},
|
||||
EXPERIMENTAL_JIT_COMPILE_REMOVED: () => {
|
||||
return {
|
||||
default: [],
|
||||
}
|
||||
},
|
||||
EXPERIMENTAL_COMPONENT_TESTING_REMOVED: () => {
|
||||
return {
|
||||
default: [{ configFile: '/path/to/cypress.config.js' }],
|
||||
}
|
||||
},
|
||||
EXPERIMENTAL_SESSION_SUPPORT_REMOVED: () => {
|
||||
return {
|
||||
default: [],
|
||||
}
|
||||
},
|
||||
EXPERIMENTAL_SESSION_AND_ORIGIN_REMOVED: () => {
|
||||
return {
|
||||
default: [],
|
||||
}
|
||||
},
|
||||
EXPERIMENTAL_SHADOW_DOM_REMOVED: () => {
|
||||
return {
|
||||
default: [],
|
||||
}
|
||||
},
|
||||
EXPERIMENTAL_NETWORK_STUBBING_REMOVED: () => {
|
||||
return {
|
||||
default: [],
|
||||
}
|
||||
},
|
||||
EXPERIMENTAL_RUN_EVENTS_REMOVED: () => {
|
||||
return {
|
||||
default: [],
|
||||
}
|
||||
},
|
||||
EXPERIMENTAL_STUDIO_REMOVED: () => {
|
||||
return {
|
||||
default: [],
|
||||
}
|
||||
},
|
||||
FIREFOX_GC_INTERVAL_REMOVED: () => {
|
||||
return {
|
||||
default: [],
|
||||
}
|
||||
},
|
||||
INCOMPATIBLE_PLUGIN_RETRIES: () => {
|
||||
return {
|
||||
default: ['./path/to/cypress-plugin-retries'],
|
||||
}
|
||||
},
|
||||
CONFIG_FILE_MIGRATION_NEEDED: () => {
|
||||
return {
|
||||
default: ['/path/to/projectRoot'],
|
||||
}
|
||||
},
|
||||
LEGACY_CONFIG_FILE: () => {
|
||||
return {
|
||||
default: ['cypress.json', '/path/to/projectRoot'],
|
||||
}
|
||||
},
|
||||
SETUP_NODE_EVENTS_DO_NOT_SUPPORT_DEV_SERVER: () => {
|
||||
return {
|
||||
default: ['/path/to/project/cypress.config.js'],
|
||||
}
|
||||
},
|
||||
CONFIG_FILE_INVALID_DEV_START_EVENT: () => {
|
||||
return {
|
||||
default: ['/path/to/plugins/file.js'],
|
||||
}
|
||||
},
|
||||
CONFIG_FILE_DEV_SERVER_INVALID_RETURN: () => {
|
||||
return {
|
||||
default: [{}],
|
||||
@@ -1214,11 +1142,6 @@ describe('visual error templates', () => {
|
||||
default: ['spec.{ts,js}', ['support.ts', 'support.js']],
|
||||
}
|
||||
},
|
||||
PLUGINS_FILE_CONFIG_OPTION_REMOVED: () => {
|
||||
return {
|
||||
default: [{ name: 'pluginsFile', configFile: '/path/to/cypress.config.js.ts' }],
|
||||
}
|
||||
},
|
||||
VIDEO_UPLOAD_ON_PASSES_REMOVED: () => {
|
||||
return {
|
||||
default: [{ name: 'videoUploadOnPasses', configFile: '/path/to/cypress.config.js.ts' }],
|
||||
@@ -1274,36 +1197,6 @@ describe('visual error templates', () => {
|
||||
default: [makeErr()],
|
||||
}
|
||||
},
|
||||
MIGRATION_ALREADY_OCURRED: () => {
|
||||
return {
|
||||
default: ['custom.config.js', 'custom.json'],
|
||||
}
|
||||
},
|
||||
TEST_FILES_RENAMED: () => {
|
||||
return {
|
||||
default: [{ name: 'testFiles', newName: 'specPattern', configFile: '/path/to/cypress.config.js.ts' }],
|
||||
}
|
||||
},
|
||||
COMPONENT_FOLDER_REMOVED: () => {
|
||||
return {
|
||||
default: [{ name: 'componentFolder', configFile: '/path/to/cypress.config.js.ts' }],
|
||||
}
|
||||
},
|
||||
INTEGRATION_FOLDER_REMOVED: () => {
|
||||
return {
|
||||
default: [{ name: 'integrationFolder', configFile: '/path/to/cypress.config.js.ts' }],
|
||||
}
|
||||
},
|
||||
MIGRATION_MISMATCHED_CYPRESS_VERSIONS: () => {
|
||||
return {
|
||||
default: ['9.6.0', '10.0.0'],
|
||||
}
|
||||
},
|
||||
MIGRATION_CYPRESS_NOT_FOUND: () => {
|
||||
return {
|
||||
default: [],
|
||||
}
|
||||
},
|
||||
DEV_SERVER_CONFIG_FILE_NOT_FOUND: () => {
|
||||
return {
|
||||
default: ['vite', '/dev/project', ['vite.config.js', 'vite.config.ts']],
|
||||
|
||||
@@ -31,7 +31,6 @@ export interface ClientTestContext {
|
||||
allBundlers: WizardBundler[]
|
||||
warnings: []
|
||||
}
|
||||
migration: {}
|
||||
user: AuthenticatedUserShape | null
|
||||
cloudTypes: typeof cloudTypes
|
||||
__mockPartial: any
|
||||
@@ -104,7 +103,6 @@ export function makeClientTestContext (): ClientTestContext {
|
||||
},
|
||||
],
|
||||
},
|
||||
migration: {},
|
||||
__mockPartial: {},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
import { MIGRATION_STEPS } from '@packages/types'
|
||||
import type { Migration } from '../generated/test-graphql-types.gen'
|
||||
import type { MaybeResolver } from './clientTestUtils'
|
||||
|
||||
let _id = 0
|
||||
|
||||
const id = () => {
|
||||
_id++
|
||||
|
||||
return _id.toString()
|
||||
}
|
||||
|
||||
export const stubMigration: MaybeResolver<Migration> = {
|
||||
__typename: 'Migration',
|
||||
filteredSteps: MIGRATION_STEPS.map((name, index) => {
|
||||
return {
|
||||
id: (index + 1).toString(),
|
||||
index: index + 1,
|
||||
isCompleted: false,
|
||||
isCurrentStep: name === 'renameAuto',
|
||||
__typename: 'MigrationStep',
|
||||
name,
|
||||
}
|
||||
}),
|
||||
specFiles: [
|
||||
{
|
||||
__typename: 'MigrationFile',
|
||||
testingType: 'e2e',
|
||||
before: {
|
||||
__typename: 'MigrationFileData',
|
||||
id: id(),
|
||||
relative: 'cypress/integration/app.spec.js',
|
||||
parts: [
|
||||
{ id: id(), __typename: 'MigrationFilePart', text: 'cypress/', highlight: false },
|
||||
{ id: id(), __typename: 'MigrationFilePart', text: 'integration', highlight: true },
|
||||
{ id: id(), __typename: 'MigrationFilePart', text: '/app', highlight: false },
|
||||
{ id: id(), __typename: 'MigrationFilePart', text: '.spec.', highlight: true },
|
||||
{ id: id(), __typename: 'MigrationFilePart', text: 'js', highlight: false },
|
||||
],
|
||||
},
|
||||
after: {
|
||||
__typename: 'MigrationFileData',
|
||||
id: id(),
|
||||
relative: 'cypress/integration/app.spec.js',
|
||||
parts: [
|
||||
{ id: id(), __typename: 'MigrationFilePart', text: 'cypress/', highlight: false },
|
||||
{ id: id(), __typename: 'MigrationFilePart', text: 'integration', highlight: true },
|
||||
{ id: id(), __typename: 'MigrationFilePart', text: '/app', highlight: false },
|
||||
{ id: id(), __typename: 'MigrationFilePart', text: '.cy.', highlight: true },
|
||||
{ id: id(), __typename: 'MigrationFilePart', text: 'js', highlight: false },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
manualFiles: {
|
||||
id: id(),
|
||||
__typename: 'ManualMigration',
|
||||
completed: false,
|
||||
files: [
|
||||
{
|
||||
id: id(),
|
||||
__typename: 'ManualMigrationFile',
|
||||
moved: false,
|
||||
relative: 'cypress/component/button-spec.js',
|
||||
},
|
||||
{
|
||||
id: id(),
|
||||
__typename: 'ManualMigrationFile',
|
||||
moved: true,
|
||||
relative: 'cypress/component/hello.spec.tsx',
|
||||
},
|
||||
],
|
||||
},
|
||||
configBeforeCode: `{
|
||||
"baseUrl": "http://localhost:1234/",
|
||||
"retries": 2
|
||||
}`,
|
||||
configAfterCode: `const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
retries: 2,
|
||||
e2e: {
|
||||
// End-to-end config overrides go here
|
||||
baseUrl: "http://localhost:1234/"
|
||||
|
||||
setupNodeEvents (on, config) {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these directly
|
||||
return require('cypress/plugins/index.js')(on, config) }
|
||||
}
|
||||
},
|
||||
})`,
|
||||
integrationFolder: 'cypress/integration',
|
||||
componentFolder: 'cypress/component',
|
||||
supportFiles:
|
||||
{
|
||||
__typename: 'MigrationFile',
|
||||
testingType: 'e2e',
|
||||
before: {
|
||||
id: id(),
|
||||
relative: 'cypress/support/index.js',
|
||||
__typename: 'MigrationFileData',
|
||||
parts: [
|
||||
{
|
||||
id: id(),
|
||||
__typename: 'MigrationFilePart',
|
||||
text: 'cypress/support/',
|
||||
highlight: false,
|
||||
},
|
||||
{
|
||||
id: id(),
|
||||
__typename: 'MigrationFilePart',
|
||||
text: 'index',
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
id: id(),
|
||||
__typename: 'MigrationFilePart',
|
||||
text: '.js',
|
||||
highlight: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
after: {
|
||||
id: id(),
|
||||
relative: 'cypress/support/e2e.js',
|
||||
__typename: 'MigrationFileData',
|
||||
parts: [
|
||||
{
|
||||
id: id(),
|
||||
__typename: 'MigrationFilePart',
|
||||
text: 'cypress/support/',
|
||||
highlight: false,
|
||||
},
|
||||
{
|
||||
id: id(),
|
||||
__typename: 'MigrationFilePart',
|
||||
text: 'e2e',
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
id: id(),
|
||||
__typename: 'MigrationFilePart',
|
||||
text: '.js',
|
||||
highlight: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
hasComponentTesting: true,
|
||||
hasCustomComponentFolder: false,
|
||||
hasCustomComponentTestFiles: false,
|
||||
hasCustomIntegrationFolder: false,
|
||||
hasCustomIntegrationTestFiles: false,
|
||||
configFileNameAfter: 'cypress.config.js',
|
||||
configFileNameBefore: 'cypress.json',
|
||||
shouldMigratePreExtension: true,
|
||||
}
|
||||
@@ -13,9 +13,6 @@ export const stubQuery: MaybeResolver<Query> = {
|
||||
wizard (source, args, ctx) {
|
||||
return ctx.wizard
|
||||
},
|
||||
migration (source, args, ctx) {
|
||||
return ctx.migration
|
||||
},
|
||||
currentProject (source, args, ctx) {
|
||||
return ctx.currentProject
|
||||
},
|
||||
|
||||
@@ -4,7 +4,6 @@ import { stubMutation } from './stubgql-Mutation'
|
||||
import { stubQuery } from './stubgql-Query'
|
||||
import { stubGlobalProject, stubProject } from './stubgql-Project'
|
||||
import { CloudOrganizationStubs, CloudProjectStubs, CloudRecordKeyStubs, CloudRunStubs, CloudUserStubs } from '@packages/graphql/test/stubCloudTypes'
|
||||
import { stubMigration } from './stubgql-Migration'
|
||||
import type { CodegenTypeMap } from '../generated/test-graphql-types.gen'
|
||||
import { StubErrorWrapper } from './stubgql-ErrorWrapper'
|
||||
|
||||
@@ -15,7 +14,6 @@ export const GQLStubRegistry = {
|
||||
ProjectLike: stubProject,
|
||||
GlobalProject: stubGlobalProject,
|
||||
CurrentProject: stubProject,
|
||||
Migration: stubMigration,
|
||||
Mutation: stubMutation,
|
||||
Query: stubQuery,
|
||||
CloudOrganization: CloudOrganizationStubs.cyOrg,
|
||||
|
||||
@@ -221,10 +221,6 @@ mutation GlobalPageHeader_clearCurrentProject {
|
||||
currentProject {
|
||||
id
|
||||
}
|
||||
# This ensures the cache is updated with null after clearing project
|
||||
migration {
|
||||
configFileNameBefore
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@@ -909,97 +909,6 @@
|
||||
"link": "install Cypress"
|
||||
}
|
||||
},
|
||||
"migration": {
|
||||
"before": "Before",
|
||||
"after": "After",
|
||||
"heresWhy": "here's why:",
|
||||
"renameAuto": {
|
||||
"title": "We recommend automatically renaming your specs in this step",
|
||||
"changeButton": "change",
|
||||
"changedSpecFolder": "We've changed the default spec folder from:",
|
||||
"changedSpecExt": "We've changed the default spec file extension from:",
|
||||
"changedSpecPatternExplain": "We've changed the default spec file extension to {0} in order to avoid conflicts with any existing testing frameworks.",
|
||||
"optedOutMessage": "You've opted not to rename your spec file extension. You may need to change your specPattern later so we can still find your spec files.",
|
||||
"folderRenameMessage": "You've opted not to rename your spec file extension, we'll only rename the folder",
|
||||
"modal": {
|
||||
"title": "Change the existing spec file extension",
|
||||
"warning": "We recommend using the default extension to avoid inconsistencies, framework conflicts, and confusion with your team.",
|
||||
"line1": "Cypress now supports the ability to create new spec files from within the UI for both E2E and component specs.",
|
||||
"line2": "All new spec files created within Cypress will use the default pattern of: ",
|
||||
"line3": "We want to rename your existing specs so that they have a consistent filename pattern for both E2E and component testing.",
|
||||
"line4": "All documentation and example code will be using: ",
|
||||
"line5": "We've changed the placement of component specs to be next to their source files (e.g. src/Button.jsx and src/Button.cy.jsx)",
|
||||
"line6": "The new default pattern of {0} prevents targeting conflicts with other testing frameworks. (e.g. Jest)",
|
||||
"label": "Choose from the following filename patterns:",
|
||||
"option1": "{0} (recommended)",
|
||||
"option2": "Don't rename anything — keep what I have.",
|
||||
"option3": "Rename folder only.",
|
||||
"optOutAdditional": "I may need to change my {0} later if I don't use the recommended filename extension.",
|
||||
"buttonSave": "Save changes",
|
||||
"buttonCancel": "Cancel"
|
||||
}
|
||||
},
|
||||
"renameManual": {
|
||||
"title": "We need you to move your component specs manually",
|
||||
"componentFolderRemoved": "We've removed the {0} options from the Cypress config.",
|
||||
"addedSpecPattern": "We've added a new {0} option in the Cypress config that tells us where to find your component specs.",
|
||||
"cannotAuto": "We can't automatically migrate your existing component spec files. We recommend that you move the following component spec files next to your source component files (e.g. {0})",
|
||||
"ifSkipNote": "If you skip this step, Cypress will still be able to find them, but any new specs that you create will automatically be created next to your component files."
|
||||
},
|
||||
"renameSupport": {
|
||||
"title": "We'll automatically rename your existing E2E support file in this step",
|
||||
"serveDifferentTypes": "We now serve different support files for E2E and Component Testing.",
|
||||
"changedSupportFile": "We've renamed the E2E support file from:"
|
||||
},
|
||||
"configFile": {
|
||||
"title": "We need to migrate to the new Cypress configuration file",
|
||||
"changedDefault": "We've changed the default Cypress config file from:",
|
||||
"customOptions": "We've set a custom {specPattern} option based on your {options}.",
|
||||
"willConvert": "We'll automatically create a new {jsFile} file and seed it with your options from your existing {jsonFile}."
|
||||
},
|
||||
"setupComponent": {
|
||||
"title": "You need to reconfigure Cypress for component testing",
|
||||
"line1": "We've detected that you are currently using the experimental version of component testing.",
|
||||
"line2": "Your existing configuration is no longer compatible with new component testing configuration options.",
|
||||
"line3": "In a previous step, we renamed your component specs, but can't automatically migrate your existing component testing configuration.",
|
||||
"line4": "In the next screen, you'll be able to reconfigure component testing in a new guided configuration wizard."
|
||||
},
|
||||
"wizard": {
|
||||
"title": "Migrating to Cypress {version}",
|
||||
"description": "Your project requires updates to work with this version.",
|
||||
"typicalMigrationLabel": "Typical migration:",
|
||||
"typicalMigrationTime": "5-10 minutes",
|
||||
"step1": {
|
||||
"title": "Migrate existing specs",
|
||||
"description": "In this step, we'll automatically rename and/or move your existing spec files as needed.",
|
||||
"button": "Rename these specs for me",
|
||||
"buttonSkip": "Skip renaming specs",
|
||||
"buttonRenameFolder": "Rename the folder for me"
|
||||
},
|
||||
"step2": {
|
||||
"title": "Move your existing component specs",
|
||||
"description": "In this step, you'll manually move your existing component specs to their new default location.",
|
||||
"buttonWait": "Waiting for you to move your component specs...",
|
||||
"buttonDone": "Continue to next step",
|
||||
"button": "I'll do this later"
|
||||
},
|
||||
"step3": {
|
||||
"title": "Rename the Cypress support file",
|
||||
"description": "In this step, we'll automatically rename your existing support file.",
|
||||
"button": "Rename the support file for me"
|
||||
},
|
||||
"step4": {
|
||||
"title": "Migrate to the new Cypress configuration file",
|
||||
"description": "In this step, we'll automatically migrate your existing Cypress configuration to the new Cypress configuration file.",
|
||||
"button": "Migrate the configuration for me"
|
||||
},
|
||||
"step5": {
|
||||
"title": "Reconfigure component testing",
|
||||
"description": "In this step, we'll explain how you will reconfigure Cypress for component testing.",
|
||||
"button": "Finish migration and continue"
|
||||
}
|
||||
}
|
||||
},
|
||||
"majorVersionWelcome": {
|
||||
"title": "What's New in Cypress",
|
||||
"actionContinue": "Continue",
|
||||
|
||||
@@ -1041,9 +1041,6 @@ type CurrentProject implements Node & ProjectLike {
|
||||
|
||||
"""Whether the project has Typescript"""
|
||||
isUsingTypeScript: Boolean
|
||||
|
||||
"""Whether the project needs to be migrated before proceeding"""
|
||||
needsLegacyConfigMigration: Boolean
|
||||
packageManager: PackageManagerEnum!
|
||||
|
||||
"""Cached preferences for this project"""
|
||||
@@ -1161,18 +1158,15 @@ enum ErrorTypeEnum {
|
||||
CLOUD_STALE_RUN
|
||||
CLOUD_UNKNOWN_CREATE_RUN_WARNING
|
||||
CLOUD_UNKNOWN_INVALID_REQUEST
|
||||
COMPONENT_FOLDER_REMOVED
|
||||
COMPONENT_TESTING_MISMATCHED_DEPENDENCIES
|
||||
CONFIG_FILES_LANGUAGE_CONFLICT
|
||||
CONFIG_FILE_DEV_SERVER_INVALID_RETURN
|
||||
CONFIG_FILE_DEV_SERVER_IS_NOT_VALID
|
||||
CONFIG_FILE_INVALID_DEV_START_EVENT
|
||||
CONFIG_FILE_INVALID_ROOT_CONFIG
|
||||
CONFIG_FILE_INVALID_ROOT_CONFIG_COMPONENT
|
||||
CONFIG_FILE_INVALID_ROOT_CONFIG_E2E
|
||||
CONFIG_FILE_INVALID_TESTING_TYPE_CONFIG_COMPONENT
|
||||
CONFIG_FILE_INVALID_TESTING_TYPE_CONFIG_E2E
|
||||
CONFIG_FILE_MIGRATION_NEEDED
|
||||
CONFIG_FILE_NOT_FOUND
|
||||
CONFIG_FILE_REQUIRE_ERROR
|
||||
CONFIG_FILE_SETUP_NODE_EVENTS_ERROR
|
||||
@@ -1185,46 +1179,31 @@ enum ErrorTypeEnum {
|
||||
DUPLICATE_TASK_KEY
|
||||
ERROR_READING_FILE
|
||||
ERROR_WRITING_FILE
|
||||
EXPERIMENTAL_COMPONENT_TESTING_REMOVED
|
||||
EXPERIMENTAL_JIT_COMPILE_REMOVED
|
||||
EXPERIMENTAL_NETWORK_STUBBING_REMOVED
|
||||
EXPERIMENTAL_ORIGIN_DEPENDENCIES_E2E_ONLY
|
||||
EXPERIMENTAL_RUN_ALL_SPECS_E2E_ONLY
|
||||
EXPERIMENTAL_RUN_EVENTS_REMOVED
|
||||
EXPERIMENTAL_SAMESITE_REMOVED
|
||||
EXPERIMENTAL_SESSION_AND_ORIGIN_REMOVED
|
||||
EXPERIMENTAL_SESSION_SUPPORT_REMOVED
|
||||
EXPERIMENTAL_SHADOW_DOM_REMOVED
|
||||
EXPERIMENTAL_SINGLE_TAB_RUN_MODE
|
||||
EXPERIMENTAL_SKIP_DOMAIN_INJECTION_REMOVED
|
||||
EXPERIMENTAL_STUDIO_E2E_ONLY
|
||||
EXPERIMENTAL_STUDIO_REMOVED
|
||||
EXTENSION_NOT_LOADED
|
||||
FIREFOX_CDP_FAILED_TO_CONNECT
|
||||
FIREFOX_COULD_NOT_CONNECT
|
||||
FIREFOX_GC_INTERVAL_REMOVED
|
||||
FIREFOX_GECKODRIVER_FAILURE
|
||||
FIXTURE_NOT_FOUND
|
||||
FOLDER_NOT_WRITABLE
|
||||
FREE_PLAN_EXCEEDS_MONTHLY_TESTS
|
||||
FREE_PLAN_IN_GRACE_PERIOD_EXCEEDS_MONTHLY_TESTS
|
||||
FREE_PLAN_IN_GRACE_PERIOD_PARALLEL_FEATURE
|
||||
INCOMPATIBLE_PLUGIN_RETRIES
|
||||
INCORRECT_CI_BUILD_ID_USAGE
|
||||
INDETERMINATE_CI_BUILD_ID
|
||||
INJECT_DOCUMENT_DOMAIN_DEPRECATION
|
||||
INJECT_DOCUMENT_DOMAIN_E2E_ONLY
|
||||
INTEGRATION_FOLDER_REMOVED
|
||||
INVALID_CONFIG_OPTION
|
||||
INVALID_CYPRESS_INTERNAL_ENV
|
||||
INVALID_REPORTER_NAME
|
||||
INVOKED_BINARY_OUTSIDE_NPM_MODULE
|
||||
JIT_COMPONENT_TESTING
|
||||
LEGACY_CONFIG_ERROR_DURING_MIGRATION
|
||||
LEGACY_CONFIG_FILE
|
||||
MIGRATION_ALREADY_OCURRED
|
||||
MIGRATION_CYPRESS_NOT_FOUND
|
||||
MIGRATION_MISMATCHED_CYPRESS_VERSIONS
|
||||
MULTIPLE_SUPPORT_FILES_FOUND
|
||||
NO_DEFAULT_CONFIG_FILE_FOUND
|
||||
NO_PROJECT_FOUND_AT_PROJECT_ROOT
|
||||
@@ -1233,7 +1212,6 @@ enum ErrorTypeEnum {
|
||||
PARALLEL_FEATURE_NOT_AVAILABLE_IN_PLAN
|
||||
PLAN_EXCEEDS_MONTHLY_TESTS
|
||||
PLAN_IN_GRACE_PERIOD_RUN_GROUPING_FEATURE_USED
|
||||
PLUGINS_FILE_CONFIG_OPTION_REMOVED
|
||||
PLUGINS_RUN_EVENT_ERROR
|
||||
PORT_IN_USE_LONG
|
||||
PORT_IN_USE_SHORT
|
||||
@@ -1246,14 +1224,12 @@ enum ErrorTypeEnum {
|
||||
RENAMED_CONFIG_OPTION
|
||||
RENDERER_CRASHED
|
||||
RUN_GROUPING_FEATURE_NOT_AVAILABLE_IN_PLAN
|
||||
SETUP_NODE_EVENTS_DO_NOT_SUPPORT_DEV_SERVER
|
||||
SETUP_NODE_EVENTS_INVALID_EVENT_NAME_ERROR
|
||||
SETUP_NODE_EVENTS_IS_NOT_FUNCTION
|
||||
SUPPORT_FILE_NOT_FOUND
|
||||
TESTING_TYPE_NOT_CONFIGURED
|
||||
TESTS_DID_NOT_START_FAILED
|
||||
TESTS_DID_NOT_START_RETRYING
|
||||
TEST_FILES_RENAMED
|
||||
UNEXPECTED_BEFORE_BROWSER_LAUNCH_PROPERTIES
|
||||
UNEXPECTED_INTERNAL_ERROR
|
||||
UNEXPECTED_MUTATION_ERROR
|
||||
@@ -1481,149 +1457,6 @@ input LocalTestCountsInput {
|
||||
totalTests: Int!
|
||||
}
|
||||
|
||||
type ManualMigration implements Node {
|
||||
"""is the manual migration completed (all files are moved)"""
|
||||
completed: Boolean!
|
||||
|
||||
"""files needing manual migration"""
|
||||
files: [ManualMigrationFile!]!
|
||||
|
||||
"""Relay style Node ID field for the ManualMigration field"""
|
||||
id: ID!
|
||||
}
|
||||
|
||||
type ManualMigrationFile implements Node {
|
||||
"""Relay style Node ID field for the ManualMigrationFile field"""
|
||||
id: ID!
|
||||
|
||||
"""has the file been moved since opening the migration helper"""
|
||||
moved: Boolean!
|
||||
|
||||
"""name of file to migrate"""
|
||||
relative: String!
|
||||
}
|
||||
|
||||
"""Contains all data related to the 9.X to 10.0 migration UI"""
|
||||
type Migration {
|
||||
"""the component folder path used to store components tests"""
|
||||
componentFolder: String!
|
||||
|
||||
"""contents of the cypress.json file after conversion"""
|
||||
configAfterCode: String!
|
||||
|
||||
"""contents of the cypress.json file before conversion"""
|
||||
configBeforeCode: String!
|
||||
|
||||
"""the name of the config file after the migration"""
|
||||
configFileNameAfter: String!
|
||||
|
||||
"""the name of the config file to be migrated"""
|
||||
configFileNameBefore: String!
|
||||
|
||||
"""Steps filtered with the current context"""
|
||||
filteredSteps: [MigrationStep!]!
|
||||
|
||||
"""whether component testing is set up in the migrated config or not"""
|
||||
hasComponentTesting: Boolean!
|
||||
|
||||
"""whether the component folder is custom or not"""
|
||||
hasCustomComponentFolder: Boolean!
|
||||
|
||||
"""whether the testFiles member is custom or not in component testing"""
|
||||
hasCustomComponentTestFiles: Boolean!
|
||||
|
||||
"""whether the integration folder is custom or not"""
|
||||
hasCustomIntegrationFolder: Boolean!
|
||||
|
||||
"""whether the testFiles member is custom or not in integration"""
|
||||
hasCustomIntegrationTestFiles: Boolean!
|
||||
|
||||
"""the integration folder path used to store e2e tests"""
|
||||
integrationFolder: String!
|
||||
|
||||
"""Whether the project has Typescript"""
|
||||
isUsingTypeScript: Boolean
|
||||
|
||||
"""List of files needing manual conversion"""
|
||||
manualFiles: ManualMigration
|
||||
|
||||
"""whether the pre extension info should be displayed"""
|
||||
shouldMigratePreExtension: Boolean
|
||||
|
||||
"""All spec files after conversion"""
|
||||
specFiles: [MigrationFile!]!
|
||||
|
||||
"""Support files needing automated rename"""
|
||||
supportFiles: MigrationFile
|
||||
}
|
||||
|
||||
type MigrationFile {
|
||||
after: MigrationFileData!
|
||||
before: MigrationFileData!
|
||||
testingType: TestingTypeEnum!
|
||||
}
|
||||
|
||||
type MigrationFileData implements Node {
|
||||
"""Relay style Node ID field for the MigrationFileData field"""
|
||||
id: ID!
|
||||
parts: [MigrationFilePart!]!
|
||||
relative: String!
|
||||
}
|
||||
|
||||
type MigrationFilePart implements Node {
|
||||
"""is this part a folder or extension that needs migration"""
|
||||
group: String
|
||||
|
||||
"""should highlight in migration UI"""
|
||||
highlight: Boolean!
|
||||
|
||||
"""Relay style Node ID field for the MigrationFilePart field"""
|
||||
id: ID!
|
||||
|
||||
"""part of filename"""
|
||||
text: String!
|
||||
}
|
||||
|
||||
type MigrationRegexp {
|
||||
"""regexp to use to rename existing specs in component"""
|
||||
afterComponent: String!
|
||||
|
||||
"""regexp to use to rename existing specs in e2e"""
|
||||
afterE2E: String!
|
||||
|
||||
"""regexp to identify existing specs in component"""
|
||||
beforeComponent: String!
|
||||
|
||||
"""regexp to identify existing specs in e2e"""
|
||||
beforeE2E: String!
|
||||
}
|
||||
|
||||
"""Contains all data related to the 9.X to 10.0 migration UI"""
|
||||
type MigrationStep implements Node {
|
||||
"""Relay style Node ID field for the MigrationStep field"""
|
||||
id: ID!
|
||||
|
||||
"""Index of the step in the list"""
|
||||
index: Int!
|
||||
|
||||
"""Has the current step been completed"""
|
||||
isCompleted: Boolean!
|
||||
|
||||
"""This is the current step"""
|
||||
isCurrentStep: Boolean!
|
||||
|
||||
"""Identifier of the step"""
|
||||
name: MigrationStepEnum!
|
||||
}
|
||||
|
||||
enum MigrationStepEnum {
|
||||
configFile
|
||||
renameAuto
|
||||
renameManual
|
||||
renameSupport
|
||||
setupComponent
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
"""Internal use only, clears the cloud cache"""
|
||||
_clearCloudCache: Boolean
|
||||
@@ -1675,9 +1508,6 @@ type Mutation {
|
||||
dismissWarning(id: ID!): Query
|
||||
e2eExamples: [ScaffoldedFile!]!
|
||||
|
||||
"""user has finished migration component specs - move to next step"""
|
||||
finishedRenamingComponentSpecs: Query
|
||||
|
||||
"""Sets focus to the active browser window"""
|
||||
focusActiveBrowserWindow: Boolean!
|
||||
|
||||
@@ -1721,34 +1551,6 @@ type Mutation {
|
||||
"""Check if a give spec file will match the project spec pattern"""
|
||||
matchesSpecPattern(specFile: String!): Boolean!
|
||||
|
||||
"""While migrating to 10+ skip manual rename step"""
|
||||
migrateCloseManualRenameWatcher: Boolean
|
||||
|
||||
"""Merges the component testing config in cypress.config.{js,ts}"""
|
||||
migrateComponentTesting: Query
|
||||
|
||||
"""Transforms cypress.json file into cypress.config.js file"""
|
||||
migrateConfigFile: Query
|
||||
|
||||
"""While migrating to 10+ renames files to match the new .cy pattern"""
|
||||
migrateRenameSpecs(
|
||||
"""specs to move - current name"""
|
||||
after: [String!]
|
||||
|
||||
"""specs to move - current name"""
|
||||
before: [String!]
|
||||
skip: Boolean
|
||||
): Query
|
||||
|
||||
"""When the user decides to skip specs rename"""
|
||||
migrateRenameSpecsFolder: Query
|
||||
|
||||
"""While migrating to 10+ launch renaming of support file"""
|
||||
migrateRenameSupport: Query
|
||||
|
||||
"""While migrating to 10+ skip manual rename step"""
|
||||
migrateSkipManualRename: Query
|
||||
|
||||
"""
|
||||
Allow the relevant run for debugging marked as next to be considered the current relevant run
|
||||
"""
|
||||
@@ -2054,9 +1856,6 @@ type Query {
|
||||
Unique node machine identifier for this instance - may be nil if unable to resolve
|
||||
"""
|
||||
machineId: String
|
||||
|
||||
"""Metadata about the migration, null if we aren't showing it"""
|
||||
migration: Migration
|
||||
node(id: ID!): Node
|
||||
|
||||
"""Defines the suggested polling intervals for various schema resources"""
|
||||
|
||||
@@ -112,13 +112,6 @@ export const CurrentProject = objectType({
|
||||
},
|
||||
})
|
||||
|
||||
t.boolean('needsLegacyConfigMigration', {
|
||||
description: 'Whether the project needs to be migrated before proceeding',
|
||||
resolve (source, args, ctx) {
|
||||
return ctx.migration.needsCypressJsonMigration()
|
||||
},
|
||||
})
|
||||
|
||||
t.boolean('hasValidConfigFile', {
|
||||
description: 'Whether the project has a valid config file',
|
||||
resolve (source, args, ctx) {
|
||||
|
||||
@@ -1,290 +0,0 @@
|
||||
import { enumType, objectType } from 'nexus'
|
||||
import { TestingTypeEnum } from '..'
|
||||
import { MIGRATION_STEPS } from '@packages/types'
|
||||
|
||||
export const MigrationStepEnum = enumType({
|
||||
name: 'MigrationStepEnum',
|
||||
members: MIGRATION_STEPS,
|
||||
})
|
||||
|
||||
export const MigrationStep = objectType({
|
||||
name: 'MigrationStep',
|
||||
node: 'name',
|
||||
description: 'Contains all data related to the 9.X to 10.0 migration UI',
|
||||
definition (t) {
|
||||
t.nonNull.field('name', {
|
||||
type: MigrationStepEnum,
|
||||
description: 'Identifier of the step',
|
||||
})
|
||||
|
||||
t.nonNull.boolean('isCurrentStep', {
|
||||
description: 'This is the current step',
|
||||
resolve: (source, args, ctx) => {
|
||||
return ctx.coreData.migration.step === source.name
|
||||
},
|
||||
})
|
||||
|
||||
t.nonNull.boolean('isCompleted', {
|
||||
description: 'Has the current step been completed',
|
||||
resolve: (source, args, ctx) => {
|
||||
const indexOfObservedStep = ctx.coreData.migration.filteredSteps.indexOf(source.name)
|
||||
const indexOfCurrentStep = ctx.coreData.migration.filteredSteps.indexOf(ctx.coreData.migration.step)
|
||||
|
||||
return indexOfObservedStep < indexOfCurrentStep
|
||||
},
|
||||
})
|
||||
|
||||
t.nonNull.int('index', {
|
||||
description: 'Index of the step in the list',
|
||||
resolve: (source, args, ctx) => {
|
||||
return ctx.coreData.migration.filteredSteps.indexOf(source.name) + 1
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const MigrationFilePart = objectType({
|
||||
name: 'MigrationFilePart',
|
||||
node: (obj) => obj.text,
|
||||
definition (t) {
|
||||
t.nonNull.string('text', {
|
||||
description: 'part of filename',
|
||||
})
|
||||
|
||||
t.nonNull.boolean('highlight', {
|
||||
description: 'should highlight in migration UI',
|
||||
})
|
||||
|
||||
t.string('group', {
|
||||
description: 'is this part a folder or extension that needs migration',
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const ManualMigrationFile = objectType({
|
||||
name: 'ManualMigrationFile',
|
||||
node: 'relative',
|
||||
definition (t) {
|
||||
t.nonNull.boolean('moved', {
|
||||
description: 'has the file been moved since opening the migration helper',
|
||||
})
|
||||
|
||||
t.nonNull.string('relative', {
|
||||
description: 'name of file to migrate',
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const ManualMigration = objectType({
|
||||
name: 'ManualMigration',
|
||||
node: ({ files }) => files.map((f) => f.relative).join(),
|
||||
definition (t) {
|
||||
t.nonNull.list.nonNull.field('files', {
|
||||
type: ManualMigrationFile,
|
||||
description: 'files needing manual migration',
|
||||
})
|
||||
|
||||
t.nonNull.boolean('completed', {
|
||||
description: 'is the manual migration completed (all files are moved)',
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const MigrationFileData = objectType({
|
||||
name: 'MigrationFileData',
|
||||
node: (obj) => obj.parts.map((file) => file.text).join(''),
|
||||
definition (t) {
|
||||
t.nonNull.string('relative')
|
||||
|
||||
t.nonNull.list.nonNull.field('parts', {
|
||||
type: MigrationFilePart,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const MigrationFile = objectType({
|
||||
name: 'MigrationFile',
|
||||
definition (t) {
|
||||
t.nonNull.field('testingType', {
|
||||
type: TestingTypeEnum,
|
||||
})
|
||||
|
||||
t.nonNull.field('before', {
|
||||
type: MigrationFileData,
|
||||
})
|
||||
|
||||
t.nonNull.field('after', {
|
||||
type: MigrationFileData,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const MigrationRegexp = objectType({
|
||||
name: 'MigrationRegexp',
|
||||
definition (t) {
|
||||
t.nonNull.string('beforeE2E', {
|
||||
description: 'regexp to identify existing specs in e2e',
|
||||
})
|
||||
|
||||
t.nonNull.string('afterE2E', {
|
||||
description: 'regexp to use to rename existing specs in e2e',
|
||||
})
|
||||
|
||||
t.nonNull.string('beforeComponent', {
|
||||
description: 'regexp to identify existing specs in component',
|
||||
})
|
||||
|
||||
t.nonNull.string('afterComponent', {
|
||||
description: 'regexp to use to rename existing specs in component',
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const Migration = objectType({
|
||||
name: 'Migration',
|
||||
description: 'Contains all data related to the 9.X to 10.0 migration UI',
|
||||
definition (t) {
|
||||
t.nonNull.list.nonNull.field('filteredSteps', {
|
||||
type: MigrationStep,
|
||||
description: 'Steps filtered with the current context',
|
||||
resolve: (source, args, ctx) => {
|
||||
return ctx.coreData.migration.filteredSteps.map((name) => {
|
||||
return {
|
||||
name,
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
t.nonNull.list.nonNull.field('specFiles', {
|
||||
description: 'All spec files after conversion',
|
||||
type: MigrationFile,
|
||||
resolve: async (source, args, ctx) => {
|
||||
const result = await ctx.migration.getSpecsForMigrationGuide()
|
||||
|
||||
return result
|
||||
},
|
||||
})
|
||||
|
||||
t.field('manualFiles', {
|
||||
description: 'List of files needing manual conversion',
|
||||
type: ManualMigration,
|
||||
resolve: async (source, args, ctx) => {
|
||||
// avoid starting the watcher when not on this step
|
||||
if (ctx.coreData.migration.step !== 'renameManual') {
|
||||
return null
|
||||
}
|
||||
|
||||
const status = await ctx.migration.getComponentTestingMigrationStatus()
|
||||
|
||||
if (!status) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
completed: status.completed,
|
||||
// we sort it to make sure the endpoint always returns the
|
||||
// specs in the same order, so things don't jump around.
|
||||
files: [...status.files.values()]
|
||||
.sort((x, y) => y.relative.length - x.relative.length),
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
t.field('supportFiles', {
|
||||
description: 'Support files needing automated rename',
|
||||
type: MigrationFile,
|
||||
resolve: (source, args, ctx) => {
|
||||
return ctx.migration.supportFilesForMigrationGuide()
|
||||
},
|
||||
})
|
||||
|
||||
t.nonNull.string('configFileNameBefore', {
|
||||
description: 'the name of the config file to be migrated',
|
||||
resolve: (source, args, ctx) => {
|
||||
return ctx.migration.legacyConfigFile
|
||||
},
|
||||
})
|
||||
|
||||
t.nonNull.string('configFileNameAfter', {
|
||||
description: 'the name of the config file after the migration',
|
||||
resolve: (source, args, ctx) => {
|
||||
return ctx.migration.configFileNameAfterMigration
|
||||
},
|
||||
})
|
||||
|
||||
t.nonNull.string('configBeforeCode', {
|
||||
description: 'contents of the cypress.json file before conversion',
|
||||
resolve: (source, args, ctx) => {
|
||||
return JSON.stringify(ctx.coreData.migration.legacyConfigForMigration, null, 2)
|
||||
},
|
||||
})
|
||||
|
||||
t.nonNull.string('configAfterCode', {
|
||||
description: 'contents of the cypress.json file after conversion',
|
||||
resolve: (source, args, ctx) => {
|
||||
return ctx.migration.createConfigString()
|
||||
},
|
||||
})
|
||||
|
||||
t.nonNull.string('integrationFolder', {
|
||||
description: 'the integration folder path used to store e2e tests',
|
||||
resolve: async (source, args, ctx) => (await ctx.migration.integrationFolder()).toString(),
|
||||
})
|
||||
|
||||
t.nonNull.string('componentFolder', {
|
||||
description: 'the component folder path used to store components tests',
|
||||
resolve: async (source, args, ctx) => (await ctx.migration.componentFolder()).toString(),
|
||||
})
|
||||
|
||||
t.nonNull.boolean('hasCustomIntegrationFolder', {
|
||||
description: 'whether the integration folder is custom or not',
|
||||
resolve: (source, args, ctx) => {
|
||||
return ctx.coreData.migration.flags.hasCustomIntegrationFolder
|
||||
}
|
||||
,
|
||||
})
|
||||
|
||||
t.nonNull.boolean('hasCustomIntegrationTestFiles', {
|
||||
description: 'whether the testFiles member is custom or not in integration',
|
||||
resolve: (source, args, ctx) => {
|
||||
return ctx.coreData.migration.flags.hasCustomIntegrationTestFiles
|
||||
},
|
||||
})
|
||||
|
||||
t.nonNull.boolean('hasCustomComponentFolder', {
|
||||
description: 'whether the component folder is custom or not',
|
||||
resolve: (source, args, ctx) => {
|
||||
return ctx.coreData.migration.flags.hasCustomComponentFolder
|
||||
},
|
||||
})
|
||||
|
||||
t.nonNull.boolean('hasCustomComponentTestFiles', {
|
||||
description: 'whether the testFiles member is custom or not in component testing',
|
||||
resolve: (source, args, ctx) => {
|
||||
return ctx.coreData.migration.flags.hasCustomComponentTestFiles
|
||||
},
|
||||
})
|
||||
|
||||
t.nonNull.boolean('hasComponentTesting', {
|
||||
description: 'whether component testing is set up in the migrated config or not',
|
||||
resolve: (source, args, ctx) => {
|
||||
return ctx.coreData.migration.flags.hasComponentTesting
|
||||
},
|
||||
})
|
||||
|
||||
t.boolean('isUsingTypeScript', {
|
||||
description: 'Whether the project has Typescript',
|
||||
resolve (source, args, ctx) {
|
||||
return ctx.lifecycleManager.metaState.isUsingTypeScript
|
||||
},
|
||||
})
|
||||
|
||||
t.boolean('shouldMigratePreExtension', {
|
||||
description: 'whether the pre extension info should be displayed',
|
||||
resolve: (source, args, ctx) => {
|
||||
return ctx.migration.shouldMigratePreExtension
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -489,102 +489,6 @@ export const mutation = mutationType({
|
||||
},
|
||||
})
|
||||
|
||||
t.field('migrateRenameSpecs', {
|
||||
description: 'While migrating to 10+ renames files to match the new .cy pattern',
|
||||
type: Query,
|
||||
args: {
|
||||
skip: booleanArg(),
|
||||
before: list(nonNull(stringArg({
|
||||
description: 'specs to move - current name',
|
||||
}))),
|
||||
after: list(nonNull(stringArg({
|
||||
description: 'specs to move - current name',
|
||||
}))),
|
||||
},
|
||||
resolve: async (_, { skip, before, after }, ctx) => {
|
||||
if (!skip && before && after) {
|
||||
await ctx.actions.migration.renameSpecFiles(before, after)
|
||||
}
|
||||
|
||||
await ctx.actions.migration.nextStep()
|
||||
|
||||
return {}
|
||||
},
|
||||
})
|
||||
|
||||
t.field('migrateRenameSpecsFolder', {
|
||||
description: 'When the user decides to skip specs rename',
|
||||
type: Query,
|
||||
resolve: async (_, args, ctx) => {
|
||||
await ctx.actions.migration.renameSpecsFolder()
|
||||
await ctx.actions.migration.nextStep()
|
||||
|
||||
return {}
|
||||
},
|
||||
})
|
||||
|
||||
t.field('migrateSkipManualRename', {
|
||||
description: 'While migrating to 10+ skip manual rename step',
|
||||
type: Query,
|
||||
resolve: async (_, args, ctx) => {
|
||||
await ctx.actions.migration.nextStep()
|
||||
|
||||
return {}
|
||||
},
|
||||
})
|
||||
|
||||
t.field('migrateCloseManualRenameWatcher', {
|
||||
description: 'While migrating to 10+ skip manual rename step',
|
||||
type: 'Boolean',
|
||||
resolve: async (_, args, ctx) => {
|
||||
await ctx.actions.migration.closeManualRenameWatcher()
|
||||
|
||||
return true
|
||||
},
|
||||
})
|
||||
|
||||
t.field('finishedRenamingComponentSpecs', {
|
||||
description: 'user has finished migration component specs - move to next step',
|
||||
type: Query,
|
||||
resolve: async (_, args, ctx) => {
|
||||
await ctx.actions.migration.nextStep()
|
||||
|
||||
return {}
|
||||
},
|
||||
})
|
||||
|
||||
t.field('migrateRenameSupport', {
|
||||
description: 'While migrating to 10+ launch renaming of support file',
|
||||
type: Query,
|
||||
resolve: async (_, args, ctx) => {
|
||||
await ctx.actions.migration.renameSupportFile()
|
||||
await ctx.actions.migration.nextStep()
|
||||
|
||||
return {}
|
||||
},
|
||||
})
|
||||
|
||||
t.field('migrateConfigFile', {
|
||||
description: 'Transforms cypress.json file into cypress.config.js file',
|
||||
type: Query,
|
||||
resolve: async (_, args, ctx) => {
|
||||
await ctx.actions.migration.createConfigFile()
|
||||
await ctx.actions.migration.nextStep()
|
||||
|
||||
return {}
|
||||
},
|
||||
})
|
||||
|
||||
t.field('migrateComponentTesting', {
|
||||
description: 'Merges the component testing config in cypress.config.{js,ts}',
|
||||
type: Query,
|
||||
resolve: async (_, args, ctx) => {
|
||||
await ctx.actions.migration.nextStep()
|
||||
|
||||
return {}
|
||||
},
|
||||
})
|
||||
|
||||
t.field('setProjectIdInConfigFile', {
|
||||
description: 'Set the projectId field in the config file of the current project',
|
||||
type: Query,
|
||||
|
||||
@@ -5,7 +5,6 @@ import { CurrentProject } from './gql-CurrentProject'
|
||||
import { DevState } from './gql-DevState'
|
||||
import { AuthState } from './gql-AuthState'
|
||||
import { LocalSettings } from './gql-LocalSettings'
|
||||
import { Migration } from './gql-Migration'
|
||||
import { VersionData } from './gql-VersionData'
|
||||
import { Wizard } from './gql-Wizard'
|
||||
import { ErrorWrapper } from './gql-ErrorWrapper'
|
||||
@@ -42,23 +41,6 @@ export const Query = objectType({
|
||||
resolve: (root, args, ctx) => ctx.coreData.wizard,
|
||||
})
|
||||
|
||||
t.field('migration', {
|
||||
type: Migration,
|
||||
description: 'Metadata about the migration, null if we aren\'t showing it',
|
||||
resolve: async (root, args, ctx) => {
|
||||
// First check to see if "legacyConfigForMigration" is defined as that means we have started migration
|
||||
if (ctx.coreData.migration.legacyConfigForMigration) return ctx.coreData.migration.legacyConfigForMigration
|
||||
|
||||
if (!ctx.migration.needsCypressJsonMigration()) {
|
||||
return null
|
||||
}
|
||||
|
||||
await ctx.lifecycleManager.legacyMigration()
|
||||
|
||||
return ctx.coreData.migration.legacyConfigForMigration
|
||||
},
|
||||
})
|
||||
|
||||
t.nonNull.field('dev', {
|
||||
type: DevState,
|
||||
description: 'The state of any info related to local development of the runner',
|
||||
|
||||
@@ -17,7 +17,6 @@ export * from './gql-GeneratedSpecError'
|
||||
export * from './gql-GitInfo'
|
||||
export * from './gql-GlobalProject'
|
||||
export * from './gql-LocalSettings'
|
||||
export * from './gql-Migration'
|
||||
export * from './gql-Mutation'
|
||||
export * from './gql-ProjectPreferences'
|
||||
export * from './gql-Query'
|
||||
|
||||
@@ -9,8 +9,7 @@ It replaces the original electron app, `desktop-gui`.
|
||||
- Allow users to log in through Cypress Cloud
|
||||
- Onboarding for new users (configure Component Testing dev server, install dependencies, etc)
|
||||
- Select testing mode (E2E, Component)
|
||||
- Provide UI to perform automated migration steps (for example migrating `cypress.json` to `cypress.config.js` for projects upgrading from 9.x or below)
|
||||
- Provide a dismissable Welcome Screen for every major release of Cypress
|
||||
- Provide a dismissible Welcome Screen for every major release of Cypress
|
||||
|
||||
It is using the following technologies:
|
||||
|
||||
@@ -29,7 +28,7 @@ Cypress' entire back-end is powered by the `@packages/server` package. Launchpad
|
||||
|
||||
## Major Version Welcome Content
|
||||
|
||||
The content is bundled with the launchpad and at the time of writing this, it lives in `src/migration/MajorVersionWelcome.vue`. Shipping it as part of the app means it is always available upon release and it will always work offline. Guidelines for the management of the content itself are documented internally in our `prod-eng-docs`, but the implementation is documented here.
|
||||
The content is bundled with the launchpad and at the time of writing this, it lives in `src/welcome/MajorVersionWelcome.vue`. Shipping it as part of the app means it is always available upon release and it will always work offline. Guidelines for the management of the content itself are documented internally in our `prod-eng-docs`, but the implementation is documented here.
|
||||
|
||||
A constant named `MAJOR_VERSION_FOR_CONTENT` defines which major version the content is associated with for the purposes of recording user dismissal in persisted state. This needs to be bumped to match the major version that will be released, since that value is the key that records the dismissal.
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import defaultMessages from '@packages/frontend-shared/src/locales/en-US.json'
|
||||
import pkg from '../../../../package.json'
|
||||
import { getPathForPlatform } from './support/getPathForPlatform'
|
||||
|
||||
const expectStackToBe = (mode: 'open' | 'closed') => {
|
||||
@@ -34,54 +32,19 @@ describe('Config files error handling', () => {
|
||||
cy.contains('h1', 'Welcome to Cypress', { timeout: 10000 })
|
||||
})
|
||||
|
||||
it('shows the upgrade screen if there is a legacy config file', () => {
|
||||
cy.openProject('pristine-with-e2e-testing')
|
||||
cy.withCtx(async (ctx) => {
|
||||
await ctx.actions.file.writeFileInProject('cypress.json', '{}')
|
||||
await ctx.actions.file.removeFileInProject('cypress.config.js')
|
||||
})
|
||||
|
||||
cy.openProject('pristine-with-e2e-testing')
|
||||
|
||||
cy.visitLaunchpad()
|
||||
|
||||
cy.get('body').should('contain.text', defaultMessages.migration.wizard.title.replace('{version}', pkg.version.split('.')[0]))
|
||||
cy.get('body').should('contain.text', defaultMessages.migration.wizard.description)
|
||||
})
|
||||
|
||||
it('handles config files with legacy config file in same project', () => {
|
||||
cy.openProject('pristine-with-e2e-testing')
|
||||
cy.withCtx(async (ctx) => {
|
||||
await ctx.actions.file.writeFileInProject('cypress.json', '{}')
|
||||
})
|
||||
|
||||
cy.openProject('pristine-with-e2e-testing')
|
||||
cy.visitLaunchpad()
|
||||
|
||||
cy.contains('p', 'There is both a cypress.config.js and a cypress.json file at the location below:')
|
||||
cy.contains('body', 'Cypress no longer supports cypress.json')
|
||||
expectStackToBe('closed')
|
||||
|
||||
cy.withCtx(async (ctx) => {
|
||||
await ctx.actions.file.removeFileInProject('cypress.json')
|
||||
})
|
||||
|
||||
cy.findByRole('button', { name: 'Try again' }).click()
|
||||
|
||||
cy.contains('h1', 'Welcome to Cypress', { timeout: 10000 })
|
||||
})
|
||||
|
||||
it('handles deprecated config fields', () => {
|
||||
it('handles removed config fields', () => {
|
||||
cy.openProject('pristine')
|
||||
cy.withCtx(async (ctx) => {
|
||||
await ctx.actions.file.writeFileInProject('cypress.config.js', 'module.exports = { e2e: { supportFile: false, experimentalComponentTesting: true } }')
|
||||
// ensure the config set here has 'isWarning: false' to ensure it errors in UI
|
||||
// supportFile is required so the config is valid
|
||||
await ctx.actions.file.writeFileInProject('cypress.config.js', 'module.exports = { e2e: { supportFile: false, experimentalSkipDomainInjection: true } }')
|
||||
})
|
||||
|
||||
cy.openProject('pristine')
|
||||
|
||||
cy.visitLaunchpad()
|
||||
cy.get('[data-cy-testingType=e2e]').click()
|
||||
cy.get('body', { timeout: 10000 }).should('contain.text', 'experimentalComponentTesting')
|
||||
cy.get('body', { timeout: 10000 }).should('contain.text', 'experimentalSkipDomainInjection')
|
||||
expectStackToBe('closed')
|
||||
cy.withCtx(async (ctx) => {
|
||||
await ctx.actions.file.writeFileInProject('cypress.config.js', 'module.exports = { e2e: { supportFile: false } }')
|
||||
@@ -216,39 +179,31 @@ describe('Launchpad: Error System Tests', () => {
|
||||
})
|
||||
|
||||
describe('setupNodeEvents', () => {
|
||||
it('throws an error when in setupNodeEvents updating a config value that was removed in 10.X', () => {
|
||||
cy.scaffoldProject('config-update-non-migrated-value')
|
||||
cy.openProject('config-update-non-migrated-value')
|
||||
it('throws an error when in setupNodeEvents updating a config value in the root config that was removed', () => {
|
||||
cy.scaffoldProject('config-update-in-setup-node-events')
|
||||
cy.openProject('config-update-in-setup-node-events')
|
||||
cy.visitLaunchpad()
|
||||
cy.findByText('E2E Testing').click()
|
||||
cy.contains('h1', cy.i18n.launchpadErrors.generic.configErrorTitle, { timeout: 10000 })
|
||||
cy.findAllByTestId('collapsible').should('be.visible')
|
||||
cy.get('h2').contains('Error running e2e.setupNodeEvents()')
|
||||
cy.get('p').contains('The integrationFolder configuration option is now invalid when set on the config object in Cypress version 10.0.0.')
|
||||
cy.get('p').contains('It is now renamed to specPattern and configured separately as a end to end testing property: e2e.specPattern')
|
||||
cy.get('p').contains('The experimentalSkipDomainInjection experiment is over.')
|
||||
cy.get('p').contains('Read the migration guide for Cypress v14.0.0')
|
||||
})
|
||||
|
||||
it('throws an error when in setupNodeEvents updating a config value on a clone of config that was removed in 10.X', () => {
|
||||
cy.scaffoldProject('config-update-non-migrated-value-clone')
|
||||
cy.openProject('config-update-non-migrated-value-clone')
|
||||
it('throws an error when in setupNodeEvents updating a config value on a clone of config in the root config that was removed', () => {
|
||||
cy.scaffoldProject('config-update-in-setup-node-events-clone')
|
||||
cy.openProject('config-update-in-setup-node-events-clone')
|
||||
cy.visitLaunchpad()
|
||||
cy.findByText('E2E Testing').click()
|
||||
cy.contains('h1', cy.i18n.launchpadErrors.generic.configErrorTitle, { timeout: 10000 })
|
||||
cy.percySnapshot()
|
||||
|
||||
cy.get('[data-cy="alert-body"]').should('contain', 'integrationFolder')
|
||||
cy.get('p').contains('The experimentalSkipDomainInjection experiment is over.')
|
||||
cy.get('p').contains('Read the migration guide for Cypress v14.0.0')
|
||||
})
|
||||
|
||||
it('throws an error when in setupNodeEvents updating an e2e config value that was removed in 10.X', () => {
|
||||
cy.scaffoldProject('config-update-non-migrated-value-e2e')
|
||||
cy.openProject('config-update-non-migrated-value-e2e')
|
||||
cy.visitLaunchpad()
|
||||
cy.findByText('E2E Testing').click()
|
||||
cy.contains('h1', cy.i18n.launchpadErrors.generic.configErrorTitle, { timeout: 10000 })
|
||||
cy.percySnapshot()
|
||||
})
|
||||
|
||||
it('handles deprecated config fields in setupNodeEvents', () => {
|
||||
it('handles removed config fields in setupNodeEvents', () => {
|
||||
cy.scaffoldProject('pristine')
|
||||
cy.openProject('pristine')
|
||||
cy.withCtx(async (ctx) => {
|
||||
@@ -257,7 +212,7 @@ describe('setupNodeEvents', () => {
|
||||
e2e: {
|
||||
supportFile: false,
|
||||
setupNodeEvents(on, config){
|
||||
config.testFiles = '**/*.spec.js'
|
||||
config.experimentalSkipDomainInjection = true
|
||||
return config
|
||||
}
|
||||
}
|
||||
@@ -268,7 +223,7 @@ describe('setupNodeEvents', () => {
|
||||
|
||||
cy.visitLaunchpad()
|
||||
cy.get('[data-cy-testingType=e2e]').click()
|
||||
cy.get('body', { timeout: 10000 }).should('contain.text', 'testFiles')
|
||||
cy.get('body', { timeout: 10000 }).should('contain.text', 'experimentalSkipDomainInjection')
|
||||
cy.get('body', { timeout: 10000 }).should('contain.text', 'setupNodeEvents')
|
||||
expectStackToBe('closed')
|
||||
cy.withCtx(async (ctx) => {
|
||||
@@ -300,7 +255,7 @@ describe('setupNodeEvents', () => {
|
||||
cy.findByRole('button', { name: 'Try again' }).click()
|
||||
cy.get('[data-cy-testingType=e2e]').click()
|
||||
cy.contains('h1', cy.i18n.launchpadErrors.generic.configErrorTitle, { timeout: 10000 })
|
||||
cy.get('[data-cy="alert-body"]').should('contain', 'The baseUrl configuration option is now invalid when set from the root of the config object')
|
||||
cy.get('[data-cy="alert-body"]').should('contain', 'The baseUrl configuration option is invalid when set from the root of the config object')
|
||||
|
||||
cy.withCtx(async (ctx) => {
|
||||
await ctx.actions.file.writeFileInProject('cypress.config.js', `module.exports = { e2e: { baseUrl: 'http://localhost:3000', supportFile: false } }`)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,9 +23,6 @@
|
||||
v-else-if="query.data.value.isGlobalMode && !query.data.value?.currentProject"
|
||||
:gql="query.data.value"
|
||||
/>
|
||||
<MigrationWizard
|
||||
v-else-if="currentProject?.needsLegacyConfigMigration"
|
||||
/>
|
||||
<template v-else>
|
||||
<ScaffoldedFiles
|
||||
v-if="query.data.value.scaffoldedFiles"
|
||||
@@ -93,9 +90,8 @@ import StandardModal from '@cy/components/StandardModal.vue'
|
||||
import HeaderBar from '@cy/gql-components/HeaderBar.vue'
|
||||
import Spinner from '@cy/components/Spinner.vue'
|
||||
import CompareTestingTypes from './setup/CompareTestingTypes.vue'
|
||||
import MigrationWizard from './migration/MigrationWizard.vue'
|
||||
import ScaffoldedFiles from './setup/ScaffoldedFiles.vue'
|
||||
import MajorVersionWelcome from './migration/MajorVersionWelcome.vue'
|
||||
import MajorVersionWelcome from './welcome/MajorVersionWelcome.vue'
|
||||
import { useI18n } from '@cy/i18n'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import LaunchpadHeader from './setup/LaunchpadHeader.vue'
|
||||
@@ -131,7 +127,6 @@ fragment MainLaunchpadQueryData on Query {
|
||||
isLoadingConfigFile
|
||||
isLoadingNodeEvents
|
||||
isFullConfigReady
|
||||
needsLegacyConfigMigration
|
||||
currentTestingType
|
||||
activeBrowser {
|
||||
id
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
// tslint:disable-next-line: no-implicit-dependencies - need to handle this
|
||||
import { defaultMessages } from '@cy/i18n'
|
||||
import { ConvertConfigFileFragmentDoc } from '../generated/graphql-test'
|
||||
import ConvertConfigFile from './ConvertConfigFile.vue'
|
||||
|
||||
describe('<ConvertConfigFile/>', { viewportWidth: 1119 }, () => {
|
||||
it('renders the lines for components folder', () => {
|
||||
cy.mountFragment(ConvertConfigFileFragmentDoc, {
|
||||
onResult (res) {
|
||||
res.hasCustomComponentFolder = true
|
||||
|
||||
return res
|
||||
},
|
||||
render (gql) {
|
||||
return (<div class="p-[16px]">
|
||||
<ConvertConfigFile gql={gql} />
|
||||
</div>)
|
||||
},
|
||||
})
|
||||
|
||||
cy.findByText('component.specPattern').should('be.visible')
|
||||
cy.findByText('componentFolder').should('be.visible')
|
||||
})
|
||||
|
||||
it('renders the lines for components testFiles', () => {
|
||||
cy.mountFragment(ConvertConfigFileFragmentDoc, {
|
||||
onResult (res) {
|
||||
res.hasCustomComponentTestFiles = true
|
||||
|
||||
return res
|
||||
},
|
||||
render (gql) {
|
||||
return (<div class="p-[16px]">
|
||||
<ConvertConfigFile gql={gql} />
|
||||
</div>)
|
||||
},
|
||||
})
|
||||
|
||||
cy.findByText('component.specPattern').should('be.visible')
|
||||
cy.findByText('testFiles').should('be.visible')
|
||||
cy.findByText('e2e.specPattern').should('not.exist')
|
||||
})
|
||||
|
||||
it('renders the lines for e2e folder', () => {
|
||||
cy.mountFragment(ConvertConfigFileFragmentDoc, {
|
||||
onResult (res) {
|
||||
res.hasCustomIntegrationFolder = true
|
||||
|
||||
return res
|
||||
},
|
||||
render (gql) {
|
||||
return (<div class="p-[16px]">
|
||||
<ConvertConfigFile gql={gql} />
|
||||
</div>)
|
||||
},
|
||||
})
|
||||
|
||||
cy.findByText('e2e.specPattern').should('be.visible')
|
||||
cy.findByText('integrationFolder').should('be.visible')
|
||||
})
|
||||
|
||||
it('renders the lines for e2e testFiles', () => {
|
||||
cy.mountFragment(ConvertConfigFileFragmentDoc, {
|
||||
onResult (res) {
|
||||
res.hasCustomIntegrationTestFiles = true
|
||||
|
||||
return res
|
||||
},
|
||||
render (gql) {
|
||||
return (<div class="p-[16px]">
|
||||
<ConvertConfigFile gql={gql} />
|
||||
</div>)
|
||||
},
|
||||
})
|
||||
|
||||
cy.findByText('e2e.specPattern').should('be.visible')
|
||||
cy.findByText('testFiles').should('be.visible')
|
||||
cy.findByText('componentFolder').should('not.exist')
|
||||
})
|
||||
|
||||
it('renders all lines if both are custom', () => {
|
||||
cy.mountFragment(ConvertConfigFileFragmentDoc, {
|
||||
onResult (res) {
|
||||
res.hasCustomIntegrationTestFiles = true
|
||||
res.hasCustomComponentFolder = true
|
||||
|
||||
return res
|
||||
},
|
||||
render (gql) {
|
||||
return (<div class="p-[16px]">
|
||||
<ConvertConfigFile gql={gql} />
|
||||
</div>)
|
||||
},
|
||||
})
|
||||
|
||||
cy.findByText('e2e.specPattern').should('be.visible')
|
||||
cy.findByText('component.specPattern').should('be.visible')
|
||||
cy.contains('li', 'testFiles').should('contain', 'e2e.specPattern')
|
||||
cy.contains('li', 'componentFolder').should('contain', 'component.specPattern')
|
||||
})
|
||||
|
||||
it('renders expected content with title', () => {
|
||||
cy.mountFragment(ConvertConfigFileFragmentDoc, {
|
||||
render (gql) {
|
||||
return (<div class="p-[16px]">
|
||||
<ConvertConfigFile gql={gql} />
|
||||
</div>)
|
||||
},
|
||||
})
|
||||
|
||||
cy.contains(defaultMessages.migration.configFile.title).should('be.visible')
|
||||
})
|
||||
})
|
||||
@@ -1,185 +0,0 @@
|
||||
<template>
|
||||
<div class="text-[16px] leading-[24px]">
|
||||
<MigrationTitle :title="t('migration.configFile.title')" />
|
||||
<MigrationList>
|
||||
<MigrationListItem>
|
||||
{{ t("migration.configFile.changedDefault") }}
|
||||
<CodeTag class="text-red-500">
|
||||
cypress.json
|
||||
</CodeTag>
|
||||
<i-cy-arrow-right_x16 class="inline-block h-[16px] w-[16px] icon-dark-gray-300" />
|
||||
<CodeTag class="text-jade-500">
|
||||
{{ fileName }}
|
||||
</CodeTag>
|
||||
</MigrationListItem>
|
||||
<MigrationListItem v-if="props.gql.hasCustomIntegrationFolder || props.gql.hasCustomIntegrationTestFiles">
|
||||
<i18n-t
|
||||
scope="global"
|
||||
keypath="migration.configFile.customOptions"
|
||||
>
|
||||
<template #specPattern>
|
||||
<CodeTag class="text-jade-500">
|
||||
e2e.specPattern
|
||||
</CodeTag>
|
||||
</template>
|
||||
<template #options>
|
||||
<template v-if="props.gql.hasCustomIntegrationFolder && props.gql.hasCustomIntegrationTestFiles">
|
||||
<CodeTag class="text-red-500">
|
||||
integrationFolder
|
||||
</CodeTag> and <CodeTag class="text-red-500">
|
||||
testFiles
|
||||
</CodeTag> options
|
||||
</template>
|
||||
<template v-else-if="props.gql.hasCustomIntegrationFolder">
|
||||
<CodeTag class="text-red-500">
|
||||
integrationFolder
|
||||
</CodeTag> option
|
||||
</template>
|
||||
<template v-else-if="props.gql.hasCustomIntegrationTestFiles">
|
||||
<CodeTag class="text-red-500">
|
||||
testFiles
|
||||
</CodeTag> option
|
||||
</template>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</MigrationListItem>
|
||||
<MigrationListItem v-if="props.gql.hasCustomComponentFolder || props.gql.hasCustomComponentTestFiles">
|
||||
<i18n-t
|
||||
scope="global"
|
||||
keypath="migration.configFile.customOptions"
|
||||
>
|
||||
<template #specPattern>
|
||||
<CodeTag class="text-jade-500">
|
||||
component.specPattern
|
||||
</CodeTag>
|
||||
</template>
|
||||
<template #options>
|
||||
<template v-if="props.gql.hasCustomComponentFolder && props.gql.hasCustomComponentTestFiles">
|
||||
<CodeTag class="text-red-500">
|
||||
componentFolder
|
||||
</CodeTag> and <CodeTag class="text-red-500">
|
||||
testFiles
|
||||
</CodeTag> options
|
||||
</template>
|
||||
<template v-else-if="props.gql.hasCustomComponentFolder">
|
||||
<CodeTag class="text-red-500">
|
||||
componentFolder
|
||||
</CodeTag> option
|
||||
</template>
|
||||
<template v-else-if="props.gql.hasCustomComponentTestFiles">
|
||||
<CodeTag class="text-red-500">
|
||||
testFiles
|
||||
</CodeTag> option
|
||||
</template>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</MigrationListItem>
|
||||
<MigrationListItem>
|
||||
<i18n-t
|
||||
scope="global"
|
||||
keypath="migration.configFile.willConvert"
|
||||
>
|
||||
<template #jsonFile>
|
||||
<CodeTag class="text-red-500">
|
||||
{{ props.gql.configFileNameBefore }}
|
||||
</CodeTag>
|
||||
</template>
|
||||
<template #jsFile>
|
||||
<CodeTag class="text-jade-500">
|
||||
{{ props.gql.configFileNameAfter }}
|
||||
</CodeTag>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</MigrationListItem>
|
||||
</MigrationList>
|
||||
<BeforeAfter>
|
||||
<template #beforeHeader>
|
||||
<span class="mr-[8px]">{{ t('migration.before') }}</span>
|
||||
<CodeTag
|
||||
bg
|
||||
class="text-red-600 bg-red-100"
|
||||
>
|
||||
{{ props.gql.configFileNameBefore }}
|
||||
</CodeTag>
|
||||
</template>
|
||||
<template #afterHeader>
|
||||
<span class="mr-[8px]">{{ t('migration.after') }}</span>
|
||||
<CodeTag
|
||||
bg
|
||||
class="bg-jade-100 text-jade-600"
|
||||
>
|
||||
{{ props.gql.configFileNameAfter }}
|
||||
</CodeTag>
|
||||
</template>
|
||||
<template #before>
|
||||
<ShikiHighlight
|
||||
:code="codeBefore"
|
||||
lang="json"
|
||||
line-numbers
|
||||
skip-trim
|
||||
/>
|
||||
</template>
|
||||
<template #after>
|
||||
<ShikiHighlight
|
||||
:code="codeAfter"
|
||||
lang="js"
|
||||
line-numbers
|
||||
skip-trim
|
||||
/>
|
||||
</template>
|
||||
</BeforeAfter>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import CodeTag from '@cy/components/CodeTag.vue'
|
||||
import BeforeAfter from './fragments/BeforeAfter.vue'
|
||||
import ShikiHighlight from '@packages/frontend-shared/src/components/ShikiHighlight.vue'
|
||||
import MigrationList from './fragments/MigrationList.vue'
|
||||
import MigrationTitle from './fragments/MigrationTitle.vue'
|
||||
import { useI18n } from '@cy/i18n'
|
||||
import { gql } from '@urql/vue'
|
||||
import type { ConvertConfigFileFragment } from '../generated/graphql'
|
||||
import MigrationListItem from './fragments/MigrationListItem.vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
gql`
|
||||
fragment ConvertConfigFile on Migration {
|
||||
configFileNameBefore
|
||||
configFileNameAfter
|
||||
configBeforeCode
|
||||
configAfterCode
|
||||
hasCustomIntegrationFolder
|
||||
hasCustomIntegrationTestFiles
|
||||
hasCustomComponentFolder
|
||||
hasCustomComponentTestFiles
|
||||
isUsingTypeScript
|
||||
}`
|
||||
|
||||
const props = defineProps<{
|
||||
gql: ConvertConfigFileFragment
|
||||
}>()
|
||||
|
||||
const gqlCodeBeforeLines = computed(() => props.gql.configBeforeCode.split('\n').length)
|
||||
const gqlCodeAfterLines = computed(() => props.gql.configAfterCode.split('\n').length)
|
||||
const gqlCodeMaxLines = computed(() => Math.max(gqlCodeBeforeLines.value, gqlCodeAfterLines.value))
|
||||
|
||||
const codeBefore = computed(() => {
|
||||
return props.gql.configBeforeCode + Array(gqlCodeMaxLines.value - gqlCodeBeforeLines.value).fill('\n').join('')
|
||||
})
|
||||
|
||||
const codeAfter = computed(() => {
|
||||
return props.gql.configAfterCode + Array(gqlCodeMaxLines.value - gqlCodeAfterLines.value).fill('\n').join('')
|
||||
})
|
||||
|
||||
const fileName = computed(() => props.gql.isUsingTypeScript ? 'cypress.config.ts' : 'cypress.config.js')
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.before\:block {
|
||||
content:'';
|
||||
}
|
||||
</style>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user