diff --git a/circle.yml b/circle.yml index b1e59b41530b..05941114e508 100644 --- a/circle.yml +++ b/circle.yml @@ -516,13 +516,17 @@ commands: steps: - run: yarn verify:mocha:results <> - clone-repo-and-checkout-release-branch: + clone-repo-and-checkout-branch: description: | Clones an external repo and then checks out the branch that matches the next version otherwise uses 'master' branch. parameters: repo: description: "Name of the github repo to clone like: cypress-example-kitchensink" type: string + pull_request_id: + description: Pull request number to check out before installing and testing + type: integer + default: 0 steps: - restore_cached_binary - run: @@ -530,6 +534,16 @@ commands: command: | git clone --depth 1 --no-single-branch https://github.com/cypress-io/<>.git /tmp/<> cd /tmp/<> && (git checkout $(node ./scripts/get-next-version) || true) + - when: + condition: <> + steps: + - run: + name: Check out PR <> + working_directory: /tmp/<> + command: | + git fetch origin pull/<>/head:pr-<> + git checkout pr-<> + git log -n 2 test-binary-against-rwa: description: | @@ -571,7 +585,7 @@ commands: type: string default: "CI=true yarn start" steps: - - clone-repo-and-checkout-release-branch: + - clone-repo-and-checkout-branch: repo: <> - when: condition: <> @@ -701,18 +715,9 @@ commands: type: string default: "npm start --if-present" steps: - - clone-repo-and-checkout-release-branch: + - clone-repo-and-checkout-branch: repo: <> - - when: - condition: <> - steps: - - run: - name: Check out PR <> - working_directory: /tmp/<> - command: | - git fetch origin pull/<>/head:pr-<> - git checkout pr-<> - git log -n 2 + pull_request_id: <> - run: # Install deps + Cypress binary with yarn if yarn.lock present command: | @@ -724,6 +729,16 @@ commands: CYPRESS_INSTALL_BINARY=~/cypress/cypress.zip npm install ~/cypress/cypress.tgz fi working_directory: /tmp/<> + - run: + name: Scaffold new config file + working_directory: /tmp/<> + environment: + CYPRESS_INTERNAL_FORCE_SCAFFOLD: "1" + command: | + if [[ -f cypress.json ]]; then + rm -rf cypress.json + echo 'module.exports = {}' > cypress.config.js + fi - run: name: Print Cypress version working_directory: /tmp/<> @@ -1610,9 +1625,17 @@ jobs: test-kitchensink: <<: *defaults steps: - - clone-repo-and-checkout-release-branch: + - clone-repo-and-checkout-branch: repo: cypress-example-kitchensink + pull_request_id: 510 - install-required-node + - run: + name: Remove cypress.json + description: Remove cypress.json in case it exists + working_directory: /tmp/cypress-example-kitchensink + environment: + CYPRESS_INTERNAL_FORCE_SCAFFOLD: "1" + command: rm -rf cypress.json - run: name: Install prod dependencies command: yarn --production @@ -1637,7 +1660,7 @@ jobs: <<: *defaults resource_class: medium steps: - - clone-repo-and-checkout-release-branch: + - clone-repo-and-checkout-branch: repo: cypress-example-kitchensink - run: name: Install prod dependencies @@ -1662,7 +1685,7 @@ jobs: <<: *defaults resource_class: medium steps: - - clone-repo-and-checkout-release-branch: + - clone-repo-and-checkout-branch: repo: cypress-test-tiny - run: name: Run test project @@ -1846,7 +1869,7 @@ jobs: environment: CYPRESS_INTERNAL_FORCE_SCAFFOLD: "1" command: | - echo '{}' > cypress.json + echo 'module.exports = {}' > cypress.config.js npx cypress run test-full-typescript-project: @@ -1878,6 +1901,14 @@ jobs: name: Scaffold full TypeScript project 🏗 working_directory: <> command: npx @bahmutov/cly@1 init --typescript + - run: + name: Scaffold new config file + working_directory: <> + environment: + CYPRESS_INTERNAL_FORCE_SCAFFOLD: "1" + command: | + rm -rf cypress.json + echo 'export default {}' > cypress.config.ts - run: name: Run project tests 🗳 working_directory: <> @@ -1888,7 +1919,7 @@ jobs: <<: *defaults steps: - restore_workspace_binaries - - clone-repo-and-checkout-release-branch: + - clone-repo-and-checkout-branch: repo: cypress-test-tiny - run: name: Install Cypress @@ -1940,6 +1971,7 @@ jobs: - test-binary-against-repo: repo: cypress-example-kitchensink browser: "electron" + pull_request_id: 510 test-binary-against-awesome-typescript-loader: <<: *defaults @@ -1955,6 +1987,7 @@ jobs: - test-binary-against-repo: repo: cypress-example-kitchensink browser: firefox + pull_request_id: 510 "test-binary-against-kitchensink-chrome": <<: *defaults @@ -1963,6 +1996,7 @@ jobs: - test-binary-against-repo: repo: cypress-example-kitchensink browser: chrome + pull_request_id: 510 "test-binary-against-todomvc-firefox": <<: *defaults @@ -2056,6 +2090,14 @@ jobs: name: Add Cypress demo working_directory: test-binary command: npx @bahmutov/cly init + - run: + name: Scaffold new config file + working_directory: test-binary + environment: + CYPRESS_INTERNAL_FORCE_SCAFFOLD: "1" + command: | + rm -rf cypress.json + echo 'module.exports = {}' > cypress.config.js - run: name: Verify Cypress binary working_directory: test-binary diff --git a/cli/__snapshots__/cli_spec.js b/cli/__snapshots__/cli_spec.js index 398d6bdc721d..aea378cff865 100644 --- a/cli/__snapshots__/cli_spec.js +++ b/cli/__snapshots__/cli_spec.js @@ -21,19 +21,21 @@ exports['shows help for open --foo 1'] = ` --component runs component tests -c, --config sets configuration values. separate multiple values with a comma. overrides any value in - cypress.json. + cypress.config.{ts|js}. -C, --config-file path to JSON file where configuration values - are set. defaults to "cypress.json". pass - "false" to disable. + are set. defaults to + "cypress.config.{ts|js}". pass "false" to + disable. -d, --detached [bool] runs Cypress application in detached mode --e2e runs end to end tests -e, --env sets environment variables. separate multiple values with a comma. overrides any - value in cypress.json or cypress.env.json + value in cypress.config.{ts|js} or + cypress.env.json --global force Cypress into global mode as if its globally installed -p, --port runs Cypress on a specific port. overrides - any value in cypress.json. + any value in cypress.config.{ts|js}. -P, --project path to the project --dev runs cypress in development and bypasses binary check @@ -67,17 +69,17 @@ exports['shows help for run --foo 1'] = ` -b, --browser runs Cypress in the browser with the given name. if a filesystem path is supplied, Cypress will attempt to use the browser at that path. --ci-build-id the unique identifier for a run on your CI provider. typically a "BUILD_ID" env var. this value is automatically detected for most CI providers --component runs component tests - -c, --config sets configuration values. separate multiple values with a comma. overrides any value in cypress.json. - -C, --config-file path to JSON file where configuration values are set. defaults to "cypress.json". pass "false" to disable. + -c, --config sets configuration values. separate multiple values with a comma. overrides any value in cypress.config.{ts|js}. + -C, --config-file path to JSON file where configuration values are set. defaults to "cypress.config.{ts|js}". pass "false" to disable. --e2e runs end to end tests - -e, --env sets environment variables. separate multiple values with a comma. overrides any value in cypress.json or cypress.env.json + -e, --env sets environment variables. separate multiple values with a comma. overrides any value in cypress.config.{ts|js} or cypress.env.json --group a named group for recorded runs in the Cypress Dashboard -k, --key your secret Record Key. you can omit this if you set a CYPRESS_RECORD_KEY environment variable. --headed displays the browser instead of running headlessly --headless hide the browser instead of running headed (default for cypress run) --no-exit keep the browser open after tests finish --parallel enables concurrent runs and automatic load balancing of specs across multiple machines or processes - -p, --port runs Cypress on a specific port. overrides any value in cypress.json. + -p, --port runs Cypress on a specific port. overrides any value in cypress.config.{ts|js}. -P, --project path to the project -q, --quiet run quietly, using only the configured reporter --record [bool] records the run. sends test results, screenshots and videos to your Cypress Dashboard. diff --git a/cli/lib/cli.js b/cli/lib/cli.js index 778d60f710cc..83ed03901c21 100644 --- a/cli/lib/cli.js +++ b/cli/lib/cli.js @@ -107,12 +107,12 @@ const descriptions = { cacheSize: 'Used with the list command to show the sizes of the cached folders', ciBuildId: 'the unique identifier for a run on your CI provider. typically a "BUILD_ID" env var. this value is automatically detected for most CI providers', component: 'runs component tests', - config: 'sets configuration values. separate multiple values with a comma. overrides any value in cypress.json.', - configFile: 'path to JSON file where configuration values are set. defaults to "cypress.json". pass "false" to disable.', + config: 'sets configuration values. separate multiple values with a comma. overrides any value in cypress.config.{ts|js}.', + configFile: 'path to JSON file where configuration values are set. defaults to "cypress.config.{ts|js}". pass "false" to disable.', detached: 'runs Cypress application in detached mode', dev: 'runs cypress in development and bypasses binary check', e2e: 'runs end to end tests', - env: 'sets environment variables. separate multiple values with a comma. overrides any value in cypress.json or cypress.env.json', + env: 'sets environment variables. separate multiple values with a comma. overrides any value in cypress.config.{ts|js} or cypress.env.json', exit: 'keep the browser open after tests finish', forceInstall: 'force install the Cypress binary', global: 'force Cypress into global mode as if its globally installed', @@ -121,7 +121,7 @@ const descriptions = { headless: 'hide the browser instead of running headed (default for cypress run)', key: 'your secret Record Key. you can omit this if you set a CYPRESS_RECORD_KEY environment variable.', parallel: 'enables concurrent runs and automatic load balancing of specs across multiple machines or processes', - port: 'runs Cypress on a specific port. overrides any value in cypress.json.', + port: 'runs Cypress on a specific port. overrides any value in cypress.config.{ts|js}.', project: 'path to the project', quiet: 'run quietly, using only the configured reporter', record: 'records the run. sends test results, screenshots and videos to your Cypress Dashboard.', diff --git a/cli/schema/cypress.schema.json b/cli/schema/cypress.schema.json index 617664c1028d..baa58a927905 100644 --- a/cli/schema/cypress.schema.json +++ b/cli/schema/cypress.schema.json @@ -282,7 +282,7 @@ "includeShadowDom": { "type": "boolean", "default": false, - "description": "Enables including elements within the shadow DOM when using querying commands (e.g. cy.get(), cy.find()). Can be set globally in cypress.json, per-suite or per-test in the test configuration object, or programmatically with Cypress.config()" + "description": "Enables including elements within the shadow DOM when using querying commands (e.g. cy.get(), cy.find()). Can be set globally in cypress.config.{ts|js}, per-suite or per-test in the test configuration object, or programmatically with Cypress.config()" }, "clientCertificates": { "description": "Defines client certificates to use when sending requests to the specified URLs", diff --git a/cli/test/lib/cypress_spec.js b/cli/test/lib/cypress_spec.js index 2edaa3b0e169..12694b5611e3 100644 --- a/cli/test/lib/cypress_spec.js +++ b/cli/test/lib/cypress_spec.js @@ -234,12 +234,12 @@ describe('cypress', function () { }) }) - it('coerces --config-file cypress.json to string', async () => { - const args = 'cypress run --config-file cypress.json'.split(' ') + it('coerces --config-file cypress.config.js to string', async () => { + const args = 'cypress run --config-file cypress.config.js'.split(' ') const options = await cypress.cli.parseRunArguments(args) expect(options).to.deep.equal({ - configFile: 'cypress.json', + configFile: 'cypress.config.js', }) }) diff --git a/cli/test/lib/exec/open_spec.js b/cli/test/lib/exec/open_spec.js index f9d3aa5878b5..fcb975f8dd9c 100644 --- a/cli/test/lib/exec/open_spec.js +++ b/cli/test/lib/exec/open_spec.js @@ -66,10 +66,10 @@ describe('exec open', function () { }) it('spawns with --config-file set', function () { - return open.start({ configFile: 'special-cypress.json' }) + return open.start({ configFile: 'special-cypress.config.js' }) .then(() => { expect(spawn.start).to.be.calledWith( - ['--config-file', 'special-cypress.json'], + ['--config-file', 'special-cypress.config.js'], ) }) }) diff --git a/cli/test/lib/exec/run_spec.js b/cli/test/lib/exec/run_spec.js index 82428d09de30..0f23ef74c234 100644 --- a/cli/test/lib/exec/run_spec.js +++ b/cli/test/lib/exec/run_spec.js @@ -150,10 +150,10 @@ describe('exec run', function () { }) it('spawns with --config-file set', function () { - return run.start({ configFile: 'special-cypress.json' }) + return run.start({ configFile: 'special-cypress.config.js' }) .then(() => { expect(spawn.start).to.be.calledWith( - ['--run-project', process.cwd(), '--config-file', 'special-cypress.json'], + ['--run-project', process.cwd(), '--config-file', 'special-cypress.config.js'], ) }) }) diff --git a/cli/types/cypress-npm-api.d.ts b/cli/types/cypress-npm-api.d.ts index c60a34713812..c001524cb4f1 100644 --- a/cli/types/cypress-npm-api.d.ts +++ b/cli/types/cypress-npm-api.d.ts @@ -144,7 +144,7 @@ declare namespace CypressCommandLine { * * If `false` is passed, no config file will be used. * - * @default "cypress.json" + * @default "cypress.config.{ts|js}" */ configFile: string | false /** diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index 9cdf912eea84..590bc0d674fb 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -353,7 +353,7 @@ declare namespace Cypress { // no real way to type without generics /** - * Returns all environment variables set with CYPRESS_ prefix or in "env" object in "cypress.json" + * Returns all environment variables set with CYPRESS_ prefix or in "env" object in "cypress.config.{ts|js}" * * @see https://on.cypress.io/env */ @@ -362,7 +362,7 @@ declare namespace Cypress { * Returns specific environment variable or undefined * @see https://on.cypress.io/env * @example - * // cypress.json + * // cypress.config.js * { "env": { "foo": "bar" } } * Cypress.env("foo") // => bar */ @@ -2756,7 +2756,7 @@ declare namespace Cypress { retries: Nullable, openMode?: Nullable }> /** * Enables including elements within the shadow DOM when using querying - * commands (e.g. cy.get(), cy.find()). Can be set globally in cypress.json, + * commands (e.g. cy.get(), cy.find()). Can be set globally in cypress.config.{ts|js}, * per-suite or per-test in the test configuration object, or programmatically * with Cypress.config() * @default false @@ -2894,7 +2894,7 @@ declare namespace Cypress { interface PluginConfigOptions extends ResolvedConfigOptions { /** - * Absolute path to the config file (default: /cypress.json) or false + * Absolute path to the config file (default: /cypress.config.{ts|js}) or false */ configFile: string | false /** diff --git a/npm/angular/README.md b/npm/angular/README.md index 4455fcafaa7f..82358a40ca23 100644 --- a/npm/angular/README.md +++ b/npm/angular/README.md @@ -22,10 +22,10 @@ require('core-js/es7/reflect'); require('@cypress/angular/support'); ``` -Enable component testing in `cypress.json`. +Enable component testing in `cypress.config.js`. -```json -{ +```js +module.exports = { "component": { "componentFolder": "src/app", "testFiles": "**/*cy-spec.ts" diff --git a/npm/angular/cypress.config.ts b/npm/angular/cypress.config.ts new file mode 100644 index 000000000000..1b17dee3806b --- /dev/null +++ b/npm/angular/cypress.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + 'experimentalFetchPolyfill': true, + 'fixturesFolder': false, + 'includeShadowDom': true, + 'fileServerFolder': 'src', + 'projectId': 'nf7zag', + 'component': { + 'componentFolder': 'src/app', + 'testFiles': '**/*cy-spec.ts', + }, +}) diff --git a/npm/angular/cypress.json b/npm/angular/cypress.json deleted file mode 100644 index ebe21a31c348..000000000000 --- a/npm/angular/cypress.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "experimentalFetchPolyfill": true, - "fixturesFolder": false, - "includeShadowDom": true, - "fileServerFolder": "src", - "projectId": "nf7zag", - "component": { - "componentFolder": "src/app", - "testFiles": "**/*cy-spec.ts" - } -} diff --git a/npm/angular/src/app/assets-image/assets-image.component.cy-spec.ts b/npm/angular/src/app/assets-image/assets-image.component.cy-spec.ts index cfe6f9e672fa..9770b55586d2 100644 --- a/npm/angular/src/app/assets-image/assets-image.component.cy-spec.ts +++ b/npm/angular/src/app/assets-image/assets-image.component.cy-spec.ts @@ -7,7 +7,7 @@ describe('AssetsImageComponent', () => { it.skip('should create', () => { initEnv(AssetsImageComponent) mount(AssetsImageComponent) - // add "fileServerFolder": "src" in cypress.json + // add "fileServerFolder": "src" in cypress.config.{ts|js} cy.get('img#noSlash') .should('be.visible') .and(($img) => { @@ -29,7 +29,7 @@ describe('AssetsImageComponent', () => { it.skip('should create with AppModule', () => { initEnv({ imports: [AppModule] }) mount(AssetsImageComponent) - // add "fileServerFolder": "src" in cypress.json + // add "fileServerFolder": "src" in cypress.config.{ts|js} cy.get('img#noSlash') .should('be.visible') .and(($img) => { diff --git a/npm/angular/src/app/use-custom-element/use-custom-element.component.cy-spec.ts b/npm/angular/src/app/use-custom-element/use-custom-element.component.cy-spec.ts index de7528ea0b22..1046008f3210 100644 --- a/npm/angular/src/app/use-custom-element/use-custom-element.component.cy-spec.ts +++ b/npm/angular/src/app/use-custom-element/use-custom-element.component.cy-spec.ts @@ -1,7 +1,7 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' import { initEnv, mount } from '@cypress/angular' // You have to import your custom element -// And in cypress.json activate "includeShadowDom" configuration +// And in cypress.config.{ts|js} activate "includeShadowDom" configuration import '../my-custom-element' import { UseCustomElementComponent } from './use-custom-element.component' diff --git a/npm/create-cypress-tests/__snapshots__/init-component-testing.test.ts.js b/npm/create-cypress-tests/__snapshots__/init-component-testing.test.ts.js index 9947ff4275af..da624fe495ba 100644 --- a/npm/create-cypress-tests/__snapshots__/init-component-testing.test.ts.js +++ b/npm/create-cypress-tests/__snapshots__/init-component-testing.test.ts.js @@ -1,8 +1,9 @@ -exports['injects guessed next.js template cypress.json'] = ` -{ - "componentFolder": "src", - "testFiles": "**/*.spec.{js,ts,jsx,tsx}" -} +exports['injects guessed next.js template cypress.config.ts'] = ` +export default { + componentFolder: "src", + testFiles: "**/*.spec.{js,ts,jsx,tsx}" +}; + ` exports['injects guessed next.js template plugins/index.js'] = ` @@ -18,11 +19,12 @@ module.exports = (on, config) => { ` -exports['Injected overridden webpack template cypress.json'] = ` -{ - "componentFolder": "cypress/component", - "testFiles": "**/*.spec.{js,ts,jsx,tsx}" -} +exports['Injected overridden webpack template cypress.config.ts'] = ` +export default { + componentFolder: "cypress/component", + testFiles: "**/*.spec.{js,ts,jsx,tsx}" +}; + ` exports['Injected overridden webpack template plugins/index.js'] = ` diff --git a/npm/create-cypress-tests/cypress.config.js b/npm/create-cypress-tests/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/npm/create-cypress-tests/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/npm/create-cypress-tests/package.json b/npm/create-cypress-tests/package.json index 07cddcdb51fa..86e715cad9f6 100644 --- a/npm/create-cypress-tests/package.json +++ b/npm/create-cypress-tests/package.json @@ -26,7 +26,8 @@ "fs-extra": "^9.0.1", "glob": "^7.1.6", "inquirer": "7.3.3", - "ora": "^5.1.0" + "ora": "^5.1.0", + "recast": "0.20.4" }, "devDependencies": { "@types/babel__core": "^7.1.2", diff --git a/npm/create-cypress-tests/src/component-testing/babel/babelTransform.ts b/npm/create-cypress-tests/src/component-testing/babel/babelTransform.ts index 22e5858dca3a..b7089d3cc158 100644 --- a/npm/create-cypress-tests/src/component-testing/babel/babelTransform.ts +++ b/npm/create-cypress-tests/src/component-testing/babel/babelTransform.ts @@ -2,6 +2,7 @@ import path from 'path' import * as fs from 'fs-extra' import * as babel from '@babel/core' import * as babelTypes from '@babel/types' +import { prettifyCode } from '../../utils' type AST = ReturnType @@ -11,13 +12,6 @@ export type PluginsConfigAst = { requiresReturnConfig?: true } -function tryRequirePrettier () { - try { - return require('prettier') - } catch (e) { - return null - } -} const sharedBabelOptions = { // disable user config configFile: false, @@ -47,11 +41,7 @@ async function transformFileViaPlugin (filePath: string, babelPlugin: babel.Plug return false } - const maybePrettier = tryRequirePrettier() - - if (maybePrettier && maybePrettier.format) { - finalCode = maybePrettier.format(finalCode, { parser: 'babel' }) - } + finalCode = await prettifyCode(finalCode) await fs.writeFile(filePath, finalCode) diff --git a/npm/create-cypress-tests/src/component-testing/config-file-updater/configFileUpdater.test.ts b/npm/create-cypress-tests/src/component-testing/config-file-updater/configFileUpdater.test.ts new file mode 100644 index 000000000000..0168ad9d95ef --- /dev/null +++ b/npm/create-cypress-tests/src/component-testing/config-file-updater/configFileUpdater.test.ts @@ -0,0 +1,424 @@ +/// + +import * as path from 'path' +import { expect } from 'chai' + +import * as fs from 'fs-extra' +import { insertValueInJSString, insertValuesInConfigFile } from './configFileUpdater' +const projectRoot = process.cwd() + +// Test util - if needed outside the tests we can move it to utils +const stripIndent = (strings: any, ...args: any) => { + const parts = [] + + for (let i = 0; i < strings.length; i++) { + parts.push(strings[i]) + + if (i < strings.length - 1) { + parts.push(`<<${i}>>`) + } + } + + const lines = parts.join('').split('\n') + const firstLine = lines[0].length === 0 ? lines[1] : lines[0] + let indentSize = 0 + + for (let i = 0; i < firstLine.length; i++) { + if (firstLine[i] === ' ') { + indentSize++ + continue + } + + break + } + + const strippedLines = lines.map((line) => line.substring(indentSize)) + + let result = strippedLines.join('\n').trimLeft() + + args.forEach((arg: any, i: any) => { + result = result.replace(`<<${i}>>`, `${arg}`) + }) + + return result +} + +describe('lib/util/config-file-updater', () => { + context('with configFile: false', () => { + beforeEach(function () { + this.projectRoot = path.join(projectRoot, '_test-output/path/to/project/') + }) + + it('.insertValuesInConfigFile does not create a file', function () { + return insertValuesInConfigFile(this.projectRoot, {}) + .then(() => { + throw Error('file shuold not have been created here') + }).catch((err) => { + expect(err.code).to.equal('ENOENT') + }) + }) + }) + + context('with js files', () => { + describe('#insertValueInJSString', () => { + describe('es6 vs es5', () => { + it('finds the object litteral and adds the values to it es6', async () => { + const src = stripIndent`\ + export default { + foo: 42, + } + ` + + const expectedOutput = stripIndent`\ + export default { + projectId: "id1234", + viewportWidth: 400, + foo: 42, + } + ` + + const output = await insertValueInJSString(src, { projectId: 'id1234', viewportWidth: 400 }) + + expect(output).to.equal(expectedOutput) + }) + + it('finds the object litteral and adds the values to it es5', async () => { + const src = stripIndent`\ + module.exports = { + foo: 42, + } + ` + + const expectedOutput = stripIndent`\ + module.exports = { + projectId: "id1234", + viewportWidth: 400, + foo: 42, + } + ` + + const output = await insertValueInJSString(src, { projectId: 'id1234', viewportWidth: 400 }) + + expect(output).to.equal(expectedOutput) + }) + + it('works with and without the quotes around keys', async () => { + const src = stripIndent`\ + export default { + "foo": 42, + } + ` + + const expectedOutput = stripIndent`\ + export default { + projectId: "id1234", + viewportWidth: 400, + "foo": 42, + } + ` + + const output = await insertValueInJSString(src, { projectId: 'id1234', viewportWidth: 400 }) + + expect(output).to.equal(expectedOutput) + }) + }) + + describe('defineConfig', () => { + it('skips defineConfig and add to the object inside', async () => { + const src = stripIndent`\ + import { defineConfig } from "cypress" + export default defineConfig({ + foo: 42, + }) + ` + + const expectedOutput = stripIndent`\ + import { defineConfig } from "cypress" + export default defineConfig({ + projectId: "id1234", + viewportWidth: 400, + foo: 42, + }) + ` + + const output = await insertValueInJSString(src, { projectId: 'id1234', viewportWidth: 400 }) + + expect(output).to.equal(expectedOutput) + }) + + it('skips defineConfig even if it renamed in an import (es6)', async () => { + const src = stripIndent`\ + import { defineConfig as cy_defineConfig } from "cypress" + export default cy_defineConfig({ + foo: 42, + }) + ` + + const expectedOutput = stripIndent`\ + import { defineConfig as cy_defineConfig } from "cypress" + export default cy_defineConfig({ + projectId: "id1234", + viewportWidth: 400, + foo: 42, + }) + ` + + const output = await insertValueInJSString(src, { projectId: 'id1234', viewportWidth: 400 }) + + expect(output).to.equal(expectedOutput) + }) + + it('skips defineConfig even if it renamed in a require (es5)', async () => { + const src = stripIndent`\ + const { defineConfig: cy_defineConfig } = require("cypress") + module.exports = cy_defineConfig({ + foo: 42, + }) + ` + + const expectedOutput = stripIndent`\ + const { defineConfig: cy_defineConfig } = require("cypress") + module.exports = cy_defineConfig({ + projectId: "id1234", + viewportWidth: 400, + foo: 42, + }) + ` + + const output = await insertValueInJSString(src, { projectId: 'id1234', viewportWidth: 400 }) + + expect(output).to.equal(expectedOutput) + }) + }) + + describe('updates', () => { + it('updates a value if the same value is found in resolved config', async () => { + const src = stripIndent`\ + export default { + foo: 42, + } + ` + const expectedOutput = stripIndent`\ + export default { + foo: 1000, + } + ` + + const output = await insertValueInJSString(src, { foo: 1000 }) + + expect(output).to.equal(expectedOutput) + }) + + it('accepts inline comments', async () => { + const src = stripIndent`\ + export default { + foo: 12, // will do this later + viewportWidth: 800, + } + ` + const expectedOutput = stripIndent`\ + export default { + foo: 1000, // will do this later + viewportWidth: 800, + } + ` + + const output = await insertValueInJSString(src, { foo: 1000 }) + + expect(output).to.equal(expectedOutput) + }) + + it('updates a value even when this value is explicitely undefined', async () => { + const src = stripIndent`\ + export default { + foo: undefined, // will do this later + viewportWidth: 800, + } + ` + const expectedOutput = stripIndent`\ + export default { + foo: 1000, // will do this later + viewportWidth: 800, + } + ` + + const output = await insertValueInJSString(src, { foo: 1000 }) + + expect(output).to.equal(expectedOutput) + }) + + it('updates values and inserts config', async () => { + const src = stripIndent`\ + export default { + foo: 42, + bar: 84, + component: { + devServer() { + return null + } + } + } + ` + + const expectedOutput = stripIndent`\ + export default { + projectId: "id1234", + foo: 1000, + bar: 3000, + component: { + devServer() { + return null + } + } + } + ` + + const output = await insertValueInJSString(src, { foo: 1000, bar: 3000, projectId: 'id1234' }) + + expect(output).to.equal(expectedOutput) + }) + }) + + describe('subkeys', () => { + it('inserts nested values', async () => { + const src = stripIndent`\ + module.exports = { + foo: 42 + } + ` + + const output = await insertValueInJSString(src, { component: { specFilePattern: 'src/**/*.spec.cy.js' } }) + + const expectedOutput = stripIndent`\ + module.exports = { + component: { + specFilePattern: "src/**/*.spec.cy.js", + }, + foo: 42 + } + ` + + expect(output).to.equal(expectedOutput) + }) + + it('inserts nested values into existing keys', async () => { + const src = stripIndent`\ + module.exports = { + component: { + viewportWidth: 800 + }, + foo: 42 + } + ` + + const output = await insertValueInJSString(src, { component: { specFilePattern: 'src/**/*.spec.cy.js' } }) + + const expectedOutput = stripIndent`\ + module.exports = { + component: { + specFilePattern: "src/**/*.spec.cy.js", + viewportWidth: 800 + }, + foo: 42 + } + ` + + expect(output).to.equal(expectedOutput) + }) + + it('updates nested values', async () => { + const src = stripIndent`\ + module.exports = { + foo: 42, + component: { + specFilePattern: 'components/**/*.spec.cy.js', + foo: 82 + } + }` + + const output = await insertValueInJSString(src, { component: { specFilePattern: 'src/**/*.spec.cy.js' } }) + + const expectedOutput = stripIndent`\ + module.exports = { + foo: 42, + component: { + specFilePattern: "src/**/*.spec.cy.js", + foo: 82 + } + }` + + expect(output).to.equal(expectedOutput) + }) + }) + + describe('failures', () => { + it('fails if not an object litteral', () => { + const src = [ + 'const foo = {}', + 'export default foo', + ].join('\n') + + return insertValueInJSString(src, { bar: 10 }) + .then(() => { + throw Error('this should not succeed') + }) + .catch((err) => { + expect(err.message).to.equal('Cypress was unable to add/update values in your configuration file.') + }) + }) + + it('fails if one of the values to update is not a literal', () => { + const src = [ + 'const bar = 12', + 'export default {', + ' foo: bar', + '}', + ].join('\n') + + return insertValueInJSString(src, { foo: 10 }) + .then(() => { + throw Error('this should not succeed') + }) + .catch((err) => { + expect(err.message).to.equal('Cypress was unable to add/update values in your configuration file.') + }) + }) + + it('fails with inlined values', () => { + const src = stripIndent`\ + const foo = 12 + export default { + foo + } + ` + + return insertValueInJSString(src, { foo: 10 }) + .then(() => { + throw Error('this should not succeed') + }) + .catch((err) => { + expect(err.message).to.equal('Cypress was unable to add/update values in your configuration file.') + }) + }) + + it('fails if there is a spread', () => { + const src = stripIndent`\ + const foo = { bar: 12 } + export default { + bar: 8, + ...foo + } + ` + + return insertValueInJSString(src, { bar: 10 }) + .then(() => { + throw Error('this should not succeed') + }) + .catch((err) => { + expect(err.message).to.equal('Cypress was unable to add/update values in your configuration file.') + }) + }) + }) + }) + }) +}) diff --git a/npm/create-cypress-tests/src/component-testing/config-file-updater/configFileUpdater.ts b/npm/create-cypress-tests/src/component-testing/config-file-updater/configFileUpdater.ts new file mode 100644 index 000000000000..6d16505c40e3 --- /dev/null +++ b/npm/create-cypress-tests/src/component-testing/config-file-updater/configFileUpdater.ts @@ -0,0 +1,295 @@ +import _ from 'lodash' +import { parse } from '@babel/parser' +import type { File } from '@babel/types' +import type { NodePath } from 'ast-types/lib/node-path' +import { visit } from 'recast' +import type { namedTypes } from 'ast-types' +import * as fs from 'fs-extra' +import { prettifyCode } from '../../utils' + +export async function insertValuesInConfigFile (filePath: string, obj: Record = {}) { + await insertValuesInJavaScript(filePath, obj) + + return true +} + +export async function insertValuesInJavaScript (filePath: string, obj: Record) { + const fileContents = await fs.readFile(filePath, { encoding: 'utf8' }) + + let finalCode = await insertValueInJSString(fileContents, obj) + + const prettifiedCode = await prettifyCode(finalCode) + + if (prettifiedCode) { + finalCode = prettifiedCode + } + + await fs.writeFile(filePath, finalCode) +} + +export async function insertValueInJSString (fileContents: string, obj: Record): Promise { + const ast = parse(fileContents, { plugins: ['typescript'], sourceType: 'module' }) + + let objectLiteralNode: namedTypes.ObjectExpression | undefined + + function handleExport (nodePath: NodePath | NodePath): void { + if (nodePath.node.type === 'CallExpression' + && nodePath.node.callee.type === 'Identifier') { + const functionName = nodePath.node.callee.name + + if (isDefineConfigFunction(ast, functionName)) { + return handleExport(nodePath.get('arguments', 0)) + } + } + + if (nodePath.node.type === 'ObjectExpression' && !nodePath.node.properties.find((prop) => prop.type !== 'ObjectProperty')) { + objectLiteralNode = nodePath.node + + return + } + + throw new Error('Cypress was unable to add/update values in your configuration file.') + } + + visit(ast, { + visitAssignmentExpression (nodePath) { + if (nodePath.node.left.type === 'MemberExpression') { + if (nodePath.node.left.object.type === 'Identifier' && nodePath.node.left.object.name === 'module' + && nodePath.node.left.property.type === 'Identifier' && nodePath.node.left.property.name === 'exports') { + handleExport(nodePath.get('right')) + } + } + + return false + }, + visitExportDefaultDeclaration (nodePath) { + handleExport(nodePath.get('declaration')) + + return false + }, + }) + + const splicers: Splicer[] = [] + + if (!objectLiteralNode) { + // if the export is no object litteral + throw new Error('Cypress was unable to add/update values in your configuration file.') + } + + setRootKeysSplicers(splicers, obj, objectLiteralNode!, ' ') + setSubKeysSplicers(splicers, obj, objectLiteralNode!, ' ', ' ') + + // sort splicers to keep the order of the original file + const sortedSplicers = splicers.sort((a, b) => a.start === b.start ? 0 : a.start > b.start ? 1 : -1) + + if (!sortedSplicers.length) return fileContents + + let nextStartingIndex = 0 + let resultCode = '' + + sortedSplicers.forEach((splicer) => { + resultCode += fileContents.slice(nextStartingIndex, splicer.start) + splicer.replaceString + nextStartingIndex = splicer.end + }) + + return resultCode + fileContents.slice(nextStartingIndex) +} + +export function isDefineConfigFunction (ast: File, functionName: string): boolean { + let value = false + + visit(ast, { + visitVariableDeclarator (nodePath) { + // if this is a require of cypress + if (nodePath.node.init?.type === 'CallExpression' + && nodePath.node.init.callee.type === 'Identifier' + && nodePath.node.init.callee.name === 'require' + && nodePath.node.init.arguments[0].type === 'StringLiteral' + && nodePath.node.init.arguments[0].value === 'cypress') { + if (nodePath.node.id?.type === 'ObjectPattern') { + const defineConfigFunctionNode = nodePath.node.id.properties.find((prop) => { + return prop.type === 'ObjectProperty' + && prop.key.type === 'Identifier' + && prop.key.name === 'defineConfig' + }) + + if (defineConfigFunctionNode) { + value = (defineConfigFunctionNode as any).value?.name === functionName + } + } + } + + return false + }, + visitImportDeclaration (nodePath) { + if (nodePath.node.source.type === 'StringLiteral' + && nodePath.node.source.value === 'cypress') { + const defineConfigFunctionNode = nodePath.node.specifiers?.find((specifier) => { + return specifier.type === 'ImportSpecifier' + && specifier.imported.type === 'Identifier' + && specifier.imported.name === 'defineConfig' + }) + + if (defineConfigFunctionNode) { + value = (defineConfigFunctionNode as any).local?.name === functionName + } + } + + return false + }, + }) + + return value +} + +function setRootKeysSplicers ( + splicers: Splicer[], + obj: Record, + objectLiteralNode: namedTypes.ObjectExpression, + lineStartSpacer: string, +) { + const objectLiteralStartIndex = (objectLiteralNode as any).start + 1 + // add values + const objKeys = Object.keys(obj).filter((key) => ['boolean', 'number', 'string'].includes(typeof obj[key])) + + // update values + const keysToUpdate = objKeys.filter((key) => { + return objectLiteralNode.properties.find((prop) => { + return prop.type === 'ObjectProperty' + && prop.key.type === 'Identifier' + && prop.key.name === key + }) + }) + + keysToUpdate.forEach( + (key) => { + const propertyToUpdate = propertyFromKey(objectLiteralNode, key) + + if (propertyToUpdate) { + setSplicerToUpdateProperty(splicers, propertyToUpdate, obj[key], key, obj) + } + }, + ) + + const keysToInsert = objKeys.filter((key) => !keysToUpdate.includes(key)) + + if (keysToInsert.length) { + const valuesInserted = `\n${lineStartSpacer}${ keysToInsert.map((key) => `${key}: ${JSON.stringify(obj[key])},`).join(`\n${lineStartSpacer}`)}` + + splicers.push({ + start: objectLiteralStartIndex, + end: objectLiteralStartIndex, + replaceString: valuesInserted, + }) + } +} + +function setSubKeysSplicers ( + splicers: Splicer[], + obj: Record, + objectLiteralNode: namedTypes.ObjectExpression, + lineStartSpacer: string, + parentLineStartSpacer: string, +) { + const objectLiteralStartIndex = (objectLiteralNode as any).start + 1 + + const keysToUpdateWithObjects: string[] = [] + + const objSubkeys = Object.keys(obj).filter((key) => typeof obj[key] === 'object').reduce((acc: Array<{parent: string, subkey: string}>, key) => { + keysToUpdateWithObjects.push(key) + Object.entries(obj[key]).forEach(([subkey, value]) => { + if (['boolean', 'number', 'string'].includes(typeof value)) { + acc.push({ parent: key, subkey }) + } + }) + + return acc + }, []) + + // add values where the parent key needs to be created + const subkeysToInsertWithoutKey = objSubkeys.filter(({ parent }) => { + return !objectLiteralNode.properties.find((prop) => { + return prop.type === 'ObjectProperty' + && prop.key.type === 'Identifier' + && prop.key.name === parent + }) + }) + const keysToInsertForSubKeys: Record = {} + + subkeysToInsertWithoutKey.forEach((keyTuple) => { + const subkeyList = keysToInsertForSubKeys[keyTuple.parent] || [] + + subkeyList.push(keyTuple.subkey) + keysToInsertForSubKeys[keyTuple.parent] = subkeyList + }) + + let subvaluesInserted = '' + + for (const key in keysToInsertForSubKeys) { + subvaluesInserted += `\n${parentLineStartSpacer}${key}: {` + keysToInsertForSubKeys[key].forEach((subkey) => { + subvaluesInserted += `\n${parentLineStartSpacer}${lineStartSpacer}${subkey}: ${JSON.stringify(obj[key][subkey])},` + }) + + subvaluesInserted += `\n${parentLineStartSpacer}},` + } + + if (subkeysToInsertWithoutKey.length) { + splicers.push({ + start: objectLiteralStartIndex, + end: objectLiteralStartIndex, + replaceString: subvaluesInserted, + }) + } + + // add/update values where parent key already exists + keysToUpdateWithObjects.filter((parent) => { + return objectLiteralNode.properties.find((prop) => { + return prop.type === 'ObjectProperty' + && prop.key.type === 'Identifier' + && prop.key.name === parent + }) + }).forEach((key) => { + const propertyToUpdate = propertyFromKey(objectLiteralNode, key) + + if (propertyToUpdate?.value.type === 'ObjectExpression') { + setRootKeysSplicers(splicers, obj[key], propertyToUpdate.value, parentLineStartSpacer + lineStartSpacer) + } + }) +} + +function setSplicerToUpdateProperty (splicers: Splicer[], + propertyToUpdate: namedTypes.ObjectProperty, + updatedValue: any, + key: string, + obj: Record) { + if (propertyToUpdate && (isPrimitive(propertyToUpdate.value) || isUndefinedOrNull(propertyToUpdate.value))) { + splicers.push({ + start: (propertyToUpdate.value as any).start, + end: (propertyToUpdate.value as any).end, + replaceString: JSON.stringify(updatedValue), + }) + } else { + throw new Error('Cypress was unable to add/update values in your configuration file.') + } +} + +function propertyFromKey (objectLiteralNode: namedTypes.ObjectExpression | undefined, key: string): namedTypes.ObjectProperty | undefined { + return objectLiteralNode?.properties.find((prop) => { + return prop.type === 'ObjectProperty' && prop.key.type === 'Identifier' && prop.key.name === key + }) as namedTypes.ObjectProperty +} + +function isPrimitive (value: NodePath['node']): value is namedTypes.NumericLiteral | namedTypes.StringLiteral | namedTypes.BooleanLiteral { + return value.type === 'NumericLiteral' || value.type === 'StringLiteral' || value.type === 'BooleanLiteral' +} + +function isUndefinedOrNull (value: NodePath['node']): value is namedTypes.Identifier { + return value.type === 'Identifier' && ['undefined', 'null'].includes(value.name) +} + +interface Splicer{ + start: number + end: number + replaceString: string +} diff --git a/npm/create-cypress-tests/src/component-testing/init-component-testing.test.ts b/npm/create-cypress-tests/src/component-testing/init-component-testing.test.ts index e070b836ff89..0d4182a858e7 100644 --- a/npm/create-cypress-tests/src/component-testing/init-component-testing.test.ts +++ b/npm/create-cypress-tests/src/component-testing/init-component-testing.test.ts @@ -20,7 +20,7 @@ describe('init component tests script', () => { let execStub: SinonStub | null = null const e2eTestOutputPath = path.resolve(__dirname, '..', 'test-output') - const cypressConfigPath = path.join(e2eTestOutputPath, 'cypress.json') + const cypressConfigPath = path.join(e2eTestOutputPath, 'cypress.config.ts') beforeEach(async () => { logSpy = sinon.spy(global.console, 'log') @@ -55,9 +55,9 @@ describe('init component tests script', () => { function snapshotGeneratedFiles (name: string) { snapshot( - `${name} cypress.json`, + `${name} cypress.config.ts`, fs.readFileSync( - path.join(e2eTestOutputPath, 'cypress.json'), + path.join(e2eTestOutputPath, 'cypress.config.ts'), { encoding: 'utf-8' }, ), ) @@ -91,7 +91,7 @@ describe('init component tests script', () => { it('determines more presumable configuration to suggest', async () => { createTempFiles({ - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', '/cypress/support/index.js': '', '/cypress/plugins/index.js': 'module.exports = (on, config) => {}', // For next.js user will have babel config, but we want to suggest to use the closest config for the application code @@ -114,7 +114,7 @@ describe('init component tests script', () => { it('automatically suggests to the user which config to use', async () => { createTempFiles({ - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', '/cypress/support/index.js': 'import "./commands.js";', '/cypress/plugins/index.js': 'module.exports = () => {}', '/package.json': JSON.stringify({ @@ -145,7 +145,7 @@ describe('init component tests script', () => { it('Asks for preferred bundling tool if can not determine the right one', async () => { createTempFiles({ - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', '/webpack.config.js': 'module.exports = { }', '/package.json': JSON.stringify({ dependencies: { } }), }) @@ -170,7 +170,7 @@ describe('init component tests script', () => { it('Asks for framework if more than 1 option was auto detected', async () => { createTempFiles({ - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', '/webpack.config.js': 'module.exports = { }', '/package.json': JSON.stringify({ dependencies: { react: '*', vue: '^2.4.5' } }), }) @@ -195,7 +195,7 @@ describe('init component tests script', () => { it('installs the right adapter', async () => { createTempFiles({ - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', '/webpack.config.js': 'module.exports = { }', '/package.json': JSON.stringify({ dependencies: { react: '16.4.5' } }), }) @@ -213,7 +213,7 @@ describe('init component tests script', () => { it('installs the right adapter for vue 3', async () => { createTempFiles({ - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', '/vite.config.js': 'module.exports = { }', '/package.json': JSON.stringify({ dependencies: { vue: '^3.0.0' } }), }) @@ -236,7 +236,7 @@ describe('init component tests script', () => { react: '^16.0.0', }, }), - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', }) promptSpy = sinon.stub(inquirer, 'prompt').returns(Promise.resolve({ @@ -253,9 +253,9 @@ describe('init component tests script', () => { ).to.be.true }) - it('suggests right docs example and cypress.json config based on the `componentFolder` answer', async () => { + it('suggests right docs example and cypress.config.ts config based on the `componentFolder` answer', async () => { createTempFiles({ - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', '/package.json': JSON.stringify({ dependencies: { react: '^16.0.0', @@ -270,9 +270,9 @@ describe('init component tests script', () => { await initComponentTesting({ config: {}, cypressConfigPath, useYarn: true }) - const injectedCode = fs.readFileSync(path.join(e2eTestOutputPath, 'cypress.json'), { encoding: 'utf-8' }) + const injectedCode = require(path.join(e2eTestOutputPath, 'cypress.config.ts')) - expect(injectedCode).to.equal(JSON.stringify( + expect(JSON.stringify(injectedCode.default, null, 2)).to.equal(JSON.stringify( { componentFolder: 'cypress/component', testFiles: '**/*.spec.{js,ts,jsx,tsx}', @@ -284,7 +284,7 @@ describe('init component tests script', () => { it('Shows help message if cypress files are not created', async () => { createTempFiles({ - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', '/package.json': JSON.stringify({ dependencies: { react: '^16.0.0', @@ -310,7 +310,7 @@ describe('init component tests script', () => { it('Doesn\'t affect injected code if user has custom babel.config.js', async () => { createTempFiles({ '/cypress/plugins/index.js': 'module.exports = (on, config) => {}', - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', 'babel.config.js': `module.exports = ${JSON.stringify({ presets: [ '@babel/preset-env', diff --git a/npm/create-cypress-tests/src/component-testing/init-component-testing.ts b/npm/create-cypress-tests/src/component-testing/init-component-testing.ts index 726747048798..110f6c2f9c5a 100644 --- a/npm/create-cypress-tests/src/component-testing/init-component-testing.ts +++ b/npm/create-cypress-tests/src/component-testing/init-component-testing.ts @@ -8,6 +8,7 @@ import { guessTemplate } from './templates/guessTemplate' import { installFrameworkAdapter } from './installFrameworkAdapter' import { injectPluginsCode, getPluginsSourceExample } from './babel/babelTransform' import { installDependency } from '../utils' +import { insertValuesInConfigFile } from './config-file-updater/configFileUpdater' async function injectOrShowConfigCode (injectFn: () => Promise, { code, @@ -51,7 +52,7 @@ async function injectOrShowConfigCode (injectFn: () => Promise, { injected ? printSuccess() : printFailure() } -async function injectAndShowCypressJsonConfig ( +async function injectAndShowCypressConfig ( cypressJsonPath: string, componentFolder: string, ) { @@ -60,18 +61,7 @@ async function injectAndShowCypressJsonConfig ( testFiles: '**/*.spec.{js,ts,jsx,tsx}', } - async function autoInjectCypressJson () { - const currentConfig = JSON.parse(await fs.readFile(cypressJsonPath, { encoding: 'utf-8' })) - - await fs.writeFile(cypressJsonPath, JSON.stringify({ - ...currentConfig, - ...configToInject, - }, null, 2)) - - return true - } - - await injectOrShowConfigCode(autoInjectCypressJson, { + await injectOrShowConfigCode(() => insertValuesInConfigFile(cypressJsonPath, configToInject), { code: JSON.stringify(configToInject, null, 2), language: 'js', filePath: cypressJsonPath, @@ -171,7 +161,7 @@ export async function initComponentTesting ({ config, useYarn, cypressConfigP console.log(`Let's setup everything for component testing with ${chalk.cyan(chosenTemplateName)}:`) console.log() - await injectAndShowCypressJsonConfig(cypressConfigPath, componentFolder) + await injectAndShowCypressConfig(cypressConfigPath, componentFolder) await injectAndShowPluginConfig(chosenTemplate, { templatePayload, pluginsFilePath, diff --git a/npm/create-cypress-tests/src/installCypress.ts b/npm/create-cypress-tests/src/installCypress.ts index ffb2727b1c4a..de649a2a2a52 100644 --- a/npm/create-cypress-tests/src/installCypress.ts +++ b/npm/create-cypress-tests/src/installCypress.ts @@ -15,7 +15,7 @@ type InstallCypressOpts = { async function copyFiles ({ ignoreExamples, useTypescript }: InstallCypressOpts) { let fileSpinner = ora('Creating config files').start() - await fs.outputFile(path.resolve(process.cwd(), 'cypress.json'), '{}\n') + await fs.outputFile(path.resolve(process.cwd(), useTypescript ? 'cypress.config.ts' : 'cypress.config.js'), useTypescript ? `export default {}` : `module.exports = {}\n`) await fs.copy( initialTemplate.getInitialPluginsFilePath(), path.resolve('cypress', 'plugins/index.js'), @@ -54,23 +54,24 @@ async function copyFiles ({ ignoreExamples, useTypescript }: InstallCypressOpts) } export async function findInstalledOrInstallCypress (options: InstallCypressOpts) { - let cypressJsonPath = await findUp('cypress.json') + const configFile = options.useTypescript ? 'cypress.config.ts' : 'cypress.config.js' + let cypressConfigPath = await findUp(configFile) - if (!cypressJsonPath) { + if (!cypressConfigPath) { await installDependency('cypress', options) await copyFiles(options) - cypressJsonPath = await findUp('cypress.json') + cypressConfigPath = await findUp(configFile) } - if (!cypressJsonPath) { + if (!cypressConfigPath) { throw new Error('Unexpected error during cypress installation.') } + const config = await import(cypressConfigPath) + return { - cypressConfigPath: cypressJsonPath, - config: JSON.parse( - fs.readFileSync(cypressJsonPath, { encoding: 'utf-8' }).toString(), - ) as Record, + cypressConfigPath, + config: config.default, } } diff --git a/npm/create-cypress-tests/src/main.test.ts b/npm/create-cypress-tests/src/main.test.ts index 0381b5ff55fd..44382821a725 100644 --- a/npm/create-cypress-tests/src/main.test.ts +++ b/npm/create-cypress-tests/src/main.test.ts @@ -150,7 +150,7 @@ describe('create-cypress-tests', () => { expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress', 'plugins', 'index.js'))).to.equal(true) expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress', 'support', 'index.js'))).to.equal(true) expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress', 'support', 'commands.js'))).to.equal(true) - expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress.json'))).to.equal(true) + expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress.config.ts'))).to.equal(true) }) it('Copies tsconfig if typescript is installed', async () => { diff --git a/npm/create-cypress-tests/src/utils.ts b/npm/create-cypress-tests/src/utils.ts index c42a92855e93..e79055e60283 100644 --- a/npm/create-cypress-tests/src/utils.ts +++ b/npm/create-cypress-tests/src/utils.ts @@ -60,3 +60,17 @@ export async function installDependency (name: string, options: { useYarn: boole cliSpinner.succeed() } + +export async function prettifyCode (finalCode?: string | null) { + try { + const maybePrettier = require('prettier') + + if (maybePrettier && maybePrettier.format) { + finalCode = maybePrettier.format(finalCode, { parser: 'babel' }) + } + } catch (e) { + return null + } finally { + return finalCode + } +} diff --git a/npm/cypress-schematic/src/schematics/ng-add/files/cypress.config.ts b/npm/cypress-schematic/src/schematics/ng-add/files/cypress.config.ts new file mode 100644 index 000000000000..c3dffeeb7539 --- /dev/null +++ b/npm/cypress-schematic/src/schematics/ng-add/files/cypress.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + 'integrationFolder': '<%= root%>cypress/integration', + 'supportFile': '<%= root%>cypress/support/index.ts', + 'videosFolder': '<%= root%>cypress/videos', + 'screenshotsFolder': '<%= root%>cypress/screenshots', + 'pluginsFile': '<%= root%>cypress/plugins/index.ts', + 'fixturesFolder': '<%= root%>cypress/fixtures', + 'baseUrl': '<%= baseUrl%>', +}) diff --git a/npm/cypress-schematic/src/schematics/ng-add/files/cypress.json b/npm/cypress-schematic/src/schematics/ng-add/files/cypress.json deleted file mode 100644 index 4426d4e7d71a..000000000000 --- a/npm/cypress-schematic/src/schematics/ng-add/files/cypress.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "integrationFolder": "<%= root%>cypress/integration", - "supportFile": "<%= root%>cypress/support/index.ts", - "videosFolder": "<%= root%>cypress/videos", - "screenshotsFolder": "<%= root%>cypress/screenshots", - "pluginsFile": "<%= root%>cypress/plugins/index.ts", - "fixturesFolder": "<%= root%>cypress/fixtures", - "baseUrl": "<%= baseUrl%>" -} \ No newline at end of file diff --git a/npm/cypress-schematic/src/schematics/ng-add/index.spec.ts b/npm/cypress-schematic/src/schematics/ng-add/index.spec.ts index 0bf90878cb31..01f26fcc4747 100644 --- a/npm/cypress-schematic/src/schematics/ng-add/index.spec.ts +++ b/npm/cypress-schematic/src/schematics/ng-add/index.spec.ts @@ -32,7 +32,7 @@ describe('@cypress/schematic: ng-add', () => { }) it('should create cypress files', async () => { - const files = ['cypress/integration/spec.ts', 'cypress/plugins/index.ts', 'cypress/support/commands.ts', 'cypress/support/index.ts', 'cypress/tsconfig.json', 'cypress.json'] + const files = ['cypress/integration/spec.ts', 'cypress/plugins/index.ts', 'cypress/support/commands.ts', 'cypress/support/index.ts', 'cypress/tsconfig.json', 'cypress.config.ts'] const homePath = '/projects/sandbox/' return schematicRunner.runSchematicAsync('ng-add', {}, appTree).toPromise().then((tree) => { diff --git a/npm/cypress-schematic/src/schematics/ng-add/index.ts b/npm/cypress-schematic/src/schematics/ng-add/index.ts index 6d56862523fd..23979cd2c782 100644 --- a/npm/cypress-schematic/src/schematics/ng-add/index.ts +++ b/npm/cypress-schematic/src/schematics/ng-add/index.ts @@ -195,9 +195,7 @@ function modifyAngularJson (options: any): Rule { }, } - const configFile = projects[project].root - ? `${projects[project].root}/cypress.json` - : null + const configFile = getCypressConfigFile(angularJsonVal, project) if (configFile) { Object.assign(runJson.options, { configFile }) @@ -233,6 +231,17 @@ function modifyAngularJson (options: any): Rule { } } +export const getCypressConfigFile = (angularJsonVal: any, projectName: string) => { + const project = angularJsonVal.projects[projectName] + const tsConfig = project?.architect?.lint?.options?.tsConfig + + if (project.root) { + return `${project.root}/cypress.config.${tsConfig ? 'ts' : 'js'}` + } + + return null +} + export const addCypressTsConfig = (tree: Tree, angularJsonVal: any, projectName: string) => { const project = angularJsonVal.projects[projectName] let tsConfig = project?.architect?.lint?.options?.tsConfig diff --git a/npm/design-system/cypress.config.js b/npm/design-system/cypress.config.js new file mode 100644 index 000000000000..dcbf918782a3 --- /dev/null +++ b/npm/design-system/cypress.config.js @@ -0,0 +1,16 @@ +module.exports = { + viewportWidth: 1024, + viewportHeight: 800, + video: false, + projectId: 'z9dxah', + testFiles: '**/*spec.{js,jsx,ts,tsx}', + env: { + reactDevtools: true, + }, + ignoreTestFiles: [ + '**/__snapshots__/*', + '**/__image_snapshots__/*', + ], + componentFolder: 'src', + fixturesFolder: false, +} diff --git a/npm/design-system/cypress.json b/npm/design-system/cypress.json deleted file mode 100644 index 00494ad9b75c..000000000000 --- a/npm/design-system/cypress.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "viewportWidth": 1024, - "viewportHeight": 800, - "video": false, - "projectId": "z9dxah", - "testFiles": "**/*spec.{js,jsx,ts,tsx}", - "env": { - "reactDevtools": true - }, - "ignoreTestFiles": [ - "**/__snapshots__/*", - "**/__image_snapshots__/*" - ], - "componentFolder": "src", - "fixturesFolder": false -} diff --git a/npm/react/cypress.config.js b/npm/react/cypress.config.js new file mode 100644 index 000000000000..82d715eee618 --- /dev/null +++ b/npm/react/cypress.config.js @@ -0,0 +1,15 @@ +module.exports = { + 'viewportWidth': 400, + 'viewportHeight': 400, + 'video': false, + 'projectId': 'z9dxah', + 'testFiles': '**/*spec.{js,jsx,ts,tsx}', + 'env': { + 'reactDevtools': true, + }, + 'ignoreTestFiles': [ + '**/__snapshots__/*', + '**/__image_snapshots__/*', + ], + 'experimentalFetchPolyfill': true, +} diff --git a/npm/react/cypress.json b/npm/react/cypress.json deleted file mode 100644 index a6b5db93e737..000000000000 --- a/npm/react/cypress.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "viewportWidth": 400, - "viewportHeight": 400, - "video": false, - "projectId": "z9dxah", - "testFiles": "**/*spec.{js,jsx,ts,tsx}", - "env": { - "reactDevtools": true - }, - "ignoreTestFiles": [ - "**/__snapshots__/*", - "**/__image_snapshots__/*" - ], - "experimentalFetchPolyfill": true -} \ No newline at end of file diff --git a/npm/react/cypress/component/viewport-spec.jsx b/npm/react/cypress/component/viewport-spec.jsx index 74ac9ec72ca4..94353f5647da 100644 --- a/npm/react/cypress/component/viewport-spec.jsx +++ b/npm/react/cypress/component/viewport-spec.jsx @@ -1,7 +1,7 @@ const viewportWidth = 200 const viewportHeight = 100 -describe('cypress.json viewport', +describe('cypress.config.{ts|js} viewport', { viewportWidth, viewportHeight }, () => { it('should have the correct dimensions', () => { diff --git a/npm/react/examples/a11y/cypress.config.js b/npm/react/examples/a11y/cypress.config.js new file mode 100644 index 000000000000..51a4ad540b1a --- /dev/null +++ b/npm/react/examples/a11y/cypress.config.js @@ -0,0 +1,7 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'testFiles': '**/*spec.js', + 'viewportWidth': 500, + 'viewportHeight': 500, +} diff --git a/npm/react/examples/a11y/cypress.json b/npm/react/examples/a11y/cypress.json deleted file mode 100644 index 49b616efaf97..000000000000 --- a/npm/react/examples/a11y/cypress.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*spec.js", - "viewportWidth": 500, - "viewportHeight": 500 -} \ No newline at end of file diff --git a/npm/react/examples/craco/cypress.config.js b/npm/react/examples/craco/cypress.config.js new file mode 100644 index 000000000000..438a9f7531ad --- /dev/null +++ b/npm/react/examples/craco/cypress.config.js @@ -0,0 +1,6 @@ +module.exports = { + 'component': { + 'testFiles': '**/*.test.{js,ts,jsx,tsx}', + 'componentFolder': 'src', + }, +} diff --git a/npm/react/examples/craco/cypress.json b/npm/react/examples/craco/cypress.json deleted file mode 100644 index 0b8d0666485b..000000000000 --- a/npm/react/examples/craco/cypress.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "component": { - "testFiles": "**/*.test.{js,ts,jsx,tsx}", - "componentFolder": "src" - } -} diff --git a/npm/react/examples/find-webpack/cypress.config.ts b/npm/react/examples/find-webpack/cypress.config.ts new file mode 100644 index 000000000000..1075dcd8916d --- /dev/null +++ b/npm/react/examples/find-webpack/cypress.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + 'video': true, + 'projectId': 'jq5xpp', + 'component': { + 'testFiles': '**/*.spec.{js,ts,jsx,tsx}', + 'componentFolder': 'src', + }, + 'env': { + 'cypress-react-selector': { + 'root': '#__cy_root', + }, + }, +}) diff --git a/npm/react/examples/find-webpack/cypress.json b/npm/react/examples/find-webpack/cypress.json deleted file mode 100644 index 03ad0d3676ef..000000000000 --- a/npm/react/examples/find-webpack/cypress.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "video": true, - "projectId": "jq5xpp", - "component": { - "testFiles": "**/*.spec.{js,ts,jsx,tsx}", - "componentFolder": "src" - }, - "env": { - "cypress-react-selector": { - "root": "#__cy_root" - } - } -} diff --git a/npm/react/examples/nextjs-webpack-5/cypress.config.js b/npm/react/examples/nextjs-webpack-5/cypress.config.js new file mode 100644 index 000000000000..55ae64aba890 --- /dev/null +++ b/npm/react/examples/nextjs-webpack-5/cypress.config.js @@ -0,0 +1,8 @@ +module.exports = { + 'video': false, + 'testFiles': '**/*.spec.{js,jsx}', + 'viewportWidth': 500, + 'viewportHeight': 800, + 'componentFolder': 'cypress/components', + 'pluginsFile': 'cypress/plugins.js', +} diff --git a/npm/react/examples/nextjs-webpack-5/cypress.json b/npm/react/examples/nextjs-webpack-5/cypress.json deleted file mode 100644 index 18c2d6098b91..000000000000 --- a/npm/react/examples/nextjs-webpack-5/cypress.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "video": false, - "testFiles": "**/*.spec.{js,jsx}", - "viewportWidth": 500, - "viewportHeight": 800, - "componentFolder": "cypress/components", - "pluginsFile": "cypress/plugins.js" -} \ No newline at end of file diff --git a/npm/react/examples/nextjs/cypress.config.js b/npm/react/examples/nextjs/cypress.config.js new file mode 100644 index 000000000000..f657fd615a47 --- /dev/null +++ b/npm/react/examples/nextjs/cypress.config.js @@ -0,0 +1,11 @@ +module.exports = { + 'video': false, + 'testFiles': '**/*.spec.{js,jsx}', + 'viewportWidth': 500, + 'viewportHeight': 800, + 'experimentalFetchPolyfill': true, + 'componentFolder': 'cypress/components', + 'env': { + 'coverage': true, + }, +} diff --git a/npm/react/examples/nextjs/cypress.json b/npm/react/examples/nextjs/cypress.json deleted file mode 100644 index a281a06f60e6..000000000000 --- a/npm/react/examples/nextjs/cypress.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "video": false, - "testFiles": "**/*.spec.{js,jsx}", - "viewportWidth": 500, - "viewportHeight": 800, - "experimentalFetchPolyfill": true, - "componentFolder": "cypress/components", - "env": { - "coverage": true - } -} \ No newline at end of file diff --git a/npm/react/examples/react-scripts-folder/cypress.config.js b/npm/react/examples/react-scripts-folder/cypress.config.js new file mode 100644 index 000000000000..edb62d592bf7 --- /dev/null +++ b/npm/react/examples/react-scripts-folder/cypress.config.js @@ -0,0 +1,8 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'testFiles': '**/*cy-spec.js', + 'viewportWidth': 500, + 'viewportHeight': 800, + 'componentFolder': 'cypress/component', +} diff --git a/npm/react/examples/react-scripts-folder/cypress.json b/npm/react/examples/react-scripts-folder/cypress.json deleted file mode 100644 index a595a1acd3c8..000000000000 --- a/npm/react/examples/react-scripts-folder/cypress.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 500, - "viewportHeight": 800, - "componentFolder": "cypress/component" -} \ No newline at end of file diff --git a/npm/react/examples/react-scripts-typescript/cypress.config.js b/npm/react/examples/react-scripts-typescript/cypress.config.js new file mode 100644 index 000000000000..8cb0f4f57f58 --- /dev/null +++ b/npm/react/examples/react-scripts-typescript/cypress.config.js @@ -0,0 +1,7 @@ +module.exports = { + 'video': false, + 'testFiles': '**/*cy-spec.tsx', + 'viewportWidth': 500, + 'viewportHeight': 800, + 'componentFolder': 'src', +} diff --git a/npm/react/examples/react-scripts-typescript/cypress.json b/npm/react/examples/react-scripts-typescript/cypress.json deleted file mode 100644 index 67ebf9f708b3..000000000000 --- a/npm/react/examples/react-scripts-typescript/cypress.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "video": false, - "testFiles": "**/*cy-spec.tsx", - "viewportWidth": 500, - "viewportHeight": 800, - "componentFolder": "src" -} diff --git a/npm/react/examples/react-scripts/cypress.config.js b/npm/react/examples/react-scripts/cypress.config.js new file mode 100644 index 000000000000..1c05b4fca685 --- /dev/null +++ b/npm/react/examples/react-scripts/cypress.config.js @@ -0,0 +1,8 @@ +module.exports = { + 'video': false, + 'testFiles': '**/*cy-spec.js', + 'viewportWidth': 500, + 'viewportHeight': 800, + 'experimentalFetchPolyfill': true, + 'componentFolder': 'src', +} diff --git a/npm/react/examples/react-scripts/cypress.json b/npm/react/examples/react-scripts/cypress.json deleted file mode 100644 index 6c8427ea332a..000000000000 --- a/npm/react/examples/react-scripts/cypress.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "video": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 500, - "viewportHeight": 800, - "experimentalFetchPolyfill": true, - "componentFolder": "src" -} \ No newline at end of file diff --git a/npm/react/examples/sass-and-ts/cypress.config.js b/npm/react/examples/sass-and-ts/cypress.config.js new file mode 100644 index 000000000000..60e7ff2475a5 --- /dev/null +++ b/npm/react/examples/sass-and-ts/cypress.config.js @@ -0,0 +1,12 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'testFiles': '**/*spec.*', + 'viewportWidth': 500, + 'viewportHeight': 500, + 'componentFolder': 'src', + 'nodeVersion': 'system', + 'env': { + 'coverage': true, + }, +} diff --git a/npm/react/examples/sass-and-ts/cypress.json b/npm/react/examples/sass-and-ts/cypress.json deleted file mode 100644 index 1341d16e3bbe..000000000000 --- a/npm/react/examples/sass-and-ts/cypress.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*spec.*", - "viewportWidth": 500, - "viewportHeight": 500, - "componentFolder": "src", - "nodeVersion": "system", - "env": { - "coverage": true - } -} \ No newline at end of file diff --git a/npm/react/examples/snapshots/cypress.config.js b/npm/react/examples/snapshots/cypress.config.js new file mode 100644 index 000000000000..ef71668a5ee1 --- /dev/null +++ b/npm/react/examples/snapshots/cypress.config.js @@ -0,0 +1,16 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'testFiles': '**/*-spec.js', + 'viewportWidth': 500, + 'viewportHeight': 500, + 'ignoreTestFiles': [ + '**/__snapshots__/*', + '**/__image_snapshots__/*', + ], + 'env': { + 'cypress-plugin-snapshots': { + 'prettier': true, + }, + }, +} diff --git a/npm/react/examples/snapshots/cypress.json b/npm/react/examples/snapshots/cypress.json deleted file mode 100644 index 4abcd4d5d358..000000000000 --- a/npm/react/examples/snapshots/cypress.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*-spec.js", - "viewportWidth": 500, - "viewportHeight": 500, - "ignoreTestFiles": [ - "**/__snapshots__/*", - "**/__image_snapshots__/*" - ], - "env": { - "cypress-plugin-snapshots": { - "prettier": true - } - } -} \ No newline at end of file diff --git a/npm/react/examples/tailwind/cypress.config.js b/npm/react/examples/tailwind/cypress.config.js new file mode 100644 index 000000000000..07c510021f0e --- /dev/null +++ b/npm/react/examples/tailwind/cypress.config.js @@ -0,0 +1,11 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'testFiles': '**/*cy-spec.js', + 'viewportWidth': 500, + 'viewportHeight': 500, + 'componentFolder': 'src', + 'env': { + 'coverage': true, + }, +} diff --git a/npm/react/examples/tailwind/cypress.json b/npm/react/examples/tailwind/cypress.json deleted file mode 100644 index b3055fbcbb9e..000000000000 --- a/npm/react/examples/tailwind/cypress.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 500, - "viewportHeight": 500, - "componentFolder": "src", - "env": { - "coverage": true - } -} \ No newline at end of file diff --git a/npm/react/examples/using-babel-typescript/cypress.config.js b/npm/react/examples/using-babel-typescript/cypress.config.js new file mode 100644 index 000000000000..223bca975ea8 --- /dev/null +++ b/npm/react/examples/using-babel-typescript/cypress.config.js @@ -0,0 +1,8 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'testFiles': '**/*spec.tsx', + 'viewportWidth': 500, + 'viewportHeight': 500, + 'componentFolder': 'src', +} diff --git a/npm/react/examples/using-babel-typescript/cypress.json b/npm/react/examples/using-babel-typescript/cypress.json deleted file mode 100644 index 86ef45a150ab..000000000000 --- a/npm/react/examples/using-babel-typescript/cypress.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*spec.tsx", - "viewportWidth": 500, - "viewportHeight": 500, - "componentFolder": "src" -} \ No newline at end of file diff --git a/npm/react/examples/using-babel/cypress.config.js b/npm/react/examples/using-babel/cypress.config.js new file mode 100644 index 000000000000..6a6e4fa40233 --- /dev/null +++ b/npm/react/examples/using-babel/cypress.config.js @@ -0,0 +1,8 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'testFiles': '**/*spec.js', + 'viewportWidth': 500, + 'viewportHeight': 500, + 'componentFolder': 'src', +} diff --git a/npm/react/examples/using-babel/cypress.json b/npm/react/examples/using-babel/cypress.json deleted file mode 100644 index f97af0417f45..000000000000 --- a/npm/react/examples/using-babel/cypress.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*spec.js", - "viewportWidth": 500, - "viewportHeight": 500, - "componentFolder": "src" -} \ No newline at end of file diff --git a/npm/react/examples/visual-sudoku/cypress.json b/npm/react/examples/visual-sudoku/cypress.config.js similarity index 89% rename from npm/react/examples/visual-sudoku/cypress.json rename to npm/react/examples/visual-sudoku/cypress.config.js index 561f83d47bf8..d1a1bddfbf9c 100644 --- a/npm/react/examples/visual-sudoku/cypress.json +++ b/npm/react/examples/visual-sudoku/cypress.config.js @@ -1,4 +1,4 @@ -{ +module.exports = { "video": false, "fixturesFolder": false, "testFiles": "**/*cy-spec.js", diff --git a/npm/react/examples/visual-testing-with-applitools/cypress.config.js b/npm/react/examples/visual-testing-with-applitools/cypress.config.js new file mode 100644 index 000000000000..cedc749551e3 --- /dev/null +++ b/npm/react/examples/visual-testing-with-applitools/cypress.config.js @@ -0,0 +1,11 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'testFiles': '**/*spec.js', + 'viewportWidth': 1000, + 'viewportHeight': 1000, + 'componentFolder': 'src', + 'env': { + 'coverage': false, + }, +} diff --git a/npm/react/examples/visual-testing-with-applitools/cypress.json b/npm/react/examples/visual-testing-with-applitools/cypress.json deleted file mode 100644 index a86687662f4f..000000000000 --- a/npm/react/examples/visual-testing-with-applitools/cypress.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*spec.js", - "viewportWidth": 1000, - "viewportHeight": 1000, - "componentFolder": "src", - "env": { - "coverage": false - } -} \ No newline at end of file diff --git a/npm/react/examples/visual-testing-with-happo/.happo.js b/npm/react/examples/visual-testing-with-happo/.happo.js index 60e799c22bfc..a05a232d5ba8 100644 --- a/npm/react/examples/visual-testing-with-happo/.happo.js +++ b/npm/react/examples/visual-testing-with-happo/.happo.js @@ -1,8 +1,8 @@ // https://docs.happo.io/docs/cypress const { RemoteBrowserTarget } = require('happo.io') -// use the same resolution as cypress.json -const cypressConfig = require('./cypress.json') +// use the same resolution as cypress.config.js +const cypressConfig = require('./cypress.config.js') const width = cypressConfig.viewportWidth || 1000 const height = cypressConfig.viewportHeight || 660 const viewport = `${width}x${height}` diff --git a/npm/react/examples/visual-testing-with-happo/cypress.config.js b/npm/react/examples/visual-testing-with-happo/cypress.config.js new file mode 100644 index 000000000000..09a196f5ac0d --- /dev/null +++ b/npm/react/examples/visual-testing-with-happo/cypress.config.js @@ -0,0 +1,7 @@ +module.exports = { + 'video': false, + 'testFiles': '**/*cy-spec.js', + 'viewportWidth': 400, + 'viewportHeight': 700, + 'componentFolder': 'src', +} diff --git a/npm/react/examples/visual-testing-with-happo/cypress.json b/npm/react/examples/visual-testing-with-happo/cypress.json deleted file mode 100644 index 18d423f08d94..000000000000 --- a/npm/react/examples/visual-testing-with-happo/cypress.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "video": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 400, - "viewportHeight": 700, - "componentFolder": "src" -} \ No newline at end of file diff --git a/npm/react/examples/visual-testing-with-percy/cypress.config.js b/npm/react/examples/visual-testing-with-percy/cypress.config.js new file mode 100644 index 000000000000..933303bfff30 --- /dev/null +++ b/npm/react/examples/visual-testing-with-percy/cypress.config.js @@ -0,0 +1,8 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'testFiles': '**/*cy-spec.js', + 'viewportWidth': 500, + 'viewportHeight': 500, + 'componentFolder': 'src', +} diff --git a/npm/react/examples/visual-testing-with-percy/cypress.json b/npm/react/examples/visual-testing-with-percy/cypress.json deleted file mode 100644 index b268172ca3f4..000000000000 --- a/npm/react/examples/visual-testing-with-percy/cypress.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 500, - "viewportHeight": 500, - "componentFolder": "src" -} \ No newline at end of file diff --git a/npm/react/examples/webpack-file/cypress.config.js b/npm/react/examples/webpack-file/cypress.config.js new file mode 100644 index 000000000000..fea79636c340 --- /dev/null +++ b/npm/react/examples/webpack-file/cypress.config.js @@ -0,0 +1,7 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'testFiles': '**/*cy-spec.js', + 'viewportWidth': 500, + 'viewportHeight': 500, +} diff --git a/npm/react/examples/webpack-file/cypress.json b/npm/react/examples/webpack-file/cypress.json deleted file mode 100644 index 707979192c3d..000000000000 --- a/npm/react/examples/webpack-file/cypress.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 500, - "viewportHeight": 500 -} \ No newline at end of file diff --git a/npm/react/examples/webpack-file/cypress/plugins/index.js b/npm/react/examples/webpack-file/cypress/plugins/index.js index 84c951a31093..83513e0b198b 100644 --- a/npm/react/examples/webpack-file/cypress/plugins/index.js +++ b/npm/react/examples/webpack-file/cypress/plugins/index.js @@ -5,7 +5,7 @@ */ module.exports = (on, config) => { require('@cypress/react/plugins/load-webpack')(on, config, { - // from the root of the project (folder with cypress.json file) + // from the root of the project (folder with cypress.config.{ts|js} file) webpackFilename: 'webpack.config.js', }) diff --git a/npm/react/examples/webpack-options/cypress.config.js b/npm/react/examples/webpack-options/cypress.config.js new file mode 100644 index 000000000000..fea79636c340 --- /dev/null +++ b/npm/react/examples/webpack-options/cypress.config.js @@ -0,0 +1,7 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'testFiles': '**/*cy-spec.js', + 'viewportWidth': 500, + 'viewportHeight': 500, +} diff --git a/npm/react/examples/webpack-options/cypress.json b/npm/react/examples/webpack-options/cypress.json deleted file mode 100644 index 707979192c3d..000000000000 --- a/npm/react/examples/webpack-options/cypress.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 500, - "viewportHeight": 500 -} \ No newline at end of file diff --git a/npm/react/plugins/load-webpack/index.js b/npm/react/plugins/load-webpack/index.js index bed7f22d470c..368d1ea549ba 100644 --- a/npm/react/plugins/load-webpack/index.js +++ b/npm/react/plugins/load-webpack/index.js @@ -12,7 +12,7 @@ function normalizeWebpackPath (config, webpackConfigPath) { /** * Injects dev-server based on the webpack config file. * - * **Important:** `webpackFilename` path is relative to the project root (cypress.json location) + * **Important:** `webpackFilename` path is relative to the project root (cypress.config.{ts|js} location) * @type {(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, options: { webpackFilename: string }) => Cypress.PluginConfigOptions} */ function devServer (cypressDevServerConfig, { webpackFilename, indexHtml }) { diff --git a/npm/vite-dev-server/cypress.config.ts b/npm/vite-dev-server/cypress.config.ts new file mode 100644 index 000000000000..bce9fa83d67e --- /dev/null +++ b/npm/vite-dev-server/cypress.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + 'pluginsFile': 'cypress/plugins.js', + 'video': false, + 'fixturesFolder': false, + 'testFiles': '**/*.spec.*', + 'componentFolder': 'cypress/components', +}) diff --git a/npm/vite-dev-server/cypress.json b/npm/vite-dev-server/cypress.json deleted file mode 100644 index d5c8178ca335..000000000000 --- a/npm/vite-dev-server/cypress.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "pluginsFile": "cypress/plugins.js", - "video": false, - "fixturesFolder": false, - "testFiles": "**/*.spec.*", - "componentFolder": "cypress/components" -} \ No newline at end of file diff --git a/npm/vue/cypress.config.ts b/npm/vue/cypress.config.ts new file mode 100644 index 000000000000..f63bc5d24707 --- /dev/null +++ b/npm/vue/cypress.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + 'viewportWidth': 500, + 'viewportHeight': 500, + 'video': false, + 'responseTimeout': 2500, + 'projectId': '134ej7', + 'testFiles': '**/*spec.{js,ts,tsx}', + 'experimentalFetchPolyfill': true, +}) diff --git a/npm/vue/cypress.json b/npm/vue/cypress.json deleted file mode 100644 index a25995a3f06c..000000000000 --- a/npm/vue/cypress.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "viewportWidth": 500, - "viewportHeight": 500, - "video": false, - "responseTimeout": 2500, - "projectId": "134ej7", - "testFiles": "**/*spec.{js,ts,tsx}", - "experimentalFetchPolyfill": true -} \ No newline at end of file diff --git a/npm/vue/examples/code-coverage/cypress.config.js b/npm/vue/examples/code-coverage/cypress.config.js new file mode 100644 index 000000000000..a0c1176e100e --- /dev/null +++ b/npm/vue/examples/code-coverage/cypress.config.js @@ -0,0 +1,6 @@ +module.exports = { + 'componentFolder': 'src', + 'fixturesFolder': false, + 'testFiles': '**/*.spec.js', + 'video': false, +} diff --git a/npm/vue/examples/code-coverage/cypress.json b/npm/vue/examples/code-coverage/cypress.json deleted file mode 100644 index 4110fa4e4784..000000000000 --- a/npm/vue/examples/code-coverage/cypress.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "componentFolder": "src", - "fixturesFolder": false, - "testFiles": "**/*.spec.js", - "video": false -} diff --git a/npm/vue/examples/vue-cli/cypress.config.js b/npm/vue/examples/vue-cli/cypress.config.js new file mode 100644 index 000000000000..a8fd106f6a07 --- /dev/null +++ b/npm/vue/examples/vue-cli/cypress.config.js @@ -0,0 +1,6 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'testFiles': '**/*spec.js', + 'componentFolder': 'src', +} diff --git a/npm/vue/examples/vue-cli/cypress.json b/npm/vue/examples/vue-cli/cypress.json deleted file mode 100644 index 7d2950c00110..000000000000 --- a/npm/vue/examples/vue-cli/cypress.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*spec.js", - "componentFolder": "src" -} \ No newline at end of file diff --git a/npm/webpack-preprocessor/cypress.config.js b/npm/webpack-preprocessor/cypress.config.js new file mode 100644 index 000000000000..3cc3dd401641 --- /dev/null +++ b/npm/webpack-preprocessor/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'integrationFolder': 'cypress/tests', +} diff --git a/npm/webpack-preprocessor/cypress.json b/npm/webpack-preprocessor/cypress.json deleted file mode 100644 index 63c52f7bf802..000000000000 --- a/npm/webpack-preprocessor/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "integrationFolder": "cypress/tests" -} diff --git a/npm/webpack-preprocessor/examples/react-app/cypress.config.js b/npm/webpack-preprocessor/examples/react-app/cypress.config.js new file mode 100644 index 000000000000..0cf1222180f5 --- /dev/null +++ b/npm/webpack-preprocessor/examples/react-app/cypress.config.js @@ -0,0 +1,6 @@ +module.exports = { + 'baseUrl': 'http://localhost:3000', + 'fixturesFolder': false, + 'supportFile': false, + 'viewportWidth': 600, +} diff --git a/npm/webpack-preprocessor/examples/react-app/cypress.json b/npm/webpack-preprocessor/examples/react-app/cypress.json deleted file mode 100644 index fc7e1f9c6243..000000000000 --- a/npm/webpack-preprocessor/examples/react-app/cypress.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "baseUrl": "http://localhost:3000", - "fixturesFolder": false, - "supportFile": false, - "viewportWidth": 600 -} diff --git a/npm/webpack-preprocessor/examples/use-babelrc/cypress.config.js b/npm/webpack-preprocessor/examples/use-babelrc/cypress.config.js new file mode 100644 index 000000000000..4f64c2459252 --- /dev/null +++ b/npm/webpack-preprocessor/examples/use-babelrc/cypress.config.js @@ -0,0 +1,4 @@ +module.exports = { + 'fixturesFolder': false, + 'supportFile': false, +} diff --git a/npm/webpack-preprocessor/examples/use-babelrc/cypress.json b/npm/webpack-preprocessor/examples/use-babelrc/cypress.json deleted file mode 100644 index a84f6e38c9e9..000000000000 --- a/npm/webpack-preprocessor/examples/use-babelrc/cypress.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "fixturesFolder": false, - "supportFile": false -} diff --git a/npm/webpack-preprocessor/examples/use-ts-loader/cypress.config.ts b/npm/webpack-preprocessor/examples/use-ts-loader/cypress.config.ts new file mode 100644 index 000000000000..737a9350d876 --- /dev/null +++ b/npm/webpack-preprocessor/examples/use-ts-loader/cypress.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + 'fixturesFolder': false, + 'supportFile': false, +}) diff --git a/npm/webpack-preprocessor/examples/use-ts-loader/cypress.json b/npm/webpack-preprocessor/examples/use-ts-loader/cypress.json deleted file mode 100644 index a84f6e38c9e9..000000000000 --- a/npm/webpack-preprocessor/examples/use-ts-loader/cypress.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "fixturesFolder": false, - "supportFile": false -} diff --git a/packages/app/cypress.config.ts b/packages/app/cypress.config.ts new file mode 100644 index 000000000000..63354e1f5225 --- /dev/null +++ b/packages/app/cypress.config.ts @@ -0,0 +1,30 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + 'projectId': 'sehy69', + 'viewportWidth': 800, + 'viewportHeight': 850, + 'fixturesFolder': false, + 'retries': { + 'runMode': 2, + 'openMode': 0, + }, + 'nodeVersion': 'system', + 'testFiles': '**/*.spec.{j,ts,tsx,jsx}', + 'reporter': '../../node_modules/cypress-multi-reporters/index.js', + 'reporterOptions': { + 'configFile': '../../mocha-reporter-config.json', + }, + 'integrationFolder': 'cypress/e2e/integration', + 'componentFolder': 'src', + 'supportFile': false, + 'component': { + 'testFiles': '**/*.spec.{js,ts,tsx,jsx}', + 'supportFile': 'cypress/component/support/index.ts', + 'pluginsFile': 'cypress/component/plugins/index.js', + }, + 'e2e': { + 'pluginsFile': 'cypress/e2e/plugins/index.ts', + 'supportFile': 'cypress/e2e/support/e2eSupport.ts', + }, +}) diff --git a/packages/app/cypress.json b/packages/app/cypress.json deleted file mode 100644 index 2c12d46efcaf..000000000000 --- a/packages/app/cypress.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "$schema": "../../cli/schema/cypress.schema.json", - "projectId": "sehy69", - "viewportWidth": 800, - "viewportHeight": 850, - "fixturesFolder": false, - "retries": { - "runMode": 2, - "openMode": 0 - }, - "nodeVersion": "system", - "testFiles": "**/*.spec.{j,ts,tsx,jsx}", - "reporter": "../../node_modules/cypress-multi-reporters/index.js", - "reporterOptions": { - "configFile": "../../mocha-reporter-config.json" - }, - "integrationFolder": "cypress/e2e/integration", - "componentFolder": "src", - "supportFile": false, - "component": { - "testFiles": "**/*.spec.{js,ts,tsx,jsx}", - "supportFile": "cypress/component/support/index.ts", - "pluginsFile": "cypress/component/plugins/index.js" - }, - "e2e": { - "pluginsFile": "cypress/e2e/plugins/index.ts", - "supportFile": "cypress/e2e/support/e2eSupport.ts" - } -} diff --git a/packages/app/cypress/e2e/integration/runs.spec.ts b/packages/app/cypress/e2e/integration/runs.spec.ts index 13244a6aa305..7a6732ae6375 100644 --- a/packages/app/cypress/e2e/integration/runs.spec.ts +++ b/packages/app/cypress/e2e/integration/runs.spec.ts @@ -58,7 +58,8 @@ describe('App', () => { cy.loginUser() cy.visitApp() cy.withCtx(async (ctx) => { - await ctx.actions.file.writeFileInProject('cypress.json', '{}') + ctx.config.cleanupCachedConfigForActiveProject() + await ctx.actions.file.writeFileInProject('cypress.config.js', 'module.exports = {}') }) cy.get('[href="#/runs"]').click() diff --git a/packages/data-context/src/DataContext.ts b/packages/data-context/src/DataContext.ts index c1329cef18e6..b3c67e827572 100644 --- a/packages/data-context/src/DataContext.ts +++ b/packages/data-context/src/DataContext.ts @@ -14,6 +14,7 @@ import { BrowserDataSource, StorybookDataSource, CloudDataSource, + ConfigDataSource, } from './sources/' import { cached } from './util/cached' import { DataContextShell, DataContextShellConfig } from './DataContextShell' @@ -41,9 +42,9 @@ export interface DataContextConfig extends DataContextShellConfig { export class DataContext extends DataContextShell { private _coreData: CoreDataShape - constructor (private config: DataContextConfig) { - super(config) - this._coreData = config.coreData ?? makeCoreData() + constructor (private _config: DataContextConfig) { + super(_config) + this._coreData = _config.coreData ?? makeCoreData() } async initializeData () { @@ -57,14 +58,14 @@ export class DataContext extends DataContextShell { this.actions.auth.getUser(), ] - if (this.config.launchArgs.projectRoot) { - toAwait.push(this.actions.project.setActiveProject(this.config.launchArgs.projectRoot)) + if (this._config.launchArgs.projectRoot) { + toAwait.push(this.actions.project.setActiveProject(this._config.launchArgs.projectRoot)) } - if (this.config.launchArgs.testingType) { + if (this._config.launchArgs.testingType) { // It should be possible to skip the first step in the wizard, if the // user already told us the testing type via command line argument - this.actions.wizard.setTestingType(this.config.launchArgs.testingType) + this.actions.wizard.setTestingType(this._config.launchArgs.testingType) this.actions.wizard.navigate('forward') } @@ -76,15 +77,15 @@ export class DataContext extends DataContextShell { } get os () { - return this.config.os + return this._config.os } get launchArgs () { - return this.config.launchArgs + return this._config.launchArgs } get launchOptions () { - return this.config.launchOptions + return this._config.launchOptions } get coreData () { @@ -141,6 +142,11 @@ export class DataContext extends DataContextShell { return new WizardDataSource(this) } + @cached + get config () { + return new ConfigDataSource(this) + } + @cached get storybook () { return new StorybookDataSource(this) @@ -170,10 +176,10 @@ export class DataContext extends DataContextShell { get _apis () { return { - appApi: this.config.appApi, - authApi: this.config.authApi, - projectApi: this.config.projectApi, - busApi: this.config.rootBus, + appApi: this._config.appApi, + authApi: this._config.authApi, + projectApi: this._config.projectApi, + busApi: this._config.rootBus, } } diff --git a/packages/data-context/src/actions/FileActions.ts b/packages/data-context/src/actions/FileActions.ts index 59a1ad4e0924..bef4c85d0759 100644 --- a/packages/data-context/src/actions/FileActions.ts +++ b/packages/data-context/src/actions/FileActions.ts @@ -10,9 +10,19 @@ export class FileActions { throw new Error(`Cannot write file in project without active project`) } + const filePath = path.join(this.ctx.activeProject?.projectRoot, relativePath) + await this.ctx.fs.writeFile( - path.join(this.ctx.activeProject?.projectRoot, relativePath), + filePath, data, ) } + + async removeFileInProject (relativePath: string) { + if (!this.ctx.activeProject) { + throw new Error(`Cannot remove file in project without active project`) + } + + await this.ctx.fs.remove(path.join(this.ctx.activeProject?.projectRoot, relativePath)) + } } diff --git a/packages/data-context/src/actions/ProjectActions.ts b/packages/data-context/src/actions/ProjectActions.ts index f3ff3e7d2399..8107ac785e66 100644 --- a/packages/data-context/src/actions/ProjectActions.ts +++ b/packages/data-context/src/actions/ProjectActions.ts @@ -1,14 +1,14 @@ import type { CodeGenType, MutationAddProjectArgs, MutationAppCreateConfigFileArgs, MutationSetProjectPreferencesArgs, TestingTypeEnum } from '@packages/graphql/src/gen/nxs.gen' -import type { FindSpecs, FoundBrowser, FoundSpec, FullConfig, LaunchArgs, LaunchOpts, OpenProjectLaunchOptions, Preferences } from '@packages/types' +import type { FindSpecs, FoundBrowser, FoundSpec, FullConfig, LaunchArgs, LaunchOpts, OpenProjectLaunchOptions, Preferences, SettingsOptions } from '@packages/types' import path from 'path' -import type { ProjectShape } from '../data/coreDataShape' +import type { ActiveProjectShape, ProjectShape } from '../data/coreDataShape' import type { DataContext } from '..' import { codeGenerator, SpecOptions } from '../codegen' import templates from '../codegen/templates' export interface ProjectApiShape { - getConfig(projectRoot: string): Promise + getConfig(projectRoot: string, options?: SettingsOptions): Promise findSpecs(payload: FindSpecs): Promise /** * "Initializes" the given mode, since plugins can define the browsers available @@ -26,6 +26,7 @@ export interface ProjectApiShape { clearProjectPreferences(projectTitle: string): Promise clearAllProjectPreferences(): Promise closeActiveProject(): Promise + error(type: string, ...args: any): Error } export class ProjectActions { @@ -58,21 +59,33 @@ export class ProjectActions { await this.clearActiveProject() - this.ctx.coreData.app.activeProject = { + // Set initial properties, so we can set the config object on the active project + this.setActiveProjectProperties({ projectRoot, title, ctPluginsInitialized: false, e2ePluginsInitialized: false, - isFirstTimeCT: await this.ctx.project.isFirstTimeAccessing(projectRoot, 'component'), - isFirstTimeE2E: await this.ctx.project.isFirstTimeAccessing(projectRoot, 'e2e'), - config: await this.ctx.project.getResolvedConfigFields(projectRoot), - preferences: await this.ctx.project.getProjectPreferences(title), generatedSpec: null, - } + config: null, + configChildProcess: null, + }) + + this.setActiveProjectProperties({ + isCTConfigured: await this.ctx.project.isTestingTypeConfigured(projectRoot, 'component'), + isE2EConfigured: await this.ctx.project.isTestingTypeConfigured(projectRoot, 'e2e'), + preferences: await this.ctx.project.getProjectPreferences(title), + }) return this } + private setActiveProjectProperties (activeProjectProperties: Partial) { + this.ctx.coreData.app.activeProject = { + ...this.ctx.coreData.app.activeProject, + ...activeProjectProperties, + } as ActiveProjectShape + } + async loadProjects () { const projectRoots = await this.api.getProjectRootsFromCache() @@ -236,7 +249,7 @@ export class ProjectActions { throw Error(`Cannot create index.html without activeProject.`) } - if (this.ctx.activeProject?.isFirstTimeCT) { + if (this.ctx.activeProject?.isCTConfigured) { const indexHtmlPath = path.resolve(this.ctx.activeProject.projectRoot, 'cypress/component/support/index.html') await this.ctx.fs.outputFile(indexHtmlPath, template) @@ -259,7 +272,8 @@ export class ProjectActions { } const parsed = path.parse(codeGenCandidate) - const config = await this.ctx.project.getConfig(project.projectRoot) + const config = await this.ctx.config.getConfigForProject(project.projectRoot) + const getFileExtension = () => { if (codeGenType === 'integration') { const possibleExtensions = ['.spec', '.test', '-spec', '-test'] diff --git a/packages/data-context/src/actions/WizardActions.ts b/packages/data-context/src/actions/WizardActions.ts index 108d53af5b84..7d6a672a4915 100644 --- a/packages/data-context/src/actions/WizardActions.ts +++ b/packages/data-context/src/actions/WizardActions.ts @@ -120,7 +120,7 @@ export class WizardActions { } if (this.data.currentStep === 'welcome' && this.data.chosenTestingType === 'component') { - if (this.ctx.activeProject?.isFirstTimeCT) { + if (!this.ctx.activeProject?.isCTConfigured) { this.navigateToStep('selectFramework') } else if (!this.ctx.activeProject?.ctPluginsInitialized) { // not first time, and we haven't initialized plugins - initialize them @@ -134,7 +134,7 @@ export class WizardActions { } if (this.data.currentStep === 'welcome' && this.data.chosenTestingType === 'e2e') { - if (this.ctx.activeProject?.isFirstTimeE2E) { + if (!this.ctx.activeProject?.isE2EConfigured) { this.navigateToStep('configFiles') } else if (!this.ctx.activeProject?.e2ePluginsInitialized) { // not first time, and we haven't initialized plugins - initialize them diff --git a/packages/data-context/src/data/coreDataShape.ts b/packages/data-context/src/data/coreDataShape.ts index b8bcadb51b25..d33e27a2145b 100644 --- a/packages/data-context/src/data/coreDataShape.ts +++ b/packages/data-context/src/data/coreDataShape.ts @@ -1,6 +1,7 @@ -import { BUNDLERS, FoundBrowser, FoundSpec, GeneratedSpec, Preferences, ResolvedFromConfig } from '@packages/types' +import { BUNDLERS, FoundBrowser, FoundSpec, FullConfig, GeneratedSpec, Preferences } from '@packages/types' import type { NexusGenEnums, TestingTypeEnum } from '@packages/graphql/src/gen/nxs.gen' import type { BrowserWindow } from 'electron' +import type { ChildProcess } from 'child_process' export type Maybe = T | null | undefined @@ -18,15 +19,21 @@ export interface DevStateShape { refreshState: null | string } +export interface ConfigChildProcessShape { + process: ChildProcess + executedPlugins: null | 'e2e' | 'ct' +} + export interface ActiveProjectShape extends ProjectShape { title: string ctPluginsInitialized: Maybe e2ePluginsInitialized: Maybe - isFirstTimeCT: Maybe - isFirstTimeE2E: Maybe + isCTConfigured: Maybe + isE2EConfigured: Maybe currentSpecId?: Maybe specs?: FoundSpec[] - config: ResolvedFromConfig[] + config: Promise | null + configChildProcess: ConfigChildProcessShape | null preferences?: Preferences| null generatedSpec: GeneratedSpec | null } diff --git a/packages/data-context/src/sources/ConfigDataSource.ts b/packages/data-context/src/sources/ConfigDataSource.ts new file mode 100644 index 000000000000..33b2869c4efd --- /dev/null +++ b/packages/data-context/src/sources/ConfigDataSource.ts @@ -0,0 +1,62 @@ +import type { FullConfig } from '@packages/types' +import type { DataContext } from '..' + +export class ConfigDataSource { + constructor (private ctx: DataContext) {} + + async getConfigForProject (projectRoot: string): Promise { + if (!this.ctx.coreData.app.activeProject) { + throw new Error(`Cannot access config without activeProject`) + } + + if (!this.ctx.coreData.app.activeProject.config) { + this.ctx.coreData.app.activeProject.config = Promise.resolve().then(async () => { + const configFile = await this.ctx.config.getDefaultConfigBasename(projectRoot) + + return this.ctx._apis.projectApi.getConfig(projectRoot, { configFile }) + }) + } + + return this.ctx.coreData.app.activeProject.config + } + + async getDefaultConfigBasename (projectRoot: string) { + const cypressConfigFiles = ['cypress.config.js', 'cypress.config.ts'] + const legacyConfigFile = 'cypress.json' + + const filesInProjectDir = await this.ctx.fs.readdir(projectRoot) + + const foundConfigFiles = [...cypressConfigFiles, legacyConfigFile].filter((file) => filesInProjectDir.includes(file)) + + if (foundConfigFiles.length === 1) { + const configFile = foundConfigFiles[0] + + if (configFile === legacyConfigFile) { + throw this.ctx._apis.projectApi.error('CONFIG_FILE_MIGRATION_NEEDED', projectRoot, configFile) + } + + return configFile + } + + // if we found more than one, throw a language conflict + if (foundConfigFiles.length > 1) { + if (foundConfigFiles.includes(legacyConfigFile)) { + const foundFiles = foundConfigFiles.filter((f) => f !== legacyConfigFile) + + throw this.ctx._apis.projectApi.error('LEGACY_CONFIG_FILE', projectRoot, ...foundFiles) + } + + throw this.ctx._apis.projectApi.error('CONFIG_FILES_LANGUAGE_CONFLICT', projectRoot, ...foundConfigFiles) + } + + throw this.ctx._apis.projectApi.error('NO_DEFAULT_CONFIG_FILE_FOUND', projectRoot) + } + + async cleanupCachedConfigForActiveProject () { + if (!this.ctx.coreData.app.activeProject?.config) { + return + } + + this.ctx.coreData.app.activeProject.config = null + } +} diff --git a/packages/data-context/src/sources/ProjectDataSource.ts b/packages/data-context/src/sources/ProjectDataSource.ts index d01b7efb6fb7..48c4f274761c 100644 --- a/packages/data-context/src/sources/ProjectDataSource.ts +++ b/packages/data-context/src/sources/ProjectDataSource.ts @@ -1,5 +1,5 @@ import type { CodeGenType, SpecType } from '@packages/graphql/src/gen/nxs.gen' -import { FrontendFramework, FRONTEND_FRAMEWORKS, FullConfig, ResolvedFromConfig, RESOLVED_FROM, SpecFile, STORYBOOK_GLOB } from '@packages/types' +import { FrontendFramework, FRONTEND_FRAMEWORKS, ResolvedFromConfig, RESOLVED_FROM, SpecFile, STORYBOOK_GLOB } from '@packages/types' import { scanFSForAvailableDependency } from 'create-cypress-tests' import path from 'path' @@ -16,15 +16,19 @@ export class ProjectDataSource { async projectId (projectRoot: string) { const config = await this.getConfig(projectRoot) - return config.projectId + return config?.projectId ?? null } projectTitle (projectRoot: string) { return path.basename(projectRoot) } + getConfig (projectRoot: string) { + return this.ctx.config.getConfigForProject(projectRoot) + } + async findSpecs (projectRoot: string, specType: Maybe) { - const config = await this.ctx.project.getConfig(projectRoot) + const config = await this.getConfig(projectRoot) const specs = await this.api.findSpecs({ projectRoot, fixturesFolder: config.fixturesFolder ?? false, @@ -54,12 +58,8 @@ export class ProjectDataSource { return specs.find((x) => x.absolute === currentSpecAbs) ?? null } - getConfig (projectRoot: string) { - return this.configLoader.load(projectRoot) - } - async getResolvedConfigFields (projectRoot: string): Promise { - const config = await this.configLoader.load(projectRoot) + const config = await this.getConfig(projectRoot) interface ResolvedFromWithField extends ResolvedFromConfig { field: typeof RESOLVED_FROM[number] @@ -87,34 +87,22 @@ export class ProjectDataSource { }) as ResolvedFromConfig[] } - private configLoader = this.ctx.loader((projectRoots) => { - return Promise.all(projectRoots.map((root) => this.ctx._apis.projectApi.getConfig(root))) - }) - - async isFirstTimeAccessing (projectRoot: string, testingType: 'e2e' | 'component') { - try { - const config = await this.ctx.file.readJsonFile<{ e2e?: object, component?: object }>(path.join(projectRoot, 'cypress.json')) - - // If we have a cypress.json file, even with no overrides, assume that it's not our - // first time accessing (for now, until the config refactor lands) - if (testingType === 'e2e') { - return false - } - - const overrides = config.component || {} + async isTestingTypeConfigured (projectRoot: string, testingType: 'e2e' | 'component') { + const config = await this.getConfig(projectRoot) - return Object.keys(overrides).length === 0 - } catch (e) { - const err = e as Error & { code?: string } + if (!config) { + return true + } - // if they do not have a cypress.json, it's definitely their first time using Cypress. - if (err.code === 'ENOENT') { - return true - } + if (testingType === 'e2e') { + return Boolean(Object.keys(config.e2e ?? {}).length) + } - // unexpected error - throw err + if (testingType === 'component') { + return Boolean(Object.keys(config.component ?? {}).length) } + + return false } async getProjectPreferences (projectTitle: string) { diff --git a/packages/data-context/src/sources/index.ts b/packages/data-context/src/sources/index.ts index b860b90913f6..4437f8b32d91 100644 --- a/packages/data-context/src/sources/index.ts +++ b/packages/data-context/src/sources/index.ts @@ -4,6 +4,7 @@ export * from './AppDataSource' export * from './BrowserDataSource' export * from './CloudDataSource' +export * from './ConfigDataSource' export * from './EnvDataSource' export * from './FileDataSource' export * from './GitDataSource' diff --git a/packages/desktop-gui/cypress.config.js b/packages/desktop-gui/cypress.config.js new file mode 100644 index 000000000000..58733de46e1b --- /dev/null +++ b/packages/desktop-gui/cypress.config.js @@ -0,0 +1,21 @@ +module.exports = { + 'baseUrl': 'http://localhost:5005', + 'projectId': 'ypt4pf', + 'viewportWidth': 800, + 'viewportHeight': 850, + 'env': { + 'webpackFilename': 'webpack.config.ts', + 'coverage': false, + }, + 'retries': { + 'runMode': 2, + 'openMode': 0, + }, + 'nodeVersion': 'system', + 'testFiles': '**/*_spec.{js,jsx}', + 'componentFolder': 'src', + 'reporter': '../../node_modules/cypress-multi-reporters/index.js', + 'reporterOptions': { + 'configFile': '../../mocha-reporter-config.json', + }, +} diff --git a/packages/desktop-gui/cypress.json b/packages/desktop-gui/cypress.json deleted file mode 100644 index 431581dce2ff..000000000000 --- a/packages/desktop-gui/cypress.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "baseUrl": "http://localhost:5005", - "projectId": "ypt4pf", - "viewportWidth": 800, - "viewportHeight": 850, - "env": { - "webpackFilename": "webpack.config.ts", - "coverage": false - }, - "retries": { - "runMode": 2, - "openMode": 0 - }, - "nodeVersion": "system", - "testFiles": "**/*_spec.{js,jsx}", - "componentFolder": "src", - "reporter": "../../node_modules/cypress-multi-reporters/index.js", - "reporterOptions": { - "configFile": "../../mocha-reporter-config.json" - } -} \ No newline at end of file diff --git a/packages/desktop-gui/cypress/fixtures/config.json b/packages/desktop-gui/cypress/fixtures/config.json index 91fe1742a429..5c63a3c9a182 100644 --- a/packages/desktop-gui/cypress/fixtures/config.json +++ b/packages/desktop-gui/cypress/fixtures/config.json @@ -147,7 +147,7 @@ "requestTimeout": 5000, "resolvedNodePath": null, "resolvedNodeVersion": "1.2.3", - "configFile": "cypress.json", + "configFile": "cypress.config.js", "hosts": { "*.foobar.com": "127.0.0.1" }, diff --git a/packages/desktop-gui/cypress/integration/error_message_spec.js b/packages/desktop-gui/cypress/integration/error_message_spec.js index f0a21e48030d..f576458591b6 100644 --- a/packages/desktop-gui/cypress/integration/error_message_spec.js +++ b/packages/desktop-gui/cypress/integration/error_message_spec.js @@ -57,12 +57,12 @@ describe('Error Message', function () { }) it('displays error message with html escaped', function () { - this.err.message = 'Error reading from: /Users/cypress.json

