diff --git a/.gitignore b/.gitignore index ad824269bdff..dc6c36d4e187 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,7 @@ packages/example/cypress/integration # from frontend-shared packages/frontend-shared/cypress/e2e/.projects +packages/frontend-shared/src/public/shiki/themes/cypress.theme.json # from server packages/server/.cy diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4431772b6d2d..2f8687bfb2f7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -573,6 +573,8 @@ Independent packages are automatically released when code is merged into `master ![Select release for PR](https://user-images.githubusercontent.com/1271364/135139641-657015d6-2dca-42d4-a4fb-16478f61d63f.png) - Please check the "Allow edits from maintainers" checkbox when submitting your PR. This will make it easier for the maintainers to make minor adjustments, to help with tests or any other changes we may need. ![Allow edits from maintainers checkbox](https://user-images.githubusercontent.com/1271181/31393427-b3105d44-ada9-11e7-80f2-0dac51e3919e.png) +- After the PR is approved, the original contributor can merge the PR (if the original contributor has access). +- When you merge a PR into `develop`, select [**Squash and merge**](https://docs.github.com/en/github/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges#squash-and-merge-your-pull-request-commits). This will squash all commits into a single commit. *The only exception to squashing is when converting files to another language and there is a clear commit history needed to maintain from the file conversion.* ### Dependencies diff --git a/apollo.config.js b/apollo.config.js index 5e55dc74076e..a8c2728dcac7 100644 --- a/apollo.config.js +++ b/apollo.config.js @@ -9,6 +9,6 @@ module.exports = { localSchemaFile: path.join(__dirname, 'packages/graphql/schemas/schema.graphql'), }, tagName: 'gql', - includes: [path.join(__dirname, 'packages/{launchpad,app}/src/**/*.vue')], + includes: [path.join(__dirname, 'packages/{launchpad,app,frontend-shared}/src/**/*.vue')], }, } diff --git a/autobarrel.json b/autobarrel.json index c01327f42c8b..3afaf2afc552 100644 --- a/autobarrel.json +++ b/autobarrel.json @@ -5,6 +5,7 @@ "packages/data-context/src/**/*" ], "ignore": [ + "packages/data-context/src/gen", "packages/graphql/src/stitching", "packages/graphql/src/testing", "packages/graphql/src/gen" diff --git a/browser-versions.json b/browser-versions.json index c471c41893d8..bf7bd2e449e1 100644 --- a/browser-versions.json +++ b/browser-versions.json @@ -1,4 +1,4 @@ { - "chrome:beta": "95.0.4638.54", - "chrome:stable": "95.0.4638.54" + "chrome:beta": "96.0.4664.27", + "chrome:stable": "95.0.4638.69" } diff --git a/circle.yml b/circle.yml index b1e59b41530b..8e3e564c2f25 100644 --- a/circle.yml +++ b/circle.yml @@ -413,6 +413,10 @@ commands: CYPRESS_INTERNAL_FORCE_BROWSER_RELAUNCH='true' \ CYPRESS_KONFIG_ENV=production \ CYPRESS_RECORD_KEY=$TEST_LAUNCHPAD_RECORD_KEY \ + PERCY_PARALLEL_NONCE=$CIRCLE_WORKFLOW_ID \ + PERCY_ENABLE=${PERCY_TOKEN:-0} \ + PERCY_PARALLEL_TOTAL=-1 \ + yarn percy exec --parallel -- -- \ yarn workspace @packages/<> cypress:run:<> --browser <> --record --parallel --group <>-<> - store_test_results: path: /tmp/cypress @@ -516,13 +520,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 +538,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 +589,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 +719,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 +733,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/<> @@ -1005,7 +1024,7 @@ jobs: fi - wait-on-circle-jobs: job-names: > - desktop-gui-integration-tests-2x, + desktop-gui-integration-tests-7x, desktop-gui-component-tests, cli-visual-tests, runner-integration-tests-chrome, @@ -1283,9 +1302,9 @@ jobs: - run-driver-integration-tests: browser: electron - desktop-gui-integration-tests-2x: + desktop-gui-integration-tests-7x: <<: *defaults - parallelism: 2 + parallelism: 7 steps: - restore_cached_workspace - run: @@ -1610,9 +1629,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 +1664,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 +1689,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 +1873,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 +1905,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 +1923,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 +1975,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 +1991,7 @@ jobs: - test-binary-against-repo: repo: cypress-example-kitchensink browser: firefox + pull_request_id: 510 "test-binary-against-kitchensink-chrome": <<: *defaults @@ -1963,6 +2000,7 @@ jobs: - test-binary-against-repo: repo: cypress-example-kitchensink browser: chrome + pull_request_id: 510 "test-binary-against-todomvc-firefox": <<: *defaults @@ -2056,6 +2094,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 @@ -2166,7 +2212,7 @@ linux-workflow: &linux-workflow # context: test-runner:launchpad-tests # requires: # - build - - desktop-gui-integration-tests-2x: + - desktop-gui-integration-tests-7x: requires: - build - desktop-gui-component-tests: @@ -2237,7 +2283,7 @@ linux-workflow: &linux-workflow - reporter-integration-tests - Linux lint - desktop-gui-component-tests - - desktop-gui-integration-tests-2x + - desktop-gui-integration-tests-7x - runner-ct-integration-tests-chrome - runner-integration-tests-firefox - runner-integration-tests-chrome 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..9da52b40ae53 100644 --- a/cli/lib/cli.js +++ b/cli/lib/cli.js @@ -1,6 +1,5 @@ // @ts-check const _ = require('lodash') -const R = require('ramda') const commander = require('commander') const { stripIndent } = require('common-tags') const logSymbols = require('log-symbols') @@ -107,12 +106,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 +120,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.', @@ -283,12 +282,17 @@ const castCypressRunOptions = (opts) => { // only properties that have type "string | false" in our TS definition // require special handling, because CLI parsing takes care of purely // boolean arguments - const result = R.evolve({ - port: coerceAnyStringToInt, - configFile: coerceFalseOrString, - })(opts) + const castOpts = { ...opts } - return result + if (_.has(opts, 'port')) { + castOpts.port = coerceAnyStringToInt(opts.port) + } + + if (_.has(opts, 'configFile')) { + castOpts.configFile = coerceFalseOrString(opts.configFile) + } + + return castOpts } module.exports = { diff --git a/cli/lib/errors.js b/cli/lib/errors.js index aced13a48292..cedc7cb899dd 100644 --- a/cli/lib/errors.js +++ b/cli/lib/errors.js @@ -1,6 +1,5 @@ const chalk = require('chalk') const { stripIndent, stripIndents } = require('common-tags') -const { merge } = require('ramda') const la = require('lazy-ass') const is = require('check-more-types') @@ -241,7 +240,7 @@ const CYPRESS_RUN_BINARY = { function addPlatformInformation (info) { return util.getPlatformInfo().then((platform) => { - return merge(info, { platform }) + return { ...info, platform } }) } diff --git a/cli/lib/exec/info.js b/cli/lib/exec/info.js index 415d276f1cbf..cd21138029c8 100644 --- a/cli/lib/exec/info.js +++ b/cli/lib/exec/info.js @@ -6,7 +6,6 @@ const os = require('os') const chalk = require('chalk') const prettyBytes = require('pretty-bytes') const _ = require('lodash') -const R = require('ramda') // color for numbers and show values const g = chalk.green @@ -22,14 +21,20 @@ methods.findProxyEnvironmentVariables = () => { return _.pick(process.env, ['HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY']) } -const maskSensitiveVariables = R.evolve({ - CYPRESS_RECORD_KEY: R.always(''), -}) +const maskSensitiveVariables = (obj) => { + const masked = { ...obj } + + if (masked.CYPRESS_RECORD_KEY) { + masked.CYPRESS_RECORD_KEY = '' + } + + return masked +} methods.findCypressEnvironmentVariables = () => { const isCyVariable = (val, key) => key.startsWith('CYPRESS_') - return R.pickBy(isCyVariable)(process.env) + return _.pickBy(process.env, isCyVariable) } const formatCypressVariables = () => { diff --git a/cli/lib/logger.js b/cli/lib/logger.js index 679aeb52f517..088c07e058f8 100644 --- a/cli/lib/logger.js +++ b/cli/lib/logger.js @@ -1,4 +1,3 @@ -const R = require('ramda') const chalk = require('chalk') let logs = [] @@ -36,7 +35,9 @@ const always = (...messages) => { const logLines = (text) => { const lines = text.split('\n') - R.forEach(log, lines) + for (const line of lines) { + log(line) + } } const print = () => { diff --git a/cli/lib/tasks/state.js b/cli/lib/tasks/state.js index 6f92a752f760..475dfaeb94f3 100644 --- a/cli/lib/tasks/state.js +++ b/cli/lib/tasks/state.js @@ -2,7 +2,6 @@ const _ = require('lodash') const os = require('os') const path = require('path') const untildify = require('untildify') -const R = require('ramda') const debug = require('debug')('cypress:cli') const fs = require('../fs') @@ -179,9 +178,9 @@ const getBinaryPkgAsync = (binaryDir) => { }) } -const getBinaryPkgVersion = R.propOr(null, 'version') -const getBinaryElectronVersion = R.propOr(null, 'electronVersion') -const getBinaryElectronNodeVersion = R.propOr(null, 'electronNodeVersion') +const getBinaryPkgVersion = (o) => _.get(o, 'version', null) +const getBinaryElectronVersion = (o) => _.get(o, 'electronVersion', null) +const getBinaryElectronNodeVersion = (o) => _.get(o, 'electronNodeVersion', null) module.exports = { getPathToExecutable, diff --git a/cli/lib/util.js b/cli/lib/util.js index 4d2b6d7e085e..fa8e43a80c1c 100644 --- a/cli/lib/util.js +++ b/cli/lib/util.js @@ -1,5 +1,4 @@ const _ = require('lodash') -const R = require('ramda') const os = require('os') const ospath = require('ospath') const crypto = require('crypto') @@ -114,10 +113,9 @@ const logBrokenGtkDisplayWarning = () => { } function stdoutLineMatches (expectedLine, stdout) { - const lines = stdout.split('\n').map(R.trim) - const lineMatches = R.equals(expectedLine) + const lines = stdout.split('\n').map((val) => val.trim()) - return lines.some(lineMatches) + return lines.some((line) => line === expectedLine) } /** @@ -232,11 +230,14 @@ const parseOpts = (opts) => { // some options might be quoted - which leads to unexpected results // remove double quotes from certain options - const removeQuotes = { - group: dequote, - ciBuildId: dequote, + const cleanOpts = { ...opts } + const toDequote = ['group', 'ciBuildId'] + + for (const prop of toDequote) { + if (_.has(opts, prop)) { + cleanOpts[prop] = dequote(opts[prop]) + } } - const cleanOpts = R.evolve(removeQuotes, opts) debug('parsed cli options %o', cleanOpts) diff --git a/cli/package.json b/cli/package.json index 4387fc409906..dccb14bb48fa 100644 --- a/cli/package.json +++ b/cli/package.json @@ -55,7 +55,6 @@ "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", "proxy-from-env": "1.0.0", - "ramda": "~0.27.1", "request-progress": "^3.0.0", "supports-color": "^8.1.1", "tmp": "~0.2.1", diff --git a/cli/schema/cypress.schema.json b/cli/schema/cypress.schema.json index 617664c1028d..b204cf285736 100644 --- a/cli/schema/cypress.schema.json +++ b/cli/schema/cypress.schema.json @@ -44,6 +44,11 @@ "default": null, "description": "The reporter options used. Supported options depend on the reporter. See https://on.cypress.io/reporters#Reporter-Options" }, + "slowTestThreshold": { + "type": "number", + "default": 10000, + "description": "Slow test threshold in milliseconds. Only affects the visual output of some reporters. For example, the spec reporter will display the test time in yellow if over the threshold. See https://on.cypress.io/configuration#Timeouts" + }, "testFiles": { "type": [ "string", @@ -282,7 +287,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/build_spec.js b/cli/test/lib/build_spec.js index 722f2d59105b..74a27803dfa6 100644 --- a/cli/test/lib/build_spec.js +++ b/cli/test/lib/build_spec.js @@ -5,13 +5,12 @@ const makeUserPackageFile = require('../../scripts/build') const snapshot = require('../support/snapshot') const la = require('lazy-ass') const is = require('check-more-types') -const R = require('ramda') const hasVersion = (json) => { return la(is.semver(json.version), 'cannot find version', json) } -const changeVersion = R.assoc('version', 'x.y.z') +const changeVersion = (o) => ({ ...o, version: 'x.y.z' }) describe('package.json build', () => { beforeEach(function () { diff --git a/cli/test/lib/cypress_spec.js b/cli/test/lib/cypress_spec.js index 2edaa3b0e169..829c42f3e492 100644 --- a/cli/test/lib/cypress_spec.js +++ b/cli/test/lib/cypress_spec.js @@ -2,7 +2,7 @@ require('../spec_helper') const os = require('os') const path = require('path') -const R = require('ramda') +const _ = require('lodash') const snapshot = require('../support/snapshot') const Promise = require('bluebird') const tmp = Promise.promisifyAll(require('tmp')) @@ -27,11 +27,10 @@ describe('cypress', function () { sinon.stub(open, 'start').resolves() }) - const getCallArgs = R.path(['lastCall', 'args', 0]) const getStartArgs = () => { expect(open.start).to.be.called - return getCallArgs(open.start) + return _.get(open.start, ['lastCall', 'args', 0]) } it('calls open#start, passing in options', function () { @@ -100,7 +99,6 @@ describe('cypress', function () { }) }) - const getCallArgs = R.path(['lastCall', 'args', 0]) const normalizeCallArgs = (args) => { expect(args.outputPath).to.equal(outputPath) delete args.outputPath @@ -110,7 +108,7 @@ describe('cypress', function () { const getStartArgs = () => { expect(run.start).to.be.called - return normalizeCallArgs(getCallArgs(run.start)) + return normalizeCallArgs(_.get(run.start, ['lastCall', 'args', 0])) } it('calls run#start, passing in options', () => { @@ -234,12 +232,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..fb8eb2533a60 100644 --- a/cli/types/cypress-npm-api.d.ts +++ b/cli/types/cypress-npm-api.d.ts @@ -91,6 +91,10 @@ declare namespace CypressCommandLine { * Specify mocha reporter options */ reporterOptions: any + /** + * Slow test threshold in milliseconds. Only affects the visual output of some reporters. For example, the spec reporter will display the test time in yellow if over the threshold. + */ + slowTestThreshold: number /** * Specify the specs to run */ @@ -144,7 +148,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..c2eb9ae6ffe9 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 */ @@ -2577,6 +2577,11 @@ declare namespace Cypress { * @default "spec" */ reporterOptions: { [key: string]: any } + /** + * Slow test threshold in milliseconds. Only affects the visual output of some reporters. For example, the spec reporter will display the test time in yellow if over the threshold. + * @default 10000 + */ + slowTestThreshold: number /** * Whether Cypress will watch and restart tests on test file changes * @default true @@ -2756,7 +2761,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 +2899,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 /** @@ -5672,7 +5677,7 @@ declare namespace Cypress { xhr: XMLHttpRequest } - type Encodings = 'ascii' | 'base64' | 'binary' | 'hex' | 'latin1' | 'utf8' | 'utf-8' | 'ucs2' | 'ucs-2' | 'utf16le' | 'utf-16le' + type Encodings = 'ascii' | 'base64' | 'binary' | 'hex' | 'latin1' | 'utf8' | 'utf-8' | 'ucs2' | 'ucs-2' | 'utf16le' | 'utf-16le' | null type PositionType = 'topLeft' | 'top' | 'topRight' | 'left' | 'center' | 'right' | 'bottomLeft' | 'bottom' | 'bottomRight' type ViewportPreset = 'macbook-16' | 'macbook-15' | 'macbook-13' | 'macbook-11' | 'ipad-2' | 'ipad-mini' | 'iphone-xr' | 'iphone-x' | 'iphone-6+' | 'iphone-se2' | 'iphone-8' | 'iphone-7' | 'iphone-6' | 'iphone-5' | 'iphone-4' | 'iphone-3' | 'samsung-s10' | 'samsung-note9' interface Offset { diff --git a/graphql-codegen.yml b/graphql-codegen.yml index 86f7f9b41613..e29952e21d59 100644 --- a/graphql-codegen.yml +++ b/graphql-codegen.yml @@ -44,6 +44,24 @@ config: DateTime: string JSON: any generates: + './packages/data-context/src/gen/all-operations.gen.ts': + config: + <<: *documentFilters + flattenGeneratedTypes: true + schema: 'packages/graphql/schemas/schema.graphql' + documents: + - './packages/frontend-shared/src/gql-components/**/*.vue' + - './packages/app/src/**/*.vue' + - './packages/launchpad/src/**/*.vue' + plugins: + - add: + content: '/* eslint-disable */' + - 'typescript': + noExport: true + - 'typescript-operations': + noExport: true + - 'typed-document-node' + ### # Generates types for us to infer the correct "source types" when we mock out on the frontend # This ensures we have proper type checking when we're using cy.mountFragment in component tests @@ -78,11 +96,15 @@ generates: # files for useQuery / useMutation, as well as types associated with the fragments ### './packages/launchpad/src/generated/graphql.ts': - documents: './packages/launchpad/src/**/*.vue' + documents: + - './packages/launchpad/src/**/*.vue' + - './packages/frontend-shared/src/**/*.vue' <<: *vueOperations './packages/app/src/generated/graphql.ts': - documents: './packages/app/src/**/*.vue' + documents: + - './packages/app/src/**/*.vue' + - './packages/frontend-shared/src/**/*.vue' <<: *vueOperations './packages/frontend-shared/src/generated/graphql.ts': @@ -94,11 +116,15 @@ generates: # so we can actually use the document in cy.mountFragment ### './packages/launchpad/src/generated/graphql-test.ts': - documents: './packages/launchpad/src/**/*.vue' + documents: + - './packages/launchpad/src/**/*.vue' + - './packages/frontend-shared/src/**/*.vue' <<: *vueTesting './packages/app/src/generated/graphql-test.ts': - documents: './packages/app/src/**/*.vue' + documents: + - './packages/app/src/**/*.vue' + - './packages/frontend-shared/src/**/*.vue' <<: *vueTesting './packages/frontend-shared/src/generated/graphql-test.ts': 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/CHANGELOG.md b/npm/create-cypress-tests/CHANGELOG.md index ccfc9ef729a4..ca5d9c1fd808 100644 --- a/npm/create-cypress-tests/CHANGELOG.md +++ b/npm/create-cypress-tests/CHANGELOG.md @@ -1,3 +1,10 @@ +# [create-cypress-tests-v1.1.3](https://github.com/cypress-io/cypress/compare/create-cypress-tests-v1.1.2...create-cypress-tests-v1.1.3) (2021-10-29) + + +### Bug Fixes + +* revive type checker ([#18172](https://github.com/cypress-io/cypress/issues/18172)) ([af472b6](https://github.com/cypress-io/cypress/commit/af472b6419ecb2aec1abdb09df99b2fa5f56e033)) + # [create-cypress-tests-v1.1.2](https://github.com/cypress-io/cypress/compare/create-cypress-tests-v1.1.1...create-cypress-tests-v1.1.2) (2021-06-17) 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 5901324bfb42..86e715cad9f6 100644 --- a/npm/create-cypress-tests/package.json +++ b/npm/create-cypress-tests/package.json @@ -3,7 +3,7 @@ "version": "0.0.0-development", "description": "Cypress smart installation wizard", "private": false, - "main": "index.js", + "main": "dist/src/main.js", "scripts": { "build": "yarn prepare-example && tsc -p ./tsconfig.json && node scripts/example copy-to ./dist/initial-template && yarn prepare-copy-templates", "build-prod": "yarn build", @@ -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", @@ -41,6 +42,10 @@ "snap-shot-it": "7.9.3", "typescript": "^4.2.3" }, + "files": [ + "dist", + "bin" + ], "bin": { "create-cypress-tests": "dist/src/index.js" }, 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/main.ts b/npm/create-cypress-tests/src/main.ts index 4dd68128e8fc..818a58b94329 100644 --- a/npm/create-cypress-tests/src/main.ts +++ b/npm/create-cypress-tests/src/main.ts @@ -102,3 +102,5 @@ export async function main ({ useNpm, ignoreTs, setupComponentTesting, ignoreExa console.log(`\nHappy testing with ${chalk.green('cypress.io')} 🌲\n`) } + +export { scanFSForAvailableDependency } 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/CHANGELOG.md b/npm/cypress-schematic/CHANGELOG.md index 242f0ad431fa..f50756a22d84 100644 --- a/npm/cypress-schematic/CHANGELOG.md +++ b/npm/cypress-schematic/CHANGELOG.md @@ -1,3 +1,17 @@ +# [@cypress/schematic-v1.5.3](https://github.com/cypress-io/cypress/compare/@cypress/schematic-v1.5.2...@cypress/schematic-v1.5.3) (2021-10-29) + + +### Bug Fixes + +* remove outdated registry link ([#18710](https://github.com/cypress-io/cypress/issues/18710)) ([e2a869d](https://github.com/cypress-io/cypress/commit/e2a869d2a984abb6703aec966dd9124ee693b8c1)) + +# [@cypress/schematic-v1.5.2](https://github.com/cypress-io/cypress/compare/@cypress/schematic-v1.5.1...@cypress/schematic-v1.5.2) (2021-10-29) + + +### Bug Fixes + +* revive type checker ([#18172](https://github.com/cypress-io/cypress/issues/18172)) ([af472b6](https://github.com/cypress-io/cypress/commit/af472b6419ecb2aec1abdb09df99b2fa5f56e033)) + # [@cypress/schematic-v1.5.1](https://github.com/cypress-io/cypress/compare/@cypress/schematic-v1.5.0...@cypress/schematic-v1.5.1) (2021-09-10) diff --git a/npm/cypress-schematic/package.json b/npm/cypress-schematic/package.json index 353db69e6843..fa053922be27 100644 --- a/npm/cypress-schematic/package.json +++ b/npm/cypress-schematic/package.json @@ -52,8 +52,7 @@ "testing" ], "publishConfig": { - "access": "public", - "registry": "http://registry.npmjs.org/" + "access": "public" }, "builders": "./src/builders/builders.json", "ng-add": { 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/CHANGELOG.md b/npm/react/CHANGELOG.md index 4424052efd17..32c8ef992c0d 100644 --- a/npm/react/CHANGELOG.md +++ b/npm/react/CHANGELOG.md @@ -1,3 +1,12 @@ +# [@cypress/react-v5.10.2](https://github.com/cypress-io/cypress/compare/@cypress/react-v5.10.1...@cypress/react-v5.10.2) (2021-10-29) + + +### Bug Fixes + +* Next.JS 12 components testing failing with ` TypeError: Cannot read property 'traceChild' of undefined` ([#18648](https://github.com/cypress-io/cypress/issues/18648)) ([cb0cbdf](https://github.com/cypress-io/cypress/commit/cb0cbdf4c35da09a7dedcc4563a242cb4748e994)) +* remove outdated registry link ([#18710](https://github.com/cypress-io/cypress/issues/18710)) ([e2a869d](https://github.com/cypress-io/cypress/commit/e2a869d2a984abb6703aec966dd9124ee693b8c1)) +* **cypress/react:** disable react-refresh for craco setups ([#18517](https://github.com/cypress-io/cypress/issues/18517)) ([ea10795](https://github.com/cypress-io/cypress/commit/ea1079559473fc672b5e0e188b5b54bf8ebe2f98)) + # [@cypress/react-v5.10.1](https://github.com/cypress-io/cypress/compare/@cypress/react-v5.10.0...@cypress/react-v5.10.1) (2021-10-04) 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 88% 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/package.json b/npm/react/package.json index 2623073dfce9..cefdf42304ba 100644 --- a/npm/react/package.json +++ b/npm/react/package.json @@ -178,8 +178,7 @@ } }, "publishConfig": { - "access": "public", - "registry": "http://registry.npmjs.org/" + "access": "public" }, "standard": { "globals": [ 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/react/plugins/next/checkSWC.ts b/npm/react/plugins/next/checkSWC.ts new file mode 100644 index 000000000000..6ba4fb5a1cc3 --- /dev/null +++ b/npm/react/plugins/next/checkSWC.ts @@ -0,0 +1,19 @@ +import type { Configuration } from 'webpack' + +export function checkSWC ( + webpackConfig: Configuration, + cypressConfig: Cypress.Config, +) { + const hasSWCLoader = webpackConfig.module?.rules.some((rule) => { + return rule.oneOf?.some( + (oneOf) => (oneOf.use as any)?.loader === 'next-swc-loader' + ) + }) + + if (hasSWCLoader && cypressConfig.nodeVersion !== 'system') { + throw new Error(`Cypress requires "nodeVersion" to be set to "system" in order to run Next.js with SWC optimizations. +Please add "nodeVersion": "system" to your Cypress configuration and try again.`) + } + + return false +} diff --git a/npm/react/plugins/next/findNextWebpackConfig.js b/npm/react/plugins/next/findNextWebpackConfig.js index e2609de57fd3..2b4acfb59837 100644 --- a/npm/react/plugins/next/findNextWebpackConfig.js +++ b/npm/react/plugins/next/findNextWebpackConfig.js @@ -4,6 +4,7 @@ const debug = require('debug')('@cypress/react') const getNextJsBaseWebpackConfig = require('next/dist/build/webpack-config').default const { findPagesDir } = require('../../dist/next/findPagesDir') const { getRunWebpackSpan } = require('../../dist/next/getRunWebpackSpan') +const { checkSWC } = require('../../dist/next/checkSWC') async function getNextWebpackConfig (config) { let loadConfig @@ -38,6 +39,8 @@ async function getNextWebpackConfig (config) { debug('resolved next.js webpack config %o', nextWebpackConfig) + checkSWC(nextWebpackConfig, config) + return nextWebpackConfig } diff --git a/npm/react/plugins/next/getRunWebpackSpan.ts b/npm/react/plugins/next/getRunWebpackSpan.ts index ead3dcdbe227..44c0585883e7 100644 --- a/npm/react/plugins/next/getRunWebpackSpan.ts +++ b/npm/react/plugins/next/getRunWebpackSpan.ts @@ -3,13 +3,21 @@ import type { Span } from 'next/dist/telemetry/trace/trace' // Starting with v11.1.1, a trace is required. // 'next/dist/telemetry/trace/trace' only exists since v10.0.9 // and our peerDeps support back to v8 so try-catch this import +// Starting from 12.0 trace is now located in 'next/dist/trace/trace' export async function getRunWebpackSpan (): Promise<{ runWebpackSpan?: Span }> { let trace: (name: string) => Span try { - trace = await import('next/dist/telemetry/trace/trace').then((m) => m.trace) + try { + trace = await import('next/dist/telemetry/trace/trace').then((m) => m.trace) - return { runWebpackSpan: trace('cypress') } + return { runWebpackSpan: trace('cypress') } + } catch (_) { + // @ts-ignore + trace = await import('next/dist/trace/trace').then((m) => m.trace) + + return { runWebpackSpan: trace('cypress') } + } } catch (_) { return {} } diff --git a/npm/vite-dev-server/CHANGELOG.md b/npm/vite-dev-server/CHANGELOG.md index e93fbc66cc52..d620302873cd 100644 --- a/npm/vite-dev-server/CHANGELOG.md +++ b/npm/vite-dev-server/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cypress/vite-dev-server-v2.2.0](https://github.com/cypress-io/cypress/compare/@cypress/vite-dev-server-v2.1.1...@cypress/vite-dev-server-v2.2.0) (2021-10-15) + + +### Features + +* normalized signatures webpack & vite servers ([#18379](https://github.com/cypress-io/cypress/issues/18379)) ([8f5308f](https://github.com/cypress-io/cypress/commit/8f5308f7068b80fb877da539ce34fb67ba497c4f)) + # [@cypress/vite-dev-server-v2.1.1](https://github.com/cypress-io/cypress/compare/@cypress/vite-dev-server-v2.1.0...@cypress/vite-dev-server-v2.1.1) (2021-10-04) 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/CHANGELOG.md b/npm/vue/CHANGELOG.md index 5bfa81a08a55..dd9b8dd160cb 100644 --- a/npm/vue/CHANGELOG.md +++ b/npm/vue/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cypress/vue-v3.0.4](https://github.com/cypress-io/cypress/compare/@cypress/vue-v3.0.3...@cypress/vue-v3.0.4) (2021-10-29) + + +### Bug Fixes + +* remove outdated registry link ([#18710](https://github.com/cypress-io/cypress/issues/18710)) ([e2a869d](https://github.com/cypress-io/cypress/commit/e2a869d2a984abb6703aec966dd9124ee693b8c1)) + # [@cypress/vue-v3.0.3](https://github.com/cypress-io/cypress/compare/@cypress/vue-v3.0.2...@cypress/vue-v3.0.3) (2021-07-31) 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/vue/package.json b/npm/vue/package.json index c97340958290..e609046a4664 100644 --- a/npm/vue/package.json +++ b/npm/vue/package.json @@ -103,7 +103,6 @@ } }, "publishConfig": { - "access": "public", - "registry": "http://registry.npmjs.org/" + "access": "public" } } diff --git a/npm/webpack-dev-server/CHANGELOG.md b/npm/webpack-dev-server/CHANGELOG.md index 93c0f5fe19ab..3e53a7f9c5ca 100644 --- a/npm/webpack-dev-server/CHANGELOG.md +++ b/npm/webpack-dev-server/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cypress/webpack-dev-server-v1.7.0](https://github.com/cypress-io/cypress/compare/@cypress/webpack-dev-server-v1.6.0...@cypress/webpack-dev-server-v1.7.0) (2021-10-15) + + +### Features + +* normalized signatures webpack & vite servers ([#18379](https://github.com/cypress-io/cypress/issues/18379)) ([8f5308f](https://github.com/cypress-io/cypress/commit/8f5308f7068b80fb877da539ce34fb67ba497c4f)) + # [@cypress/webpack-dev-server-v1.6.0](https://github.com/cypress-io/cypress/compare/@cypress/webpack-dev-server-v1.5.0...@cypress/webpack-dev-server-v1.6.0) (2021-09-10) 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/package.json b/package.json index 2c1effed7791..6d2549a9af10 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cypress", - "version": "8.6.0", + "version": "8.7.0", "description": "Cypress.io end to end testing tool", "private": true, "scripts": { @@ -114,7 +114,6 @@ "@types/mocha": "8.0.3", "@types/node": "14.14.31", "@types/prismjs": "1.16.0", - "@types/ramda": "0.25.47", "@types/react": "16.9.50", "@types/react-dom": "16.9.8", "@types/request-promise": "4.1.45", @@ -205,7 +204,6 @@ "pretty-ms": "7.0.0", "print-arch": "1.0.0", "proxyquire": "2.1.3", - "ramda": "0.27.1", "semantic-release": "17.2.3", "semantic-release-monorepo": "7.0.3", "semver": "7.3.2", 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/new-spec.spec.ts b/packages/app/cypress/e2e/integration/new-spec.spec.ts index a085872232f9..27d1a8beb7cf 100644 --- a/packages/app/cypress/e2e/integration/new-spec.spec.ts +++ b/packages/app/cypress/e2e/integration/new-spec.spec.ts @@ -33,17 +33,17 @@ describe('Button', () => { const { Primary } = composedStories mount() }) - + it('should render Secondary', () => { const { Secondary } = composedStories mount() }) - + it('should render Large', () => { const { Large } = composedStories mount() }) - + it('should render Small', () => { const { Small } = composedStories mount() @@ -54,7 +54,7 @@ import Button from "./Button" describe(' + class="absolute bottom-8px right-8px" + :text="code" + no-icon + /> @@ -98,13 +98,10 @@ export { highlighter, inheritAttrs } diff --git a/packages/frontend-shared/src/gql-components/HeaderBar.vue b/packages/frontend-shared/src/gql-components/HeaderBar.vue index dc3e25b1ad1f..ce5717f1a818 100644 --- a/packages/frontend-shared/src/gql-components/HeaderBar.vue +++ b/packages/frontend-shared/src/gql-components/HeaderBar.vue @@ -11,7 +11,6 @@ import { gql, useQuery } from '@urql/vue' import HeaderBarContent from './HeaderBarContent.vue' import { HeaderBar_HeaderBarQueryDocument } from '../generated/graphql' -import { useI18n } from '@cy/i18n' gql` query HeaderBar_HeaderBarQuery { @@ -24,8 +23,6 @@ const props = defineProps<{ pageName?: string }>() -const { t } = useI18n() - const query = useQuery({ query: HeaderBar_HeaderBarQueryDocument }) diff --git a/packages/frontend-shared/src/gql-components/HeaderBarContent.vue b/packages/frontend-shared/src/gql-components/HeaderBarContent.vue index 19c90d3f6723..cc5bb5171514 100644 --- a/packages/frontend-shared/src/gql-components/HeaderBarContent.vue +++ b/packages/frontend-shared/src/gql-components/HeaderBarContent.vue @@ -1,6 +1,6 @@