SyntaxError' + this.err.message = 'Error reading from: /Users/cypress.config.js

SyntaxError' this.ipc.openProject.rejects(this.err) this.start() cy.get('.error') - .should('contain', 'Error reading from: /Users/cypress.json') + .should('contain', 'Error reading from: /Users/cypress.config.js') .should('not.contain', ' { openConfiguration() }) - it('notes that cypress.json is disabled', () => { - cy.contains('set from cypress.json file (currently disabled by --config-file false)') + it('notes that cypress.config.js is disabled', () => { + cy.contains('set from cypress.config.{ts|js} file (currently disabled by --config-file false)') }) }) context('when configFile is set', function () { beforeEach(function () { this.openProject.resolve(Cypress._.assign(this.config, { - configFile: 'special-cypress.json', + configFile: 'special-cypress.config.js', })) this.goToSettings() @@ -352,7 +352,7 @@ describe('Settings', () => { }) it('notes that a custom config is in use', () => { - cy.contains('set from custom config file special-cypress.json') + cy.contains('set from custom config file special-cypress.config.js') }) }) }) @@ -381,12 +381,7 @@ describe('Settings', () => { it('copies project id config to clipboard', function () { cy.get('.action-copy').click() .then(() => { - const expectedJsonConfig = { - projectId: this.config.projectId, - } - const expectedCopyCommand = JSON.stringify(expectedJsonConfig, null, 2) - - expect(this.ipc.setClipboardText).to.be.calledWith(expectedCopyCommand) + expect(this.ipc.setClipboardText).to.be.calledWith('module.exports = {\n projectId: "d8104707-a348-4653-baea-7da9c7d52448"\n}') }) }) }) diff --git a/packages/desktop-gui/cypress/integration/setup_project_spec.js b/packages/desktop-gui/cypress/integration/setup_project_spec.js index debe728add18..ddb558a288fb 100644 --- a/packages/desktop-gui/cypress/integration/setup_project_spec.js +++ b/packages/desktop-gui/cypress/integration/setup_project_spec.js @@ -8,7 +8,7 @@ const onSubmitNewProject = function (orgId) { projectName: this.config.projectName, orgId, public: false, - configFile: 'cypress.json', + configFile: 'cypress.config.js', }) }) }) @@ -26,7 +26,7 @@ const onSubmitNewProject = function (orgId) { projectRoot: '/foo/bar', orgId, public: true, - configFile: 'cypress.json', + configFile: 'cypress.config.js', }) }) }) @@ -492,7 +492,7 @@ describe('Connect to Dashboard', function () { expect(this.ipc.setProjectId).to.be.calledWith({ id: this.dashboardProjects[1].id, projectRoot: '/foo/bar', - configFile: 'cypress.json' }) + configFile: 'cypress.config.js' }) }) }) diff --git a/packages/desktop-gui/src/lib/config-file-formatted.jsx b/packages/desktop-gui/src/lib/config-file-formatted.jsx index d8d57092aa04..93aab8b73a1f 100644 --- a/packages/desktop-gui/src/lib/config-file-formatted.jsx +++ b/packages/desktop-gui/src/lib/config-file-formatted.jsx @@ -3,14 +3,14 @@ import { isUndefined } from 'lodash' const configFileFormatted = (configFile) => { if (configFile === false) { - return <>cypress.json file (currently disabled by --config-file false) + return <>cypress.config.{`{ts|js}`} file (currently disabled by --config-file false) } if (isUndefined(configFile)) { - return <>cypress.json file + return <>cypress.config.{`{ts|js}`} file } - if (['cypress.json', 'cypress.config.js'].includes(configFile)) { + if (['cypress.config.ts', 'cypress.config.js'].includes(configFile)) { return <>{configFile} file } diff --git a/packages/desktop-gui/src/runs/runs-list.jsx b/packages/desktop-gui/src/runs/runs-list.jsx index 35b887a72102..c59c5a1e8b5c 100644 --- a/packages/desktop-gui/src/runs/runs-list.jsx +++ b/packages/desktop-gui/src/runs/runs-list.jsx @@ -161,7 +161,7 @@ class RunsList extends Component { // OR if there is an error getting the runs if (this.runsStore.error) { - // project id missing, probably removed manually from cypress.json + // project id missing, probably removed manually from cypress.config.{ts|js} if (errors.isMissingProjectId(this.runsStore.error)) { return this._projectNotSetup() diff --git a/packages/desktop-gui/src/settings/project-id.jsx b/packages/desktop-gui/src/settings/project-id.jsx index 18593a8e77cf..2e40f4fa1602 100644 --- a/packages/desktop-gui/src/settings/project-id.jsx +++ b/packages/desktop-gui/src/settings/project-id.jsx @@ -3,7 +3,6 @@ import React from 'react' import Tooltip from '@cypress/react-tooltip' import ipc from '../lib/ipc' -import { isFileJSON } from '../lib/utils' import { configFileFormatted } from '../lib/config-file-formatted' const openProjectIdHelp = (e) => { @@ -39,20 +38,9 @@ const ProjectId = observer(({ project }) => { - { - isFileJSON(project.configFile) ? - <> - {'{'} - {` "projectId": "${project.id}"`} - {'}'} - - : - <> - {'module.exports = {'} - {` projectId: "${project.id}"`} - {'}'} - - } + {'module.exports = {'} + {` projectId: "${project.id}"`} + {'}'} ) diff --git a/packages/driver/cypress.config.ts b/packages/driver/cypress.config.ts new file mode 100644 index 000000000000..6422035de5bb --- /dev/null +++ b/packages/driver/cypress.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + 'projectId': 'ypt4pf', + 'baseUrl': 'http://localhost:3500', + 'testFiles': '**/*', + 'hosts': { + '*.foobar.com': '127.0.0.1', + }, + 'reporter': 'cypress-multi-reporters', + 'reporterOptions': { + 'configFile': '../../mocha-reporter-config.json', + }, +}) diff --git a/packages/driver/cypress.json b/packages/driver/cypress.json deleted file mode 100644 index 0128042adffd..000000000000 --- a/packages/driver/cypress.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "projectId": "ypt4pf", - "baseUrl": "http://localhost:3500", - "testFiles": "**/*", - "hosts": { - "*.foobar.com": "127.0.0.1" - }, - "reporter": "cypress-multi-reporters", - "reporterOptions": { - "configFile": "../../mocha-reporter-config.json" - } -} diff --git a/packages/driver/cypress/fixtures/fileSpec.json b/packages/driver/cypress/fixtures/fileSpec.json new file mode 100644 index 000000000000..da4f53f4b122 --- /dev/null +++ b/packages/driver/cypress/fixtures/fileSpec.json @@ -0,0 +1,3 @@ +{ + "baseUrl": "http://localhost:3500" +} \ No newline at end of file diff --git a/packages/driver/cypress/integration/commands/files_spec.js b/packages/driver/cypress/integration/commands/files_spec.js index 8050db9b1b9f..104558a88da5 100644 --- a/packages/driver/cypress/integration/commands/files_spec.js +++ b/packages/driver/cypress/integration/commands/files_spec.js @@ -90,7 +90,7 @@ describe('src/cy/commands/files', () => { }) it('really works', () => { - cy.readFile('cypress.json').its('baseUrl').should('eq', 'http://localhost:3500') + cy.readFile('./cypress/fixtures/fileSpec.json').its('baseUrl').should('eq', 'http://localhost:3500') }) it('works when contents are supposed to be null', () => { diff --git a/packages/driver/cypress/integration/commands/net_stubbing_spec.ts b/packages/driver/cypress/integration/commands/net_stubbing_spec.ts index de7df1a9eeab..0fa3850db63e 100644 --- a/packages/driver/cypress/integration/commands/net_stubbing_spec.ts +++ b/packages/driver/cypress/integration/commands/net_stubbing_spec.ts @@ -968,7 +968,7 @@ describe('network stubbing', 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.{ts|js}" file const corsUrl = 'http://diff.foobar.com:3501/no-cors' before(() => { diff --git a/packages/driver/cypress/integration/commands/request_spec.js b/packages/driver/cypress/integration/commands/request_spec.js index b466141e3613..0e9509f2fdf7 100644 --- a/packages/driver/cypress/integration/commands/request_spec.js +++ b/packages/driver/cypress/integration/commands/request_spec.js @@ -830,7 +830,7 @@ describe('src/cy/commands/request', () => { expect(this.logs.length).to.eq(1) expect(lastLog.get('error')).to.eq(err) expect(lastLog.get('state')).to.eq('failed') - expect(err.message).to.eq('`cy.request()` must be provided a fully qualified `url` - one that begins with `http`. By default `cy.request()` will use either the current window\'s origin or the `baseUrl` in `cypress.json`. Neither of those values were present.') + expect(err.message).to.eq('`cy.request()` must be provided a fully qualified `url` - one that begins with `http`. By default `cy.request()` will use either the current window\'s origin or the `baseUrl` in `cypress.config.ts`. Neither of those values were present.') expect(err.docsUrl).to.eq('https://on.cypress.io/request') done() @@ -851,7 +851,7 @@ describe('src/cy/commands/request', () => { expect(this.logs.length).to.eq(1) expect(lastLog.get('error')).to.eq(err) expect(lastLog.get('state')).to.eq('failed') - expect(err.message).to.eq('`cy.request()` must be provided a fully qualified `url` - one that begins with `http`. By default `cy.request()` will use either the current window\'s origin or the `baseUrl` in `cypress.json` (currently disabled by --config-file=false). Neither of those values were present.') + expect(err.message).to.eq('`cy.request()` must be provided a fully qualified `url` - one that begins with `http`. By default `cy.request()` will use either the current window\'s origin or the `baseUrl` in `cypress.config.{ts|js}` (currently disabled by --config-file=false). Neither of those values were present.') done() }) diff --git a/packages/driver/src/cypress/error_messages.ts b/packages/driver/src/cypress/error_messages.ts index bdbc6350ce88..262b040cc901 100644 --- a/packages/driver/src/cypress/error_messages.ts +++ b/packages/driver/src/cypress/error_messages.ts @@ -21,7 +21,7 @@ const format = (data) => { const formatConfigFile = (configFile) => { if (configFile === false) { - return '`cypress.json` (currently disabled by --config-file=false)' + return '`cypress.config.{ts|js}` (currently disabled by --config-file=false)' } return `\`${format(configFile)}\`` diff --git a/packages/driver/src/cypress/mocha.ts b/packages/driver/src/cypress/mocha.ts index 8b46babf1dde..ad43cd564193 100644 --- a/packages/driver/src/cypress/mocha.ts +++ b/packages/driver/src/cypress/mocha.ts @@ -144,7 +144,7 @@ const setMochaProps = (specWindow, _mocha) => { // to the mocha instance for clarity m.Mocha = M - // this needs to be part of the configuration of cypress.json + // this needs to be part of the configuration of cypress.config.{ts|js} // we can't just forcibly use bdd return ui(specWindow, _mocha) } diff --git a/packages/driver/src/cypress/shadow_dom_utils.ts b/packages/driver/src/cypress/shadow_dom_utils.ts index 06790502eef2..473b5f12cb00 100644 --- a/packages/driver/src/cypress/shadow_dom_utils.ts +++ b/packages/driver/src/cypress/shadow_dom_utils.ts @@ -1,6 +1,6 @@ /** * Order of preference for including shadow dom: -* command-level > programmatic config > test-level > suite-level > cypress.json +* command-level > programmatic config > test-level > suite-level > cypress.config.{ts|js} */ export const resolveShadowDomInclusion = (Cypress: Cypress.Cypress, commandValue?: boolean): boolean => { if (commandValue != null) return commandValue diff --git a/packages/example/cypress.json b/packages/example/cypress.config.js similarity index 59% rename from packages/example/cypress.json rename to packages/example/cypress.config.js index 628b3740dedd..c43d27f47714 100644 --- a/packages/example/cypress.json +++ b/packages/example/cypress.config.js @@ -1,4 +1,4 @@ -{ +module.exports = { "projectId": "2pz86o" } \ No newline at end of file diff --git a/packages/example/package.json b/packages/example/package.json index 2275117c0e3b..d6e427a5aab4 100644 --- a/packages/example/package.json +++ b/packages/example/package.json @@ -28,7 +28,7 @@ "devDependencies": { "chai": "3.5.0", "cross-env": "6.0.3", - "cypress-example-kitchensink": "1.15.2", + "cypress-example-kitchensink": "cypress-io/cypress-example-kitchensink#feat/use-config-file", "gulp": "4.0.2", "gulp-clean": "0.4.0", "gulp-gh-pages": "0.6.0-6", diff --git a/packages/frontend-shared/cypress.config.ts b/packages/frontend-shared/cypress.config.ts new file mode 100644 index 000000000000..b083724d2fa9 --- /dev/null +++ b/packages/frontend-shared/cypress.config.ts @@ -0,0 +1,25 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + 'projectId': 'sehy69', + 'baseUrl': 'http://localhost:5555', + 'viewportWidth': 800, + 'viewportHeight': 850, + 'retries': { + 'runMode': 2, + 'openMode': 0, + }, + 'nodeVersion': 'system', + 'testFiles': '**/*.spec.{js,ts,tsx,jsx}', + 'reporter': '../../node_modules/cypress-multi-reporters/index.js', + 'reporterOptions': { + 'configFile': '../../mocha-reporter-config.json', + }, + 'componentFolder': 'src', + 'component': { + 'testFiles': '**/*.spec.{js,ts,tsx,jsx}', + }, + 'e2e': { + 'supportFile': 'cypress/e2e/support/e2eSupport.ts', + }, +}) diff --git a/packages/frontend-shared/cypress.json b/packages/frontend-shared/cypress.json deleted file mode 100644 index d778bbea8372..000000000000 --- a/packages/frontend-shared/cypress.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "projectId": "sehy69", - "baseUrl": "http://localhost:5555", - "viewportWidth": 800, - "viewportHeight": 850, - "retries": { - "runMode": 2, - "openMode": 0 - }, - "nodeVersion": "system", - "testFiles": "**/*.spec.{js,ts,tsx,jsx}", - "reporter": "../../node_modules/cypress-multi-reporters/index.js", - "reporterOptions": { - "configFile": "../../mocha-reporter-config.json" - }, - "componentFolder": "src", - "component": { - "testFiles": "**/*.spec.{js,ts,tsx,jsx}" - }, - "e2e": { - "supportFile": "cypress/e2e/support/e2eSupport.ts" - } -} diff --git a/packages/frontend-shared/cypress/e2e/support/e2eProjectDirs.ts b/packages/frontend-shared/cypress/e2e/support/e2eProjectDirs.ts index ea9d637c7075..19a2d62fbb21 100644 --- a/packages/frontend-shared/cypress/e2e/support/e2eProjectDirs.ts +++ b/packages/frontend-shared/cypress/e2e/support/e2eProjectDirs.ts @@ -27,6 +27,7 @@ export const e2eProjectDirs = [ 'issue-8111-iframe-input', 'max-listeners', 'multiple-task-registrations', + 'multiples-config-files-with-json', 'no-scaffolding', 'no-server', 'non-existent-spec', @@ -53,6 +54,7 @@ export const e2eProjectDirs = [ 'plugins-async-error', 'plugins-root-async-error', 'pristine', + 'pristine-with-config-file', 'read-only-project-root', 'record', 'remote-debugging-disconnect', @@ -69,6 +71,7 @@ export const e2eProjectDirs = [ 'todos', 'ts-installed', 'ts-proj', + 'ts-proj-compiler', 'ts-proj-custom-names', 'ts-proj-esmoduleinterop-true', 'ts-proj-tsconfig-in-plugins', @@ -76,6 +79,7 @@ export const e2eProjectDirs = [ 'ts-proj-with-paths', 'uncaught-support-file', 'unify-onboarding', + 'unify-onboarding-with-config', 'unify-plugin-errors', 'various-file-types', 'webpack-preprocessor', diff --git a/packages/frontend-shared/cypress/fixtures/config.json b/packages/frontend-shared/cypress/fixtures/config.json index 91fe1742a429..5c63a3c9a182 100644 --- a/packages/frontend-shared/cypress/fixtures/config.json +++ b/packages/frontend-shared/cypress/fixtures/config.json @@ -147,7 +147,7 @@ "requestTimeout": 5000, "resolvedNodePath": null, "resolvedNodeVersion": "1.2.3", - "configFile": "cypress.json", + "configFile": "cypress.config.js", "hosts": { "*.foobar.com": "127.0.0.1" }, diff --git a/packages/frontend-shared/cypress/support/mock-graphql/stubgql-Mutation.ts b/packages/frontend-shared/cypress/support/mock-graphql/stubgql-Mutation.ts index 9889c0487a64..5827a7774109 100644 --- a/packages/frontend-shared/cypress/support/mock-graphql/stubgql-Mutation.ts +++ b/packages/frontend-shared/cypress/support/mock-graphql/stubgql-Mutation.ts @@ -11,8 +11,8 @@ export const stubMutation: MaybeResolver = { id: `project:${args.path}`, title: path.basename(args.path), projectRoot: args.path, - isFirstTimeCT: true, - isFirstTimeE2E: true, + isCTConfigured: true, + isE2EConfigured: true, __typename: 'Project', config, codeGenGlob: '/**/*.vue', diff --git a/packages/frontend-shared/cypress/support/mock-graphql/stubgql-Project.ts b/packages/frontend-shared/cypress/support/mock-graphql/stubgql-Project.ts index 027fef136d22..0021aa829c6e 100644 --- a/packages/frontend-shared/cypress/support/mock-graphql/stubgql-Project.ts +++ b/packages/frontend-shared/cypress/support/mock-graphql/stubgql-Project.ts @@ -15,8 +15,8 @@ export const createTestProject = (title: string): CodegenTypeMap['Project'] => { // TODO: What a mess, type this without all the hacks return { ...testNodeId('Project'), - isFirstTimeCT: true, - isFirstTimeE2E: true, + isCTConfigured: true, + isE2EConfigured: true, projectId: `${snakeTitle}-id`, title, projectRoot: `/usr/local/dev/projects/${snakeTitle}`, diff --git a/packages/graphql/schemas/schema.graphql b/packages/graphql/schemas/schema.graphql index 19ca6f5b78c0..94d80bc91b74 100644 --- a/packages/graphql/schemas/schema.graphql +++ b/packages/graphql/schemas/schema.graphql @@ -515,7 +515,7 @@ enum PluginsState { uninitialized } -"""A Cypress Project is represented by a cypress.json file""" +"""A Cypress Project is represented by a cypress.config.{ts|js} file""" type Project implements Node { """The remote associated project from Cypress Cloud""" cloudProject: CloudProject @@ -553,10 +553,10 @@ type Project implements Node { id: ID! """Whether the user configured this project to use Component Testing""" - isFirstTimeCT: Boolean! + isCTConfigured: Boolean! """Whether the user configured this project to use e2e Testing""" - isFirstTimeE2E: Boolean! + isE2EConfigured: Boolean! """Cached preferences for this project""" preferences: ProjectPreferences diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts index adce470e2f4d..33f585112688 100644 --- a/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts @@ -219,11 +219,13 @@ export const mutation = mutationType({ try { await ctx.actions.wizard.initializeOpenProject() ctx.coreData.baseError = null - } catch (error: any) { + } catch (error) { + const e = error as Error + ctx.coreData.baseError = { title: 'Cypress Configuration Error', - message: error.message, - stack: error.stack, + message: e.message, + stack: e.stack, } } }, @@ -268,7 +270,18 @@ export const mutation = mutationType({ path: nonNull(stringArg()), }, resolve: async (_, args, ctx) => { - await ctx.actions.project.setActiveProject(args.path) + try { + await ctx.actions.project.setActiveProject(args.path) + ctx.coreData.baseError = null + } catch (error) { + const e = error as Error + + ctx.coreData.baseError = { + title: 'Cypress Configuration Error', + message: e.message, + stack: e.stack, + } + } }, }) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-Project.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-Project.ts index 96b454b91365..5ca9b2d3cf61 100644 --- a/packages/graphql/src/schemaTypes/objectTypes/gql-Project.ts +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-Project.ts @@ -29,7 +29,7 @@ const GeneratedSpec = objectType({ export const Project = objectType({ name: 'Project', - description: 'A Cypress Project is represented by a cypress.json file', + description: 'A Cypress Project is represented by a cypress.config.{ts|js} file', node: 'projectRoot', definition (t) { t.field('cloudProject', { @@ -48,7 +48,7 @@ export const Project = objectType({ t.string('projectId', { description: 'Used to associate project with Cypress cloud', - resolve: (source, args, ctx) => ctx.project.projectId(source.projectRoot).then((val) => val ?? null), + resolve: (source, args, ctx) => ctx.project.projectId(source.projectRoot), }) t.nonNull.string('projectRoot') @@ -57,17 +57,17 @@ export const Project = objectType({ resolve: (source, args, ctx) => ctx.project.projectTitle(source.projectRoot), }) - t.nonNull.boolean('isFirstTimeCT', { + t.nonNull.boolean('isCTConfigured', { description: 'Whether the user configured this project to use Component Testing', resolve: (source, args, ctx) => { - return ctx.project.isFirstTimeAccessing(source.projectRoot, 'component') + return ctx.project.isTestingTypeConfigured(source.projectRoot, 'component') }, }) - t.nonNull.boolean('isFirstTimeE2E', { + t.nonNull.boolean('isE2EConfigured', { description: 'Whether the user configured this project to use e2e Testing', resolve: (source, args, ctx) => { - return ctx.project.isFirstTimeAccessing(source.projectRoot, 'e2e') + return ctx.project.isTestingTypeConfigured(source.projectRoot, 'e2e') }, }) diff --git a/packages/launchpad/cypress.config.ts b/packages/launchpad/cypress.config.ts new file mode 100644 index 000000000000..0c82f6f8f473 --- /dev/null +++ b/packages/launchpad/cypress.config.ts @@ -0,0 +1,26 @@ +export default { + 'projectId': 'sehy69', + 'viewportWidth': 800, + 'viewportHeight': 850, + 'retries': { + 'runMode': 2, + 'openMode': 0, + }, + 'nodeVersion': 'system', + 'testFiles': '**/*.spec.{js,ts,tsx,jsx}', + 'reporter': '../../node_modules/cypress-multi-reporters/index.js', + 'reporterOptions': { + 'configFile': '../../mocha-reporter-config.json', + }, + 'componentFolder': 'src', + 'component': { + 'testFiles': '**/*.spec.{js,ts,tsx,jsx}', + 'supportFile': 'cypress/component/support/index.ts', + 'pluginsFile': 'cypress/component/plugins/index.js', + }, + 'e2e': { + 'supportFile': 'cypress/e2e/support/e2eSupport.ts', + 'integrationFolder': 'cypress/e2e/integration', + 'pluginsFile': 'cypress/e2e/plugins/index.ts', + }, +} diff --git a/packages/launchpad/cypress.json b/packages/launchpad/cypress.json deleted file mode 100644 index ee408115b831..000000000000 --- a/packages/launchpad/cypress.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$schema": "../../cli/schema/cypress.schema.json", - "projectId": "sehy69", - "viewportWidth": 800, - "viewportHeight": 850, - "retries": { - "runMode": 2, - "openMode": 0 - }, - "nodeVersion": "system", - "testFiles": "**/*.spec.{js,ts,tsx,jsx}", - "reporter": "../../node_modules/cypress-multi-reporters/index.js", - "reporterOptions": { - "configFile": "../../mocha-reporter-config.json" - }, - "componentFolder": "src", - "component": { - "testFiles": "**/*.spec.{js,ts,tsx,jsx}", - "supportFile": "cypress/component/support/index.ts", - "pluginsFile": "cypress/component/plugins/index.js" - }, - "e2e": { - "supportFile": "cypress/e2e/support/e2eSupport.ts", - "integrationFolder": "cypress/e2e/integration", - "pluginsFile": "cypress/e2e/plugins/index.ts" - } -} diff --git a/packages/launchpad/cypress/component/support/attachFileWithPath.ts b/packages/launchpad/cypress/component/support/attachFileWithPath.ts index d74b11bfce07..96480817f489 100644 --- a/packages/launchpad/cypress/component/support/attachFileWithPath.ts +++ b/packages/launchpad/cypress/component/support/attachFileWithPath.ts @@ -7,7 +7,7 @@ declare global { } export function attachedFileWithPath (subject: HTMLInputElement, path: string) { - const attachedFile = new File([new Blob()], 'cypress.json') + const attachedFile = new File([new Blob()], 'cypress.config.ts') Object.defineProperty(attachedFile, 'path', { value: path }) diff --git a/packages/launchpad/cypress/e2e/integration/config-files-error-handling.spec.ts b/packages/launchpad/cypress/e2e/integration/config-files-error-handling.spec.ts new file mode 100644 index 000000000000..6232d796b563 --- /dev/null +++ b/packages/launchpad/cypress/e2e/integration/config-files-error-handling.spec.ts @@ -0,0 +1,87 @@ +describe('Config files error handling', () => { + beforeEach(() => { + cy.setupE2E('pristine-with-config-file') + cy.visitLaunchpad() + }) + + it('it handles multiples config files', () => { + cy.withCtx(async (ctx) => { + await ctx.actions.file.writeFileInProject('cypress.config.ts', 'export default {}') + }) + + cy.get('[data-cy-testingType=e2e]').click() + + cy.get('body').should('contain.text', 'Configuration Files') + + cy.get('button').contains('Continue').click() + cy.get('body') + .should('contain.text', 'Cypress Configuration Error') + .and('contain.text', 'There is both a `cypress.config.js` and a `cypress.config.ts` at the location below') + + cy.withCtx(async (ctx) => { + await ctx.actions.file.removeFileInProject('cypress.config.ts') + }) + + cy.get('[data-testid=error-retry-button]').click() + cy.get('body') + .should('not.contain.text', 'Cypress Configuration Error') + }) + + it('it handles legacy config file', () => { + cy.withCtx(async (ctx) => { + await ctx.actions.file.writeFileInProject('cypress.json', '{}') + await ctx.actions.file.removeFileInProject('cypress.config.js') + }) + + cy.get('[data-cy-testingType=e2e]').click() + + cy.get('body').should('contain.text', 'Configuration Files') + + cy.get('button').contains('Continue').click() + + cy.get('body') + .should('contain.text', 'Cypress Configuration Error') + .and('contain.text', 'There is a cypress.json file at the location below:') + + cy.withCtx(async (ctx) => { + await ctx.actions.file.removeFileInProject('cypress.json') + }) + + cy.get('[data-testid=error-retry-button]').click() + cy.get('body') + .should('contain.text', 'Cypress Configuration Error') + .and('contain.text', 'Could not find a Cypress configuration file, exiting.') + + cy.withCtx(async (ctx) => { + await ctx.actions.file.writeFileInProject('cypress.config.js', 'module.exports = {}') + }) + + cy.get('[data-testid=error-retry-button]').click() + cy.get('body') + .should('not.contain.text', 'Cypress Configuration Error') + }) + + it('it handles config files with legacy config file in same project', () => { + cy.withCtx(async (ctx) => { + await ctx.actions.file.writeFileInProject('cypress.json', '{}') + }) + + cy.get('[data-cy-testingType=e2e]').click() + + cy.get('body').should('contain.text', 'Configuration Files') + + cy.get('button').contains('Continue').click() + + cy.get('body') + .should('contain.text', 'Cypress Configuration Error') + .and('contain.text', 'There is both a `cypress.config.js` and a cypress.json file at the location below') + + cy.withCtx(async (ctx) => { + await ctx.actions.file.removeFileInProject('cypress.json') + }) + + cy.get('[data-testid=error-retry-button]').click() + cy.get('body') + .should('not.contain.text', 'Cypress Configuration Error') + }) +}) diff --git a/packages/launchpad/cypress/e2e/integration/onboarding-flow.spec.ts b/packages/launchpad/cypress/e2e/integration/onboarding-flow.spec.ts index fea2270ea945..a53ef1db6481 100644 --- a/packages/launchpad/cypress/e2e/integration/onboarding-flow.spec.ts +++ b/packages/launchpad/cypress/e2e/integration/onboarding-flow.spec.ts @@ -1,10 +1,8 @@ describe('Onboarding Flow', () => { - beforeEach(() => { + it('can scaffold a project in e2e mode', () => { cy.setupE2E('unify-onboarding') cy.loginUser() - }) - it('can scaffold a project in e2e mode', () => { cy.visitLaunchpad() cy.get('[data-cy-testingType=component]').click() cy.get('[data-cy=select-framework]').click() @@ -19,4 +17,12 @@ describe('Onboarding Flow', () => { cy.findByText('Next Step').click() cy.get('h1').should('contain', 'Dependencies') }) + + it('redirects to initialize plugin if CT is configured', () => { + cy.setupE2E('unify-onboarding-with-config') + + cy.visitLaunchpad() + cy.get('[data-cy-testingType=component]').click() + cy.get('h1').should('contain', 'Initializing Config...') + }) }) diff --git a/packages/launchpad/cypress/e2e/integration/open-mode.spec.ts b/packages/launchpad/cypress/e2e/integration/open-mode.spec.ts index 6b39d8549562..204c76f3168f 100644 --- a/packages/launchpad/cypress/e2e/integration/open-mode.spec.ts +++ b/packages/launchpad/cypress/e2e/integration/open-mode.spec.ts @@ -11,6 +11,8 @@ describe('Launchpad: Open Mode', () => { }) it('goes directly to e2e tests when launched with --e2e', () => { + cy.setupE2E('todos') + cy.withCtx(async (ctx) => { // Though the data context is previously initialized, // we re-initialize it here so that it reflects the new launchArg @@ -19,15 +21,16 @@ describe('Launchpad: Open Mode', () => { }) cy.withCtx(async (ctx, o) => { - await ctx.actions.project.setActiveProject(o.projectDir('todos')) ctx.emitter.toLaunchpad() }) // e2e testing is configured for the todo project, so we don't expect an error. - cy.get('h1').should('contain', 'Initializing Config...') + cy.get('h1').should('contain', 'Configuration Files') }) it('goes directly to component tests when launched with --component', () => { + cy.setupE2E('todos') + cy.withCtx(async (ctx) => { // Though the data context is previously initialized, // we re-initialize it here so that it reflects the new launchArg @@ -36,7 +39,6 @@ describe('Launchpad: Open Mode', () => { }) cy.withCtx(async (ctx, o) => { - await ctx.actions.project.setActiveProject(o.projectDir('todos')) ctx.emitter.toLaunchpad() }) @@ -46,8 +48,9 @@ describe('Launchpad: Open Mode', () => { describe('when there is a list of projects', () => { it('goes to an active project if one is added', () => { + cy.setupE2E('todos') + cy.withCtx(async (ctx, o) => { - await ctx.actions.project.setActiveProject(o.projectDir('todos')) ctx.emitter.toLaunchpad() }) diff --git a/packages/launchpad/cypress/fixtures/test-project/cypress.config.ts b/packages/launchpad/cypress/fixtures/test-project/cypress.config.ts new file mode 100644 index 000000000000..eaf31cec46f1 --- /dev/null +++ b/packages/launchpad/cypress/fixtures/test-project/cypress.config.ts @@ -0,0 +1,5 @@ +import { defineConfig } from "cypress"; + +export default defineConfig({ + "projectId": "test01" +}) \ No newline at end of file diff --git a/packages/launchpad/cypress/fixtures/test-project/cypress.json b/packages/launchpad/cypress/fixtures/test-project/cypress.json deleted file mode 100644 index fdaf8410dd73..000000000000 --- a/packages/launchpad/cypress/fixtures/test-project/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "projectId": "test01" -} \ No newline at end of file diff --git a/packages/launchpad/src/global/GlobalPage.spec.tsx b/packages/launchpad/src/global/GlobalPage.spec.tsx index 45989aa0654e..37ba341240e1 100644 --- a/packages/launchpad/src/global/GlobalPage.spec.tsx +++ b/packages/launchpad/src/global/GlobalPage.spec.tsx @@ -48,7 +48,7 @@ describe('', { viewportHeight: 900, viewportWidth: 1200 }, () => { it('can add a project when clicking the button', () => { cy.contains('button', defaultMessages.globalPage.addProjectButton).click() cy.get('input[type=file]') - .attachFileWithPath('absolute/path/to/yet-another-test-project/cypress.json') + .attachFileWithPath('absolute/path/to/yet-another-test-project/cypress.config.ts') .trigger('change', { force: true }) // .findByText('yet-another-test-project').should('be.visible') }) diff --git a/packages/launchpad/src/global/GlobalPageHeader.spec.tsx b/packages/launchpad/src/global/GlobalPageHeader.spec.tsx index 4e527bdd1085..acde8620f1bc 100644 --- a/packages/launchpad/src/global/GlobalPageHeader.spec.tsx +++ b/packages/launchpad/src/global/GlobalPageHeader.spec.tsx @@ -44,7 +44,7 @@ describe('', () => { it('handles a file upload', () => { cy.get(fileInputSelector) - .attachFile('test-project/cypress.json') + .attachFile('test-project/cypress.config.ts') .get(addProjectSelector) .click() .get('@fileUpload').should('have.been.called') diff --git a/packages/launchpad/src/settings/project/Config.spec.tsx b/packages/launchpad/src/settings/project/Config.spec.tsx index 507ab962db61..57a0373ba66f 100644 --- a/packages/launchpad/src/settings/project/Config.spec.tsx +++ b/packages/launchpad/src/settings/project/Config.spec.tsx @@ -1,12 +1,12 @@ import Config from './Config.vue' -import jsonObject from '../../../cypress.json?raw' +import cypressConfig from '../../../cypress.config' import { defaultMessages } from '@cy/i18n' import { each } from 'lodash' describe('', () => { it('renders the title, description, code, and legend', () => { cy.mount(() =>
) - cy.get('[data-testid=config-code]').contains(jsonObject) + cy.get('[data-testid=config-code]').contains(JSON.stringify(cypressConfig, null, 2)) cy.contains(defaultMessages.settingsPage.config.title) // TODO: write a support file helper for ignoring the {0} values etc diff --git a/packages/launchpad/src/settings/project/Config.vue b/packages/launchpad/src/settings/project/Config.vue index 8b6baf6eda2e..05f56d86329d 100644 --- a/packages/launchpad/src/settings/project/Config.vue +++ b/packages/launchpad/src/settings/project/Config.vue @@ -28,10 +28,10 @@ import { ref } from 'vue' import SettingsSection from '../SettingsSection.vue' import { useI18n } from '@cy/i18n' -import cypressJson from '../../../cypress.json?raw' // TODO: remove this +import cypressConfig from '../../../cypress.config' import ConfigLegend from './ConfigLegend.vue' import ConfigCode from './ConfigCode.vue' -const code = ref(JSON.parse(JSON.stringify(cypressJson, null, 2))) +const code = ref(JSON.parse(JSON.stringify(cypressConfig, null, 2))) const { t } = useI18n() diff --git a/packages/launchpad/src/settings/project/ConfigCode.spec.tsx b/packages/launchpad/src/settings/project/ConfigCode.spec.tsx index b394867939d1..b6603b9e46ea 100644 --- a/packages/launchpad/src/settings/project/ConfigCode.spec.tsx +++ b/packages/launchpad/src/settings/project/ConfigCode.spec.tsx @@ -1,9 +1,9 @@ import ConfigCode from './ConfigCode.vue' -import jsonObject from '../../../cypress.json' +import config from '../../../cypress.config' import { defaultMessages } from '@cy/i18n' const selector = '[data-testid=code]' -const jsonString = JSON.stringify(jsonObject, null, 2) +const configString = JSON.stringify(config, null, 2) describe('', () => { beforeEach(() => { @@ -16,12 +16,12 @@ describe('', () => { */ } { /* @ts-ignore */ } - + )) }) it('renders the code passed in', () => { - cy.get(selector).should('contain.text', jsonString) + cy.get(selector).should('contain.text', configString) }) // This needs to be skipped because it cannot be tested unless "Emulate a focused page" is checked. diff --git a/packages/launchpad/src/setup/TestingTypeCards.spec.tsx b/packages/launchpad/src/setup/TestingTypeCards.spec.tsx index 5f46f0983cbf..4c7a0e4d9de4 100644 --- a/packages/launchpad/src/setup/TestingTypeCards.spec.tsx +++ b/packages/launchpad/src/setup/TestingTypeCards.spec.tsx @@ -9,8 +9,8 @@ describe('TestingTypeCards', () => { cy.mountFragment(TestingTypeCardsFragmentDoc, { onResult: (result, ctx) => { if (result.app.activeProject) { - result.app.activeProject.isFirstTimeCT = true - result.app.activeProject.isFirstTimeE2E = true + result.app.activeProject.isCTConfigured = false + result.app.activeProject.isE2EConfigured = false } }, render: (gqlVal) => { @@ -28,8 +28,8 @@ describe('TestingTypeCards', () => { cy.mountFragment(TestingTypeCardsFragmentDoc, { onResult: (result, ctx) => { if (result.app.activeProject) { - result.app.activeProject.isFirstTimeCT = false - result.app.activeProject.isFirstTimeE2E = false + result.app.activeProject.isCTConfigured = true + result.app.activeProject.isE2EConfigured = true } }, render: (gqlVal) => { @@ -45,8 +45,8 @@ describe('TestingTypeCards', () => { cy.mountFragment(TestingTypeCardsFragmentDoc, { onResult: (result, ctx) => { if (result.app.activeProject) { - result.app.activeProject.isFirstTimeCT = false - result.app.activeProject.isFirstTimeE2E = true + result.app.activeProject.isCTConfigured = true + result.app.activeProject.isE2EConfigured = false } }, render: (gqlVal) => { diff --git a/packages/launchpad/src/setup/TestingTypeCards.vue b/packages/launchpad/src/setup/TestingTypeCards.vue index d7c19a2d33d7..03750091c0d8 100644 --- a/packages/launchpad/src/setup/TestingTypeCards.vue +++ b/packages/launchpad/src/setup/TestingTypeCards.vue @@ -5,8 +5,8 @@ :id="e2e.type" :data-cy-testingType="e2e.type" :title="e2e.title" - :description="firstTimeE2E ? e2e.description : 'LAUNCH'" - :configured="!firstTimeE2E" + :description="isE2EConfigured ? 'LAUNCH' : e2e.description " + :configured="isE2EConfigured" :image="e2ePreview" role="button" @click="e2eNextStep" @@ -19,8 +19,8 @@ :id="ct.type" :data-cy-testingType="ct.type" :title="ct.title" - :description="firstTimeCT ? ct.description : 'LAUNCH'" - :configured="!firstTimeCT" + :description="isCTConfigured ? 'LAUNCH' : ct.description" + :configured="isCTConfigured" :image="ctPreview" role="button" @click="ctNextStep" @@ -48,8 +48,8 @@ fragment TestingTypeCards on Query { app { activeProject { id - isFirstTimeCT - isFirstTimeE2E + isCTConfigured + isE2EConfigured } } wizard { @@ -79,8 +79,8 @@ const ct = computed(() => { return props.gql.wizard.testingTypes.find((x) => x.type === 'component') }) -const firstTimeCT = computed(() => props.gql.app.activeProject?.isFirstTimeCT) -const firstTimeE2E = computed(() => props.gql.app.activeProject?.isFirstTimeE2E) +const isCTConfigured = computed(() => Boolean(props.gql.app.activeProject?.isCTConfigured)) +const isE2EConfigured = computed(() => Boolean(props.gql.app.activeProject?.isE2EConfigured)) const ctNextStep = async () => { return mutation.executeMutation({ input: { testingType: 'component', direction: 'forward' } }) diff --git a/packages/reporter/cypress.config.ts b/packages/reporter/cypress.config.ts new file mode 100644 index 000000000000..55704573b981 --- /dev/null +++ b/packages/reporter/cypress.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + 'projectId': 'ypt4pf', + 'baseUrl': 'http://localhost:5006', + 'viewportWidth': 400, + 'viewportHeight': 450, + 'reporter': '../../node_modules/cypress-multi-reporters/index.js', + 'reporterOptions': { + 'configFile': '../../mocha-reporter-config.json', + }, + 'retries': { + 'runMode': 2, + 'openMode': 0, + }, +}) diff --git a/packages/reporter/cypress.json b/packages/reporter/cypress.json deleted file mode 100644 index bbf940fae4c6..000000000000 --- a/packages/reporter/cypress.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "projectId": "ypt4pf", - "baseUrl": "http://localhost:5006", - "viewportWidth": 400, - "viewportHeight": 450, - "reporter": "../../node_modules/cypress-multi-reporters/index.js", - "reporterOptions": { - "configFile": "../../mocha-reporter-config.json" - }, - "retries": { - "runMode": 2, - "openMode": 0 - } -} diff --git a/packages/runner-ct/cypress.config.ts b/packages/runner-ct/cypress.config.ts new file mode 100644 index 000000000000..c1d0800a04bb --- /dev/null +++ b/packages/runner-ct/cypress.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + testFiles: '**/*spec.{ts,tsx}', + video: true, + env: { + reactDevtools: false, + }, + reporter: '../../node_modules/cypress-multi-reporters/index.js', + reporterOptions: { + configFile: '../../mocha-reporter-config.json', + }, + component: { + testFiles: '**/*spec.{ts,tsx}', + }, +}) diff --git a/packages/runner-ct/cypress.json b/packages/runner-ct/cypress.json deleted file mode 100644 index 9f846dd0f7fd..000000000000 --- a/packages/runner-ct/cypress.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "testFiles": "**/*spec.{ts,tsx}", - "video": true, - "env": { - "reactDevtools": false - }, - "reporter": "../../node_modules/cypress-multi-reporters/index.js", - "reporterOptions": { - "configFile": "../../mocha-reporter-config.json" - }, - "component": { - "testFiles": "**/*spec.{ts,tsx}" - } -} diff --git a/packages/runner-shared/src/config-file-formatted.tsx b/packages/runner-shared/src/config-file-formatted.tsx index 92f95e07bea4..4fc087d8e796 100644 --- a/packages/runner-shared/src/config-file-formatted.tsx +++ b/packages/runner-shared/src/config-file-formatted.tsx @@ -1,11 +1,13 @@ import React from 'react' -import { isUndefined } from 'lodash' const configFileFormatted = (configFile) => { if (configFile === false) { return ( <> - cypress.json + +cypress.config. + {`{ts | js}`} + {' '} file (currently disabled by {' '} @@ -15,10 +17,12 @@ file (currently disabled by ) } - if (isUndefined(configFile) || configFile === 'cypress.json') { + if (['cypress.config.ts', 'cypress.config.js'].includes(configFile)) { return ( <> - cypress.json + + {configFile} + {' '} file diff --git a/packages/runner/cypress.config.js b/packages/runner/cypress.config.js new file mode 100644 index 000000000000..3b33ab67a183 --- /dev/null +++ b/packages/runner/cypress.config.js @@ -0,0 +1,15 @@ +module.exports = { + 'projectId': 'ypt4pf', + 'baseUrl': 'http://localhost:3500', + 'retries': { + 'runMode': 2, + 'openMode': 0, + }, + 'env': { + 'CypressInternal_UseInlineSpecList': true, + }, + 'reporter': '../../node_modules/cypress-multi-reporters/index.js', + 'reporterOptions': { + 'configFile': '../../mocha-reporter-config.json', + }, +} diff --git a/packages/runner/cypress.json b/packages/runner/cypress.json deleted file mode 100644 index e944678dde18..000000000000 --- a/packages/runner/cypress.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "projectId": "ypt4pf", - "baseUrl": "http://localhost:3500", - "retries": { - "runMode": 2, - "openMode": 0 - }, - "env": { - "CypressInternal_UseInlineSpecList": true - }, - "reporter": "../../node_modules/cypress-multi-reporters/index.js", - "reporterOptions": { - "configFile": "../../mocha-reporter-config.json" - } -} diff --git a/packages/server/lib/cache.js b/packages/server/lib/cache.js index 2e8410612043..adba40cbb4d0 100644 --- a/packages/server/lib/cache.js +++ b/packages/server/lib/cache.js @@ -39,6 +39,7 @@ module.exports = { USER: {}, PROJECTS: [], PROJECT_PREFERENCES: {}, + PROJECTS_CONFIG: {}, } }, diff --git a/packages/server/lib/config.ts b/packages/server/lib/config.ts index 6b3a350d5f45..7aec4f32b509 100644 --- a/packages/server/lib/config.ts +++ b/packages/server/lib/config.ts @@ -203,9 +203,9 @@ export type FullConfig = resolved: ResolvedConfigurationOptions } -export function get (projectRoot, options = {}): Promise { +export function get (projectRoot, options: {configFile?: string | false } = { configFile: undefined }): Promise { return Promise.all([ - settings.read(projectRoot, options).then(validateFile('cypress.json')), + settings.read(projectRoot, options).then(validateFile(options.configFile ?? 'cypress.config.{ts|js}')), settings.readEnv(projectRoot).then(validateFile('cypress.env.json')), ]) .spread((settings, envFile) => { @@ -422,7 +422,7 @@ export function updateWithPluginValues (cfg, overrides) { } // combines the default configuration object with values specified in the -// configuration file like "cypress.json". Values in configuration file +// configuration file like "cypress.{ts|js}". Values in configuration file // overwrite the defaults. export function resolveConfigValues (config, defaults, resolved = {}) { // pick out only known configuration keys @@ -743,7 +743,7 @@ export function parseEnv (cfg: Record, envCLI: Record, resolveFrom('env', envProc) resolveFrom('cli', envCLI) - // envCfg is from cypress.json + // envCfg is from cypress.config.{ts|js} // envFile is from cypress.env.json // envProc is from process env vars // envCLI is from CLI arguments diff --git a/packages/server/lib/configFiles.ts b/packages/server/lib/configFiles.ts deleted file mode 100644 index b8a0495b1bce..000000000000 --- a/packages/server/lib/configFiles.ts +++ /dev/null @@ -1,2 +0,0 @@ -// the first file is the default created file -export const CYPRESS_CONFIG_FILES = ['cypress.json', 'cypress.config.js', 'cypress.config.ts'] diff --git a/packages/server/lib/config_options.ts b/packages/server/lib/config_options.ts index d5fa13eb2b4e..fff78dccda3f 100644 --- a/packages/server/lib/config_options.ts +++ b/packages/server/lib/config_options.ts @@ -47,7 +47,7 @@ const testingTypeOptions = [ isFolder: true, }, { name: 'configFile', - defaultValue: 'cypress.json', + defaultValue: 'cypress.config.js', validation: v.isStringOrFalse, // not truly internal, but can only be set via cli, // so we don't consider it a "public" option diff --git a/packages/server/lib/errors.js b/packages/server/lib/errors.js index 61696d437275..3d121e2301fc 100644 --- a/packages/server/lib/errors.js +++ b/packages/server/lib/errors.js @@ -625,7 +625,7 @@ const getMsgByType = function (type, arg1 = {}, arg2, arg3) { 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.{ts|js}" case 'SETTINGS_VALIDATION_ERROR': filePath = `\`${arg1}\`` @@ -700,6 +700,20 @@ const getMsgByType = function (type, arg1 = {}, arg2, arg3) { Could not find a Cypress configuration file, exiting. We looked but did not find a default config file in this folder: ${chalk.blue(arg1)}` + case 'CONFIG_FILE_MIGRATION_NEEDED': + return stripIndent` + There is a cypress.json file at the location below: + ${arg1} + + Cypress no longer supports 'cypress.json', please migrate to 'cypress.config.{ts|js}'. + ` + case 'LEGACY_CONFIG_FILE': + return stripIndent` + There is both a \`${arg2}\` and a cypress.json file at the location below: + ${arg1} + + Cypress no longer supports 'cypress.json' config, please remove it from your project. + ` // TODO: update with vetted cypress language case 'CONFIG_FILES_LANGUAGE_CONFLICT': return stripIndent` @@ -932,7 +946,7 @@ const getMsgByType = function (type, arg1 = {}, arg2, arg3) { You can safely remove this option from your config.` case 'EXPERIMENTAL_COMPONENT_TESTING_REMOVED': return stripIndent`\ - The ${chalk.yellow(`\`experimentalComponentTesting\``)} configuration option was removed in Cypress version \`7.0.0\`. Please remove this flag from \`cypress.json\`. + The ${chalk.yellow(`\`experimentalComponentTesting\``)} configuration option was removed in Cypress version \`7.0.0\`. Please remove this flag from \`cypress.config.{ts|js}\`. Cypress Component Testing is now a standalone command. You can now run your component tests with: diff --git a/packages/server/lib/makeDataContext.ts b/packages/server/lib/makeDataContext.ts index a5f318edbb97..b29dfa5e9399 100644 --- a/packages/server/lib/makeDataContext.ts +++ b/packages/server/lib/makeDataContext.ts @@ -1,13 +1,16 @@ import { DataContext } from '@packages/data-context' +import os from 'os' + import specsUtil from './util/specs' -import type { FindSpecs, FoundBrowser, LaunchArgs, LaunchOpts, OpenProjectLaunchOptions, PlatformName, Preferences } from '@packages/types' +import type { FindSpecs, FoundBrowser, LaunchArgs, LaunchOpts, OpenProjectLaunchOptions, PlatformName, Preferences, SettingsOptions } from '@packages/types' import browserUtils from './browsers/utils' import auth from './gui/auth' import user from './user' import * as config from './config' -import type { EventEmitter } from 'events' +import { EventEmitter } from 'events' import { openProject } from './open_project' import cache from './cache' +import errors from './errors' import { graphqlSchema } from '@packages/graphql/src/schema' const { getBrowsers } = browserUtils @@ -18,6 +21,27 @@ interface MakeDataContextOptions { launchArgs: LaunchArgs } +let legacyDataContext: DataContext | undefined + +// For testing +export function clearLegacyDataContext () { + legacyDataContext = undefined +} + +export function makeLegacyDataContext (launchArgs: LaunchArgs = {} as LaunchArgs): DataContext { + if (legacyDataContext && process.env.LAUNCHPAD) { + throw new Error(`Expected ctx to be passed as an arg, but used legacy data context`) + } else if (!legacyDataContext) { + legacyDataContext = makeDataContext({ + rootBus: new EventEmitter, + launchArgs, + os: os.platform() as PlatformName, + }) + } + + return legacyDataContext +} + export function makeDataContext (options: MakeDataContextOptions) { return new DataContext({ schema: graphqlSchema, @@ -40,8 +64,8 @@ export function makeDataContext (options: MakeDataContextOptions) { }, }, projectApi: { - getConfig (projectRoot: string) { - return config.get(projectRoot) + getConfig (projectRoot: string, options?: SettingsOptions) { + return config.get(projectRoot, options) }, launchProject (browser: FoundBrowser, spec: Cypress.Spec, options?: LaunchOpts) { return openProject.launch({ ...browser }, spec, options) @@ -79,6 +103,9 @@ export function makeDataContext (options: MakeDataContextOptions) { closeActiveProject () { return openProject.closeActiveProject() }, + error (type: string, ...args: any) { + throw errors.throw(type, ...args) + }, }, }) } diff --git a/packages/server/lib/modes/index.ts b/packages/server/lib/modes/index.ts index 22304c1bdeec..c9ad2c6d762f 100644 --- a/packages/server/lib/modes/index.ts +++ b/packages/server/lib/modes/index.ts @@ -1,4 +1,10 @@ +import { makeLegacyDataContext } from '../makeDataContext' + export = (mode, options) => { + if (!process.env.LAUNCHPAD) { + makeLegacyDataContext(options) + } + if (mode === 'record') { return require('./record').run(options) } diff --git a/packages/server/lib/modes/record.js b/packages/server/lib/modes/record.js index 7fae7dd0dcf9..a78b154af5c2 100644 --- a/packages/server/lib/modes/record.js +++ b/packages/server/lib/modes/record.js @@ -620,6 +620,7 @@ const createRunAndRecordSpecs = (options = {}) => { projectId, specPattern, testingType, + configFile: config ? config.configFile : null, }) .then((resp) => { if (!resp) { diff --git a/packages/server/lib/modes/run.js b/packages/server/lib/modes/run.js index 7d212a772f13..fb81137a915f 100644 --- a/packages/server/lib/modes/run.js +++ b/packages/server/lib/modes/run.js @@ -624,19 +624,21 @@ const createAndOpenProject = async (socketId, options) => { await checkAccess(projectRoot) - return openProjectCreate(projectRoot, socketId, options) - .then((open_project) => open_project.getProject()) - .then((project) => { - return Promise.all([ - project, - project.getConfig(), - getProjectId(project, projectId), - ]).then(([project, config, projectId]) => ({ - project, - config, - projectId, - })) - }) + const open_project = await openProjectCreate(projectRoot, socketId, options) + const project = await open_project.getProject() + + const [_project, _config, _projectId] = await Promise.all([ + project, + project.getConfig(), + getProjectId(project, projectId), + ]) + + return { + project: _project, + config: _config, + projectId: _projectId, + configFile: project.options.configFile, + } } const removeOldProfiles = (browser) => { @@ -1533,7 +1535,7 @@ module.exports = { options.browsers = browsers return createAndOpenProject(socketId, options) - .then(({ project, projectId, config }) => { + .then(({ project, projectId, config, configFile }) => { debug('project created and opened with config %o', config) // if we have a project id and a key but record hasnt been given @@ -1541,7 +1543,7 @@ module.exports = { recordMode.throwIfRecordParamsWithoutRecording(record, ciBuildId, parallel, group, tag) if (record) { - recordMode.throwIfNoProjectId(projectId, settings.configFile(options)) + recordMode.throwIfNoProjectId(projectId, settings.configFile(options.configFile === undefined || options.configFile === null ? { configFile } : options)) recordMode.throwIfIncorrectCiBuildIdUsage(ciBuildId, parallel, group) recordMode.throwIfIndeterminateCiBuildId(ciBuildId, parallel, group) } diff --git a/packages/server/lib/project-base.ts b/packages/server/lib/project-base.ts index b57c180b7809..bc015681c7e3 100644 --- a/packages/server/lib/project-base.ts +++ b/packages/server/lib/project-base.ts @@ -33,7 +33,8 @@ import preprocessor from './plugins/preprocessor' import { SpecsStore } from './specs-store' import { checkSupportFile, getDefaultConfigFilePath } from './project_utils' import type { FoundBrowser, OpenProjectLaunchOptions } from '@packages/types' -import { DataContextShell } from '@packages/data-context/src/DataContextShell' +import { makeLegacyDataContext } from './makeDataContext' +import type { DataContext } from '@packages/data-context' // Cannot just use RuntimeConfigOptions as is because some types are not complete. // Instead, this is an interface of values that have been manually validated to exist @@ -67,7 +68,7 @@ export class ProjectBase extends EE { public id: string protected watchers: Watchers - protected ctx: DataContextShell + protected ctx: DataContext protected _cfg?: Cfg protected _server?: TServer protected _automation?: Automation @@ -107,7 +108,7 @@ export class ProjectBase extends EE { this.spec = null this.browser = null this.id = createHmac('sha256', 'secret-key').update(projectRoot).digest('hex') - this.ctx = options.ctx ?? new DataContextShell() + this.ctx = options.ctx ?? makeLegacyDataContext() debug('Project created %o', { testingType: this.testingType, @@ -702,7 +703,7 @@ export class ProjectBase extends EE { async initializeConfig (browsers: FoundBrowser[] = []): Promise { // set default for "configFile" if undefined if (this.options.configFile === undefined || this.options.configFile === null) { - this.options.configFile = await getDefaultConfigFilePath(this.projectRoot, !this.options.args?.runProject) + this.options.configFile = await getDefaultConfigFilePath(this.projectRoot, this.ctx) } let theCfg: Cfg = await config.get(this.projectRoot, this.options) @@ -755,7 +756,7 @@ export class ProjectBase extends EE { return this._cfg } - // returns project config (user settings + defaults + cypress.json) + // returns project config (user settings + defaults + cypress.config.{ts|js}) // with additional object "state" which are transient things like // window width and height, DevTools open or not, etc. getConfig (): Cfg { @@ -859,6 +860,7 @@ export class ProjectBase extends EE { async getProjectId () { await this.verifyExistence() + const readSettings = await settings.read(this.projectRoot, this.options) if (readSettings && readSettings.projectId) { diff --git a/packages/server/lib/project_static.ts b/packages/server/lib/project_static.ts index b216451b2662..fa8bc935525b 100644 --- a/packages/server/lib/project_static.ts +++ b/packages/server/lib/project_static.ts @@ -26,7 +26,7 @@ export function paths () { export async function getPathsAndIds () { const projectRoots: string[] = await cache.getProjectRoots() - // this assumes that the configFile for a cached project is 'cypress.json' + // this assumes that the configFile for a cached project is 'cypress.config.{ts|js}' // https://git.io/JeGyF return Promise.all(projectRoots.map(async (projectRoot) => { return { @@ -137,7 +137,7 @@ export function remove (path) { export async function add (path, options) { // don't cache a project if a non-default configFile is set // https://git.io/JeGyF - if (settings.configFile(options) !== 'cypress.json') { + if (options.configFile !== undefined && settings.configFile(options) !== 'cypress.config.js' && settings.configFile(options) !== 'cypress.config.ts') { return Promise.resolve({ path }) } diff --git a/packages/server/lib/project_utils.ts b/packages/server/lib/project_utils.ts index 1b51b642e29e..8b40172dc365 100644 --- a/packages/server/lib/project_utils.ts +++ b/packages/server/lib/project_utils.ts @@ -5,7 +5,7 @@ import * as settings from './util/settings' import errors from './errors' import { fs } from './util/fs' import { escapeFilenameInUrl } from './util/escape_filename' -import { CYPRESS_CONFIG_FILES } from './configFiles' +import { makeLegacyDataContext } from './makeDataContext' const debug = Debug('cypress:server:project_utils') @@ -133,25 +133,6 @@ export const checkSupportFile = async ({ return } -export async function getDefaultConfigFilePath (projectRoot: string, returnDefaultValueIfNotFound: boolean = true): Promise { - const filesInProjectDir = await fs.readdir(projectRoot) - - const foundConfigFiles = CYPRESS_CONFIG_FILES.filter((file) => filesInProjectDir.includes(file)) - - // if we only found one default file, it is the one - if (foundConfigFiles.length === 1) { - return foundConfigFiles[0] - } - - // if we found more than one, throw a language conflict - if (foundConfigFiles.length > 1) { - throw errors.throw('CONFIG_FILES_LANGUAGE_CONFLICT', projectRoot, ...foundConfigFiles) - } - - if (returnDefaultValueIfNotFound) { - // Default is to create a new `cypress.json` file if one does not exist. - return CYPRESS_CONFIG_FILES[0] - } - - throw errors.get('NO_DEFAULT_CONFIG_FILE_FOUND', projectRoot) +export async function getDefaultConfigFilePath (projectRoot: string, ctx = makeLegacyDataContext()): Promise { + return ctx.config.getDefaultConfigBasename(projectRoot) } diff --git a/packages/server/lib/saved_state.js b/packages/server/lib/saved_state.js index abef16ff4590..bf619f2d1785 100644 --- a/packages/server/lib/saved_state.js +++ b/packages/server/lib/saved_state.js @@ -49,12 +49,24 @@ const formStatePath = (projectRoot) => { debug('missing project path, looking for project here') - const cypressJsonPath = cwd('cypress.json') + let cypressConfigPath = cwd('cypress.config.js') - return fs.pathExistsAsync(cypressJsonPath) + return fs.pathExistsAsync(cypressConfigPath) .then((found) => { if (found) { - debug('found cypress file %s', cypressJsonPath) + debug('found cypress file %s', cypressConfigPath) + projectRoot = cwd() + + return + } + + cypressConfigPath = cwd('cypress.config.ts') + + return fs.pathExistsAsync(cypressConfigPath) + }) + .then((found) => { + if (found) { + debug('found cypress file %s', cypressConfigPath) projectRoot = cwd() } diff --git a/packages/server/lib/server-base.ts b/packages/server/lib/server-base.ts index 80a0d5f5d4a3..c0ee87d15f52 100644 --- a/packages/server/lib/server-base.ts +++ b/packages/server/lib/server-base.ts @@ -241,7 +241,7 @@ export abstract class ServerBase { const { morgan, clientRoute } = config const app = express() - // set the cypress config from the cypress.json file + // set the cypress config from the cypress.config.{ts|js} file app.set('view engine', 'html') // since we use absolute paths, configure express-handlebars to not automatically find layouts diff --git a/packages/server/lib/util/settings.ts b/packages/server/lib/util/settings.ts index fcc17c276ff3..188458287560 100644 --- a/packages/server/lib/util/settings.ts +++ b/packages/server/lib/util/settings.ts @@ -5,24 +5,21 @@ import errors from '../errors' import { fs } from '../util/fs' import { requireAsync } from './require_async' import Debug from 'debug' +import type { SettingsOptions } from '@packages/types' const debug = Debug('cypress:server:settings') -interface SettingsOptions { - testingType?: 'component' |'e2e' - configFile?: string | false - args?: { - runProject?: string - } -} - -function jsCode (obj) { +function configCode (obj, isTS?: boolean) { const objJSON = obj && !_.isEmpty(obj) ? JSON.stringify(_.omit(obj, 'configFile'), null, 2) : `{ }` + if (isTS) { + return `export default ${objJSON}` + } + return `module.exports = ${objJSON} ` } @@ -103,7 +100,11 @@ function _write (file, obj = {}) { debug('writing javascript file') - return fs.writeFileAsync(file, jsCode(obj)) + const fileExtension = file?.split('.').pop() + + const isTSFile = fileExtension === 'ts' + + return fs.writeFileAsync(file, configCode(obj, isTSFile)) .return(obj) .catch((err) => { return _logWriteErr(file, err) @@ -125,14 +126,11 @@ export function isComponentTesting (options: SettingsOptions = {}) { export function configFile (options: SettingsOptions = {}) { // default is only used in tests. // This prevents a the change from becoming bigger than it should - // FIXME: remove the default - return options.configFile === false ? false : (options.configFile || 'cypress.json') + return options.configFile === false ? false : (options.configFile || 'cypress.config.js') } export function id (projectRoot, options = {}) { - const file = pathToConfigFile(projectRoot, options) - - return fs.readJson(file) + return read(projectRoot, options) .then((config) => config.projectId) .catch(() => { return null @@ -146,19 +144,13 @@ export function read (projectRoot, options: SettingsOptions = {}) { const file = pathToConfigFile(projectRoot, options) - const readPromise = /\.json$/.test(file) ? fs.readJSON(path.resolve(projectRoot, file)) : requireAsync(file, { + return requireAsync(file, { projectRoot, loadErrorCode: 'CONFIG_FILE_ERROR', }) - - return readPromise .catch((err) => { if (err.type === 'MODULE_NOT_FOUND' || err.code === 'ENOENT') { - if (options.args?.runProject) { - return Promise.reject(errors.get('CONFIG_FILE_NOT_FOUND', options.configFile, projectRoot)) - } - - return _write(file, {}) + return Promise.reject(errors.get('CONFIG_FILE_NOT_FOUND', options.configFile, projectRoot)) } return Promise.reject(err) @@ -173,7 +165,7 @@ export function read (projectRoot, options: SettingsOptions = {}) { } debug('resolved configObject', configObject) - const changed = _applyRewriteRules(configObject) + const changed: { projectId?: string, component?: {}, e2e?: {} } = _applyRewriteRules(configObject) // if our object is unchanged // then just return it @@ -181,7 +173,7 @@ export function read (projectRoot, options: SettingsOptions = {}) { return configObject } - // else write the new reduced obj + // else write the new reduced obj and store the projectId on the cache return _write(file, changed) .then((config) => { return config diff --git a/packages/server/test/integration/cypress_spec.js b/packages/server/test/integration/cypress_spec.js index 7a4d14fff8e6..53b4aa11de9c 100644 --- a/packages/server/test/integration/cypress_spec.js +++ b/packages/server/test/integration/cypress_spec.js @@ -12,7 +12,6 @@ const commitInfo = require('@cypress/commit-info') const Fixtures = require('@tooling/system-tests/lib/fixtures') const snapshot = require('snap-shot-it') const stripAnsi = require('strip-ansi') -const debug = require('debug')('test') const pkg = require('@packages/root') const detect = require('@packages/launcher/lib/detect') const launch = require('@packages/launcher/lib/browsers') @@ -116,6 +115,7 @@ describe('lib/cypress', () => { Fixtures.scaffold() this.todosPath = Fixtures.projectPath('todos') this.pristinePath = Fixtures.projectPath('pristine') + this.pristineWithConfigPath = Fixtures.projectPath('pristine-with-config-file') this.noScaffolding = Fixtures.projectPath('no-scaffolding') this.recordPath = Fixtures.projectPath('record') this.pluginConfig = Fixtures.projectPath('plugin-config') @@ -457,13 +457,13 @@ describe('lib/cypress', () => { }) it('scaffolds out integration and example specs if they do not exist when not runMode', function () { - return config.get(this.pristinePath) + return config.get(this.pristineWithConfigPath) .then((cfg) => { return fs.statAsync(cfg.integrationFolder) .then(() => { throw new Error('integrationFolder should not exist!') }).catch(() => { - return cypress.start([`--run-project=${this.pristinePath}`, '--no-run-mode']) + return cypress.start([`--run-project=${this.pristineWithConfigPath}`, '--no-run-mode']) }).then(() => { return fs.statAsync(cfg.integrationFolder) }).then(() => { @@ -488,7 +488,7 @@ describe('lib/cypress', () => { return Promise.all([ fs.statAsync(path.join(this.pristinePath, 'cypress')).reflect(), - fs.statAsync(path.join(this.pristinePath, 'cypress.json')).reflect(), + fs.statAsync(path.join(this.pristinePath, 'cypress.config.js')).reflect(), ]) .each(ensureDoesNotExist) .then(() => { @@ -496,7 +496,7 @@ describe('lib/cypress', () => { }).then(() => { return Promise.all([ fs.statAsync(path.join(this.pristinePath, 'cypress')).reflect(), - fs.statAsync(path.join(this.pristinePath, 'cypress.json')).reflect(), + fs.statAsync(path.join(this.pristinePath, 'cypress.config.js')).reflect(), ]) }).each(ensureDoesNotExist) .then(() => { @@ -505,11 +505,9 @@ describe('lib/cypress', () => { }) it('does not scaffold integration or example specs when runMode', function () { - return settings.write(this.pristinePath, {}) + return cypress.start([`--run-project=${this.pristineWithConfigPath}`]) .then(() => { - return cypress.start([`--run-project=${this.pristinePath}`]) - }).then(() => { - return fs.statAsync(path.join(this.pristinePath, 'cypress', 'integration')) + return fs.statAsync(path.join(this.pristineWithConfigPath, 'cypress', 'integration')) }).then(() => { throw new Error('integration folder should not exist!') }).catch((err) => { @@ -520,13 +518,13 @@ describe('lib/cypress', () => { }) it('scaffolds out fixtures + files if they do not exist', function () { - return config.get(this.pristinePath) + return config.get(this.pristineWithConfigPath) .then((cfg) => { return fs.statAsync(cfg.fixturesFolder) .then(() => { throw new Error('fixturesFolder should not exist!') }).catch(() => { - return cypress.start([`--run-project=${this.pristinePath}`, '--no-run-mode']) + return cypress.start([`--run-project=${this.pristineWithConfigPath}`, '--no-run-mode']) }).then(() => { return fs.statAsync(cfg.fixturesFolder) }).then(() => { @@ -536,15 +534,15 @@ describe('lib/cypress', () => { }) it('scaffolds out support + files if they do not exist', function () { - const supportFolder = path.join(this.pristinePath, 'cypress/support') + const supportFolder = path.join(this.pristineWithConfigPath, 'cypress/support') - return config.get(this.pristinePath) + return config.get(this.pristineWithConfigPath) .then(() => { return fs.statAsync(supportFolder) .then(() => { throw new Error('supportFolder should not exist!') }).catch({ code: 'ENOENT' }, () => { - return cypress.start([`--run-project=${this.pristinePath}`, '--no-run-mode']) + return cypress.start([`--run-project=${this.pristineWithConfigPath}`, '--no-run-mode']) }).then(() => { return fs.statAsync(supportFolder) }).then(() => { @@ -611,7 +609,7 @@ describe('lib/cypress', () => { }) }) - it('can change the reporter with cypress.json', function () { + it('can change the reporter with cypress.config.js', function () { sinon.spy(Reporter, 'create') return config.get(this.idsPath) @@ -767,8 +765,8 @@ describe('lib/cypress', () => { }) }) - it('logs error and exits when project has cypress.json syntax error', function () { - return fs.writeFileAsync(`${this.todosPath}/cypress.json`, '{\'foo\': \'bar}') + it('logs error and exits when project has cypress.config.js syntax error', function () { + return fs.writeFileAsync(`${this.todosPath}/cypress.config.js`, `module.exports = {`) .then(() => { return cypress.start([`--run-project=${this.todosPath}`]) }).then(() => { @@ -785,12 +783,12 @@ describe('lib/cypress', () => { }) }) - it('logs error and exits when project has invalid cypress.json values', function () { + it('logs error and exits when project has invalid cypress.config.js values', function () { return settings.write(this.todosPath, { baseUrl: 'localhost:9999' }) .then(() => { return cypress.start([`--run-project=${this.todosPath}`]) }).then(() => { - this.expectExitWithErr('SETTINGS_VALIDATION_ERROR', 'cypress.json') + this.expectExitWithErr('SETTINGS_VALIDATION_ERROR', 'cypress.config.js') }) }) @@ -839,18 +837,18 @@ describe('lib/cypress', () => { // for headed projects! // also make sure we test the rest of the integration functionality // for headed errors! <-- not unit tests, but integration tests! - it('logs error and exits when project folder has read permissions only and cannot write cypress.json', function () { + it('logs error and exits when project folder has read permissions only and cannot write cypress.config.js', function () { // test disabled if running as root (such as inside docker) - root can write all things at all times if (process.geteuid() === 0) { return } const permissionsPath = path.resolve('./permissions') - const cypressJson = path.join(permissionsPath, 'cypress.json') + const cypressConfig = path.join(permissionsPath, 'cypress.config.js') return fs.mkdirAsync(permissionsPath) .then(() => { - return fs.outputFileAsync(cypressJson, '{}') + return fs.outputFileAsync(cypressConfig, 'module.exports = {}') }).then(() => { // read only return fs.chmodAsync(permissionsPath, '555') @@ -1178,10 +1176,10 @@ describe('lib/cypress', () => { }) describe('--config-file', () => { - it('false does not require cypress.json to run', function () { - return fs.statAsync(path.join(this.pristinePath, 'cypress.json')) + it('false does not require cypress.config.js to run', function () { + return fs.statAsync(path.join(this.pristinePath, 'cypress.config.js')) .then(() => { - throw new Error('cypress.json should not exist') + throw new Error('cypress.config.js should not exist') }).catch({ code: 'ENOENT' }, () => { return cypress.start([ `--run-project=${this.pristinePath}`, @@ -1823,27 +1821,6 @@ describe('lib/cypress', () => { }) }) }) - - it('creates custom config file if it does not exist', function () { - return cypress.start([ - `--config-file=${this.filename}`, - ]) - .then(() => { - debug('cypress started with config %s', this.filename) - const options = Events.start.firstCall.args[0] - - debug('first call arguments %o', Events.start.firstCall.args) - - return Events.handleEvent(options, {}, {}, 123, 'open:project', this.pristinePath) - }).then(() => { - expect(this.open, 'open was called').to.be.called - - return fs.readJsonAsync(path.join(this.pristinePath, this.filename)) - .then((json) => { - expect(json, 'json file is empty').to.deep.equal({}) - }) - }) - }) }) }) diff --git a/packages/server/test/integration/websockets_spec.js b/packages/server/test/integration/websockets_spec.js index 51dcef5381db..774883f5533c 100644 --- a/packages/server/test/integration/websockets_spec.js +++ b/packages/server/test/integration/websockets_spec.js @@ -28,7 +28,7 @@ describe('Web Sockets', () => { this.idsPath = Fixtures.projectPath('ids') - return config.get(this.idsPath, { port: cyPort }) + return config.get(this.idsPath, { port: cyPort, configFile: 'cypress.config.js' }) .then((cfg) => { this.cfg = cfg this.ws = new ws.Server({ port: wsPort }) diff --git a/packages/server/test/unit/cache_spec.js b/packages/server/test/unit/cache_spec.js index 96d81c24e9ce..0dd80d5e1625 100644 --- a/packages/server/test/unit/cache_spec.js +++ b/packages/server/test/unit/cache_spec.js @@ -255,6 +255,7 @@ describe('lib/cache', () => { }, PROJECTS: ['foo'], PROJECT_PREFERENCES: {}, + PROJECTS_CONFIG: {}, }) }) }) diff --git a/packages/server/test/unit/config_spec.js b/packages/server/test/unit/config_spec.js index 8a712138ffd8..4dfa915fb107 100644 --- a/packages/server/test/unit/config_spec.js +++ b/packages/server/test/unit/config_spec.js @@ -101,21 +101,21 @@ describe('lib/config', () => { }) it('can override default port', function () { - return config.get(this.projectRoot, { port: 8080 }) + return config.get(this.projectRoot, { port: 8080, configFile: 'cypress.config.js' }) .then((obj) => { expect(obj.port).to.eq(8080) }) }) it('updates browserUrl', function () { - return config.get(this.projectRoot, { port: 8080 }) + return config.get(this.projectRoot, { port: 8080, configFile: 'cypress.config.js' }) .then((obj) => { expect(obj.browserUrl).to.eq('http://localhost:8080/__/') }) }) it('updates proxyUrl', function () { - return config.get(this.projectRoot, { port: 8080 }) + return config.get(this.projectRoot, { port: 8080, configFile: 'cypress.config.js' }) .then((obj) => { expect(obj.proxyUrl).to.eq('http://localhost:8080') }) @@ -144,10 +144,10 @@ describe('lib/config', () => { return this.expectValidationPasses() }) - it('validates cypress.json', function () { + it('validates cypress.config.js', function () { this.setup({ reporter: 5 }) - return this.expectValidationFails('cypress.json') + return this.expectValidationFails('cypress.config.{ts|js}') }) it('validates cypress.env.json', function () { diff --git a/packages/server/test/unit/gui/events_spec.js b/packages/server/test/unit/gui/events_spec.js index 8c4002cb14f8..e334f7629014 100644 --- a/packages/server/test/unit/gui/events_spec.js +++ b/packages/server/test/unit/gui/events_spec.js @@ -926,7 +926,7 @@ describe('lib/gui/events', () => { describe('set:project:id', () => { it('calls writeProjectId with projectRoot', function () { - const arg = { id: '1', projectRoot: '/project/root/', configFile: 'cypress.json' } + const arg = { id: '1', projectRoot: '/project/root/', configFile: 'cypress.config.js' } const stubWriteProjectId = sinon.stub(ProjectStatic, 'writeProjectId').resolves() return this.handleEvent('set:project:id', arg) @@ -940,7 +940,7 @@ describe('lib/gui/events', () => { describe('setup:dashboard:project', () => { it('returns result of ProjectStatic.createCiProject', function () { - const arg = { projectRoot: '/project/root/', configFile: 'cypress.json' } + const arg = { projectRoot: '/project/root/', configFile: 'cypress.config.js' } const stubCreateCiProject = sinon.stub(ProjectStatic, 'createCiProject').resolves() return this.handleEvent('setup:dashboard:project', arg) diff --git a/packages/server/test/unit/plugins/index_spec.js b/packages/server/test/unit/plugins/index_spec.js index e76df148fb9f..6d5099326389 100644 --- a/packages/server/test/unit/plugins/index_spec.js +++ b/packages/server/test/unit/plugins/index_spec.js @@ -20,7 +20,7 @@ describe('lib/plugins/index', () => { configExtras = { projectRoot: '/path/to/project/root', - configFile: '/path/to/project/root/cypress.json', + configFile: '/path/to/project/root/cypress.config.js', } getOptions = (overrides = {}) => { diff --git a/packages/server/test/unit/project_spec.js b/packages/server/test/unit/project_spec.js index 2387cd11115e..39ce06fba903 100644 --- a/packages/server/test/unit/project_spec.js +++ b/packages/server/test/unit/project_spec.js @@ -43,7 +43,7 @@ describe('lib/project-base', () => { this.todosPath = Fixtures.projectPath('todos') this.idsPath = Fixtures.projectPath('ids') - this.pristinePath = Fixtures.projectPath('pristine') + this.pristinePath = Fixtures.projectPath('pristine-with-config-file') sinon.stub(scaffold, 'isNewProject').resolves(false) sinon.stub(chokidar, 'watch').returns({ @@ -149,7 +149,7 @@ describe('lib/project-base', () => { const integrationFolder = 'foo/bar/baz' beforeEach(function () { - sinon.stub(config, 'get').withArgs(this.todosPath, { foo: 'bar', configFile: 'cypress.json' }) + sinon.stub(config, 'get').withArgs(this.todosPath, { foo: 'bar', configFile: 'cypress.config.js' }) .resolves({ baz: 'quux', integrationFolder, browsers: [] }) }) @@ -345,7 +345,7 @@ This option will not have an effect in Some-other-name. Tests that rely on web s it('calls checkSupportFile with server config when scaffolding is finished', function () { return this.project.open().then(() => { expect(this.checkSupportFileStub).to.be.calledWith({ - configFile: 'cypress.json', + configFile: 'cypress.config.js', supportFile: '/foo/bar/cypress/support/index.js', }) }) @@ -383,9 +383,9 @@ This option will not have an effect in Some-other-name. Tests that rely on web s }) // TODO: skip this for now - it.skip('watches cypress.json', function () { + it.skip('watches cypress.config.js', function () { return this.server.open().bind(this).then(() => { - expect(Watchers.prototype.watch).to.be.calledWith('/Users/brian/app/cypress.json') + expect(Watchers.prototype.watch).to.be.calledWith('/Users/brian/app/cypress.config.js') }) }) @@ -713,17 +713,17 @@ This option will not have an effect in Some-other-name. Tests that rely on web s beforeEach(function () { this.project = new ProjectBase({ projectRoot: '/_test-output/path/to/project-e2e', testingType: 'e2e' }) this.project._server = { close () {}, startWebsockets () {} } - sinon.stub(settings, 'pathToConfigFile').returns('/path/to/cypress.json') + sinon.stub(settings, 'pathToConfigFile').returns('/path/to/cypress.config.js') sinon.stub(settings, 'pathToCypressEnvJson').returns('/path/to/cypress.env.json') this.watch = sinon.stub(this.project.watchers, 'watch') this.watchTree = sinon.stub(this.project.watchers, 'watchTree') }) - it('watches cypress.json and cypress.env.json', function () { + it('watches cypress.config.js and cypress.env.json', function () { this.project.watchSettings({ onSettingsChanged () {} }, {}) expect(this.watch).to.be.calledOnce expect(this.watchTree).to.be.calledOnce - expect(this.watchTree).to.be.calledWith('/path/to/cypress.json') + expect(this.watchTree).to.be.calledWith('/path/to/cypress.config.js') expect(this.watch).to.be.calledWith('/path/to/cypress.env.json') }) @@ -964,7 +964,7 @@ This option will not have an effect in Some-other-name. Tests that rely on web s context('.add', () => { beforeEach(function () { - this.pristinePath = Fixtures.projectPath('pristine') + this.pristinePath = Fixtures.projectPath('pristine-with-config-file') }) it('inserts path into cache', function () { diff --git a/packages/server/test/unit/project_utils_spec.ts b/packages/server/test/unit/project_utils_spec.ts index c8c1acedd5a7..dd22774515b3 100644 --- a/packages/server/test/unit/project_utils_spec.ts +++ b/packages/server/test/unit/project_utils_spec.ts @@ -101,7 +101,7 @@ describe('lib/project_utils', () => { describe('checkSupportFile', () => { it('does nothing when {supportFile: false}', async () => { const ret = await checkSupportFile({ - configFile: 'cypress.json', + configFile: 'cypress.config.ts', supportFile: false, }) @@ -111,7 +111,7 @@ describe('lib/project_utils', () => { it('throws when support file does not exist', async () => { try { await checkSupportFile({ - configFile: 'cypress.json', + configFile: 'cypress.config.ts', supportFile: '/this/file/does/not/exist/foo/bar/cypress/support/index.js', }) } catch (e) { @@ -132,11 +132,11 @@ describe('lib/project_utils', () => { readdirStub.restore() }) - it('finds cypress.json when present', async () => { - readdirStub.withArgs(projectRoot).resolves(['cypress.json']) + it('finds cypress.config.ts when present', async () => { + readdirStub.withArgs(projectRoot).resolves(['cypress.config.ts']) const ret = await getDefaultConfigFilePath(projectRoot) - expect(ret).to.equal('cypress.json') + expect(ret).to.equal('cypress.config.ts') }) it('defaults to cypress.config.js when present', async () => { @@ -146,15 +146,8 @@ describe('lib/project_utils', () => { expect(ret).to.equal('cypress.config.js') }) - it('defaults to cypress.json when no file is returned', async () => { - readdirStub.withArgs(projectRoot).resolves([]) - const ret = await getDefaultConfigFilePath(projectRoot) - - expect(ret).to.equal('cypress.json') - }) - it('errors if two default files are present', async () => { - readdirStub.withArgs(projectRoot).resolves(['cypress.config.js', 'cypress.json']) + readdirStub.withArgs(projectRoot).resolves(['cypress.config.js', 'cypress.config.ts']) try { await getDefaultConfigFilePath(projectRoot) throw Error('should have failed') @@ -166,7 +159,7 @@ describe('lib/project_utils', () => { it('errors if no file is present and we asked not to create any', async () => { readdirStub.withArgs(projectRoot).resolves([]) try { - await getDefaultConfigFilePath(projectRoot, false) + await getDefaultConfigFilePath(projectRoot) throw Error('should have failed') } catch (err) { expect(err).to.have.property('type', 'NO_DEFAULT_CONFIG_FILE_FOUND') diff --git a/packages/server/test/unit/scaffold_spec.js b/packages/server/test/unit/scaffold_spec.js index 8001b3f3ca59..2a6a8d00dd4a 100644 --- a/packages/server/test/unit/scaffold_spec.js +++ b/packages/server/test/unit/scaffold_spec.js @@ -22,7 +22,7 @@ describe('lib/scaffold', () => { context('.isNewProject', () => { beforeEach(function () { - this.pristinePath = Fixtures.projectPath('pristine') + this.pristinePath = Fixtures.projectPath('pristine-with-config-file') }) it('is true when integrationFolder is empty', function () { @@ -129,7 +129,7 @@ describe('lib/scaffold', () => { context('.integration', () => { beforeEach(function () { - const pristinePath = Fixtures.projectPath('pristine') + const pristinePath = Fixtures.projectPath('pristine-with-config-file') return config.get(pristinePath).then((cfg) => { this.cfg = cfg; @@ -212,7 +212,7 @@ describe('lib/scaffold', () => { context('.removeIntegration', () => { beforeEach(function () { - const pristinePath = Fixtures.projectPath('pristine') + const pristinePath = Fixtures.projectPath('pristine-with-config-file') return config.get(pristinePath).then((cfg) => { this.cfg = cfg; @@ -323,7 +323,7 @@ describe('lib/scaffold', () => { context('.support', () => { beforeEach(function () { - const pristinePath = Fixtures.projectPath('pristine') + const pristinePath = Fixtures.projectPath('pristine-with-config-file') return config.get(pristinePath).then((cfg) => { this.cfg = cfg; @@ -400,7 +400,7 @@ describe('lib/scaffold', () => { context('.plugins', () => { beforeEach(function () { - const pristinePath = Fixtures.projectPath('pristine') + const pristinePath = Fixtures.projectPath('pristine-with-config-file') return config.get(pristinePath).then((cfg) => { this.cfg = cfg; @@ -456,7 +456,7 @@ describe('lib/scaffold', () => { context('.fixture', () => { beforeEach(function () { - const pristinePath = Fixtures.projectPath('pristine') + const pristinePath = Fixtures.projectPath('pristine-with-config-file') return config.get(pristinePath).then((cfg) => { this.cfg = cfg; diff --git a/packages/server/test/unit/util/settings_spec.js b/packages/server/test/unit/util/settings_spec.js index a7c4f2c2aaeb..06b490214990 100644 --- a/packages/server/test/unit/util/settings_spec.js +++ b/packages/server/test/unit/util/settings_spec.js @@ -6,19 +6,19 @@ const settings = require(`../../../lib/util/settings`) const projectRoot = process.cwd() const defaultOptions = { - configFile: 'cypress.json', + configFile: 'cypress.config.js', } describe('lib/util/settings', () => { context('with default configFile option', () => { beforeEach(function () { this.setup = (obj = {}) => { - return fs.writeJsonAsync('cypress.json', obj) + return fs.writeFileAsync('cypress.config.js', `module.exports = ${JSON.stringify(obj)}`) } }) afterEach(() => { - return fs.removeAsync('cypress.json') + return fs.removeAsync('cypress.config.js') }) context('nested cypress object', () => { @@ -29,7 +29,7 @@ describe('lib/util/settings', () => { }).then((obj) => { expect(obj).to.deep.eq({ foo: 'bar' }) - return fs.readJsonAsync('cypress.json') + return require(path.join(projectRoot, 'cypress.config.js')) }).then((obj) => { expect(obj).to.deep.eq({ foo: 'bar' }) }) @@ -84,13 +84,13 @@ describe('lib/util/settings', () => { }) afterEach(function () { - return fs.removeAsync(`${this.projectRoot}cypress.json`) + return fs.removeAsync(`${this.projectRoot}cypress.config.js`) }) it('returns project id for project', function () { - return fs.writeJsonAsync(`${this.projectRoot}cypress.json`, { + return fs.writeFileAsync(`${this.projectRoot}cypress.config.js`, `module.exports = { projectId: 'id-123', - }) + }`) .then(() => { return settings.id(this.projectRoot, defaultOptions) }).then((id) => { @@ -100,7 +100,7 @@ describe('lib/util/settings', () => { }) context('.read', () => { - it('promises cypress.json', function () { + it('promises cypress.config.js', function () { return this.setup({ foo: 'bar' }) .then(() => { return settings.read(projectRoot, defaultOptions) @@ -109,7 +109,7 @@ describe('lib/util/settings', () => { }) }) - it('promises cypress.json and merges CT specific properties for via testingType: component', function () { + it('promises cypress.config.js and merges CT specific properties for via testingType: component', function () { return this.setup({ a: 'b', component: { a: 'c' } }) .then(() => { return settings.read(projectRoot, { ...defaultOptions, testingType: 'component' }) @@ -118,7 +118,7 @@ describe('lib/util/settings', () => { }) }) - it('promises cypress.json and merges e2e specific properties', function () { + it('promises cypress.config.js and merges e2e specific properties', function () { return this.setup({ a: 'b', e2e: { a: 'c' } }) .then(() => { return settings.read(projectRoot, defaultOptions) @@ -170,7 +170,7 @@ describe('lib/util/settings', () => { }).catch((err) => { expect(err.type).to.equal('CONFIG_FILE_NOT_FOUND') - return fs.access(path.join(projectRoot, 'cypress.json')) + return fs.access(path.join(projectRoot, 'cypress.config.js')) .then(() => { throw Error('file should not have been created here') }).catch((err) => { @@ -181,7 +181,7 @@ describe('lib/util/settings', () => { }) context('.write', () => { - it('promises cypress.json updates', function () { + it('promises cypress.config.js updates', function () { return this.setup().then(() => { return settings.write(projectRoot, { foo: 'bar' }, defaultOptions) }).then((obj) => { @@ -212,7 +212,7 @@ describe('lib/util/settings', () => { it('.write does not create a file', function () { return settings.write(this.projectRoot, {}, this.options) .then(() => { - return fs.access(path.join(this.projectRoot, 'cypress.json')) + return fs.access(path.join(this.projectRoot, 'cypress.config.js')) .then(() => { throw Error('file shuold not have been created here') }).catch((err) => { diff --git a/packages/types/src/config.ts b/packages/types/src/config.ts index ab71a73b5d1c..f069098e2bd4 100644 --- a/packages/types/src/config.ts +++ b/packages/types/src/config.ts @@ -30,3 +30,11 @@ export interface SampleConfigFile{ warningText?: string warningLink?: string } + +export interface SettingsOptions { + testingType?: 'component' |'e2e' + configFile?: string | false + args?: { + runProject?: string + } +} diff --git a/packages/types/src/server.ts b/packages/types/src/server.ts index 92d7a98a5e2b..d33621ec58c9 100644 --- a/packages/types/src/server.ts +++ b/packages/types/src/server.ts @@ -67,7 +67,7 @@ export interface OpenProjectLaunchOptions { configFile?: string | false browsers?: Cypress.Browser[] - // Callback to reload the Desktop GUI when cypress.json is changed. + // Callback to reload the Desktop GUI when cypress.config.{ts|js} is changed. onSettingsChanged?: false | (() => void) // Optional callbacks used for triggering events via the web socket diff --git a/packages/ui-components/cypress.config.js b/packages/ui-components/cypress.config.js new file mode 100644 index 000000000000..64f641119e33 --- /dev/null +++ b/packages/ui-components/cypress.config.js @@ -0,0 +1,12 @@ +module.exports = { + 'fixturesFolder': false, + 'projectId': 'ypt4pf', + 'reporter': '../../node_modules/cypress-multi-reporters/index.js', + 'reporterOptions': { + 'configFile': '../../mocha-reporter-config.json', + }, + 'retries': { + 'runMode': 2, + 'openMode': 0, + }, +} diff --git a/packages/ui-components/cypress.json b/packages/ui-components/cypress.json deleted file mode 100644 index 88a0a5a24700..000000000000 --- a/packages/ui-components/cypress.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "fixturesFolder": false, - "projectId": "ypt4pf", - "reporter": "../../node_modules/cypress-multi-reporters/index.js", - "reporterOptions": { - "configFile": "../../mocha-reporter-config.json" - }, - "retries": { - "runMode": 2, - "openMode": 0 - } -} diff --git a/system-tests/__snapshots__/config_spec.js b/system-tests/__snapshots__/config_spec.js index 7b09652976ff..59b4710799e6 100644 --- a/system-tests/__snapshots__/config_spec.js +++ b/system-tests/__snapshots__/config_spec.js @@ -140,14 +140,14 @@ exports['e2e config applies defaultCommandTimeout globally 1'] = ` ` exports['e2e config throws error when invalid viewportWidth in the configuration file 1'] = ` -We found an invalid value in the file: \`cypress.json\` +We found an invalid value in the file: \`cypress.config.js\` Expected \`viewportWidth\` to be a number. Instead the value was: \`"foo"\` ` exports['e2e config throws error when invalid browser in the configuration file 1'] = ` -We found an invalid value in the file: \`cypress.json\` +We found an invalid value in the file: \`cypress.config.js\` Found an error while validating the \`browsers\` list. Expected \`family\` to be either chromium or firefox. Instead the value was: \`{"name":"bad browser","family":"unknown family","displayName":"Bad browser","version":"no version","path":"/path/to","majorVersion":123}\` @@ -155,9 +155,27 @@ Found an error while validating the \`browsers\` list. Expected \`family\` to be exports['e2e config throws error when multiple default config file are found in project 1'] = ` There is both a \`cypress.config.js\` and a \`cypress.config.ts\` at the location below: -/foo/bar/.projects/pristine +/foo/bar/.projects/pristine-with-config-file Cypress does not know which one to read for config. Please remove one of the two and try again. +` + +exports['e2e config throws error when cypress.json is found in project and need migration 1'] = ` +There is a cypress.json file at the location below: +/foo/bar/.projects/pristine + +Cypress no longer supports 'cypress.json', please migrate to 'cypress.config.{ts|js}'. + + +` + +exports['e2e config throws error when cypress.json is found in project and cypress.config.{ts|js} exists as well 1'] = ` +There is both a \`cypress.config.js\` and a cypress.json file at the location below: +/foo/bar/.projects/multiples-config-files-with-json + +Cypress no longer supports 'cypress.json' config, please remove it from your project. + + ` diff --git a/system-tests/__snapshots__/record_spec.js b/system-tests/__snapshots__/record_spec.js index 1ecb387ff6e8..f20e2330745d 100644 --- a/system-tests/__snapshots__/record_spec.js +++ b/system-tests/__snapshots__/record_spec.js @@ -259,7 +259,7 @@ We dynamically generated a new test to display this failure. exports['e2e record api interaction errors project 404 errors and exits 1'] = ` We could not find a project with the ID: pid123 -This projectId came from your 'cypress.json' file or an environment variable. +This projectId came from your 'cypress.config.js' file or an environment variable. Please log into the Dashboard and find your project. @@ -369,7 +369,7 @@ https://on.cypress.io/how-do-i-record-runs exports['e2e record projectId errors and exits without projectId 1'] = ` You passed the --record flag but this project has not been setup to record. -This project is missing the 'projectId' inside of 'cypress.json'. +This project is missing the 'projectId' inside of 'cypress.config.js'. We cannot uniquely identify this project without this id. diff --git a/system-tests/__snapshots__/visit_spec.js b/system-tests/__snapshots__/visit_spec.js index 948ebf2aaa8d..879e7ef4b031 100644 --- a/system-tests/__snapshots__/visit_spec.js +++ b/system-tests/__snapshots__/visit_spec.js @@ -473,7 +473,7 @@ exports['e2e visit / normal response timeouts / fails when visit times out'] = ` Your page did not fire its \`load\` event within \`1000ms\`. -You can try increasing the \`pageLoadTimeout\` value in \`cypress.json\` to wait longer. +You can try increasing the \`pageLoadTimeout\` value in \`cypress.config.js\` to wait longer. Browsers will not fire the \`load\` event until all stylesheets and scripts are done downloading. @@ -486,7 +486,7 @@ When this \`load\` event occurs, Cypress will continue running commands. Your page did not fire its \`load\` event within \`500ms\`. -You can try increasing the \`pageLoadTimeout\` value in \`cypress.json\` to wait longer. +You can try increasing the \`pageLoadTimeout\` value in \`cypress.config.js\` to wait longer. Browsers will not fire the \`load\` event until all stylesheets and scripts are done downloading. diff --git a/system-tests/__snapshots__/web_security_spec.js b/system-tests/__snapshots__/web_security_spec.js index 8ab2521a70ed..9832c07ced6a 100644 --- a/system-tests/__snapshots__/web_security_spec.js +++ b/system-tests/__snapshots__/web_security_spec.js @@ -45,7 +45,7 @@ Cypress does not allow you to navigate to a different origin URL within a single You may need to restructure some of your test code to avoid this problem. -Alternatively you can also disable Chrome Web Security in Chromium-based browsers which will turn off this restriction by setting { chromeWebSecurity: false } in \`cypress.json\`. +Alternatively you can also disable Chrome Web Security in Chromium-based browsers which will turn off this restriction by setting { chromeWebSecurity: false } in \`cypress.config.js\`. https://on.cypress.io/cross-origin-violation [stack trace lines] @@ -68,7 +68,7 @@ Cypress does not allow you to navigate to a different origin URL within a single You may need to restructure some of your test code to avoid this problem. -Alternatively you can also disable Chrome Web Security in Chromium-based browsers which will turn off this restriction by setting { chromeWebSecurity: false } in \`cypress.json\`. +Alternatively you can also disable Chrome Web Security in Chromium-based browsers which will turn off this restriction by setting { chromeWebSecurity: false } in \`cypress.config.js\`. https://on.cypress.io/cross-origin-violation [stack trace lines] @@ -91,7 +91,7 @@ Cypress does not allow you to navigate to a different origin URL within a single You may need to restructure some of your test code to avoid this problem. -Alternatively you can also disable Chrome Web Security in Chromium-based browsers which will turn off this restriction by setting { chromeWebSecurity: false } in \`cypress.json\`. +Alternatively you can also disable Chrome Web Security in Chromium-based browsers which will turn off this restriction by setting { chromeWebSecurity: false } in \`cypress.config.js\`. https://on.cypress.io/cross-origin-violation [stack trace lines] diff --git a/system-tests/lib/fixtures.js b/system-tests/lib/fixtures.js index e92233577d5c..d3e1e0f19b23 100644 --- a/system-tests/lib/fixtures.js +++ b/system-tests/lib/fixtures.js @@ -32,6 +32,10 @@ module.exports = { const from = path.join(projects, project) const to = path.join(tmpDir, project) + if (fs.existsSync(to)) { + fs.removeSync(to) + } + fs.copySync(from, to) }, diff --git a/system-tests/lib/support/helpers/electron_stub.js b/system-tests/lib/support/helpers/electron_stub.js new file mode 100644 index 000000000000..40a4a7394d41 --- /dev/null +++ b/system-tests/lib/support/helpers/electron_stub.js @@ -0,0 +1,51 @@ +// a stubbed out version of electron +// for using in all of our tests :-) +module.exports = { + shell: {}, + dialog: {}, + ipcMain: { + on () {}, + removeAllListeners () {}, + }, + nativeImage: { + createFromPath () { + return {} + }, + }, + app: { + on () {}, + exit () {}, + commandLine: { + appendSwitch () {}, + appendArgument () {}, + }, + disableHardwareAcceleration () {}, + async whenReady () {}, + dock: { + show () {}, + hide () {}, + }, + }, + systemPreferences: { + isDarkMode () {}, + subscribeNotification () {}, + }, + BrowserWindow: { + fromWebContents () {}, + getExtensions () {}, + removeExtension () {}, + addExtension () {}, + }, + Menu: { + buildFromTemplate () {}, + setApplicationMenu () {}, + }, + Tray () { + return { + on () {}, + setToolTip () {}, + setImage () {}, + setPressedImage () {}, + } + }, +} diff --git a/system-tests/projects/browser-extensions/cypress.config.js b/system-tests/projects/browser-extensions/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/browser-extensions/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/browser-extensions/cypress.json b/system-tests/projects/browser-extensions/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/browser-extensions/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/busted-support-file/cypress.config.js b/system-tests/projects/busted-support-file/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/busted-support-file/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/busted-support-file/cypress.json b/system-tests/projects/busted-support-file/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/busted-support-file/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/chrome-browser-preferences/cypress.config.js b/system-tests/projects/chrome-browser-preferences/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/chrome-browser-preferences/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/chrome-browser-preferences/cypress.json b/system-tests/projects/chrome-browser-preferences/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/chrome-browser-preferences/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/component-tests/cypress.config.js b/system-tests/projects/component-tests/cypress.config.js new file mode 100644 index 000000000000..0c7254d8b2f0 --- /dev/null +++ b/system-tests/projects/component-tests/cypress.config.js @@ -0,0 +1,4 @@ +module.exports = { + 'projectId': 'abc123', + 'componentFolder': 'cypress/component-tests', +} diff --git a/system-tests/projects/component-tests/cypress.json b/system-tests/projects/component-tests/cypress.json deleted file mode 100644 index b3bc0babdd85..000000000000 --- a/system-tests/projects/component-tests/cypress.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "projectId": "abc123", - "componentFolder": "cypress/component-tests" -} \ No newline at end of file diff --git a/system-tests/projects/config-with-invalid-browser/cypress.config.js b/system-tests/projects/config-with-invalid-browser/cypress.config.js new file mode 100644 index 000000000000..2277b0787ed5 --- /dev/null +++ b/system-tests/projects/config-with-invalid-browser/cypress.config.js @@ -0,0 +1,12 @@ +module.exports = { + 'browsers': [ + { + 'name': 'bad browser', + 'family': 'unknown family', + 'displayName': 'Bad browser', + 'version': 'no version', + 'path': '/path/to', + 'majorVersion': 123, + }, + ], +} diff --git a/system-tests/projects/config-with-invalid-browser/cypress.json b/system-tests/projects/config-with-invalid-browser/cypress.json deleted file mode 100644 index 71c2cfbbf0ad..000000000000 --- a/system-tests/projects/config-with-invalid-browser/cypress.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "browsers": [ - { - "name": "bad browser", - "family": "unknown family", - "displayName": "Bad browser", - "version": "no version", - "path": "/path/to", - "majorVersion": 123 - } - ] -} diff --git a/system-tests/projects/config-with-invalid-viewport/cypress.config.js b/system-tests/projects/config-with-invalid-viewport/cypress.config.js new file mode 100644 index 000000000000..cda4d27347e5 --- /dev/null +++ b/system-tests/projects/config-with-invalid-viewport/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'viewportWidth': 'foo', +} diff --git a/system-tests/projects/config-with-invalid-viewport/cypress.json b/system-tests/projects/config-with-invalid-viewport/cypress.json deleted file mode 100644 index 3e411ccd676a..000000000000 --- a/system-tests/projects/config-with-invalid-viewport/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "viewportWidth": "foo" -} diff --git a/system-tests/projects/config-with-short-timeout/cypress.config.js b/system-tests/projects/config-with-short-timeout/cypress.config.js new file mode 100644 index 000000000000..dfb84e7cd15e --- /dev/null +++ b/system-tests/projects/config-with-short-timeout/cypress.config.js @@ -0,0 +1,5 @@ +module.exports = { + 'defaultCommandTimeout': 1000, + 'pluginsFile': false, + 'supportFile': false, +} diff --git a/system-tests/projects/config-with-short-timeout/cypress.json b/system-tests/projects/config-with-short-timeout/cypress.json deleted file mode 100644 index 9dd38efd5217..000000000000 --- a/system-tests/projects/config-with-short-timeout/cypress.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "defaultCommandTimeout": 1000, - "pluginsFile": false, - "supportFile": false -} diff --git a/system-tests/projects/cookies/cypress.config.js b/system-tests/projects/cookies/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/cookies/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/cookies/cypress.json b/system-tests/projects/cookies/cypress.json deleted file mode 100644 index 9e26dfeeb6e6..000000000000 --- a/system-tests/projects/cookies/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/system-tests/projects/default-layout/cypress.config.js b/system-tests/projects/default-layout/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/default-layout/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/default-layout/cypress.json b/system-tests/projects/default-layout/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/default-layout/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/downloads/cypress.config.js b/system-tests/projects/downloads/cypress.config.js new file mode 100644 index 000000000000..3a77c847f08c --- /dev/null +++ b/system-tests/projects/downloads/cypress.config.js @@ -0,0 +1,5 @@ +module.exports = { + 'fixturesFolder': false, + 'pluginsFile': false, + 'supportFile': false, +} diff --git a/system-tests/projects/downloads/cypress.json b/system-tests/projects/downloads/cypress.json deleted file mode 100644 index e81c35571a05..000000000000 --- a/system-tests/projects/downloads/cypress.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "fixturesFolder": false, - "pluginsFile": false, - "supportFile": false -} diff --git a/system-tests/projects/e2e/cypress.config.js b/system-tests/projects/e2e/cypress.config.js new file mode 100644 index 000000000000..877daa2db3e4 --- /dev/null +++ b/system-tests/projects/e2e/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'retries': null, +} diff --git a/system-tests/projects/e2e/cypress.json b/system-tests/projects/e2e/cypress.json deleted file mode 100644 index 0f77b44749ce..000000000000 --- a/system-tests/projects/e2e/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "retries": null -} diff --git a/system-tests/projects/empty-folders/cypress.config.js b/system-tests/projects/empty-folders/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/empty-folders/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/empty-folders/cypress.json b/system-tests/projects/empty-folders/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/empty-folders/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/failures/cypress/cypress.config.js b/system-tests/projects/failures/cypress/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/failures/cypress/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/failures/cypress/cypress.json b/system-tests/projects/failures/cypress/cypress.json deleted file mode 100644 index 9e26dfeeb6e6..000000000000 --- a/system-tests/projects/failures/cypress/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/system-tests/projects/firefox-memory/cypress.config.js b/system-tests/projects/firefox-memory/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/firefox-memory/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/firefox-memory/cypress.json b/system-tests/projects/firefox-memory/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/firefox-memory/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/fixture-subfolder-of-integration/cypress.config.js b/system-tests/projects/fixture-subfolder-of-integration/cypress.config.js new file mode 100644 index 000000000000..5c5433c400de --- /dev/null +++ b/system-tests/projects/fixture-subfolder-of-integration/cypress.config.js @@ -0,0 +1,7 @@ +module.exports = { + 'pluginsFile': false, + 'supportFile': false, + 'integrationFolder': 'test', + 'fixturesFolder': 'test/fixtures', + 'testFiles': '**/*spec.js', +} diff --git a/system-tests/projects/fixture-subfolder-of-integration/cypress.json b/system-tests/projects/fixture-subfolder-of-integration/cypress.json deleted file mode 100644 index d324ec085e59..000000000000 --- a/system-tests/projects/fixture-subfolder-of-integration/cypress.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "pluginsFile": false, - "supportFile": false, - "integrationFolder": "test", - "fixturesFolder": "test/fixtures", - "testFiles": "**/*spec.js" -} diff --git a/system-tests/projects/folder-same-as-fixture/cypress.config.js b/system-tests/projects/folder-same-as-fixture/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/folder-same-as-fixture/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/folder-same-as-fixture/cypress.json b/system-tests/projects/folder-same-as-fixture/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/folder-same-as-fixture/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/hooks-after-rerun/cypress.config.js b/system-tests/projects/hooks-after-rerun/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/hooks-after-rerun/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/hooks-after-rerun/cypress.json b/system-tests/projects/hooks-after-rerun/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/hooks-after-rerun/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/ids/cypress.config.js b/system-tests/projects/ids/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/ids/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/ids/cypress.json b/system-tests/projects/ids/cypress.json deleted file mode 100644 index 9e26dfeeb6e6..000000000000 --- a/system-tests/projects/ids/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/system-tests/projects/integration-outside-project-root/project-root/cypress.config.js b/system-tests/projects/integration-outside-project-root/project-root/cypress.config.js new file mode 100644 index 000000000000..0f2dc30b98f3 --- /dev/null +++ b/system-tests/projects/integration-outside-project-root/project-root/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'integrationFolder': '../integration', +} diff --git a/system-tests/projects/integration-outside-project-root/project-root/cypress.json b/system-tests/projects/integration-outside-project-root/project-root/cypress.json deleted file mode 100644 index a3f0bee68816..000000000000 --- a/system-tests/projects/integration-outside-project-root/project-root/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "integrationFolder": "../integration" -} diff --git a/system-tests/projects/issue-8111-iframe-input/cypress.config.js b/system-tests/projects/issue-8111-iframe-input/cypress.config.js new file mode 100644 index 000000000000..85067c9cc962 --- /dev/null +++ b/system-tests/projects/issue-8111-iframe-input/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'supportFolder': false, +} diff --git a/system-tests/projects/issue-8111-iframe-input/cypress.json b/system-tests/projects/issue-8111-iframe-input/cypress.json deleted file mode 100644 index 9c5417cd8268..000000000000 --- a/system-tests/projects/issue-8111-iframe-input/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "supportFolder": false -} diff --git a/system-tests/projects/max-listeners/cypress.config.js b/system-tests/projects/max-listeners/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/max-listeners/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/max-listeners/cypress.json b/system-tests/projects/max-listeners/cypress.json deleted file mode 100644 index 9e26dfeeb6e6..000000000000 --- a/system-tests/projects/max-listeners/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/system-tests/projects/multiple-task-registrations/cypress.config.js b/system-tests/projects/multiple-task-registrations/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/multiple-task-registrations/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/multiple-task-registrations/cypress.json b/system-tests/projects/multiple-task-registrations/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/multiple-task-registrations/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/multiples-config-files-with-json/cypress.config.js b/system-tests/projects/multiples-config-files-with-json/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/multiples-config-files-with-json/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/multiples-config-files-with-json/cypress.json b/system-tests/projects/multiples-config-files-with-json/cypress.json new file mode 100644 index 000000000000..8ad5c80f7eab --- /dev/null +++ b/system-tests/projects/multiples-config-files-with-json/cypress.json @@ -0,0 +1,7 @@ +{ + "pageLoadTimeout": 10000, + "e2e": { + "defaultCommandTimeout": 500, + "videoCompression": 20 + } +} \ No newline at end of file diff --git a/system-tests/projects/no-scaffolding/cypress.config.js b/system-tests/projects/no-scaffolding/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/no-scaffolding/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/no-scaffolding/cypress.json b/system-tests/projects/no-scaffolding/cypress.json deleted file mode 100644 index 9e26dfeeb6e6..000000000000 --- a/system-tests/projects/no-scaffolding/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/system-tests/projects/no-server/cypress.config.js b/system-tests/projects/no-server/cypress.config.js new file mode 100644 index 000000000000..8e9b800a298b --- /dev/null +++ b/system-tests/projects/no-server/cypress.config.js @@ -0,0 +1,6 @@ +module.exports = { + 'cypress': { + 'integrationFolder': 'my-tests', + 'fileServerFolder': 'dev', + }, +} diff --git a/system-tests/projects/no-server/cypress.json b/system-tests/projects/no-server/cypress.json deleted file mode 100644 index a2f26c3597d9..000000000000 --- a/system-tests/projects/no-server/cypress.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "cypress": { - "integrationFolder": "my-tests", - "fileServerFolder": "dev" - } -} \ No newline at end of file diff --git a/system-tests/projects/non-existent-spec/cypress.config.js b/system-tests/projects/non-existent-spec/cypress.config.js new file mode 100644 index 000000000000..f0064695754a --- /dev/null +++ b/system-tests/projects/non-existent-spec/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'supportFile': false, +} diff --git a/system-tests/projects/non-existent-spec/cypress.json b/system-tests/projects/non-existent-spec/cypress.json deleted file mode 100644 index 0c2bdde8665b..000000000000 --- a/system-tests/projects/non-existent-spec/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "supportFile": false -} diff --git a/system-tests/projects/non-proxied/cypress.config.js b/system-tests/projects/non-proxied/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/non-proxied/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/non-proxied/cypress.json b/system-tests/projects/non-proxied/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/non-proxied/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/odd-directory-name/cypress.config.js b/system-tests/projects/odd-directory-name/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/odd-directory-name/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-after-screenshot/cypress.config.js b/system-tests/projects/plugin-after-screenshot/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugin-after-screenshot/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-after-screenshot/cypress.json b/system-tests/projects/plugin-after-screenshot/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugin-after-screenshot/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugin-after-spec-deletes-video/cypress.config.js b/system-tests/projects/plugin-after-spec-deletes-video/cypress.config.js new file mode 100644 index 000000000000..4f64c2459252 --- /dev/null +++ b/system-tests/projects/plugin-after-spec-deletes-video/cypress.config.js @@ -0,0 +1,4 @@ +module.exports = { + 'fixturesFolder': false, + 'supportFile': false, +} diff --git a/system-tests/projects/plugin-after-spec-deletes-video/cypress.json b/system-tests/projects/plugin-after-spec-deletes-video/cypress.json deleted file mode 100644 index a84f6e38c9e9..000000000000 --- a/system-tests/projects/plugin-after-spec-deletes-video/cypress.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "fixturesFolder": false, - "supportFile": false -} diff --git a/system-tests/projects/plugin-before-browser-launch-deprecation/cypress.config.js b/system-tests/projects/plugin-before-browser-launch-deprecation/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugin-before-browser-launch-deprecation/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-before-browser-launch-deprecation/cypress.json b/system-tests/projects/plugin-before-browser-launch-deprecation/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugin-before-browser-launch-deprecation/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugin-browser/cypress.config.js b/system-tests/projects/plugin-browser/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugin-browser/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-browser/cypress.json b/system-tests/projects/plugin-browser/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugin-browser/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugin-config-version/cypress.config.js b/system-tests/projects/plugin-config-version/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugin-config-version/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-config-version/cypress.json b/system-tests/projects/plugin-config-version/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugin-config-version/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugin-config/cypress.config.js b/system-tests/projects/plugin-config/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugin-config/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-config/cypress.json b/system-tests/projects/plugin-config/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugin-config/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugin-empty/cypress.config.js b/system-tests/projects/plugin-empty/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugin-empty/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-empty/cypress.json b/system-tests/projects/plugin-empty/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugin-empty/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugin-event-deprecated/cypress.config.js b/system-tests/projects/plugin-event-deprecated/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugin-event-deprecated/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-event-deprecated/cypress.json b/system-tests/projects/plugin-event-deprecated/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugin-event-deprecated/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugin-extension/cypress.config.js b/system-tests/projects/plugin-extension/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugin-extension/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-extension/cypress.json b/system-tests/projects/plugin-extension/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugin-extension/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugin-filter-browsers/cypress.config.js b/system-tests/projects/plugin-filter-browsers/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugin-filter-browsers/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-filter-browsers/cypress.json b/system-tests/projects/plugin-filter-browsers/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugin-filter-browsers/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugin-retries/cypress.config.js b/system-tests/projects/plugin-retries/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugin-retries/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-retries/cypress.json b/system-tests/projects/plugin-retries/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugin-retries/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugin-returns-bad-config/cypress.config.js b/system-tests/projects/plugin-returns-bad-config/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugin-returns-bad-config/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-returns-bad-config/cypress.json b/system-tests/projects/plugin-returns-bad-config/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugin-returns-bad-config/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugin-returns-empty-browsers-list/cypress.config.js b/system-tests/projects/plugin-returns-empty-browsers-list/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugin-returns-empty-browsers-list/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-returns-empty-browsers-list/cypress.json b/system-tests/projects/plugin-returns-empty-browsers-list/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugin-returns-empty-browsers-list/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugin-returns-invalid-browser/cypress.config.js b/system-tests/projects/plugin-returns-invalid-browser/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugin-returns-invalid-browser/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-returns-invalid-browser/cypress.json b/system-tests/projects/plugin-returns-invalid-browser/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugin-returns-invalid-browser/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugin-run-event-throws/cypress.config.js b/system-tests/projects/plugin-run-event-throws/cypress.config.js new file mode 100644 index 000000000000..4f64c2459252 --- /dev/null +++ b/system-tests/projects/plugin-run-event-throws/cypress.config.js @@ -0,0 +1,4 @@ +module.exports = { + 'fixturesFolder': false, + 'supportFile': false, +} diff --git a/system-tests/projects/plugin-run-event-throws/cypress.json b/system-tests/projects/plugin-run-event-throws/cypress.json deleted file mode 100644 index a84f6e38c9e9..000000000000 --- a/system-tests/projects/plugin-run-event-throws/cypress.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "fixturesFolder": false, - "supportFile": false -} diff --git a/system-tests/projects/plugin-run-events/cypress.config.js b/system-tests/projects/plugin-run-events/cypress.config.js new file mode 100644 index 000000000000..4f64c2459252 --- /dev/null +++ b/system-tests/projects/plugin-run-events/cypress.config.js @@ -0,0 +1,4 @@ +module.exports = { + 'fixturesFolder': false, + 'supportFile': false, +} diff --git a/system-tests/projects/plugin-run-events/cypress.json b/system-tests/projects/plugin-run-events/cypress.json deleted file mode 100644 index a84f6e38c9e9..000000000000 --- a/system-tests/projects/plugin-run-events/cypress.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "fixturesFolder": false, - "supportFile": false -} diff --git a/system-tests/projects/plugin-validation-error/cypress.config.js b/system-tests/projects/plugin-validation-error/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugin-validation-error/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugin-validation-error/cypress.json b/system-tests/projects/plugin-validation-error/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugin-validation-error/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugins-absolute-path/cypress.config.js b/system-tests/projects/plugins-absolute-path/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugins-absolute-path/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugins-absolute-path/cypress.json b/system-tests/projects/plugins-absolute-path/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugins-absolute-path/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugins-async-error/cypress.config.js b/system-tests/projects/plugins-async-error/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugins-async-error/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugins-async-error/cypress.json b/system-tests/projects/plugins-async-error/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugins-async-error/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/plugins-root-async-error/cypress.config.js b/system-tests/projects/plugins-root-async-error/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/plugins-root-async-error/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/plugins-root-async-error/cypress.json b/system-tests/projects/plugins-root-async-error/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/plugins-root-async-error/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/pristine-with-config-file/app.js b/system-tests/projects/pristine-with-config-file/app.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/system-tests/projects/pristine-with-config-file/cypress.config.js b/system-tests/projects/pristine-with-config-file/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/pristine-with-config-file/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/read-only-project-root/cypress.config.js b/system-tests/projects/read-only-project-root/cypress.config.js new file mode 100644 index 000000000000..877daa2db3e4 --- /dev/null +++ b/system-tests/projects/read-only-project-root/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'retries': null, +} diff --git a/system-tests/projects/read-only-project-root/cypress.json b/system-tests/projects/read-only-project-root/cypress.json deleted file mode 100644 index 0f77b44749ce..000000000000 --- a/system-tests/projects/read-only-project-root/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "retries": null -} diff --git a/system-tests/projects/record/cypress.config.js b/system-tests/projects/record/cypress.config.js new file mode 100644 index 000000000000..411b63264e86 --- /dev/null +++ b/system-tests/projects/record/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'projectId': 'abc123', +} diff --git a/system-tests/projects/record/cypress.json b/system-tests/projects/record/cypress.json deleted file mode 100644 index 45fc46124471..000000000000 --- a/system-tests/projects/record/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "projectId": "abc123" -} diff --git a/system-tests/projects/remote-debugging-disconnect/cypress.config.js b/system-tests/projects/remote-debugging-disconnect/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/remote-debugging-disconnect/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/remote-debugging-disconnect/cypress.json b/system-tests/projects/remote-debugging-disconnect/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/remote-debugging-disconnect/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/remote-debugging-port-removed/cypress.config.js b/system-tests/projects/remote-debugging-port-removed/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/remote-debugging-port-removed/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/remote-debugging-port-removed/cypress.json b/system-tests/projects/remote-debugging-port-removed/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/remote-debugging-port-removed/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/retries-2/cypress.config.js b/system-tests/projects/retries-2/cypress.config.js new file mode 100644 index 000000000000..aceff2a31cc0 --- /dev/null +++ b/system-tests/projects/retries-2/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'retries': 2, +} diff --git a/system-tests/projects/retries-2/cypress.json b/system-tests/projects/retries-2/cypress.json deleted file mode 100644 index cd6342eef42e..000000000000 --- a/system-tests/projects/retries-2/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "retries": 2 -} diff --git a/system-tests/projects/same-fixtures-integration-folders/cypress.config.js b/system-tests/projects/same-fixtures-integration-folders/cypress.config.js new file mode 100644 index 000000000000..88a6bdbc4ed7 --- /dev/null +++ b/system-tests/projects/same-fixtures-integration-folders/cypress.config.js @@ -0,0 +1,6 @@ +module.exports = { + 'pluginsFile': false, + 'supportFile': false, + 'fixturesFolder': 'cypress/integration', + 'testFiles': '**/*spec.js', +} diff --git a/system-tests/projects/same-fixtures-integration-folders/cypress.json b/system-tests/projects/same-fixtures-integration-folders/cypress.json deleted file mode 100644 index 8aaf4cebbc0f..000000000000 --- a/system-tests/projects/same-fixtures-integration-folders/cypress.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "pluginsFile": false, - "supportFile": false, - "fixturesFolder": "cypress/integration", - "testFiles": "**/*spec.js" -} diff --git a/system-tests/projects/screen-size/cypress.config.js b/system-tests/projects/screen-size/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/screen-size/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/screen-size/cypress.json b/system-tests/projects/screen-size/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/screen-size/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/shadow-dom-global-inclusion/cypress.config.js b/system-tests/projects/shadow-dom-global-inclusion/cypress.config.js new file mode 100644 index 000000000000..361b5c94d55a --- /dev/null +++ b/system-tests/projects/shadow-dom-global-inclusion/cypress.config.js @@ -0,0 +1,5 @@ +module.exports = { + 'includeShadowDom': true, + 'pluginsFile': false, + 'supportFile': false, +} diff --git a/system-tests/projects/shadow-dom-global-inclusion/cypress.json b/system-tests/projects/shadow-dom-global-inclusion/cypress.json deleted file mode 100644 index 1ae377bbf7fd..000000000000 --- a/system-tests/projects/shadow-dom-global-inclusion/cypress.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "includeShadowDom": true, - "pluginsFile": false, - "supportFile": false -} diff --git a/system-tests/projects/spec-generation/cypress.config.js b/system-tests/projects/spec-generation/cypress.config.js new file mode 100644 index 000000000000..79ad5c8c1402 --- /dev/null +++ b/system-tests/projects/spec-generation/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'componentFolder': 'src', +} diff --git a/system-tests/projects/spec-generation/cypress.json b/system-tests/projects/spec-generation/cypress.json deleted file mode 100644 index e89f59283819..000000000000 --- a/system-tests/projects/spec-generation/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "componentFolder": "src" -} \ No newline at end of file diff --git a/system-tests/projects/studio-no-source-maps/cypress.config.js b/system-tests/projects/studio-no-source-maps/cypress.config.js new file mode 100644 index 000000000000..8638ba2f105b --- /dev/null +++ b/system-tests/projects/studio-no-source-maps/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'experimentalStudio': true, +} diff --git a/system-tests/projects/studio-no-source-maps/cypress.json b/system-tests/projects/studio-no-source-maps/cypress.json deleted file mode 100644 index 156a3ac524c8..000000000000 --- a/system-tests/projects/studio-no-source-maps/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "experimentalStudio": true -} diff --git a/system-tests/projects/studio/cypress.config.js b/system-tests/projects/studio/cypress.config.js new file mode 100644 index 000000000000..8638ba2f105b --- /dev/null +++ b/system-tests/projects/studio/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'experimentalStudio': true, +} diff --git a/system-tests/projects/studio/cypress.json b/system-tests/projects/studio/cypress.json deleted file mode 100644 index 156a3ac524c8..000000000000 --- a/system-tests/projects/studio/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "experimentalStudio": true -} diff --git a/system-tests/projects/system-node/cypress.config.js b/system-tests/projects/system-node/cypress.config.js new file mode 100644 index 000000000000..8d21334bfe8b --- /dev/null +++ b/system-tests/projects/system-node/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'nodeVersion': 'system', +} diff --git a/system-tests/projects/system-node/cypress.json b/system-tests/projects/system-node/cypress.json deleted file mode 100644 index ceb03f061915..000000000000 --- a/system-tests/projects/system-node/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "nodeVersion": "system" -} diff --git a/system-tests/projects/task-not-registered/cypress.config.js b/system-tests/projects/task-not-registered/cypress.config.js new file mode 100644 index 000000000000..877daa2db3e4 --- /dev/null +++ b/system-tests/projects/task-not-registered/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'retries': null, +} diff --git a/system-tests/projects/task-not-registered/cypress.json b/system-tests/projects/task-not-registered/cypress.json deleted file mode 100644 index 0f77b44749ce..000000000000 --- a/system-tests/projects/task-not-registered/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "retries": null -} diff --git a/system-tests/projects/todos/cypress.config.js b/system-tests/projects/todos/cypress.config.js new file mode 100644 index 000000000000..c60f6b7c09d8 --- /dev/null +++ b/system-tests/projects/todos/cypress.config.js @@ -0,0 +1,11 @@ +module.exports = { + 'integrationFolder': 'tests', + 'fixturesFolder': 'tests/_fixtures', + 'supportFile': 'tests/_support/spec_helper.js', + 'port': 8888, + 'projectId': 'abc123', + 'pluginsFile': false, + component: { + specFilePattern: 'src/**/*.spec.cy.js', + }, +} diff --git a/system-tests/projects/todos/cypress.json b/system-tests/projects/todos/cypress.json deleted file mode 100644 index c98ed7c0b3ac..000000000000 --- a/system-tests/projects/todos/cypress.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "integrationFolder": "tests", - "fixturesFolder": "tests/_fixtures", - "supportFile": "tests/_support/spec_helper.js", - "port": 8888, - "projectId": "abc123", - "pluginsFile": false -} diff --git a/system-tests/projects/ts-installed/cypress.config.js b/system-tests/projects/ts-installed/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/ts-installed/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/ts-installed/cypress.json b/system-tests/projects/ts-installed/cypress.json deleted file mode 100644 index 9e26dfeeb6e6..000000000000 --- a/system-tests/projects/ts-installed/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/system-tests/projects/ts-proj-custom-names/cypress.config.js b/system-tests/projects/ts-proj-custom-names/cypress.config.js new file mode 100644 index 000000000000..946f26dbc696 --- /dev/null +++ b/system-tests/projects/ts-proj-custom-names/cypress.config.js @@ -0,0 +1,4 @@ +module.exports = { + 'supportFile': 'cypress/support.ts', + 'pluginsFile': 'cypress/plugins.ts', +} diff --git a/system-tests/projects/ts-proj-custom-names/cypress.json b/system-tests/projects/ts-proj-custom-names/cypress.json deleted file mode 100644 index a054eca6f9e0..000000000000 --- a/system-tests/projects/ts-proj-custom-names/cypress.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "supportFile": "cypress/support.ts", - "pluginsFile": "cypress/plugins.ts" -} diff --git a/system-tests/projects/ts-proj-esmoduleinterop-true/cypress.config.js b/system-tests/projects/ts-proj-esmoduleinterop-true/cypress.config.js new file mode 100644 index 000000000000..f0064695754a --- /dev/null +++ b/system-tests/projects/ts-proj-esmoduleinterop-true/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'supportFile': false, +} diff --git a/system-tests/projects/ts-proj-esmoduleinterop-true/cypress.json b/system-tests/projects/ts-proj-esmoduleinterop-true/cypress.json deleted file mode 100644 index 0c2bdde8665b..000000000000 --- a/system-tests/projects/ts-proj-esmoduleinterop-true/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "supportFile": false -} diff --git a/system-tests/projects/ts-proj-tsconfig-in-plugins/cypress.config.js b/system-tests/projects/ts-proj-tsconfig-in-plugins/cypress.config.js new file mode 100644 index 000000000000..f0064695754a --- /dev/null +++ b/system-tests/projects/ts-proj-tsconfig-in-plugins/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'supportFile': false, +} diff --git a/system-tests/projects/ts-proj-tsconfig-in-plugins/cypress.json b/system-tests/projects/ts-proj-tsconfig-in-plugins/cypress.json deleted file mode 100644 index 0c2bdde8665b..000000000000 --- a/system-tests/projects/ts-proj-tsconfig-in-plugins/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "supportFile": false -} diff --git a/system-tests/projects/ts-proj-with-module-esnext/cypress.config.js b/system-tests/projects/ts-proj-with-module-esnext/cypress.config.js new file mode 100644 index 000000000000..85067c9cc962 --- /dev/null +++ b/system-tests/projects/ts-proj-with-module-esnext/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'supportFolder': false, +} diff --git a/system-tests/projects/ts-proj-with-module-esnext/cypress.json b/system-tests/projects/ts-proj-with-module-esnext/cypress.json deleted file mode 100644 index 9c5417cd8268..000000000000 --- a/system-tests/projects/ts-proj-with-module-esnext/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "supportFolder": false -} diff --git a/system-tests/projects/ts-proj-with-paths/cypress.config.js b/system-tests/projects/ts-proj-with-paths/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/ts-proj-with-paths/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/ts-proj-with-paths/cypress.json b/system-tests/projects/ts-proj-with-paths/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/ts-proj-with-paths/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/ts-proj/cypress.config.js b/system-tests/projects/ts-proj/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/ts-proj/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/ts-proj/cypress.json b/system-tests/projects/ts-proj/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/ts-proj/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/uncaught-support-file/cypress.config.js b/system-tests/projects/uncaught-support-file/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/uncaught-support-file/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/uncaught-support-file/cypress.json b/system-tests/projects/uncaught-support-file/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/uncaught-support-file/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/unify-onboarding-with-config/cypress.config.js b/system-tests/projects/unify-onboarding-with-config/cypress.config.js new file mode 100644 index 000000000000..39e12cab152c --- /dev/null +++ b/system-tests/projects/unify-onboarding-with-config/cypress.config.js @@ -0,0 +1,6 @@ +module.exports = { + component: { + testFiles: '**/*cy-spec.{js,jsx,ts,tsx}', + componentFolder: 'src', + }, +} diff --git a/system-tests/projects/unify-onboarding-with-config/cypress/plugins/index.js b/system-tests/projects/unify-onboarding-with-config/cypress/plugins/index.js new file mode 100644 index 000000000000..d8e8f3f055c6 --- /dev/null +++ b/system-tests/projects/unify-onboarding-with-config/cypress/plugins/index.js @@ -0,0 +1,21 @@ +/// +const { startDevServer } = require('@cypress/webpack-dev-server') + +const webpackConfig = { + output: { + publicPath: '/', + }, +} + +/** + * @type Cypress.PluginConfig + */ +module.exports = (on, config) => { + if (config.testingType !== 'component') { + throw Error(`This is an component testing project. testingType should be 'component'. Received ${config.testingType}`) + } + + on('dev-server:start', (options) => startDevServer({ options, webpackConfig })) + + return config +} diff --git a/system-tests/projects/unify-onboarding-with-config/index.html b/system-tests/projects/unify-onboarding-with-config/index.html new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/system-tests/projects/unify-onboarding/cypress.config.js b/system-tests/projects/unify-onboarding/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/unify-onboarding/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/unify-onboarding/cypress/plugins/index.js b/system-tests/projects/unify-onboarding/cypress/plugins/index.js new file mode 100644 index 000000000000..d8e8f3f055c6 --- /dev/null +++ b/system-tests/projects/unify-onboarding/cypress/plugins/index.js @@ -0,0 +1,21 @@ +/// +const { startDevServer } = require('@cypress/webpack-dev-server') + +const webpackConfig = { + output: { + publicPath: '/', + }, +} + +/** + * @type Cypress.PluginConfig + */ +module.exports = (on, config) => { + if (config.testingType !== 'component') { + throw Error(`This is an component testing project. testingType should be 'component'. Received ${config.testingType}`) + } + + on('dev-server:start', (options) => startDevServer({ options, webpackConfig })) + + return config +} diff --git a/system-tests/projects/unify-plugin-errors/cypress.config.js b/system-tests/projects/unify-plugin-errors/cypress.config.js new file mode 100644 index 000000000000..821d12808891 --- /dev/null +++ b/system-tests/projects/unify-plugin-errors/cypress.config.js @@ -0,0 +1,5 @@ +module.exports = { + e2e: { + baseUrl: 'https://cypress.com', + }, +} diff --git a/system-tests/projects/unify-plugin-errors/cypress.json b/system-tests/projects/unify-plugin-errors/cypress.json deleted file mode 100644 index 9e26dfeeb6e6..000000000000 --- a/system-tests/projects/unify-plugin-errors/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/system-tests/projects/various-file-types/cypress.config.js b/system-tests/projects/various-file-types/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/various-file-types/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/webpack-preprocessor-awesome-typescript-loader/cypress.config.js b/system-tests/projects/webpack-preprocessor-awesome-typescript-loader/cypress.config.js new file mode 100644 index 000000000000..877daa2db3e4 --- /dev/null +++ b/system-tests/projects/webpack-preprocessor-awesome-typescript-loader/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'retries': null, +} diff --git a/system-tests/projects/webpack-preprocessor-awesome-typescript-loader/cypress.json b/system-tests/projects/webpack-preprocessor-awesome-typescript-loader/cypress.json deleted file mode 100644 index 0f77b44749ce..000000000000 --- a/system-tests/projects/webpack-preprocessor-awesome-typescript-loader/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "retries": null -} diff --git a/system-tests/projects/webpack-preprocessor-ts-loader-compiler-options/cypress.config.js b/system-tests/projects/webpack-preprocessor-ts-loader-compiler-options/cypress.config.js new file mode 100644 index 000000000000..877daa2db3e4 --- /dev/null +++ b/system-tests/projects/webpack-preprocessor-ts-loader-compiler-options/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'retries': null, +} diff --git a/system-tests/projects/webpack-preprocessor-ts-loader-compiler-options/cypress.json b/system-tests/projects/webpack-preprocessor-ts-loader-compiler-options/cypress.json deleted file mode 100644 index 0f77b44749ce..000000000000 --- a/system-tests/projects/webpack-preprocessor-ts-loader-compiler-options/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "retries": null -} diff --git a/system-tests/projects/webpack-preprocessor-ts-loader/cypress.config.js b/system-tests/projects/webpack-preprocessor-ts-loader/cypress.config.js new file mode 100644 index 000000000000..877daa2db3e4 --- /dev/null +++ b/system-tests/projects/webpack-preprocessor-ts-loader/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'retries': null, +} diff --git a/system-tests/projects/webpack-preprocessor-ts-loader/cypress.json b/system-tests/projects/webpack-preprocessor-ts-loader/cypress.json deleted file mode 100644 index 0f77b44749ce..000000000000 --- a/system-tests/projects/webpack-preprocessor-ts-loader/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "retries": null -} diff --git a/system-tests/projects/webpack-preprocessor/cypress.config.js b/system-tests/projects/webpack-preprocessor/cypress.config.js new file mode 100644 index 000000000000..877daa2db3e4 --- /dev/null +++ b/system-tests/projects/webpack-preprocessor/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + 'retries': null, +} diff --git a/system-tests/projects/webpack-preprocessor/cypress.json b/system-tests/projects/webpack-preprocessor/cypress.json deleted file mode 100644 index 0f77b44749ce..000000000000 --- a/system-tests/projects/webpack-preprocessor/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "retries": null -} diff --git a/system-tests/projects/working-preprocessor/cypress.config.js b/system-tests/projects/working-preprocessor/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/working-preprocessor/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/working-preprocessor/cypress.json b/system-tests/projects/working-preprocessor/cypress.json deleted file mode 100644 index 0967ef424bce..000000000000 --- a/system-tests/projects/working-preprocessor/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/system-tests/projects/yarn-v2-pnp/cypress.config.js b/system-tests/projects/yarn-v2-pnp/cypress.config.js new file mode 100644 index 000000000000..4ba52ba2c8df --- /dev/null +++ b/system-tests/projects/yarn-v2-pnp/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/system-tests/projects/yarn-v2-pnp/cypress.json b/system-tests/projects/yarn-v2-pnp/cypress.json deleted file mode 100644 index 9e26dfeeb6e6..000000000000 --- a/system-tests/projects/yarn-v2-pnp/cypress.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/system-tests/test/config_spec.js b/system-tests/test/config_spec.js index c39a9eebff95..3954734321f7 100644 --- a/system-tests/test/config_spec.js +++ b/system-tests/test/config_spec.js @@ -77,12 +77,21 @@ describe('e2e config', () => { }) it('throws error when multiple default config file are found in project', function () { + const projectRoot = Fixtures.projectPath('pristine-with-config-file') + + return fs.writeFile(path.join(projectRoot, 'cypress.config.ts'), 'export default {}').then(() => { + return systemTests.exec(this, { + project: projectRoot, + expectedExitCode: 1, + snapshot: true, + }) + }) + }) + + it('throws error when cypress.json is found in project and need migration', function () { const projectRoot = Fixtures.projectPath('pristine') - return Promise.all([ - fs.writeFile(path.join(projectRoot, 'cypress.config.js'), 'module.exports = {}'), - fs.writeFile(path.join(projectRoot, 'cypress.config.ts'), 'export default {}'), - ]).then(() => { + return fs.writeFile(path.join(projectRoot, 'cypress.json'), '{}').then(() => { return systemTests.exec(this, { project: projectRoot, expectedExitCode: 1, @@ -90,4 +99,14 @@ describe('e2e config', () => { }) }) }) + + it('throws error when cypress.json is found in project and cypress.config.{ts|js} exists as well', function () { + const projectRoot = Fixtures.projectPath('multiples-config-files-with-json') + + return systemTests.exec(this, { + project: projectRoot, + expectedExitCode: 1, + snapshot: true, + }) + }) }) diff --git a/system-tests/test/plugins_spec.js b/system-tests/test/plugins_spec.js index 211ee1b94f02..e85909cbc648 100644 --- a/system-tests/test/plugins_spec.js +++ b/system-tests/test/plugins_spec.js @@ -194,7 +194,7 @@ describe('e2e plugins', function () { config: { env: { projectRoot: e2eProject, - configFile: path.join(e2eProject, 'cypress.json'), + configFile: path.join(e2eProject, 'cypress.config.js'), }, }, }) diff --git a/yarn.lock b/yarn.lock index e0960852eaeb..778f7b696b7c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16951,10 +16951,9 @@ cyclist@^1.0.1: resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= -cypress-example-kitchensink@1.15.2: - version "1.15.2" - resolved "https://registry.yarnpkg.com/cypress-example-kitchensink/-/cypress-example-kitchensink-1.15.2.tgz#325015726291a5e1e0d0cf89177eb9dec1c13e19" - integrity sha512-Ni/xbpMEllrNBrDVxh9juu7W4sbyBGpENuWvFdiojjBxzyvCCHaYCJIdF5kgGNzE5aP4AkoGW/jEk1KiKQzALA== +cypress-example-kitchensink@cypress-io/cypress-example-kitchensink#feat/use-config-file: + version "0.0.0-development" + resolved "https://codeload.github.com/cypress-io/cypress-example-kitchensink/tar.gz/9de74fdcfa724324001b82a4a9d0582a38533db0" dependencies: npm-run-all "^4.1.2" serve "11.3.0"