diff --git a/.circleci/cache-version.txt b/.circleci/cache-version.txt index c620bbdae266..9b6f1250fb50 100644 --- a/.circleci/cache-version.txt +++ b/.circleci/cache-version.txt @@ -1,3 +1,3 @@ # Bump this version to force CI to re-create the cache from scratch. -07-19-23 \ No newline at end of file +09-3-23 diff --git a/.circleci/workflows.yml b/.circleci/workflows.yml index 9359b05f9ba7..3400182b7dfd 100644 --- a/.circleci/workflows.yml +++ b/.circleci/workflows.yml @@ -29,8 +29,8 @@ mainBuildFilters: &mainBuildFilters - develop - /^release\/\d+\.\d+\.\d+$/ # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - - 'update-v8-snapshot-cache-on-develop' - - 'revert-runner' + - 'publish-binary' + - 'chore/update_electron25_and_node18' # usually we don't build Mac app - it takes a long time # but sometimes we want to really confirm we are doing the right thing @@ -41,7 +41,7 @@ macWorkflowFilters: &darwin-workflow-filters - equal: [ develop, << pipeline.git.branch >> ] # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ] - - equal: [ 'revert-runner', << pipeline.git.branch >> ] + - equal: [ 'chore/update_electron25_and_node18', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -51,8 +51,9 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters or: - equal: [ develop, << pipeline.git.branch >> ] # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - - equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ] - - equal: [ 'revert-runner', << pipeline.git.branch >> ] + - equal: [ 'jordanpowell88/update-angular-tsconfig-path', << pipeline.git.branch >> ] + - equal: [ 'publish-binary', << pipeline.git.branch >> ] + - equal: [ 'chore/update_electron25_and_node18', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -72,7 +73,7 @@ windowsWorkflowFilters: &windows-workflow-filters - equal: [ develop, << pipeline.git.branch >> ] # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ] - - equal: [ 'revert-runner', << pipeline.git.branch >> ] + - equal: [ 'chore/update_electron25_and_node18', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -81,7 +82,7 @@ executors: # the Docker image with Cypress dependencies and Chrome browser cy-doc: docker: - - image: cypress/browsers:node16.16.0-chrome106-ff99-edge + - image: cypress/browsers-internal:node18.15.0-chrome114-ff115 # by default, we use "medium" to balance performance + CI costs. bump or reduce on a per-job basis if needed. resource_class: medium environment: @@ -91,7 +92,7 @@ executors: # Docker image with non-root "node" user non-root-docker-user: docker: - - image: cypress/browsers:node16.16.0-chrome106-ff99-edge + - image: cypress/browsers-internal:node18.15.0-chrome114-ff115 user: node environment: PLATFORM: linux @@ -134,12 +135,24 @@ executors: DISABLE_SNAPSHOT_REQUIRE: 1 commands: + # This command inserts SHOULD_PERSIST_ARTIFACTS into BASH_ENV. This way, we can define the variable in one place and use it in multiple steps. + # Run this command in a job before you want to use the SHOULD_PERSIST_ARTIFACTS variable. + setup_should_persist_artifacts: + steps: + - run: + name: Set environment variable to determine whether or not to persist artifacts + command: | + echo "Setting SHOULD_PERSIST_ARTIFACTS variable" + echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "publish-binary" && "$CIRCLE_BRANCH" != "update-v8-snapshot-cache-on-develop" && "$CIRCLE_BRANCH" != "chore/update_electron25_and_node18" ]]; then + export SHOULD_PERSIST_ARTIFACTS=true + fi' >> "$BASH_ENV" + # You must run `setup_should_persist_artifacts` command and be using bash before running this command verify_should_persist_artifacts: steps: - run: name: Check current branch to persist artifacts command: | - if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "update-v8-snapshot-cache-on-develop" && "$CIRCLE_BRANCH" != "revert-runner" ]]; then + if [[ -z "$SHOULD_PERSIST_ARTIFACTS" ]]; then echo "Not uploading artifacts or posting install comment for this branch." circleci-agent step halt fi @@ -201,6 +214,7 @@ commands: command: | source ./scripts/ensure-node.sh yarn gulp buildProd + yarn gulp syncCloudValidations - run: name: Build packages command: | @@ -493,7 +507,7 @@ commands: # internal PR CYPRESS_RECORD_KEY=$MAIN_RECORD_KEY \ CYPRESS_INTERNAL_ENABLE_TELEMETRY="true" \ - yarn cypress:run --record --parallel --group 5x-driver-<> --browser <> + yarn cypress:run --record --parallel --group 5x-driver-<> --browser <> --runner-ui else # external PR TESTFILES=$(circleci tests glob "cypress/e2e/**/*.cy.*" | circleci tests split --total=$CIRCLE_NODE_TOTAL) @@ -502,7 +516,7 @@ commands: if [[ -z "$TESTFILES" ]]; then echo "Empty list of test files" fi - yarn cypress:run --browser <> --spec $TESTFILES + yarn cypress:run --browser <> --spec $TESTFILES --runner-ui fi working_directory: packages/driver - verify-mocha-results @@ -576,7 +590,7 @@ commands: if [[ <> == 'ct' ]]; then # component tests are located side by side with the source codes. # for the app component tests, ignore specs that are known to cause failures on contributor PRs (see https://discuss.circleci.com/t/how-to-exclude-certain-files-from-circleci-test-globbing/41028) - TESTFILES=$(find src -regextype posix-extended -name '*.cy.*' -not -regex '.*(FileMatch|PromoAction|SelectorPlayground).cy.*' | circleci tests split --total=$CIRCLE_NODE_TOTAL) + TESTFILES=$(find src -regextype posix-extended -name '*.cy.*' -not -regex '.*(FileMatch|PromoAction|SelectorPlayground|useDurationFormat|useTestingType|SpecPatterns).cy.*' | circleci tests split --total=$CIRCLE_NODE_TOTAL) else GLOB="cypress/e2e/**/*cy.*" TESTFILES=$(circleci tests glob "$GLOB" | circleci tests split --total=$CIRCLE_NODE_TOTAL) @@ -673,14 +687,21 @@ commands: path: ~/.npm/_logs post-install-comment: + parameters: + package_url_path: + type: string + default: npm-package-url.json + binary_url_path: + type: string + default: binary-url.json description: Post GitHub comment with a blurb on how to install pre-release version steps: - run: name: Post pre-release install comment command: | node scripts/add-install-comment.js \ - --npm npm-package-url.json \ - --binary binary-url.json + --npm << parameters.package_url_path >> \ + --binary << parameters.binary_url_path >> verify-mocha-results: description: Double-check that Mocha tests ran as expected. @@ -718,7 +739,7 @@ commands: cd ~/cypress/.. # install some deps for get-next-version - npm i semver@7.3.2 conventional-recommended-bump@6.1.0 conventional-changelog-angular@5.0.12 + npm i semver@7.3.2 conventional-recommended-bump@6.1.0 conventional-changelog-angular@5.0.12 minimist@1.2.5 NEXT_VERSION=$(node ./cypress/scripts/get-next-version.js) cd - @@ -803,13 +824,10 @@ commands: working_directory: /tmp/<> command: yarn types - run: + # NOTE: we do not need to wait for the vite dev server to start working_directory: /tmp/<> command: <> background: true - - run: - condition: <> - name: "Waiting on server to boot: <>" - command: "npx wait-on <>" - when: condition: <> steps: @@ -1028,6 +1046,33 @@ commands: command: node ./scripts/wait-on-circle-jobs.js --job-names="<>" build-binary: + steps: + - run: + name: Build the Cypress binary + no_output_timeout: "45m" + command: | + source ./scripts/ensure-node.sh + node --version + if [[ `node ./scripts/get-platform-key.js` == 'linux-arm64' ]]; then + # these are missing on Circle and there is no way to pre-install them on Arm + sudo apt-get update + sudo apt-get install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb + DISABLE_SNAPSHOT_REQUIRE=1 yarn binary-build --version $(node ./scripts/get-next-version.js) --createTar + else + yarn binary-build --version $(node ./scripts/get-next-version.js) --createTar + fi + - store_artifacts: + path: cypress-dist.tgz + + check-if-binary-exists: + steps: + - run: + name: Check if binary exists, exit if it does + command: | + source ./scripts/ensure-node.sh + yarn check-binary-on-cdn --version $(node ./scripts/get-next-version.js) --type binary --file cypress.zip + + build-and-package-binary: steps: - run: name: Check environment variables before code sign (if on Mac/Windows) @@ -1060,9 +1105,6 @@ commands: fi - run: name: Build the Cypress binary - environment: - DEBUG: electron-builder,electron-osx-sign* - # notarization on Mac can take a while no_output_timeout: "45m" command: | source ./scripts/ensure-node.sh @@ -1075,6 +1117,23 @@ commands: else yarn binary-build --version $(node ./scripts/get-next-version.js) fi + - run: + name: Package the Cypress binary + environment: + DEBUG: electron-builder,electron-osx-sign*,electron-notarize* + # notarization on Mac can take a while + no_output_timeout: "45m" + command: | + source ./scripts/ensure-node.sh + node --version + if [[ `node ./scripts/get-platform-key.js` == 'linux-arm64' ]]; then + # these are missing on Circle and there is no way to pre-install them on Arm + sudo apt-get update + sudo apt-get install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb + DISABLE_SNAPSHOT_REQUIRE=1 yarn binary-package --version $(node ./scripts/get-next-version.js) + else + yarn binary-package --version $(node ./scripts/get-next-version.js) + fi - run: name: Zip the binary command: | @@ -1094,6 +1153,19 @@ commands: paths: - cypress/cypress.zip + trigger-publish-binary-pipeline: + steps: + - run: + name: "Trigger publish-binary pipeline" + command: | + source ./scripts/ensure-node.sh + echo $SHOULD_PERSIST_ARTIFACTS + node ./scripts/binary/trigger-publish-binary-pipeline.js + - persist_to_workspace: + root: ~/ + paths: + - triggered_pipeline.json + build-cypress-npm-package: parameters: executor: @@ -1250,7 +1322,7 @@ jobs: - install-required-node - run: name: Check TS Types - command: NODE_OPTIONS=--max_old_space_size=4096 yarn gulp checkTs + command: NODE_OPTIONS=--max_old_space_size=4096 yarn check-ts --concurrency=1 # a special job that keeps polling Circle and when all @@ -1491,10 +1563,6 @@ jobs: - run: name: "Lint types 🧹" command: yarn workspace cypress dtslint - # todo(lachlan): do we need this? yarn check-ts does something very similar - # - run: - # name: "TypeScript check 🧩" - # command: yarn type-check --ignore-progress - store-npm-logs server-unit-tests: @@ -1775,7 +1843,7 @@ jobs: PERCY_ENABLE=${PERCY_TOKEN:-0} \ PERCY_PARALLEL_TOTAL=-1 \ yarn percy exec --parallel -- -- \ - yarn cypress:run --record --parallel --group reporter + yarn cypress:run --record --parallel --group reporter --runner-ui working_directory: packages/reporter - verify-mocha-results - store_test_results: @@ -1879,11 +1947,7 @@ jobs: - restore_cached_workspace - run: name: Build - command: yarn workspace @cypress/vue build - - run: - name: Type Check - command: yarn typecheck - working_directory: npm/vue + command: yarn lerna run build --scope @cypress/vue - store_test_results: path: npm/vue/test_results - store_artifacts: @@ -2006,13 +2070,64 @@ jobs: resource_class: << parameters.resource_class >> steps: - restore_cached_workspace - - build-binary + - check-if-binary-exists + - build-and-package-binary - build-cypress-npm-package: executor: << parameters.executor >> + - setup_should_persist_artifacts - verify_should_persist_artifacts - upload-build-artifacts - post-install-comment + create-and-trigger-packaging-artifacts: + <<: *defaults + parameters: + <<: *defaultsParameters + resource_class: + type: string + default: xlarge + resource_class: << parameters.resource_class >> + steps: + - restore_cached_workspace + - check-if-binary-exists + - setup_should_persist_artifacts + - build-binary + - trigger-publish-binary-pipeline + + get-published-artifacts: + <<: *defaults + parameters: + <<: *defaultsParameters + resource_class: + type: string + default: large + resource_class: << parameters.resource_class >> + steps: + - restore_cached_workspace + - run: + name: Check pipeline info + command: cat ~/triggered_pipeline.json + - setup_should_persist_artifacts + - run: + name: Download binary artifacts + command: | + source ./scripts/ensure-node.sh + node ./scripts/binary/get-published-artifacts.js --pipelineInfo ~/triggered_pipeline.json --platformKey $(node ./scripts/get-platform-key.js) + - persist_to_workspace: + root: ~/ + paths: + - cypress/cypress.zip + - cypress/cypress.tgz + - verify_should_persist_artifacts + - persist_to_workspace: + root: ~/ + paths: + - cypress/binary-url.json + - cypress/npm-package-url.json + - post-install-comment: + package_url_path: ~/cypress/npm-package-url.json + binary_url_path: ~/cypress/binary-url.json + test-kitchensink: <<: *defaults parameters: @@ -2069,7 +2184,6 @@ jobs: CYPRESS_PROJECT_ID=$TEST_KITCHENSINK_PROJECT_ID \ CYPRESS_RECORD_KEY=$TEST_KITCHENSINK_RECORD_KEY \ CYPRESS_INTERNAL_ENV=staging \ - CYPRESS_video=false \ yarn cypress:run --project /tmp/cypress-example-kitchensink --record - store-npm-logs @@ -2128,7 +2242,7 @@ jobs: <<: *defaults resource_class: small docker: - - image: cypress/base:12.0.0-libgbm + - image: cypress/base-internal:18.15.0 steps: - restore_workspace_binaries - run: mkdir test-binary @@ -2143,15 +2257,15 @@ jobs: - run: name: Verify Cypress binary working_directory: test-binary - command: $(npm bin)/cypress verify + command: npx cypress verify - run: name: Print Cypress version working_directory: test-binary - command: $(npm bin)/cypress version + command: npx cypress version - run: name: Cypress info working_directory: test-binary - command: $(npm bin)/cypress info + command: npx cypress info test-types-cypress-and-jest: parameters: @@ -2255,6 +2369,7 @@ jobs: - test-binary-against-repo: repo: cypress-example-recipes command: npm run test:ci:firefox + browser: firefox test-binary-against-recipes-chrome: <<: *defaults @@ -2262,6 +2377,7 @@ jobs: - test-binary-against-repo: repo: cypress-example-recipes command: npm run test:ci:chrome + browser: chrome test-binary-against-recipes: <<: *defaults @@ -2269,6 +2385,7 @@ jobs: - test-binary-against-repo: repo: cypress-example-recipes command: npm run test:ci + browser: electron # This is a special job. It allows you to test the current # built test runner against a pull request in the repo @@ -2296,7 +2413,7 @@ jobs: steps: - test-binary-against-repo: repo: cypress-example-kitchensink - browser: "electron" + browser: electron test-binary-against-kitchensink-firefox: <<: *defaults @@ -2676,13 +2793,23 @@ linux-x64-workflow: &linux-x64-workflow - run-vite-dev-server-integration-tests - v8-integration-tests - - create-build-artifacts: + - create-and-trigger-packaging-artifacts: context: - test-runner:upload - - test-runner:commit-status-checks - test-runner:build-binary + - publish-binary requires: - build + - wait-for-binary-publish: + type: approval + requires: + - create-and-trigger-packaging-artifacts + - get-published-artifacts: + context: + - publish-binary + - test-runner:commit-status-checks + requires: + - wait-for-binary-publish # various testing scenarios, like building full binary # and testing it on a real project - test-against-staging: @@ -2700,66 +2827,66 @@ linux-x64-workflow: &linux-x64-workflow - build - test-npm-module-on-minimum-node-version: requires: - - create-build-artifacts + - get-published-artifacts - test-types-cypress-and-jest: requires: - - create-build-artifacts + - get-published-artifacts - test-full-typescript-project: requires: - - create-build-artifacts + - get-published-artifacts - test-binary-against-kitchensink: requires: - - create-build-artifacts + - get-published-artifacts - test-npm-module-and-verify-binary: <<: *mainBuildFilters requires: - - create-build-artifacts + - get-published-artifacts - test-binary-against-staging: context: test-runner:record-tests <<: *mainBuildFilters requires: - - create-build-artifacts + - get-published-artifacts - test-binary-against-kitchensink-chrome: <<: *mainBuildFilters requires: - - create-build-artifacts + - get-published-artifacts - test-binary-against-recipes-firefox: <<: *mainBuildFilters requires: - - create-build-artifacts + - get-published-artifacts - test-binary-against-recipes-chrome: <<: *mainBuildFilters requires: - - create-build-artifacts + - get-published-artifacts - test-binary-against-recipes: <<: *mainBuildFilters requires: - - create-build-artifacts + - get-published-artifacts - test-binary-against-kitchensink-firefox: <<: *mainBuildFilters requires: - - create-build-artifacts + - get-published-artifacts - test-binary-against-todomvc-firefox: <<: *mainBuildFilters requires: - - create-build-artifacts + - get-published-artifacts - test-binary-against-cypress-realworld-app: context: test-runner:cypress-record-key <<: *mainBuildFilters requires: - - create-build-artifacts + - get-published-artifacts - test-binary-as-specific-user: name: "test binary as a non-root user" executor: non-root-docker-user requires: - - create-build-artifacts + - get-published-artifacts - test-binary-as-specific-user: name: "test binary as a root user" requires: - - create-build-artifacts + - get-published-artifacts - binary-system-tests: requires: - - create-build-artifacts + - get-published-artifacts - system-tests-node-modules-install linux-arm64-workflow: &linux-arm64-workflow @@ -2777,17 +2904,34 @@ linux-arm64-workflow: &linux-arm64-workflow requires: - linux-arm64-node-modules-install - - create-build-artifacts: - name: linux-arm64-create-build-artifacts + - create-and-trigger-packaging-artifacts: + name: linux-arm64-create-and-trigger-packaging-artifacts context: - test-runner:upload - test-runner:commit-status-checks - test-runner:build-binary + - publish-binary executor: linux-arm64 resource_class: arm.medium requires: - linux-arm64-build + - wait-for-binary-publish: + name: linux-arm64-wait-for-binary-publish + type: approval + requires: + - linux-arm64-create-and-trigger-packaging-artifacts + + - get-published-artifacts: + name: linux-arm64-get-published-artifacts + context: + - publish-binary + - test-runner:commit-status-checks + executor: linux-arm64 + resource_class: arm.medium + requires: + - linux-arm64-wait-for-binary-publish + - v8-integration-tests: name: linux-arm64-v8-integration-tests executor: linux-arm64 @@ -2963,6 +3107,7 @@ windows-workflow: &windows-workflow - test-runner:build-binary requires: - windows-build + - test-binary-against-kitchensink-chrome: name: windows-test-binary-against-kitchensink-chrome executor: windows diff --git a/.eslintrc.js b/.eslintrc.js index 12aa005137ac..0f6bc16d6bd2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -40,6 +40,8 @@ module.exports = { 'cli/types/**', // these fixtures are supposed to fail linting 'npm/eslint-plugin-dev/test/fixtures/**', + // Cloud generated + 'system-tests/lib/validations/**', ], overrides: [ { diff --git a/.gitattributes b/.gitattributes index 86f60e7ec9b9..4a597b0345e7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,4 +4,5 @@ **/.eslintrc text eol=lf -packages/errors/__snapshot-html__/** linguist-generated=true \ No newline at end of file +packages/errors/__snapshot-html__/** linguist-generated=true +system-tests/lib/validations/** linguist-generated=true \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000000..21255064a7d7 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,5 @@ +# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners +# +# Changes to the Module API, after:run, or after:spec results should be +# reviewed by Brian and/or Jennifer +/system-tests/__snapshots__/results_spec.ts.js @brian-mann @jennifer-shehane diff --git a/.github/ISSUE_TEMPLATE/1-bug-report.yml b/.github/ISSUE_TEMPLATE/1-bug-report.yml index 17f8f2feee6a..20a8945f0063 100644 --- a/.github/ISSUE_TEMPLATE/1-bug-report.yml +++ b/.github/ISSUE_TEMPLATE/1-bug-report.yml @@ -43,7 +43,7 @@ body: attributes: label: Node version description: What version of node.js are you using to run Cypress? - placeholder: ex. v16.16.0 + placeholder: ex. v18.15.0 validations: required: true - type: input diff --git a/.github/ISSUE_TEMPLATE/2-memory-issue.yml b/.github/ISSUE_TEMPLATE/2-memory-issue.yml index 485381b5dfe4..b827f20ea293 100644 --- a/.github/ISSUE_TEMPLATE/2-memory-issue.yml +++ b/.github/ISSUE_TEMPLATE/2-memory-issue.yml @@ -51,7 +51,7 @@ body: attributes: label: Node version description: What version of node.js are you using to run Cypress? - placeholder: ex. v16.16.0 + placeholder: ex. v18.15.0 validations: required: true - type: input diff --git a/.github/ISSUE_TEMPLATE/3-install-issue.yml b/.github/ISSUE_TEMPLATE/3-install-issue.yml index 35f657501629..bc373cdfdac2 100644 --- a/.github/ISSUE_TEMPLATE/3-install-issue.yml +++ b/.github/ISSUE_TEMPLATE/3-install-issue.yml @@ -38,7 +38,7 @@ body: attributes: label: Node version description: What version of node.js are you using to run Cypress? - placeholder: ex. v16.16.0 + placeholder: ex. v18.15.0 validations: required: true - type: dropdown diff --git a/.github/workflows/report_weekly_app_kpis.yml b/.github/workflows/report_weekly_app_kpis.yml index be4b097af066..de727b058be5 100644 --- a/.github/workflows/report_weekly_app_kpis.yml +++ b/.github/workflows/report_weekly_app_kpis.yml @@ -84,6 +84,30 @@ jobs: script: | const script = require('./scripts/reports/triage_mitigation_kpis.js') await script.getIssueMitigationMetrics(github, context, core, "${{ env.START_DATE }}", "${{ env.END_DATE }}", "${{ env.PROJECT_BOARD_NUMBER }}"); + - name: Generate Feature Request KPIs + id: feature-metrics + uses: actions/github-script@v6 + env: + START_DATE: ${{ github.event.inputs.start-date }} + END_DATE: ${{ github.event.inputs.end-date }} + PROJECT_BOARD_NUMBER: 9 + with: + github-token: ${{ secrets.TRIAGE_BOARD_TOKEN }} + script: | + const script = require('./scripts/reports/triage_feature_requests_metrics.js') + await script.getFeatureRequestMetrics(github, context, core, "${{ env.START_DATE }}", "${{ env.END_DATE }}", "${{ env.PROJECT_BOARD_NUMBER }}"); + - name: Generate Feature Review KPIs + id: feature-review-metrics + uses: actions/github-script@v6 + env: + START_DATE: ${{ github.event.inputs.start-date }} + END_DATE: ${{ github.event.inputs.end-date }} + PROJECT_BOARD_NUMBER: 9 + with: + github-token: ${{ secrets.TRIAGE_BOARD_TOKEN }} + script: | + const script = require('./scripts/reports/triage_feature_review_metrics.js') + await script.getFeatureReviewMetrics(github, context, core, "${{ env.START_DATE }}", "${{ env.END_DATE }}", "${{ env.PROJECT_BOARD_NUMBER }}"); - name: Generate KPI Report id: generate-report uses: actions/github-script@v6 @@ -95,5 +119,5 @@ jobs: github-token: ${{ secrets.TRIAGE_BOARD_TOKEN }} script: | const script = require('./scripts/reports/generate_kpi_report.js') - await script.generateKPIReport(github, context, core, ${{ steps.non-mono-repo-open-closed-metrics.outputs.results }}, ${{ steps.mono-repo-open-closed-metrics.outputs.results }}, ${{ steps.triage-metrics.outputs.results }}, ${{ steps.mitigation-metrics.outputs.results }} ); + await script.generateKPIReport(github, context, core, ${{ steps.non-mono-repo-open-closed-metrics.outputs.results }}, ${{ steps.mono-repo-open-closed-metrics.outputs.results }}, ${{ steps.triage-metrics.outputs.results }}, ${{ steps.mitigation-metrics.outputs.results }}, ${{ steps.feature-metrics.outputs.results }}, ${{ steps.feature-review-metrics.outputs.results }} ); \ No newline at end of file diff --git a/.github/workflows/snyk_sca_scan.yaml b/.github/workflows/snyk_sca_scan.yaml index 1aa7fcfb5410..eb2c591908e0 100644 --- a/.github/workflows/snyk_sca_scan.yaml +++ b/.github/workflows/snyk_sca_scan.yaml @@ -1,32 +1,43 @@ name: Snyk Software Composition Analysis Scan -# This git workflow leverages Snyk actions to perform a Software Composition +# This git workflow leverages Snyk actions to perform a Software Composition # Analysis scan on our Opensource libraries upon Pull Requests to the -# "develop" branch. We use this as a control to prevent vulnerable packages -# from being introduced into the codebase. +# "develop" branch. We use this as a control to prevent vulnerable packages +# from being introduced into the codebase. +# Enhancements were made to this action to build the yarn packages to reduce +# Snyk scan errors that were complaining about the yarn.locks etc. Also +# implemented PAT token for actions to resolve an issue with the action not +# running and reporting back to the PR status checks on: - pull_request_target: - types: - - opened - branches: + pull_request: + branches: - develop jobs: Snyk_SCA_Scan: runs-on: ubuntu-latest strategy: matrix: - node-version: [16.x] + node-version: [18.x] steps: - - uses: actions/checkout@v3 - - name: Setting up Node + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + token: ${{ secrets.BOT_GITHUB_ACTION_TOKEN }} + - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: ${{ matrix.node-version }} + node-version: 18 + cache: 'yarn' + - name: Run yarn + run: yarn + - name: Run build + run: yarn build - name: Installing snyk-delta and dependencies run: npm i -g snyk-delta - uses: snyk/actions/setup@master - name: Perform SCA Scan continue-on-error: false run: | - snyk test --all-projects --strict-out-of-sync=false --detection-depth=6 --exclude=docker,Dockerfile --severity-threshold=critical + snyk test --all-projects --strict-out-of-sync=false --detection-depth=6 --exclude=system-tests,tooling,docker,Dockerfile --severity-threshold=critical env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} diff --git a/.github/workflows/snyk_static_analysis_scan.yaml b/.github/workflows/snyk_static_analysis_scan.yaml index d32553086d01..bf33e1f65e98 100644 --- a/.github/workflows/snyk_static_analysis_scan.yaml +++ b/.github/workflows/snyk_static_analysis_scan.yaml @@ -1,19 +1,30 @@ name: Snyk Static Analysis Scan -# This git workflow leverages Snyk actions to perform a Static Application +# This git workflow leverages Snyk actions to perform a Static Application # Testing scan (SAST) on our first-party code upon Pull Requests to the -# "develop" branch. We use this as a control to prevent vulnerabilities -# from being introduced into the codebase. +# "develop" branch. We use this as a control to prevent vulnerabilities +# from being introduced into the codebase. on: - pull_request_target: - types: - - opened - branches: + pull_request: + branches: - develop jobs: Snyk_SAST_Scan : runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + token: ${{ secrets.BOT_GITHUB_ACTION_TOKEN }} + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: 'yarn' + - name: Run yarn + run: yarn + - name: Run build + run: yarn build - uses: snyk/actions/setup@master - name: Perform Static Analysis Test continue-on-error: true diff --git a/.github/workflows/update-browser-versions.yml b/.github/workflows/update-browser-versions.yml index be0e08ad3f5e..1f13316f7731 100644 --- a/.github/workflows/update-browser-versions.yml +++ b/.github/workflows/update-browser-versions.yml @@ -1,5 +1,7 @@ name: Update Browser Versions on: + workflow_dispatch: + schedule: - cron: '0 8 * * *' # every day at 8am UTC (3/4am EST/EDT) jobs: @@ -26,7 +28,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 18 - name: Check for new Chrome versions id: get-versions uses: actions/github-script@v6 @@ -104,6 +106,7 @@ jobs: }) # Update available and a PR doesn't already exist - name: Create Pull Request + id: create-pr if: ${{ steps.check-need-for-pr.outputs.needs_pr == 'true' }} uses: actions/github-script@v6 with: @@ -117,4 +120,5 @@ jobs: branchName: '${{ steps.check-branch.outputs.branch_name }}', description: '${{ steps.get-versions.outputs.description }}', body: 'This PR was auto-generated to update the version(s) of Chrome for driver tests', + addToProjectBoard: true, }) diff --git a/.github/workflows/update_v8_snapshot_cache.yml b/.github/workflows/update_v8_snapshot_cache.yml index 61f06d52a336..f2a9572a2a02 100644 --- a/.github/workflows/update_v8_snapshot_cache.yml +++ b/.github/workflows/update_v8_snapshot_cache.yml @@ -62,7 +62,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: 'yarn' - name: Run yarn run: yarn diff --git a/.gitignore b/.gitignore index f67b890a1140..b6583eab0c39 100644 --- a/.gitignore +++ b/.gitignore @@ -395,3 +395,6 @@ tooling/v8-snapshot/cache/dev-win32 tooling/v8-snapshot/cache/prod-darwin tooling/v8-snapshot/cache/prod-linux tooling/v8-snapshot/cache/prod-win32 + +# Cloud API validations +system-tests/lib/validations diff --git a/.node-version b/.node-version index 431076a9486e..55bffd620b9a 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -16.16.0 +18.15.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8db01d52f313..3f562577b436 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -163,7 +163,7 @@ Here is a list of the core packages in this repository with a short description, | [socket](./packages/socket) | `@packages/socket` | A wrapper around socket.io to provide common libraries. | | [ts](./packages/ts) | `@packages/ts` | A centralized version of typescript. | | [types](./packages/types) | `@packages/types` | The shared internal Cypress types. | - | [v8-snapshot-require](./packages/v8-snapshot-require) | `@packages/v8-snapshot-requie` | Tool to load a snapshot for Electron applications that was created by `@tooling/v8-snapshot`. | + | [v8-snapshot-require](./packages/v8-snapshot-require) | `@packages/v8-snapshot-require` | Tool to load a snapshot for Electron applications that was created by `@tooling/v8-snapshot`. | | [web-config](./packages/web-config) | `@packages/web-config` | The web-related configuration. | Private packages involved in development of the app live within the [`tooling`](./tooling) directory and are in the `@tooling/` namespace. They are discrete modules with different responsibilities, but each is necessary for development of the Cypress app and is not necessarily useful outside of the Cypress app. @@ -428,7 +428,7 @@ The repository has one protected branch: We want to publish our [standalone npm packages](./npm) continuously as new features are added. Therefore, after any pull request that changes independent `@cypress/` packages in the [`npm`](./npm) directory will automatically publish when a PR is merged directly into `develop` and the entire build passes. We used [`semantic-release`](https://semantic-release.gitbook.io/semantic-release/) to automate the release of these packages to npm. -We do not continuously deploy the Cypress binary, so `develop` contains all of the new features and fixes that are staged to go out in the next update of the main Cypress app. If you make changes to an npm package that can't be published until the binary is also updated, you should make a pull request against specifying this is not be merged until the scheduled Cypress app release date. +We do not continuously deploy the Cypress binary, so `develop` contains all of the new features and fixes that are staged to go out in the next update of the main Cypress app. If you make changes to an npm package that can't be published until the binary is also updated, the pull request should clearly state that it should not be merged until the next scheduled Cypress app release date. ### Pull Requests diff --git a/LICENSE b/LICENSE index 22d286996ac5..c7379e8b1d09 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Cypress.io +Copyright (c) 2023 Cypress.io Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 9867193933f2..aeaf893644ae 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,11 @@

Fast, easy and reliable testing for anything that runs in a browser.

+

+ + Cypress Conf Link + +

Join us, we're hiring.

diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index b3881e9bf717..6418a505b6e8 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -1,7 +1,113 @@ +## 13.3.0 + +_Released 09/19/2023 (PENDING)_ + +**Features:** + + - Introduces new layout for Runs page providing additional run information. Addresses [#27203](https://github.com/cypress-io/cypress/issues/27203). + +## 13.2.0 + +_Released 09/12/2023_ + +**Features:** + + - Adds support for Nx users who want to run Angular Component Testing in parallel. Addressed in [#27723](https://github.com/cypress-io/cypress/pull/27723). + +**Bugfixes:** + +- Edge cases where `cy.intercept()` would not properly intercept and asset response bodies would not properly be captured for test replay have been addressed. Addressed in [#27771](https://github.com/cypress-io/cypress/pull/27771). +- Fixed an issue where `enter`, `keyup`, and `space` events were not triggering `click` events properly in some versions of Firefox. Addressed in [#27715](https://github.com/cypress-io/cypress/pull/27715). +- Fixed a regression in `13.0.0` where tests using Basic Authorization can potentially hang indefinitely on chromium browsers. Addressed in [#27781](https://github.com/cypress-io/cypress/pull/27781). +- Fixed a regression in `13.0.0` where component tests using an intercept that matches all requests can potentially hang indefinitely. Addressed in [#27788](https://github.com/cypress-io/cypress/pull/27788). + +**Dependency Updates:** + +- Upgraded Electron from `21.0.0` to `25.8.0`, which updates bundled Chromium from `106.0.5249.51` to `114.0.5735.289`. Additionally, the Node version binary has been upgraded from `16.16.0` to `18.15.0`. This does **NOT** have an impact on the node version you are using with Cypress and is merely an internal update to the repository & shipped binary. Addressed in [#27715](https://github.com/cypress-io/cypress/pull/27715). Addresses [#27595](https://github.com/cypress-io/cypress/issues/27595). + +## 13.1.0 + +_Released 08/31/2023_ + +**Features:** + + - Introduces a status icon representing the `latest` test run in the Sidebar for the Runs Page. Addresses [#27206](https://github.com/cypress-io/cypress/issues/27206). + +**Bugfixes:** + +- Fixed a regression introduced in Cypress [13.0.0](#13-0-0) where the [Module API](https://docs.cypress.io/guides/guides/module-api), [`after:run`](https://docs.cypress.io/api/plugins/after-run-api), and [`after:spec`](https://docs.cypress.io/api/plugins/after-spec-api) results did not include the `stats.skipped` field for each run result. Fixes [#27694](https://github.com/cypress-io/cypress/issues/27694). Addressed in [#27695](https://github.com/cypress-io/cypress/pull/27695). +- Individual CDP errors that occur while capturing data for test replay will no longer prevent the entire run from being available. Addressed in [#27709](https://github.com/cypress-io/cypress/pull/27709). +- Fixed an issue where the release date on the `v13` landing page was a day behind. Fixed in [#27711](https://github.com/cypress-io/cypress/pull/27711). +- Fixed an issue where fatal protocol errors would leak between specs causing all subsequent specs to fail to upload protocol information. Fixed in [#27720](https://github.com/cypress-io/cypress/pull/27720) +- Updated `plist` from `3.0.6` to `3.1.0` to address [CVE-2022-37616](https://github.com/advisories/GHSA-9pgh-qqpf-7wqj) and [CVE-2022-39353](https://github.com/advisories/GHSA-crh6-fp67-6883). Fixed in [#27710](https://github.com/cypress-io/cypress/pull/27710). + +## 13.0.0 + +_Released 08/29/2023_ + +**Breaking Changes:** + +- The [`video`](https://docs.cypress.io/guides/references/configuration#Videos) configuration option now defaults to `false`. Addresses [#26157](https://github.com/cypress-io/cypress/issues/26157). +- The [`videoCompression`](https://docs.cypress.io/guides/references/configuration#Videos) configuration option now defaults to `false`. Addresses [#26160](https://github.com/cypress-io/cypress/issues/26160). +- The [`videoUploadOnPasses`](https://docs.cypress.io/guides/references/configuration#Videos) configuration option has been removed. Please see our [screenshots & videos guide](https://docs.cypress.io/guides/guides/screenshots-and-videos#Delete-videos-for-specs-without-failing-or-retried-tests) on how to accomplish similar functionality. Addresses [#26899](https://github.com/cypress-io/cypress/issues/26899). +- Requests for assets at relative paths for component testing are now correctly forwarded to the dev server. Fixes [#26725](https://github.com/cypress-io/cypress/issues/26725). +- The [`cy.readFile()`](/api/commands/readfile) command is now retry-able as a [query command](https://on.cypress.io/retry-ability). This should not affect any tests using it; the functionality is unchanged. However, it can no longer be overwritten using [`Cypress.Commands.overwrite()`](/api/cypress-api/custom-commands#Overwrite-Existing-Commands). Addressed in [#25595](https://github.com/cypress-io/cypress/pull/25595). +- The current spec path is now passed from the AUT iframe using a query parameter rather than a path segment. This allows for requests for assets at relative paths to be correctly forwarded to the dev server. Fixes [#26725](https://github.com/cypress-io/cypress/issues/26725). +- The deprecated configuration option `nodeVersion` has been removed. Addresses [#27016](https://github.com/cypress-io/cypress/issues/27016). +- The properties and values returned by the [Module API](https://docs.cypress.io/guides/guides/module-api) and included in the arguments of handlers for the [`after:run`](https://docs.cypress.io/api/plugins/after-run-api) and [`after:spec`](https://docs.cypress.io/api/plugins/after-spec-api) have been changed to be more consistent. Addresses [#23805](https://github.com/cypress-io/cypress/issues/23805). +- For Cypress Cloud runs with Test Replay enabled, the Cypress Runner UI is now hidden during the run since the Runner will be visible during Test Replay. As such, if video is recorded (which is now defaulted to `false`) during the run, the Runner will not be visible. In addition, if a runner screenshot (`cy.screenshot({ capture: runner })`) is captured, it will no longer contain the Runner. +- The browser and browser page unexpectedly closing in the middle of a test run are now gracefully handled. Addressed in [#27592](https://github.com/cypress-io/cypress/issues/27592). +- Automation performance is now improved by switching away from websockets to direct CDP calls for Chrome and Electron browsers. Addressed in [#27592](https://github.com/cypress-io/cypress/issues/27592). +- Edge cases where `cy.intercept()` would not properly intercept have been addressed. Addressed in [#27592](https://github.com/cypress-io/cypress/issues/27592). +- Node 14 support has been removed and Node 16 support has been deprecated. Node 16 may continue to work with Cypress `v13`, but will not be supported moving forward to closer coincide with [Node 16's end-of-life](https://nodejs.org/en/blog/announcements/nodejs16-eol) schedule. It is recommended that users update to at least Node 18. +- The minimum supported Typescript version is `4.x`. + +**Features:** + +- Consolidates and improves terminal output when uploading test artifacts to Cypress Cloud. Addressed in [#27402](https://github.com/cypress-io/cypress/pull/27402) + +**Bugfixes:** + +- Fixed an issue where Cypress's internal `tsconfig` would conflict with properties set in the user's `tsconfig.json` such as `module` and `moduleResolution`. Fixes [#26308](https://github.com/cypress-io/cypress/issues/26308) and [#27448](https://github.com/cypress-io/cypress/issues/27448). +- Clarified Svelte 4 works correctly with Component Testing and updated dependencies checks to reflect this. It was incorrectly flagged as not supported. Fixes [#27465](https://github.com/cypress-io/cypress/issues/27465). +- Resolve the `process/browser` global inside `@cypress/webpack-batteries-included-preprocessor` to resolve to `process/browser.js` in order to explicitly provide the file extension. File resolution must include the extension for `.mjs` and `.js` files inside ESM packages in order to resolve correctly. Fixes[#27599](https://github.com/cypress-io/cypress/issues/27599). +- Fixed an issue where the correct `pnp` process was not being discovered. Fixes [#27562](https://github.com/cypress-io/cypress/issues/27562). +- Fixed incorrect type declarations for Cypress and Chai globals that asserted them to be local variables of the global scope rather than properties on the global object. Fixes [#27539](https://github.com/cypress-io/cypress/issues/27539). Fixed in [#27540](https://github.com/cypress-io/cypress/pull/27540). +- Dev Servers will now respect and use the `port` configuration option if present. Fixes [#27675](https://github.com/cypress-io/cypress/issues/27675). + +**Dependency Updates:** + +- Upgraded [`@cypress/request`](https://www.npmjs.com/package/@cypress/request) from `^2.88.11` to `^3.0.0` to address the [CVE-2023-28155](https://github.com/advisories/GHSA-p8p7-x288-28g6) security vulnerability. Addresses [#27535](https://github.com/cypress-io/cypress/issues/27535). Addressed in [#27495](https://github.com/cypress-io/cypress/pull/27495). + +## 12.17.4 + +_Released 08/15/2023_ + +**Bugfixes:** + +- Fixed an issue where having `cypress.config` in a nested directory would cause problems with locating the `component-index.html` file when using component testing. Fixes [#26400](https://github.com/cypress-io/cypress/issues/26400). + +**Dependency Updates:** + +- Upgraded [`webpack`](https://www.npmjs.com/package/webpack) from `v4` to `v5`. This means that we are now bundling your `e2e` tests with webpack 5. We don't anticipate this causing any noticeable changes. However, if you'd like to keep bundling your `e2e` tests with wepback 4 you can use the same process as before by pinning [@cypress/webpack-batteries-included-preprocessor](https://www.npmjs.com/package/@cypress/webpack-batteries-included-preprocessor) to `v2.x.x` and hooking into the [file:preprocessor](https://docs.cypress.io/api/plugins/preprocessors-api#Usage) plugin event. This will restore the previous bundling process. Additionally, if you're using [@cypress/webpack-batteries-included-preprocessor](https://www.npmjs.com/package/@cypress/webpack-batteries-included-preprocessor) already, a new version has been published to support webpack `v5`. +- Upgraded [`tough-cookie`](https://www.npmjs.com/package/tough-cookie) from `4.0` to `4.1.3`, [`@cypress/request`](https://www.npmjs.com/package/@cypress/request) from `2.88.11` to `2.88.12` and [`@cypress/request-promise`](https://www.npmjs.com/package/@cypress/request-promise) from `4.2.6` to `4.2.7` to address a [security vulnerability](https://security.snyk.io/vuln/SNYK-JS-TOUGHCOOKIE-5672873). Fixes [#27261](https://github.com/cypress-io/cypress/issues/27261). + +## 12.17.3 + +_Released 08/01/2023_ + +**Bugfixes:** + +- Fixed an issue where unexpected branch names were being recorded for cypress runs when executed by GitHub Actions. The HEAD branch name will now be recorded by default for pull request workflows if a branch name cannot otherwise be detected from user overrides or from local git data. Fixes [#27389](https://github.com/cypress-io/cypress/issues/27389). + +**Performance:** + +- Fixed an issue where unnecessary requests were being paused. No longer sends `X-Cypress-Is-XHR-Or-Fetch` header and infers resource type off of the server pre-request object. Fixes [#26620](https://github.com/cypress-io/cypress/issues/26620) and [#26622](https://github.com/cypress-io/cypress/issues/26622). + ## 12.17.2 -_Released 07/18/2023 (PENDING)_ +_Released 07/20/2023_ **Bugfixes:** @@ -173,11 +279,11 @@ _Released 04/17/2023_ **Bugfixes:** - - Capture the [Azure](https://azure.microsoft.com/) CI provider's environment variable [`SYSTEM_PULLREQUEST_PULLREQUESTNUMBER`](https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#system-variables-devops-services) to display the linked PR number in the Cloud. Addressed in [#26215](https://github.com/cypress-io/cypress/pull/26215). - - Fixed an issue in the onboarding wizard where project framework & bundler would not be auto-detected when opening directly into component testing mode using the `--component` CLI flag. Fixes [#22777](https://github.com/cypress-io/cypress/issues/22777) and [#26388](https://github.com/cypress-io/cypress/issues/26388). - - Updated to use the `SEMAPHORE_GIT_WORKING_BRANCH` [Semphore](https://docs.semaphoreci.com) CI environment variable to correctly associate a Cloud run to the current branch. Previously this was incorrectly associating a run to the target branch. Fixes [#26309](https://github.com/cypress-io/cypress/issues/26309). - - Fix an edge case in Component Testing where a custom `baseUrl` in `tsconfig.json` for Next.js 13.2.0+ is not respected. This was partially fixed in [#26005](https://github.com/cypress-io/cypress/pull/26005), but an edge case was missed. Fixes [#25951](https://github.com/cypress-io/cypress/issues/25951). - - Fixed an issue where `click` events fired on `.type('{enter}')` did not propagate through shadow roots. Fixes [#26392](https://github.com/cypress-io/cypress/issues/26392). +- Capture the [Azure](https://azure.microsoft.com/) CI provider's environment variable [`SYSTEM_PULLREQUEST_PULLREQUESTNUMBER`](https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#system-variables-devops-services) to display the linked PR number in the Cloud. Addressed in [#26215](https://github.com/cypress-io/cypress/pull/26215). +- Fixed an issue in the onboarding wizard where project framework & bundler would not be auto-detected when opening directly into component testing mode using the `--component` CLI flag. Fixes [#22777](https://github.com/cypress-io/cypress/issues/22777) and [#26388](https://github.com/cypress-io/cypress/issues/26388). +- Updated to use the `SEMAPHORE_GIT_WORKING_BRANCH` [Semphore](https://docs.semaphoreci.com) CI environment variable to correctly associate a Cloud run to the current branch. Previously this was incorrectly associating a run to the target branch. Fixes [#26309](https://github.com/cypress-io/cypress/issues/26309). +- Fix an edge case in Component Testing where a custom `baseUrl` in `tsconfig.json` for Next.js 13.2.0+ is not respected. This was partially fixed in [#26005](https://github.com/cypress-io/cypress/pull/26005), but an edge case was missed. Fixes [#25951](https://github.com/cypress-io/cypress/issues/25951). +- Fixed an issue where `click` events fired on `.type('{enter}')` did not propagate through shadow roots. Fixes [#26392](https://github.com/cypress-io/cypress/issues/26392). **Misc:** @@ -199,16 +305,16 @@ _Released 03/28/2023_ **Bugfixes:** - - Fixed a compatibility issue so that component test projects can use [Vite](https://vitejs.dev/) version 4.2.0 and greater. Fixes [#26138](https://github.com/cypress-io/cypress/issues/26138). - - Fixed an issue where [`cy.intercept()`](https://docs.cypress.io/api/commands/intercept) added an additional `content-length` header to spied requests that did not set a `content-length` header on the original request. Fixes [#24407](https://github.com/cypress-io/cypress/issues/24407). - - Changed the way that Git hashes are loaded so that non-relevant runs are excluded from the Debug page. Fixes [#26058](https://github.com/cypress-io/cypress/issues/26058). - - Corrected the [`.type()`](https://docs.cypress.io/api/commands/type) command to account for shadow root elements when determining whether or not focus needs to be simulated before typing. Fixes [#26198](https://github.com/cypress-io/cypress/issues/26198). - - Fixed an issue where an incorrect working directory could be used for Git operations on Windows. Fixes [#23317](https://github.com/cypress-io/cypress/issues/23317). - - Capture the [Buildkite](https://buildkite.com/) CI provider's environment variable `BUILDKITE_RETRY_COUNT` to handle CI retries in the Cloud. Addressed in [#25750](https://github.com/cypress-io/cypress/pull/25750). +- Fixed a compatibility issue so that component test projects can use [Vite](https://vitejs.dev/) version 4.2.0 and greater. Fixes [#26138](https://github.com/cypress-io/cypress/issues/26138). +- Fixed an issue where [`cy.intercept()`](https://docs.cypress.io/api/commands/intercept) added an additional `content-length` header to spied requests that did not set a `content-length` header on the original request. Fixes [#24407](https://github.com/cypress-io/cypress/issues/24407). +- Changed the way that Git hashes are loaded so that non-relevant runs are excluded from the Debug page. Fixes [#26058](https://github.com/cypress-io/cypress/issues/26058). +- Corrected the [`.type()`](https://docs.cypress.io/api/commands/type) command to account for shadow root elements when determining whether or not focus needs to be simulated before typing. Fixes [#26198](https://github.com/cypress-io/cypress/issues/26198). +- Fixed an issue where an incorrect working directory could be used for Git operations on Windows. Fixes [#23317](https://github.com/cypress-io/cypress/issues/23317). +- Capture the [Buildkite](https://buildkite.com/) CI provider's environment variable `BUILDKITE_RETRY_COUNT` to handle CI retries in the Cloud. Addressed in [#25750](https://github.com/cypress-io/cypress/pull/25750). **Misc:** - - Made some minor styling updates to the Debug page. Addresses [#26041](https://github.com/cypress-io/cypress/issues/26041). +- Made some minor styling updates to the Debug page. Addresses [#26041](https://github.com/cypress-io/cypress/issues/26041). ## 12.8.1 @@ -278,7 +384,7 @@ _Released 02/24/2023_ **Misc:** - - Made updates to the way that the Debug Page header displays information. Addresses [#25796](https://github.com/cypress-io/cypress/issues/25796) and [#25798](https://github.com/cypress-io/cypress/issues/25798). +- Made updates to the way that the Debug Page header displays information. Addresses [#25796](https://github.com/cypress-io/cypress/issues/25796) and [#25798](https://github.com/cypress-io/cypress/issues/25798). ## 12.6.0 diff --git a/cli/__snapshots__/cli_spec.js b/cli/__snapshots__/cli_spec.js index 36d6ee4f9869..6cca25fe06c9 100644 --- a/cli/__snapshots__/cli_spec.js +++ b/cli/__snapshots__/cli_spec.js @@ -86,6 +86,8 @@ exports['shows help for run --foo 1'] = ` -q, --quiet run quietly, using only the configured reporter --record [bool] records the run. sends test results, screenshots and videos to Cypress Cloud. -r, --reporter runs a specific mocha reporter. pass a path to use a custom reporter. defaults to "spec" + --runner-ui displays the Cypress Runner UI + --no-runner-ui hides the Cypress Runner UI -o, --reporter-options options for the mocha reporter. defaults to "null" -s, --spec runs specific spec file(s). defaults to "all" -t, --tag named tag(s) for recorded runs in Cypress Cloud diff --git a/cli/lib/cli.js b/cli/lib/cli.js index 248a7d72a10a..2be77ecd3943 100644 --- a/cli/lib/cli.js +++ b/cli/lib/cli.js @@ -122,6 +122,8 @@ const descriptions = { record: 'records the run. sends test results, screenshots and videos to Cypress Cloud.', reporter: 'runs a specific mocha reporter. pass a path to use a custom reporter. defaults to "spec"', reporterOptions: 'options for the mocha reporter. defaults to "null"', + runnerUi: 'displays the Cypress Runner UI', + noRunnerUi: 'hides the Cypress Runner UI', spec: 'runs specific spec file(s). defaults to "all"', tag: 'named tag(s) for recorded runs in Cypress Cloud', version: 'prints Cypress version', @@ -252,6 +254,8 @@ const addCypressRunCommand = (program) => { .option('-q, --quiet', text('quiet')) .option('--record [bool]', text('record'), coerceFalse) .option('-r, --reporter ', text('reporter')) + .option('--runner-ui', text('runnerUi')) + .option('--no-runner-ui', text('noRunnerUi')) .option('-o, --reporter-options ', text('reporterOptions')) .option('-s, --spec ', text('spec')) .option('-t, --tag ', text('tag')) diff --git a/cli/lib/exec/run.js b/cli/lib/exec/run.js index 5eedabc27b53..965e2f9fe975 100644 --- a/cli/lib/exec/run.js +++ b/cli/lib/exec/run.js @@ -133,6 +133,10 @@ const processRunOptions = (options = {}) => { args.push('--reporter-options', options.reporterOptions) } + if (options.runnerUi != null) { + args.push('--runner-ui', options.runnerUi) + } + // if we have specific spec(s) push that into the args if (options.spec) { args.push('--spec', options.spec) diff --git a/cli/lib/util.js b/cli/lib/util.js index 30a4f763ef68..3a3b4399adb6 100644 --- a/cli/lib/util.js +++ b/cli/lib/util.js @@ -21,7 +21,6 @@ const isInstalledGlobally = require('is-installed-globally') const logger = require('./logger') const debug = require('debug')('cypress:cli') const fs = require('./fs') -const semver = require('semver') const pkg = require(path.join(__dirname, '..', 'package.json')) @@ -226,6 +225,7 @@ const parseOpts = (opts) => { 'reporter', 'reporterOptions', 'record', + 'runnerUi', 'runProject', 'spec', 'tag') @@ -305,21 +305,6 @@ const util = { opts.ORIGINAL_NODE_OPTIONS = process.env.NODE_OPTIONS } - // https://github.com/cypress-io/cypress/issues/18914 - // Node 17+ ships with OpenSSL 3 by default, so we may need the option - // --openssl-legacy-provider so that webpack@4 can use the legacy MD4 hash - // function. This option doesn't exist on Node <17 or when it is built - // against OpenSSL 1, so we have to detect Node's major version and check - // which version of OpenSSL it was built against before spawning the plugins - // process. - - // To be removed when the Cypress binary pulls in the @cypress/webpack-batteries-included-preprocessor - // version that has been updated to webpack >= 5.61, which no longer relies on - // Node's builtin crypto.hash function. - if (process.versions && semver.satisfies(process.versions.node, '>=17.0.0') && semver.satisfies(process.versions.openssl, '>=3', { includePrerelease: true })) { - opts.ORIGINAL_NODE_OPTIONS = `${opts.ORIGINAL_NODE_OPTIONS || ''} --openssl-legacy-provider` - } - return opts }, diff --git a/cli/package.json b/cli/package.json index df22f47d7c01..9fe77271a209 100644 --- a/cli/package.json +++ b/cli/package.json @@ -20,9 +20,9 @@ "unit": "cross-env BLUEBIRD_DEBUG=1 NODE_ENV=test mocha --reporter mocha-multi-reporters --reporter-options configFile=../mocha-reporter-config.json" }, "dependencies": { - "@cypress/request": "^2.88.11", + "@cypress/request": "^3.0.0", "@cypress/xvfb": "^1.2.4", - "@types/node": "^14.14.31", + "@types/node": "^18.17.5", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", "arch": "^2.2.0", @@ -55,6 +55,7 @@ "minimist": "^1.2.8", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", + "process": "^0.11.10", "proxy-from-env": "1.0.0", "request-progress": "^3.0.0", "semver": "^7.5.3", @@ -94,7 +95,7 @@ "execa-wrap": "1.4.0", "hasha": "5.2.2", "mocha": "6.2.2", - "mock-fs": "5.1.1", + "mock-fs": "5.2.0", "mocked-env": "1.3.2", "nock": "13.2.9", "proxyquire": "2.1.3", @@ -123,7 +124,7 @@ "cypress": "bin/cypress" }, "engines": { - "node": "^14.0.0 || ^16.0.0 || >=18.0.0" + "node": "^16.0.0 || ^18.0.0 || >=20.0.0" }, "types": "types", "exports": { diff --git a/cli/scripts/build.js b/cli/scripts/build.js index b5fe4fb8c24d..155a8a47a35e 100644 --- a/cli/scripts/build.js +++ b/cli/scripts/build.js @@ -1,6 +1,7 @@ const _ = require('lodash') const path = require('path') const shell = require('shelljs') +const minimist = require('minimist') const fs = require('../lib/fs') @@ -24,7 +25,7 @@ function getStdout (cmd) { return shell.exec(cmd).trim() } -function preparePackageForNpmRelease (json) { +function preparePackageForNpmRelease (json, branchName) { // modify the existing package.json // to prepare it for releasing to npm delete json.devDependencies @@ -36,7 +37,7 @@ function preparePackageForNpmRelease (json) { _.extend(json, { version, buildInfo: { - commitBranch: process.env.CIRCLE_BRANCH || getStdout('git branch --show-current'), + commitBranch: branchName || process.env.CIRCLE_BRANCH || getStdout('git branch --show-current'), commitSha: getStdout('git rev-parse HEAD'), commitDate: new Date(getStdout('git show -s --format=%ci')).toISOString(), stable: false, @@ -57,9 +58,9 @@ function preparePackageForNpmRelease (json) { return json } -function makeUserPackageFile () { +function makeUserPackageFile (branchName) { return fs.readJsonAsync(packageJsonSrc) - .then(preparePackageForNpmRelease) + .then((json) => preparePackageForNpmRelease(json, branchName)) .then((json) => { return fs.outputJsonAsync(packageJsonDest, json, { spaces: 2, @@ -71,7 +72,9 @@ function makeUserPackageFile () { module.exports = makeUserPackageFile if (!module.parent) { - makeUserPackageFile() + const args = minimist(process.argv) + + makeUserPackageFile(args.branch) .catch((err) => { /* eslint-disable no-console */ console.error('Could not write user package file') diff --git a/cli/test/lib/cli_spec.js b/cli/test/lib/cli_spec.js index e688125f26b7..9de88e13ce0d 100644 --- a/cli/test/lib/cli_spec.js +++ b/cli/test/lib/cli_spec.js @@ -474,15 +474,25 @@ describe('cli', () => { expect(run.start).to.be.calledWith({ ciBuildId: '123', group: 'staging' }) }) - it('call run with --auto-cancel-after-failures', () => { + it('calls run with --auto-cancel-after-failures', () => { this.exec('run --auto-cancel-after-failures 4') expect(run.start).to.be.calledWith({ autoCancelAfterFailures: '4' }) }) - it('call run with --auto-cancel-after-failures with false', () => { + it('calls run with --auto-cancel-after-failures with false', () => { this.exec('run --auto-cancel-after-failures false') expect(run.start).to.be.calledWith({ autoCancelAfterFailures: 'false' }) }) + + it('calls run with --runner-ui', () => { + this.exec('run --runner-ui') + expect(run.start).to.be.calledWith({ runnerUi: true }) + }) + + it('calls run with --no-runner-ui', () => { + this.exec('run --no-runner-ui') + expect(run.start).to.be.calledWith({ runnerUi: false }) + }) }) context('cypress open', () => { diff --git a/cli/test/lib/cypress_spec.js b/cli/test/lib/cypress_spec.js index 0ed0dd9ef0ea..b2650e20ca1e 100644 --- a/cli/test/lib/cypress_spec.js +++ b/cli/test/lib/cypress_spec.js @@ -105,6 +105,7 @@ describe('cypress', function () { .then((args) => { expect(args.spec).to.equal('foo') expect(args.autoCancelAfterFailures).to.equal(4) + expect(args.runnerUi).to.be.undefined }) }) diff --git a/cli/test/lib/exec/run_spec.js b/cli/test/lib/exec/run_spec.js index 312d77791f3f..959bf65133cf 100644 --- a/cli/test/lib/exec/run_spec.js +++ b/cli/test/lib/exec/run_spec.js @@ -234,5 +234,14 @@ describe('exec run', function () { ]) }) }) + + it('spawns with --runner-ui', function () { + return run.start({ runnerUi: true }) + .then(() => { + expect(spawn.start).to.be.calledWith([ + '--run-project', process.cwd(), '--runner-ui', true, + ]) + }) + }) }) }) diff --git a/cli/test/lib/tasks/dependency_spec.js b/cli/test/lib/tasks/dependency_spec.js new file mode 100644 index 000000000000..49d00ad99f57 --- /dev/null +++ b/cli/test/lib/tasks/dependency_spec.js @@ -0,0 +1,26 @@ +/** + * as of Webpack 5, dependencies that are polyfilled through the Provide plugin must be defined inside the CLI + * in order to guarantee there is a version of the dependency accessible by the cypress CLI, either in the cypress directory + * or the root of their project. Currently, these two dependencies are 'buffer' and 'process' + */ +describe('dependencies', () => { + it('process dependency exists in package.json and is available', () => { + const { dependencies } = require('../../../package.json') + + expect(dependencies.process).to.be.ok + + const process = require('process') + + expect(typeof process).to.equal('object') + }) + + it('buffer dependency exists in package.json and is available', () => { + const { dependencies } = require('../../../package.json') + + expect(dependencies.buffer).to.be.ok + + const buffer = require('buffer') + + expect(typeof buffer).to.equal('object') + }) +}) diff --git a/cli/test/lib/util_spec.js b/cli/test/lib/util_spec.js index 008f4719e2fa..26110cabc982 100644 --- a/cli/test/lib/util_spec.js +++ b/cli/test/lib/util_spec.js @@ -278,68 +278,6 @@ describe('util', () => { ORIGINAL_NODE_OPTIONS: '--require foo.js', }) }) - - // https://github.com/cypress-io/cypress/issues/18914 - it('includes --openssl-legacy-provider in Node 17+ w/ OpenSSL 3', () => { - sandbox.stub(process.versions, 'node').value('v17.1.0') - sandbox.stub(process.versions, 'openssl').value('3.0.0-quic') - - restoreEnv = mockedEnv({ - NODE_OPTIONS: '--require foo.js', - }) - - let childOptions = util.getOriginalNodeOptions() - - expect(childOptions.ORIGINAL_NODE_OPTIONS).to.eq('--require foo.js --openssl-legacy-provider') - - restoreEnv() - restoreEnv = mockedEnv({}) - childOptions = util.getOriginalNodeOptions() - - expect(childOptions.ORIGINAL_NODE_OPTIONS).to.eq(' --openssl-legacy-provider') - }) - - // https://github.com/cypress-io/cypress/issues/19320 - it('does not include --openssl-legacy-provider in Node 17+ w/ OpenSSL 1', () => { - sandbox.stub(process.versions, 'node').value('v17.1.0') - sandbox.stub(process.versions, 'openssl').value('1.0.0') - - restoreEnv = mockedEnv({ - NODE_OPTIONS: '--require foo.js', - }) - - let childOptions = util.getOriginalNodeOptions() - - expect(childOptions.ORIGINAL_NODE_OPTIONS).to.eq('--require foo.js') - expect(childOptions.ORIGINAL_NODE_OPTIONS).not.to.contain('--openssl-legacy-provider') - - restoreEnv() - restoreEnv = mockedEnv({}) - childOptions = util.getOriginalNodeOptions() - - expect(childOptions.ORIGINAL_NODE_OPTIONS).to.be.undefined - }) - - // https://github.com/cypress-io/cypress/issues/18914 - it('does not include --openssl-legacy-provider in Node <=16', () => { - sandbox.stub(process.versions, 'node').value('v16.14.2') - sandbox.stub(process.versions, 'openssl').value('1.0.0') - - restoreEnv = mockedEnv({}) - - let childOptions = util.getOriginalNodeOptions() - - expect(childOptions.ORIGINAL_NODE_OPTIONS).to.be.undefined - - restoreEnv = mockedEnv({ - NODE_OPTIONS: '--require foo.js', - }) - - childOptions = util.getOriginalNodeOptions() - - expect(childOptions.ORIGINAL_NODE_OPTIONS).to.eq('--require foo.js') - expect(childOptions.ORIGINAL_NODE_OPTIONS).not.to.contain('--openssl-legacy-provider') - }) }) context('.exit', () => { diff --git a/cli/types/cypress-expect.d.ts b/cli/types/cypress-expect.d.ts index 74f71a57de81..bea4c7f566d3 100644 --- a/cli/types/cypress-expect.d.ts +++ b/cli/types/cypress-expect.d.ts @@ -1,3 +1,3 @@ // Cypress adds chai expect and assert to global -declare const expect: Chai.ExpectStatic -declare const assert: Chai.AssertStatic +declare var expect: Chai.ExpectStatic +declare var assert: Chai.AssertStatic diff --git a/cli/types/cypress-global-vars.d.ts b/cli/types/cypress-global-vars.d.ts index ddeaa326a9ef..e7665012797d 100644 --- a/cli/types/cypress-global-vars.d.ts +++ b/cli/types/cypress-global-vars.d.ts @@ -7,7 +7,7 @@ cy.get('button').click() cy.get('.result').contains('Expected text') ``` */ -declare const cy: Cypress.cy & CyEventEmitter +declare var cy: Cypress.cy & CyEventEmitter /** * Global variable `Cypress` holds common utilities and constants. @@ -19,4 +19,4 @@ Cypress.version // => "1.4.0" Cypress._ // => Lodash _ ``` */ -declare const Cypress: Cypress.Cypress & CyEventEmitter +declare var Cypress: Cypress.Cypress & CyEventEmitter diff --git a/cli/types/cypress-npm-api.d.ts b/cli/types/cypress-npm-api.d.ts index 93a72b52a701..ffeda31685ea 100644 --- a/cli/types/cypress-npm-api.d.ts +++ b/cli/types/cypress-npm-api.d.ts @@ -7,13 +7,6 @@ // but for now describe it as an ambient module declare namespace CypressCommandLine { - type HookName = 'before' | 'beforeEach' | 'afterEach' | 'after' - - interface TestError { - name: string - message: string - stack: string - } /** * All options that one can pass to "cypress.run" * @see https://on.cypress.io/module-api#cypress-run @@ -99,6 +92,10 @@ declare namespace CypressCommandLine { * Specify the number of failures to cancel a run being recorded to the Cloud or false to disable auto-cancellation. */ autoCancelAfterFailures: number | false + /** + * Whether to display the Cypress Runner UI + */ + runnerUi: boolean } /** @@ -174,9 +171,9 @@ declare namespace CypressCommandLine { * Cypress single test result */ interface TestResult { + duration: number title: string[] state: string - body: string /** * Error string as it's presented in console if the test fails */ @@ -186,20 +183,6 @@ declare namespace CypressCommandLine { interface AttemptResult { state: string - error: TestError | null - wallClockStartedAt: dateTimeISO - wallClockDuration: ms - videoTimestamp: ms - screenshots: ScreenshotInformation[] - } - - /** - * Information about a single "before", "beforeEach", "afterEach" and "after" hook. - */ - interface HookInformation { - hookName: HookName - title: string[] - body: string } /** @@ -216,58 +199,69 @@ declare namespace CypressCommandLine { width: pixels } + interface SpecResult { + /** + * resolved filename of the spec + */ + absolute: string + /** + * file extension like ".js" + */ + fileExtension: string + /** + * file name without extension like "spec" + */ + fileName: string + /** + * filename like "spec.js" + */ + name: string + /** + * name relative to the project root, like "cypress/integration/spec.js" + */ + relative: string + } + /** * Cypress test run result for a single spec. */ interface RunResult { + error: string | null + /** + * Reporter name like "spec" + */ + reporter: string + /** + * This is controlled by the reporter, and Cypress cannot guarantee + * the properties. Usually this object has suites, tests, passes, etc + */ + reporterStats: object + screenshots: ScreenshotInformation[] /** * Accurate test results collected by Cypress. */ stats: { - suites: number - tests: number + duration?: ms + endedAt: dateTimeISO + failures: number passes: number pending: number skipped: number - failures: number startedAt: dateTimeISO - endedAt: dateTimeISO - duration: ms - wallClockDuration?: number + suites: number + tests: number } /** - * Reporter name like "spec" - */ - reporter: string - /** - * This is controlled by the reporter, and Cypress cannot guarantee - * the properties. Usually this object has suites, tests, passes, etc + * information about the spec test file. */ - reporterStats: object - hooks: HookInformation[] + spec: SpecResult tests: TestResult[] - error: string | null video: string | null - /** - * information about the spec test file. - */ - spec: { - /** - * filename like "spec.js" - */ - name: string - /** - * name relative to the project root, like "cypress/integration/spec.js" - */ - relative: string - /** - * resolved filename of the spec - */ - absolute: string - relativeToCommonRoot: string - } - shouldUploadVideo: boolean - skippedSpec: boolean + } + + type PublicConfig = Omit & { + browsers: Cypress.PublicBrowser[] + cypressInternalEnv: string } /** @@ -275,29 +269,28 @@ declare namespace CypressCommandLine { * @see https://on.cypress.io/module-api */ interface CypressRunResult { - status: 'finished' - startedTestsAt: dateTimeISO + browserName: string + browserPath: string + browserVersion: string + config: PublicConfig + cypressVersion: string endedTestsAt: dateTimeISO - totalDuration: ms - totalSuites: number - totalTests: number + osName: string + osVersion: string + runs: RunResult[] + /** + * If Cypress test run was recorded, full url will be provided. + * @see https://on.cypress.io/cloud-introduction + */ + runUrl?: string + startedTestsAt: dateTimeISO + totalDuration: number totalFailed: number totalPassed: number totalPending: number totalSkipped: number - /** - * If Cypress test run is being recorded, full url will be provided. - * @see https://on.cypress.io/dashboard-introduction - */ - runUrl?: string - runs: RunResult[] - browserPath: string - browserName: string - browserVersion: string - osName: string - osVersion: string - cypressVersion: string - config: Cypress.ResolvedConfigOptions + totalSuites: number + totalTests: number } /** diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index b2b1c3272ab4..a40f2fcdf92c 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -134,6 +134,19 @@ declare namespace Cypress { unsupportedVersion?: boolean } + /** + * Browser that's exposed in public APIs + */ + interface PublicBrowser { + channel: BrowserChannel + displayName: string + family: string + majorVersion?: string | number | null + name: BrowserName + path: string + version: string + } + interface Ensure { /** * Throws an error if `subject` is not one of the passed in `type`s. @@ -2936,18 +2949,13 @@ declare namespace Cypress { * @default "cypress/downloads" */ downloadsFolder: string - /** - * If set to `system`, Cypress will try to find a `node` executable on your path to use when executing your plugins. Otherwise, Cypress will use the Node version bundled with Cypress. - * @default "bundled" - */ - nodeVersion: 'system' | 'bundled' /** * The application under test cannot redirect more than this limit. * @default 20 */ redirectionLimit: number /** - * If `nodeVersion === 'system'` and a `node` executable is found, this will be the full filesystem path to that executable. + * If a `node` executable is found, this will be the full filesystem path to that executable. * @default null */ resolvedNodePath: string @@ -3016,15 +3024,10 @@ declare namespace Cypress { */ videoCompression: number | boolean /** - * Whether Cypress will record a video of the test run when running headlessly. - * @default true + * Whether Cypress will record a video of the test run when executing in run mode. + * @default false */ video: boolean - /** - * Whether Cypress will upload the video to Cypress Cloud even if all tests are passing. This applies only when recording your runs to Cypress Cloud. Turn this off if you'd like the video uploaded only when there are failing tests. - * @default true - */ - videoUploadOnPasses: boolean /** * Whether Chrome Web Security for same-origin policy and insecure mixed content is enabled. Read more about this here * @default true @@ -3265,6 +3268,9 @@ declare namespace Cypress { socketIoRoute: string spec: Cypress['spec'] | null specs: Array + protocolEnabled: boolean + hideCommandLog: boolean + hideRunnerUi: boolean } interface SuiteConfigOverrides extends Partial< diff --git a/cli/types/index.d.ts b/cli/types/index.d.ts index 39c93067a163..5167a954f11b 100644 --- a/cli/types/index.d.ts +++ b/cli/types/index.d.ts @@ -4,7 +4,7 @@ // Mike Woudenberg // Robbert van Markus // Nicholas Boll -// TypeScript Version: 3.4 +// TypeScript Version: 4.3 // Updated by the Cypress team: https://www.cypress.io/about/ /// diff --git a/cli/types/tests/cypress-npm-api-test.ts b/cli/types/tests/cypress-npm-api-test.ts index ba04ed7a5802..bea7236891ca 100644 --- a/cli/types/tests/cypress-npm-api-test.ts +++ b/cli/types/tests/cypress-npm-api-test.ts @@ -43,12 +43,7 @@ cypress.run({}).then((results) => { // the caller can determine if Cypress ran or failed to launch cypress.run().then(results => { - if (results.status === 'failed') { - results // $ExpectType CypressFailedRunResult - } else { - results // $ExpectType CypressRunResult - results.status // $ExpectType "finished" - } + results // $ExpectType CypressRunResult | CypressFailedRunResult }) const config = defineConfig({ diff --git a/cli/types/tests/cypress-tests.ts b/cli/types/tests/cypress-tests.ts index dd306c4ed4d6..035ec815d7d1 100644 --- a/cli/types/tests/cypress-tests.ts +++ b/cli/types/tests/cypress-tests.ts @@ -1201,3 +1201,20 @@ namespace CypressRequireTests { Cypress.require({}) // $ExpectError Cypress.require(123) // $ExpectError } + +namespace CypressGlobalsTests { + Cypress + cy + expect + assert + + window.Cypress + window.cy + window.expect + window.assert + + globalThis.Cypress + globalThis.cy + globalThis.expect + globalThis.assert +} diff --git a/docker-compose.yml b/docker-compose.yml index 5e059aab7108..83fd12748ddd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,7 +33,7 @@ services: - .:/opt/cypress ci: # This should mirror the image used in workflows.yml - image: cypress/browsers:node16.16.0-chrome106-ff99-edge + image: cypress/browsers-internal:node18.15.0-chrome114-ff115 ports: - 5566:5566 - 5567:5567 diff --git a/guides/building-release-artifacts.md b/guides/building-release-artifacts.md index 349c393fcf28..11f8aee787cb 100644 --- a/guides/building-release-artifacts.md +++ b/guides/building-release-artifacts.md @@ -33,7 +33,7 @@ The steps above: The npm package requires a corresponding binary of the same version. In production, it will try to retrieve the binary from the Cypress CDN if it is not cached locally. -You can build the Cypress binary locally by running `yarn binary-build`. You can use Linux to build the Cypress binary (just like it is in CI) by running `yarn binary-build` inside of `yarn docker`. +You can build the Cypress binary locally by running `yarn binary-build`, then package the binary by running `yarn binary-package`. You can use Linux to build the Cypress binary (just like it is in CI) by running `yarn binary-build` and `yarn binary-package` inside of `yarn docker`. If you're on macOS and building locally, you'll need a code-signing certificate in your keychain, which you can get by following the [instructions on Apple's website](https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/Procedures/Procedures.html#//apple_ref/doc/uid/TP40005929-CH4-SW30). Also, you'll also most likely want to skip notarization since it requires an Apple Developer Program account - set `SKIP_NOTARIZATION=1` when building locally to do this. [More info about code signing in CI](./code-signing.md). diff --git a/guides/protocol-development.md b/guides/protocol-development.md new file mode 100644 index 000000000000..db5d088935ee --- /dev/null +++ b/guides/protocol-development.md @@ -0,0 +1,10 @@ +# Protocol Development + +In production, the capture code used to capture and communicate test data will be retrieved from the Cloud. However, in order to develop the capture code locally, developers will: + +* Clone the `cypress-services` repo + * Run `yarn` + * Run `yarn watch` in `packages/app-capture-protocol` +* Clone the `cypress` repo + * Run `yarn` + * Execute `CYPRESS_LOCAL_PROTOCOL_PATH=path/to/cypress-services/packages/app-capture-protocol/dist/index.js CYPRESS_INTERNAL_ENV=staging yarn cypress:run --record --key --project ` on a project in record mode diff --git a/guides/release-process.md b/guides/release-process.md index 530ad3d90bf6..b5c8871b06d4 100644 --- a/guides/release-process.md +++ b/guides/release-process.md @@ -17,12 +17,13 @@ The `@cypress/`-namespaced NPM packages that live inside the [`/npm`](../npm) di - [Set up](https://cypress-io.atlassian.net/wiki/spaces/INFRA/pages/1534853121/AWS+SSO+Cypress) an AWS SSO profile with the [Team-CypressApp-Prod](https://cypress-io.atlassian.net/wiki/spaces/INFRA/pages/1534853121/AWS+SSO+Cypress#Team-CypressApp-Prod) role. The release scripts assumes the name of your profile is `prod`. Make sure to open the "App Developer" expando for some necessary config values. Your AWS config file should end up looking like the following: ``` - [prod] + [profile prod] sso_start_url = sso_region = - aws_access_key_id = - aws_secret_access_key = - aws_session_token = + sso_account_id = + sso_role_name = + region = + cli_pager = ``` - Set up the following environment variables: @@ -42,6 +43,13 @@ The `@cypress/`-namespaced NPM packages that live inside the [`/npm`](../npm) di CF_TOKEN="..." ``` +- Ensure that you have the following repositories checked out locally and ready to contribute to: + - [`cypress-realworld-app`](https://github.com/cypress-io/cypress-realworld-app) + - [`cypress-documentation`](https://github.com/cypress-io/cypress-documentation) + - [`cypress-docker-images`](https://github.com/cypress-io/cypress-docker-images) + - [cypress-io/release-automations][release-automations] + + If you don't have access to 1Password, ask a team member who has done a deploy. Tip: Use [as-a](https://github.com/bahmutov/as-a) to manage environment variables for different situations. @@ -80,13 +88,17 @@ _Note: It is advisable to notify the team that the `develop` branch is locked do 2. Ensure all changes to the links manifest to [`on.cypress.io`](https://github.com/cypress-io/cypress-services/tree/develop/packages/on) have been merged to `develop` and deployed. -3. Create a Release PR - +3. Create a Release PR - Bump, submit, get approvals on, and merge a new PR. This PR should: - Bump the Cypress `version` in [`package.json`](package.json) - Bump the [`packages/example`](../packages/example) dependency if there is a new [`cypress-example-kitchensink`](https://github.com/cypress-io/cypress-example-kitchensink/releases) version - Follow the writing the [Cypress Changelog release steps](./writing-the-cypress-changelog.md#release) to update the [`cli/CHANGELOG.md`](../cli/CHANGELOG.md). 4. Once the `develop` branch is passing in CI and you have confirmed the `cypress-bot` has commented on the commit with the pre-release versions for `darwin-x64`, `darwin-arm64`, `linux-x64`,`linux-arm64`, and `win32-x64`, publishing can proceed. + Tips for getting a green build: + - If the `windows` workflow is failing with timeout errors, you can retry from the last failed step. + - Sometimes a test can get stuck in a failing state between attempts on the `windows` workflow. In these cases, kicking off a full run of the workflow can help get it into a passing state. + - If the `linux-x64` workflow fails due to a flaky test but percy finalizes the build, you *must* restart the workflow from the failed steps. Restarting the entire workflow after a finalized Percy build can cause Percy to fail the next attempt with a "Build has already been finalized" error, requiring pushing a new commit to start fresh. 5. Log into AWS SSO with `aws sso login --profile `. If you have setup your credentials under a different profile than `prod`, be sure to set the `AWS_PROFILE` environment variable to that profile name for the remaining steps. For example, if you are using `production` instead of `prod`, do `export AWS_PROFILE=production`. @@ -173,7 +185,9 @@ _Note: It is advisable to notify the team that the `develop` branch is locked do 23. Notify the team that `develop` is reopen, and post a message to the Releases Slack channel with a link to the changelog. -24. Check all `cypress-test-*` and `cypress-example-*` repositories, and if there is a branch named `x.y.z` for testing the features or fixes from the newly published version `x.y.z`, update that branch to refer to the newly published NPM version in `package.json`. Then, get the changes approved and merged into that project's main branch. For projects without a `x.y.z` branch, you can go to the Renovate dependency issue and check the box next to `Update dependency cypress to X.Y.Z`. It will automatically create a PR. Once it passes, you can merge it. Try updating at least the following projects: +24. If utilizing the `SKIP_RELEASE_CHANGELOG_VALIDATION_FOR_BRANCHES` to override and skip changelog validation for this release, change its value as needed or delete it from CircleCI so that subsequent releases and PRs will go through changelog validation. + +25. Check all `cypress-test-*` and `cypress-example-*` repositories, and if there is a branch named `x.y.z` for testing the features or fixes from the newly published version `x.y.z`, update that branch to refer to the newly published NPM version in `package.json`. Then, get the changes approved and merged into that project's main branch. For projects without a `x.y.z` branch, you can go to the Renovate dependency issue and check the box next to `Update dependency cypress to X.Y.Z`. It will automatically create a PR. Once it passes, you can merge it. Try updating at least the following projects: - [cypress-example-todomvc](https://github.com/cypress-io/cypress-example-todomvc/issues/99) - [cypress-realworld-app](https://github.com/cypress-io/cypress-realworld-app/issues/41) - [cypress-example-recipes](https://github.com/cypress-io/cypress-example-recipes/issues/225) diff --git a/npm/create-cypress-tests/CHANGELOG.md b/npm/create-cypress-tests/CHANGELOG.md index 3b2f80df83dd..86aab50ae430 100644 --- a/npm/create-cypress-tests/CHANGELOG.md +++ b/npm/create-cypress-tests/CHANGELOG.md @@ -1,3 +1,5 @@ +# [create-cypress-tests-v2.0.3](https://github.com/cypress-io/cypress/compare/create-cypress-tests-v2.0.2...create-cypress-tests-v2.0.3) (2023-09-07) + # [create-cypress-tests-v2.0.2](https://github.com/cypress-io/cypress/compare/create-cypress-tests-v2.0.1...create-cypress-tests-v2.0.2) (2023-04-07) # [create-cypress-tests-v2.0.1](https://github.com/cypress-io/cypress/compare/create-cypress-tests-v2.0.0...create-cypress-tests-v2.0.1) (2023-01-03) diff --git a/npm/create-cypress-tests/package.json b/npm/create-cypress-tests/package.json index b49dcad6e3ec..5d7a30a91a29 100644 --- a/npm/create-cypress-tests/package.json +++ b/npm/create-cypress-tests/package.json @@ -32,12 +32,12 @@ "@types/babel__core": "^7.1.2", "@types/inquirer": "7.3.1", "@types/mock-fs": "4.10.0", - "@types/node": "14.14.31", + "@types/node": "18.17.5", "@types/ora": "^3.2.0", "@types/semver": "7.5.0", "copy": "0.3.2", "mocha": "7.1.1", - "mock-fs": "5.1.1", + "mock-fs": "5.2.0", "snap-shot-it": "7.9.3", "typescript": "^4.7.4" }, diff --git a/npm/cypress-schematic/CHANGELOG.md b/npm/cypress-schematic/CHANGELOG.md index 21f00b1230b2..d2fb989a6401 100644 --- a/npm/cypress-schematic/CHANGELOG.md +++ b/npm/cypress-schematic/CHANGELOG.md @@ -1,3 +1,5 @@ +# [@cypress/schematic-v2.5.1](https://github.com/cypress-io/cypress/compare/@cypress/schematic-v2.5.0...@cypress/schematic-v2.5.1) (2023-09-07) + # [@cypress/schematic-v2.5.0](https://github.com/cypress-io/cypress/compare/@cypress/schematic-v2.4.0...@cypress/schematic-v2.5.0) (2023-01-25) diff --git a/npm/cypress-schematic/package.json b/npm/cypress-schematic/package.json index bc5e98c58956..fa6c8fc4f824 100644 --- a/npm/cypress-schematic/package.json +++ b/npm/cypress-schematic/package.json @@ -22,7 +22,7 @@ "@schematics/angular": "^14.2.1", "@types/chai-enzyme": "0.6.7", "@types/mocha": "8.0.3", - "@types/node": "^18.0.6", + "@types/node": "^18.17.5", "chai": "4.2.0", "mocha": "3.5.3", "typescript": "^4.7.4" diff --git a/npm/grep/CHANGELOG.md b/npm/grep/CHANGELOG.md index 0642638fdb13..bb91332f8a12 100644 --- a/npm/grep/CHANGELOG.md +++ b/npm/grep/CHANGELOG.md @@ -1,3 +1,8 @@ +# [@cypress/grep-v4.0.0](https://github.com/cypress-io/cypress/compare/@cypress/grep-v3.1.5...@cypress/grep-v4.0.0) (2023-08-29) + + +* `@cypress/grep-v4.0.0` was inadvertently released and published. There are no breaking changes or any other changes in this release. + # [@cypress/grep-v3.1.5](https://github.com/cypress-io/cypress/compare/@cypress/grep-v3.1.4...@cypress/grep-v3.1.5) (2023-03-15) diff --git a/npm/grep/cypress.config.js b/npm/grep/cypress.config.js index eca9ad3ab817..31107ca7e869 100644 --- a/npm/grep/cypress.config.js +++ b/npm/grep/cypress.config.js @@ -11,5 +11,4 @@ module.exports = defineConfig({ specPattern: '**/spec.js', }, fixturesFolder: false, - video: false, }) diff --git a/npm/mount-utils/src/index.ts b/npm/mount-utils/src/index.ts index 87ace86aa7af..4d00f3507161 100644 --- a/npm/mount-utils/src/index.ts +++ b/npm/mount-utils/src/index.ts @@ -57,7 +57,7 @@ export function setupHooks (optionalCallback?: Function) { }) // @ts-ignore - Cypress.on('test:before:run', () => { + Cypress.on('test:before:after:run:async', () => { optionalCallback?.() }) } diff --git a/npm/react/CHANGELOG.md b/npm/react/CHANGELOG.md index cebe0b462559..1719e3ab9aad 100644 --- a/npm/react/CHANGELOG.md +++ b/npm/react/CHANGELOG.md @@ -1,3 +1,8 @@ +# [@cypress/react-v8.0.0](https://github.com/cypress-io/cypress/compare/@cypress/react-v7.0.3...@cypress/react-v8.0.0) (2023-08-29) + + +* `@cypress/react-v8.0.0` was inadvertently released and published. There are no breaking changes or any other changes in this release. + # [@cypress/react-v7.0.3](https://github.com/cypress-io/cypress/compare/@cypress/react-v7.0.2...@cypress/react-v7.0.3) (2023-03-20) diff --git a/npm/react/babel.config.js b/npm/react/babel.config.js index ad413ba0d752..de339017a46a 100644 --- a/npm/react/babel.config.js +++ b/npm/react/babel.config.js @@ -8,7 +8,7 @@ module.exports = { // allow lazy loaded components with dynamic "import(...)" // https://babeljs.io/docs/en/babel-plugin-syntax-dynamic-import/ '@babel/plugin-syntax-dynamic-import', - '@babel/plugin-proposal-class-properties', + '@babel/plugin-transform-class-properties', // https://babeljs.io/docs/en/babel-plugin-transform-modules-commonjs // loose ES6 modules allow us to dynamically mock imports during tests [ diff --git a/npm/react/cypress.config.js b/npm/react/cypress.config.js index 71fce84b661e..2764f9c4c037 100644 --- a/npm/react/cypress.config.js +++ b/npm/react/cypress.config.js @@ -1,7 +1,6 @@ module.exports = { 'viewportWidth': 400, 'viewportHeight': 400, - 'video': false, 'projectId': 'z9dxah', 'env': { 'reactDevtools': true, diff --git a/npm/react/cypress/component/advanced/react-router-v6/in-memory.cy.jsx b/npm/react/cypress/component/advanced/react-router-v6/in-memory.cy.jsx index b77554446647..1ce8ef804134 100644 --- a/npm/react/cypress/component/advanced/react-router-v6/in-memory.cy.jsx +++ b/npm/react/cypress/component/advanced/react-router-v6/in-memory.cy.jsx @@ -21,7 +21,7 @@ describe('React Memory Router', () => { cy.log('**About** component') cy.contains('h2', 'About') // because the routing is in memory, the URL stays at the spec filename - cy.location('pathname').should('match', /in-memory.cy.jsx$/) + cy.location('search').should('match', /in-memory.cy.jsx$/) // Go to home route cy.contains('a', 'Home').click() @@ -29,7 +29,7 @@ describe('React Memory Router', () => { cy.log('**Home** component') cy.contains('h2', 'Home') // from the "Home" component // still at the spec url - cy.location('pathname').should('match', /in-memory.cy.jsx$/) + cy.location('search').should('match', /in-memory.cy.jsx$/) // Go to about route cy.log('back to **About** component') @@ -37,6 +37,6 @@ describe('React Memory Router', () => { cy.contains('h2', 'About') // still at the spec url - cy.location('pathname').should('match', /in-memory.cy.jsx$/) + cy.location('search').should('match', /in-memory.cy.jsx$/) }) }) diff --git a/npm/react/cypress/component/basic/window.cy.jsx b/npm/react/cypress/component/basic/window.cy.jsx index bc5fc837929d..b516d689f25f 100644 --- a/npm/react/cypress/component/basic/window.cy.jsx +++ b/npm/react/cypress/component/basic/window.cy.jsx @@ -27,7 +27,7 @@ it('has the same window from the component as from test', () => { mount() cy.contains('component') cy.window() - .its('location.pathname') + .its('location.search') // this filename .should('match', /window.cy.jsx$/) diff --git a/npm/react/package.json b/npm/react/package.json index e7b2505aa7a3..e916668ba98e 100644 --- a/npm/react/package.json +++ b/npm/react/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "rimraf dist && rollup -c rollup.config.mjs", "postbuild": "node ../../scripts/sync-exported-npm-with-cli.js", - "build-prod": "yarn build", + "check-ts": "tsc --noEmit", "cy:open": "node ../../scripts/cypress.js open --component", "cy:open:debug": "node --inspect-brk ../../scripts/start.js --component-testing --run-project ${PWD}", "cy:run": "node ../../scripts/cypress.js run --component", diff --git a/npm/react18/package.json b/npm/react18/package.json index 2ffc31d894f3..5c9837bbebf9 100644 --- a/npm/react18/package.json +++ b/npm/react18/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "rimraf dist && rollup -c rollup.config.mjs", "postbuild": "node ../../scripts/sync-exported-npm-with-cli.js", - "build-prod": "yarn build", + "check-ts": "tsc --noEmit", "watch": "yarn build --watch --watch.exclude ./dist/**/*", "lint": "eslint --ext .js,.jsx,.ts,.tsx,.json, ." }, diff --git a/npm/vite-dev-server/CHANGELOG.md b/npm/vite-dev-server/CHANGELOG.md index f70a568750d8..5a89a1a34ffa 100644 --- a/npm/vite-dev-server/CHANGELOG.md +++ b/npm/vite-dev-server/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cypress/vite-dev-server-v5.0.6](https://github.com/cypress-io/cypress/compare/@cypress/vite-dev-server-v5.0.5...@cypress/vite-dev-server-v5.0.6) (2023-08-29) + + +### Bug Fixes + +* allow cypress config.port to override devServer.port for proxying assets ([f82fdf0](https://github.com/cypress-io/cypress/commit/f82fdf026eeab125a2b974e4257a7ac5e33640eb)) + # [@cypress/vite-dev-server-v5.0.5](https://github.com/cypress-io/cypress/compare/@cypress/vite-dev-server-v5.0.4...@cypress/vite-dev-server-v5.0.5) (2023-03-20) diff --git a/npm/vite-dev-server/cypress/e2e/react.cy.ts b/npm/vite-dev-server/cypress/e2e/react.cy.ts index cd3ab8f8729f..ce4925dd9849 100644 --- a/npm/vite-dev-server/cypress/e2e/react.cy.ts +++ b/npm/vite-dev-server/cypress/e2e/react.cy.ts @@ -17,7 +17,7 @@ for (const project of VITE_REACT) { describe(`Working with ${project}`, () => { beforeEach(() => { cy.scaffoldProject(project) - cy.openProject(project, ['--config-file', 'cypress-vite.config.ts']) + cy.openProject(project, ['--config-file', 'cypress-vite.config.ts', '--component']) cy.startAppServer('component') }) diff --git a/npm/vite-dev-server/cypress/e2e/vite-dev-server.cy.ts b/npm/vite-dev-server/cypress/e2e/vite-dev-server.cy.ts index b20700e7bdd3..b295a5a832ac 100644 --- a/npm/vite-dev-server/cypress/e2e/vite-dev-server.cy.ts +++ b/npm/vite-dev-server/cypress/e2e/vite-dev-server.cy.ts @@ -5,7 +5,7 @@ import dedent from 'dedent' describe('Config options', () => { it('works with tailwind', () => { cy.scaffoldProject('tailwind-vite') - cy.openProject('tailwind-vite') + cy.openProject('tailwind-vite', ['--component']) cy.startAppServer('component') cy.visitApp() @@ -44,7 +44,7 @@ describe('Config options', () => { it('supports supportFile = false', () => { cy.scaffoldProject('vite2.9.1-react') - cy.openProject('vite2.9.1-react', ['--config-file', 'cypress-vite-no-support.config.ts']) + cy.openProject('vite2.9.1-react', ['--config-file', 'cypress-vite-no-support.config.ts', '--component']) cy.startAppServer('component') cy.visitApp() @@ -53,28 +53,11 @@ describe('Config options', () => { cy.get('.passed > .num').should('contain', 1) }) - it('chooses new port when specified port is in use', () => { - cy.scaffoldProject('vite2.9.1-react') - cy.openProject('vite2.9.1-react', ['--config-file', 'cypress-vite-port-in-use.config.ts']) - cy.startAppServer('component') - - cy.visitApp() - - cy.contains('App.cy.jsx').click() - cy.get('.passed > .num').should('contain', 2) - - cy.withCtx(async (ctx) => { - const config = ctx.lifecycleManager.loadedFullConfig - - expect(config.baseUrl).to.equal('http://localhost:3001') - }) - }) - it('supports serving files with whitespace', () => { const specWithWhitespace = 'spec with whitespace.cy.jsx' cy.scaffoldProject('vite2.9.1-react') - cy.openProject('vite2.9.1-react', ['--config-file', 'cypress-vite.config.ts']) + cy.openProject('vite2.9.1-react', ['--config-file', 'cypress-vite.config.ts', '--component']) cy.startAppServer('component') cy.withCtx(async (ctx, { specWithWhitespace }) => { @@ -91,7 +74,7 @@ describe('Config options', () => { it('supports @cypress/vite-dev-server', () => { cy.scaffoldProject('vite2.9.1-react') - cy.openProject('vite2.9.1-react', ['--config-file', 'cypress-vite-dev-server-function.config.ts']) + cy.openProject('vite2.9.1-react', ['--config-file', 'cypress-vite-dev-server-function.config.ts', '--component']) cy.startAppServer('component') cy.visitApp() @@ -102,7 +85,7 @@ describe('Config options', () => { it('supports viteConfig as an async function', () => { cy.scaffoldProject('vite2.9.1-react') - cy.openProject('vite2.9.1-react', ['--config-file', 'cypress-vite-async-function-config.config.ts']) + cy.openProject('vite2.9.1-react', ['--config-file', 'cypress-vite-async-function-config.config.ts', '--component']) cy.startAppServer('component') cy.visitApp() @@ -132,7 +115,7 @@ describe('sourcemaps', () => { ` cy.scaffoldProject('vite3.0.2-react') - cy.openProject('vite3.0.2-react', ['--config-file', 'cypress-vite.config.ts']) + cy.openProject('vite3.0.2-react', ['--config-file', 'cypress-vite.config.ts', '--component']) cy.startAppServer('component') cy.withCtx(async (ctx, o) => { diff --git a/npm/vite-dev-server/src/resolveConfig.ts b/npm/vite-dev-server/src/resolveConfig.ts index 51e86f655fa5..827011b9227f 100644 --- a/npm/vite-dev-server/src/resolveConfig.ts +++ b/npm/vite-dev-server/src/resolveConfig.ts @@ -65,6 +65,7 @@ export const createViteDevServerConfig = async (config: ViteDevServerConfig, vit function makeCypressViteConfig (config: ViteDevServerConfig, vite: Vite): InlineConfig { const { cypressConfig: { + port, projectRoot, devServerPublicPathRoute, supportFile, @@ -74,6 +75,8 @@ function makeCypressViteConfig (config: ViteDevServerConfig, vite: Vite): Inline specs, } = config + const vitePort = port ?? undefined + // Vite caches its output in the .vite directory in the node_modules where vite lives. // So we want to find that node_modules path and ensure it's added to the "allow" list const vitePathNodeModules = path.dirname(path.dirname(require.resolve(`vite/package.json`, { @@ -122,6 +125,7 @@ function makeCypressViteConfig (config: ViteDevServerConfig, vite: Vite): Inline vite.searchForWorkspaceRoot?.(process.cwd()), ], }, + port: vitePort, host: '127.0.0.1', // Disable file watching and HMR when executing tests in `run` mode ...(isTextTerminal diff --git a/npm/vite-plugin-cypress-esm/CHANGELOG.md b/npm/vite-plugin-cypress-esm/CHANGELOG.md index bb4139b30369..b79b0e488a2c 100644 --- a/npm/vite-plugin-cypress-esm/CHANGELOG.md +++ b/npm/vite-plugin-cypress-esm/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cypress/vite-plugin-cypress-esm-v1.1.0](https://github.com/cypress-io/cypress/compare/@cypress/vite-plugin-cypress-esm-v1.0.1...@cypress/vite-plugin-cypress-esm-v1.1.0) (2023-08-07) + + +### Features + +* Improve ignore capability to allow module & import matching ([#27461](https://github.com/cypress-io/cypress/issues/27461)) ([1f60dea](https://github.com/cypress-io/cypress/commit/1f60dea61c2c3dd1260f57db631975a1933c266d)) + # [@cypress/vite-plugin-cypress-esm-v1.0.1](https://github.com/cypress-io/cypress/compare/@cypress/vite-plugin-cypress-esm-v1.0.0...@cypress/vite-plugin-cypress-esm-v1.0.1) (2023-05-23) diff --git a/npm/vite-plugin-cypress-esm/README.md b/npm/vite-plugin-cypress-esm/README.md index ea25b21ef836..81feb67a5b08 100644 --- a/npm/vite-plugin-cypress-esm/README.md +++ b/npm/vite-plugin-cypress-esm/README.md @@ -43,13 +43,13 @@ export default defineConfig({ }) ``` -### `ignoreList` +### `ignoreModuleList` -Some modules may be incompatible with Proxy-based implementation. The eventual goal is to support wrapping all modules in a Proxy to better facilitate testing. For now, if you run into any issues with a particular module, you can add it to the `ignoreList` like so: +Some modules may be incompatible with Proxy-based implementation. The eventual goal is to support wrapping all modules in a Proxy to better facilitate testing. For now, if you run into any issues with a particular module, you can tell the plugin to skip it like so: ```ts CypressEsm({ - ignoreList: ['react-router', 'react-router-dom'] + ignoreModuleList: ['react-router', 'react-router-dom'] }) ``` @@ -57,25 +57,40 @@ You can also use a glob, which uses [`picomatch`](https://github.com/micromatch/ ```ts CypressEsm({ - ignoreList: ['*react*'] + ignoreModuleList: ['*react*'] }) ``` -This will exclude modules matching the supplied pattern from being processed by this plugin. It is important to note that the actual import of any matching module into other files/modules will still be processed unless those destinations are themselves excluded via the list. +This will exclude modules matching the supplied pattern(s) from being processed by this plugin. It is important to note that the act of importing any matching module into other files/modules will still be processed unless those destinations are themselves excluded via the list, but those imports will receive the unaltered version. -React is known to have some conflicts with the Proxy implementation that cause problems stubbing internal React functionality. Since it is unlikely you want to stub parts of React itself, it's a good idea to add it to the `ignoreList`. +Certain third-party dependencies such as React are known to have some conflicts with the Proxy implementation that cause problems stubbing internal functionality. Since it is unlikely you want to stub parts of React itself, it's a good idea to add it to the `ignoreModuleList`. + +### `ignoreImportList` + +There may be times when you want to use an unaltered dependency rather than the proxied version created by this plugin in a specific location, or want to use the standard import mechanism rather than the one provided by this plugin. This may be because: +1. You have a test that needs to validate original/unaltered behavior +2. You have a dependency (internal or external) that you wish to exclude from the processing done by this plugin. This is commonly due to third-party libraries that behave in a way that is unsupported. +3. You have code that relies on auto-hoisting which breaks when this plugin restructures the code (see [Auto-hoisting](#auto-hoisting)) + +To instruct this plugin to skip a given import and use the unaltered target module use `ignoreImportList`. This also supports `picomatch` patterns. + +```ts +CypressEsm({ + ignoreImportList: ['**/internal/problematic-file.js'] +}) +``` ## Known Issues ### Import Syntax -All known [import syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) is supported, however there may edge cases that have not been identified. +All known [import syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) is supported, however there may be edge cases that have not been identified. ### Regular Expression matching This module uses Regular Expression matching to transform the modules on the server to facilitate wrapping them in a `Proxy` on the client. In future updates, a more robust AST-based approach will be explored. A limitation of the current approach is that it does not recognize syntax from actual code vs content found within strings (for instance, an error string that contains example code syntax). This can result in inappropriately modified string constants. -### Auto-hosting +### Auto-hoisting ESM imports are automatically hoisted to the top of a given module so they happen first before any code that references them. This plugin does not currently perform any hoisting, so imports are transformed to variable references in place. If you have code that attempts to reference an imported value prior to that import it will likely break. This is a known issue with HMR logic in Svelte projects, and will typically present as a "use before define" error. @@ -99,7 +114,7 @@ import { foo, bar } from './mod_1.js' bar(foo) //=> false ``` -In this example, `bar(foo)` is passing a reference to `mod_1.foo`, where `mod_1` is a module wrapped in a `Proxy`. In the original `mod_1.js`, the reference to `foo` is the original, unwrapped `foo`, so the comparison return `false`. This may cause issues in some libraries, such as React Router when lazy loading routes. You can add modules to `ignoreList` to work around this issue. +In this example, `bar(foo)` is passing a reference to `mod_1.foo`, where `mod_1` is a module wrapped in a `Proxy`. In the original `mod_1.js`, the reference to `foo` is the original, unwrapped `foo`, so the comparison return `false`. This may cause issues in some libraries, such as React Router when lazy loading routes. You can add modules to `ignoreModuleList` to work around this issue. ### Sinon compatibility @@ -113,7 +128,7 @@ If you encounter issues: 1. Ensure you're using the very latest version of this Plugin and Cypress 2. Try temporarily removing this plugin from your test's Vite config - if the issue is still present then it is not related to this plugin. 3. Verify you have not encountered one of the [Known Issues](#known-issues) -3. If the issue disappeared then try narrowing down if it's related to a specific module/dependency by using the `ignoreList` config +3. If the issue disappeared then try narrowing down if it's related to a specific module/dependency by using the `ignoreModuleList` & `ignoreImportList` config 4. If your problem isn't related to a specific dependency and can't be isolated please file a bug report [here](https://github.com/cypress-io/cypress/issues/new?labels=npm:%20@cypress/vite-plugin-cypress-esm). A reproduction case project is extremely helpful to track down specific issues, and capturing [Debug Logs](#debugging) from both your terminal *and* the browser devtools console is very helpful. ## License diff --git a/npm/vite-plugin-cypress-esm/client/moduleCache.js b/npm/vite-plugin-cypress-esm/client/moduleCache.js index d7ec78f12032..a6f5b526f241 100644 --- a/npm/vite-plugin-cypress-esm/client/moduleCache.js +++ b/npm/vite-plugin-cypress-esm/client/moduleCache.js @@ -46,16 +46,28 @@ function createProxyModule (module) { log(`🧪 Redefining ${key}`) - Object.defineProperty(target, key, { + const params = { ...descriptor, ...overrides, - }) + } + + // If a property defines accessors it cannot also specify `value` and/or `writable`. + // Those are implicit from the presence of the accessor functions. + if ('get' in params || 'set' in params) { + delete params.writable + delete params.value + } + + Object.defineProperty(target, key, params) - if (typeof descriptor.value === 'function') { + // The underlying value could be a raw value *or* a value provided by a getter + const describedValue = descriptor.value || descriptor.get?.() + + if (typeof describedValue === 'function') { // This is how you can see if something is a class - // Playground: https://regex101.com/r/OS2Iyg/1 + // TODO: Revisit, there has to be a better way to do this // Important! RegEx instances are stateful, do not extract to a constant - const isClass = /class.+?\{.+?\}/gms.test(descriptor.value.toString()) + const isClass = /^class\s.+?\{.+?\}/gms.test(describedValue.toString()) if (isClass) { log(`🏗️ Handling ${key} as a constructor`) @@ -69,11 +81,20 @@ function createProxyModule (module) { log(`🎁 Handling ${key} with a standard wrapper function`) proxies[key] = function (...params) { - return target[key].apply(this, params) + // Prefer invoking with `apply` so we get proper context in the invoked function + if (target[key].apply) { + return target[key].apply(this, params) + } + + // Certain weird edge-cases manage to create functions without the Function + // prototype, thus no `apply` 🤷. Fall back to straight invocation + return target[key](params) } } proxies[key].prototype = target[key].prototype + } else { + log(`${key} is not a function`) } }) } @@ -83,7 +104,7 @@ function createProxyModule (module) { return module.default } - if (module.default && typeof module.default !== 'function') { + if (module.default) { redefinePropertyDescriptors(module.default, { writable: true, enumerable: true, @@ -165,15 +186,21 @@ function cacheAndProxifyModule (id, module) { log(`🔨 creating proxy module for ${id}`) - const moduleProxy = createProxyModule(module) + try { + const moduleProxy = createProxyModule(module) - log(`✅ created proxy module for ${id}`) + log(`✅ created proxy module for ${id}`) - __cypressModuleCache.set(module, moduleProxy) + __cypressModuleCache.set(module, moduleProxy) - log(`📈 Module cache now contains ${__cypressModuleCache.size} entries`) + log(`📈 Module cache now contains ${__cypressModuleCache.size} entries`) - return moduleProxy + return moduleProxy + } catch (err) { + console.warn(`Failed to proxy module ${id}, using original which will *not* support stub/spy`, err) + + return module + } } window.__cypressDynamicModule = function (id, importPromise, _debug = false) { diff --git a/npm/vite-plugin-cypress-esm/cypress.config.ts b/npm/vite-plugin-cypress-esm/cypress.config.ts index 47f27ebf5885..3ea2aa0a48f5 100644 --- a/npm/vite-plugin-cypress-esm/cypress.config.ts +++ b/npm/vite-plugin-cypress-esm/cypress.config.ts @@ -17,7 +17,8 @@ export default defineConfig({ jsxRuntime: 'classic', }), CypressEsm({ - ignoreList: ['**/*ignoreList.cy.ts', '*MyAsync*'], + ignoreModuleList: ['**/ignoreModuleList.cy.ts', '*MyAsync*'], + ignoreImportList: ['**/ImmutableModuleB*'], }), ], } diff --git a/npm/vite-plugin-cypress-esm/cypress/component/fixtures/MyImmutableModule.ts b/npm/vite-plugin-cypress-esm/cypress/component/fixtures/ImmutableModuleA.ts similarity index 100% rename from npm/vite-plugin-cypress-esm/cypress/component/fixtures/MyImmutableModule.ts rename to npm/vite-plugin-cypress-esm/cypress/component/fixtures/ImmutableModuleA.ts diff --git a/npm/vite-plugin-cypress-esm/cypress/component/fixtures/ImmutableModuleB.ts b/npm/vite-plugin-cypress-esm/cypress/component/fixtures/ImmutableModuleB.ts new file mode 100644 index 000000000000..ce60dbad5d76 --- /dev/null +++ b/npm/vite-plugin-cypress-esm/cypress/component/fixtures/ImmutableModuleB.ts @@ -0,0 +1,7 @@ +export function unstubbable () { + return 'Hello from immutable' +} + +export default function nospy () { + return 'You cannot spy on this' +} diff --git a/npm/vite-plugin-cypress-esm/cypress/component/ignoreImportList.cy.ts b/npm/vite-plugin-cypress-esm/cypress/component/ignoreImportList.cy.ts new file mode 100644 index 000000000000..efa50da7e028 --- /dev/null +++ b/npm/vite-plugin-cypress-esm/cypress/component/ignoreImportList.cy.ts @@ -0,0 +1,16 @@ +// This import path should match `ignoreImportPath` and be ignored +import * as Immutable from './fixtures/ImmutableModuleB' + +describe('ignoreImportList', () => { + it('ignored import is not proxified and cannot be stubbed', () => { + let called = false + + try { + cy.stub(Immutable, 'unstubbable') + } catch (e) { + expect(e.message).to.eq('ES Modules cannot be stubbed') + called = true + } + expect(called).to.be.true + }) +}) diff --git a/npm/vite-plugin-cypress-esm/cypress/component/ignoreList.cy.ts b/npm/vite-plugin-cypress-esm/cypress/component/ignoreModuleList.cy.ts similarity index 73% rename from npm/vite-plugin-cypress-esm/cypress/component/ignoreList.cy.ts rename to npm/vite-plugin-cypress-esm/cypress/component/ignoreModuleList.cy.ts index 128ae88da8d9..ab01553dbf74 100644 --- a/npm/vite-plugin-cypress-esm/cypress/component/ignoreList.cy.ts +++ b/npm/vite-plugin-cypress-esm/cypress/component/ignoreModuleList.cy.ts @@ -1,7 +1,8 @@ -import * as Immutable from './fixtures/MyImmutableModule' +// The referenced module should be ignored due to `ignoreModuleList` entry +import * as Immutable from './fixtures/ImmutableModuleA' -describe('ignoreList', () => { - it('ignoreList module is not proxified and cannot be stubbed', () => { +describe('ignoreModuleList', () => { + it('ignored module is not proxified and cannot be stubbed', () => { let called = false try { @@ -13,7 +14,7 @@ describe('ignoreList', () => { expect(called).to.be.true }) - it('ignoreList module is not proxified and cannot be spied', () => { + it('ignored module is not proxified and cannot be spied', () => { let called = false try { diff --git a/npm/vite-plugin-cypress-esm/package.json b/npm/vite-plugin-cypress-esm/package.json index 57e283e278fe..ad600a9c85d5 100644 --- a/npm/vite-plugin-cypress-esm/package.json +++ b/npm/vite-plugin-cypress-esm/package.json @@ -8,7 +8,8 @@ "build-prod": "tsc || echo 'built, with type errors'", "check-ts": "tsc --noEmit", "cypress:open": "node ../../scripts/cypress open --project . --component", - "test": "node ../../scripts/cypress run --project . --component", + "cypress:run": "node ../../scripts/cypress run --project . --component", + "test": "npm run cypress:run", "watch": "tsc -w", "lint": "eslint --ext .js,.ts,.json, ." }, diff --git a/npm/vite-plugin-cypress-esm/src/index.ts b/npm/vite-plugin-cypress-esm/src/index.ts index 9704f48f32f4..8d2fd8f48bab 100644 --- a/npm/vite-plugin-cypress-esm/src/index.ts +++ b/npm/vite-plugin-cypress-esm/src/index.ts @@ -14,21 +14,68 @@ const MODULE_CACHE_FILEPATH = path.resolve( ) interface CypressEsmOptions { + /** + * @deprecated Use {@link ignoreModuleList}, any items here will be added to ignoreModuleList + */ ignoreList?: string[] + /** + * Array of picomatch patterns of modules to ignore (leave untouched). Any ignored modules + * will not support stub/spy of their contents/dependencies. Use this to skip problematic + * modules which are structured in a way that prevent this plugin from proxying them - this + * is typically only an issue for complex third-party libraries. + * + * Example: + * Module A imports Module B + * Adding `A` to `ignoreModuleList` will prevent usages of `B` within `A` from being stubbed + */ + ignoreModuleList?: string[] + /** + * Array of picomatch patterns of imports to ignore (use unaltered module). Any ignored + * imports will not support stub/spy. Use this to remedy usages of a proxied module that cause + * problems. + * + * Example: + * Module A imports Module B + * Adding `B` to `ignoreImportList` will prevent usages of `B` within `A` from being stubbed + */ + ignoreImportList?: string[] +} + +const assertIsArrayOrUndefined = (name: string, value: any): void => { + if (value && (!Array.isArray(value) || value.some((val) => typeof val !== 'string'))) { + throw new Error(`ESM plugin config value '${name}' must be an array of strings`) + } } export const CypressEsm = (options?: CypressEsmOptions): Plugin => { - const ignoreList = options?.ignoreList ?? [] - const ignoreMatcher = picomatch(ignoreList) + // Validate config + assertIsArrayOrUndefined('ignoreList', options?.ignoreList) + assertIsArrayOrUndefined('ignoreModuleList', options?.ignoreModuleList) + assertIsArrayOrUndefined('ignoreImportList', options?.ignoreImportList) + + const ignoreModuleList = ([] as string[]).concat(options?.ignoreModuleList ?? []).concat(options?.ignoreList ?? []) + const ignoreImportList = options?.ignoreImportList ?? [] + const ignoreModuleMatcher = picomatch(ignoreModuleList) + const ignoreImportMatcher = picomatch(ignoreImportList) /** - * If a module ID is explicitly ignored then bypass our custom mapping on it + * If a module ID is explicitly ignored then do not proxify it * * @param moduleId * @returns */ const isModuleOnIgnoreList = (moduleId: string) => { - return ignoreMatcher(moduleId) + return ignoreModuleMatcher(moduleId) + } + + /** + * If a given import target (path) is explicitly ignored then bypass our custom mapping on it + * + * @param importTarget + * @returns + */ + const isImportOnIgnoreList = (importTarget: string) => { + return ignoreImportMatcher(importTarget) } /** @@ -78,7 +125,13 @@ export const CypressEsm = (options?: CypressEsmOptions): Plugin => { return code.replace( importRegex, (match, importVars: string, importTarget: string) => { - debug(`Mapping import ${counter + 1} in module ${moduleId}`) + if (isImportOnIgnoreList(importTarget)) { + debug(`⏭️ Import ${importTarget} matches ignoreImportList, ignoring`) + + return match + } + + debug(`Mapping import ${counter + 1} (${importTarget}) in module ${moduleId}`) if (isNonJsTarget(importTarget)) { debug(`Import ${importTarget} appears to be an asset and will not be re-mapped`) @@ -120,7 +173,7 @@ export const CypressEsm = (options?: CypressEsmOptions): Plugin => { // support `import { foo as bar } from 'module'` syntax, converting to `const { foo: bar } ...` decl = decl.replace(/(? { RE, (match, importVars: string, importTarget: string) => { if (isNonJsTarget(importTarget)) { - debug(`Import ${importTarget} appears to be an asset and will not be re-mapped`) + debug(`🎨 Import ${importTarget} appears to be an asset, ignoring`) return match } @@ -179,13 +232,13 @@ export const CypressEsm = (options?: CypressEsmOptions): Plugin => { enforce: 'post', transform (code, id, options) { if (isModuleOnIgnoreList(id)) { - debug(`Ignoring module ${id} due to ignoreList`) + debug(`⏭️ Module ${id} matches ignoreModuleList, ignoring`) return } if (isNonJsTarget(id)) { - debug(`Module ${id} appears to be an asset, ignoring`) + debug(`🎨 Module ${id} appears to be an asset, ignoring`) return } diff --git a/npm/vue/CHANGELOG.md b/npm/vue/CHANGELOG.md index c37f9b82e73f..e9b3316f01e4 100644 --- a/npm/vue/CHANGELOG.md +++ b/npm/vue/CHANGELOG.md @@ -1,3 +1,8 @@ +# [@cypress/vue-v6.0.0](https://github.com/cypress-io/cypress/compare/@cypress/vue-v5.0.5...@cypress/vue-v6.0.0) (2023-08-29) + + +* `@cypress/vue-v6.0.0` was inadvertently released and published. There are no breaking changes or any other changes in this release. + # [@cypress/vue-v5.0.5](https://github.com/cypress-io/cypress/compare/@cypress/vue-v5.0.4...@cypress/vue-v5.0.5) (2023-03-20) diff --git a/npm/vue/cypress.config.ts b/npm/vue/cypress.config.ts index 5af9d619996f..d4c8b1be979c 100644 --- a/npm/vue/cypress.config.ts +++ b/npm/vue/cypress.config.ts @@ -3,7 +3,6 @@ import { defineConfig } from 'cypress' export default defineConfig({ 'viewportWidth': 500, 'viewportHeight': 500, - 'video': false, 'responseTimeout': 2500, 'projectId': '134ej7', 'experimentalFetchPolyfill': true, diff --git a/npm/vue/package.json b/npm/vue/package.json index a22f0588f1a7..2f7ac9525cce 100644 --- a/npm/vue/package.json +++ b/npm/vue/package.json @@ -9,7 +9,6 @@ "cy:run": "node ../../scripts/cypress.js run --component --project ${PWD}", "build": "rimraf dist && rollup -c rollup.config.mjs", "postbuild": "node ../../scripts/sync-exported-npm-with-cli.js", - "typecheck": "yarn tsd && vue-tsc --noEmit", "check-ts": "yarn tsd && vue-tsc --noEmit", "lint": "eslint --ext .js,.jsx,.ts,.tsx,.json,.vue .", "test": "yarn cy:run", diff --git a/npm/vue2/package.json b/npm/vue2/package.json index dea49368f93f..16a237a58059 100644 --- a/npm/vue2/package.json +++ b/npm/vue2/package.json @@ -4,7 +4,7 @@ "description": "Browser-based Component Testing for Vue.js@2 with Cypress.io ✌️🌲", "main": "dist/cypress-vue2.cjs.js", "scripts": { - "typecheck": "tsc --noEmit", + "check-ts": "tsc --noEmit", "build": "rimraf dist && yarn rollup -c rollup.config.mjs", "postbuild": "node ../../scripts/sync-exported-npm-with-cli.js", "build-prod": "yarn build", diff --git a/npm/webpack-batteries-included-preprocessor/CHANGELOG.md b/npm/webpack-batteries-included-preprocessor/CHANGELOG.md index 45070570c2c1..c3e84d30c4ea 100644 --- a/npm/webpack-batteries-included-preprocessor/CHANGELOG.md +++ b/npm/webpack-batteries-included-preprocessor/CHANGELOG.md @@ -1,3 +1,29 @@ +# [@cypress/webpack-batteries-included-preprocessor-v3.0.2](https://github.com/cypress-io/cypress/compare/@cypress/webpack-batteries-included-preprocessor-v3.0.1...@cypress/webpack-batteries-included-preprocessor-v3.0.2) (2023-08-31) + + +### Bug Fixes + +* change how tsconfig is aliased in webpack-batteries-included-preprocessor ([#27706](https://github.com/cypress-io/cypress/issues/27706)) ([6081751](https://github.com/cypress-io/cypress/commit/6081751c411a45bb9eaf7ba200d4921acdcc2422)) + +# [@cypress/webpack-batteries-included-preprocessor-v3.0.1](https://github.com/cypress-io/cypress/compare/@cypress/webpack-batteries-included-preprocessor-v3.0.0...@cypress/webpack-batteries-included-preprocessor-v3.0.1) (2023-08-29) + + +### Bug Fixes + +* resolve process/browser to process/browser.js to resolve correctly in ESM packages where .mjs or .js files exist where process is being used and globally imported. [run ci] ([#27611](https://github.com/cypress-io/cypress/issues/27611)) ([8b5c551](https://github.com/cypress-io/cypress/commit/8b5c551890024c6389b881e081114c6f1519ba98)) + +# [@cypress/webpack-batteries-included-preprocessor-v3.0.0](https://github.com/cypress-io/cypress/compare/@cypress/webpack-batteries-included-preprocessor-v2.4.1...@cypress/webpack-batteries-included-preprocessor-v3.0.0) (2023-08-14) + + +### breaking + +* support webpack v5 ([00fb578](https://github.com/cypress-io/cypress/commit/00fb5782eb47ffe46c774c7579157499e5e916e0)) + + +### BREAKING CHANGES + +* Since cypress now bundles with webpack v5, the minimum webpack version is now version 5 as this iswhat cypress will support in the monorepo moving forward. If you wish to use webpack 4, please use v2 of this package. + # [@cypress/webpack-batteries-included-preprocessor-v2.4.1](https://github.com/cypress-io/cypress/compare/@cypress/webpack-batteries-included-preprocessor-v2.4.0...@cypress/webpack-batteries-included-preprocessor-v2.4.1) (2023-03-14) diff --git a/npm/webpack-batteries-included-preprocessor/README.md b/npm/webpack-batteries-included-preprocessor/README.md index 0d34e70a9c80..f7c0c54a7390 100644 --- a/npm/webpack-batteries-included-preprocessor/README.md +++ b/npm/webpack-batteries-included-preprocessor/README.md @@ -14,6 +14,8 @@ This preprocessor is a wrapper for [@cypress/webpack-preprocessor](https://githu Note that installing [@cypress/webpack-preprocessor](https://github.com/cypress-io/cypress-webpack-preprocessor) is also required. This allows you to update its version separately from this wrapper. +For webpack `v5`, use `@cypress/webpack-batteries-included-preprocessor@3.x.x`. For webpack `v4`, use `@cypress/webpack-batteries-included-preprocessor@2.x.x`. + ```sh npm install --save-dev @cypress/webpack-batteries-included-preprocessor @cypress/webpack-preprocessor ``` diff --git a/npm/webpack-batteries-included-preprocessor/empty.js b/npm/webpack-batteries-included-preprocessor/empty.js deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/npm/webpack-batteries-included-preprocessor/index.js b/npm/webpack-batteries-included-preprocessor/index.js index 05130765dc02..28126d1dab83 100644 --- a/npm/webpack-batteries-included-preprocessor/index.js +++ b/npm/webpack-batteries-included-preprocessor/index.js @@ -1,4 +1,5 @@ const path = require('path') +const webpack = require('webpack') const webpackPreprocessor = require('@cypress/webpack-preprocessor') const hasTsLoader = (rules) => { @@ -26,8 +27,8 @@ const addTypeScriptConfig = (file, options) => { const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin') // node will try to load a projects tsconfig.json instead of the node - // package using require('tsconfig'), so we alias it as 'tsconfig-package' - const configFile = require('tsconfig-package').findSync(path.dirname(file.filePath)) + // package using require('tsconfig'), so we alias it as 'tsconfig-aliased-for-wbip' + const configFile = require('tsconfig-aliased-for-wbip').findSync(path.dirname(file.filePath)) webpackOptions.module.rules.push({ test: /\.tsx?$/, @@ -107,8 +108,8 @@ const getDefaultWebpackOptions = () => { plugins: [ ...[ 'babel-plugin-add-module-exports', - '@babel/plugin-proposal-class-properties', - '@babel/plugin-proposal-object-rest-spread', + '@babel/plugin-transform-class-properties', + '@babel/plugin-transform-object-rest-spread', ].map(require.resolve), [require.resolve('@babel/plugin-transform-runtime'), { absoluteRuntime: path.dirname(require.resolve('@babel/runtime/package')), @@ -131,23 +132,59 @@ const getDefaultWebpackOptions = () => { loader: require.resolve('coffee-loader'), }], }, + plugins: [ + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], + // As of Webpack 5, a new option called resolve.fullySpecified, was added. + // This option means that a full path, in particular to .mjs / .js files + // in ESM packages must have the full path of an import specified. + // Otherwise, compilation fails as this option defaults to true. + // This means we need to adjust our global injections to always + // resolve to include the full file extension if a file resolution is provided. + // @see https://github.com/cypress-io/cypress/issues/27599 + // @see https://webpack.js.org/configuration/module/#resolvefullyspecified + process: 'process/browser.js', + }), + ], resolve: { extensions: ['.js', '.json', '.jsx', '.mjs', '.coffee'], - alias: { - 'child_process': require.resolve('./empty'), - 'cluster': require.resolve('./empty'), - 'console': require.resolve('./empty'), - 'dgram': require.resolve('./empty'), - 'dns': require.resolve('./empty'), - 'fs': require.resolve('./empty'), - 'http2': require.resolve('./empty'), - 'inspector': require.resolve('./empty'), - 'module': require.resolve('./empty'), - 'net': require.resolve('./empty'), - 'perf_hooks': require.resolve('./empty'), - 'readline': require.resolve('./empty'), - 'repl': require.resolve('./empty'), - 'tls': require.resolve('./empty'), + fallback: { + assert: require.resolve('assert/'), + buffer: require.resolve('buffer/'), + child_process: false, + cluster: false, + console: false, + constants: require.resolve('constants-browserify'), + crypto: require.resolve('crypto-browserify'), + dgram: false, + dns: false, + domain: require.resolve('domain-browser'), + events: require.resolve('events/'), + fs: false, + http: require.resolve('stream-http'), + https: require.resolve('https-browserify'), + http2: false, + inspector: false, + module: false, + net: false, + os: require.resolve('os-browserify/browser'), + path: require.resolve('path-browserify'), + perf_hooks: false, + punycode: require.resolve('punycode/'), + process: require.resolve('process/browser.js'), + querystring: require.resolve('querystring-es3'), + readline: false, + repl: false, + stream: require.resolve('stream-browserify'), + string_decoder: require.resolve('string_decoder/'), + sys: require.resolve('util/'), + timers: require.resolve('timers-browserify'), + tls: false, + tty: require.resolve('tty-browserify'), + url: require.resolve('url/'), + util: require.resolve('util/'), + vm: require.resolve('vm-browserify'), + zlib: require.resolve('browserify-zlib'), }, plugins: [], }, diff --git a/npm/webpack-batteries-included-preprocessor/package.json b/npm/webpack-batteries-included-preprocessor/package.json index 5ddc6c3bb876..2a9698d7cdfc 100644 --- a/npm/webpack-batteries-included-preprocessor/package.json +++ b/npm/webpack-batteries-included-preprocessor/package.json @@ -8,27 +8,47 @@ "lint": "eslint --ext .js,.ts,.json, ." }, "dependencies": { - "@babel/core": "^7.11.1", - "@babel/plugin-proposal-class-properties": "^7.10.4", - "@babel/plugin-proposal-object-rest-spread": "^7.11.0", - "@babel/plugin-transform-runtime": "^7.11.0", - "@babel/preset-env": "^7.11.0", - "@babel/preset-react": "^7.10.4", - "@babel/runtime": "^7.11.2", - "babel-loader": "^8.1.0", + "@babel/core": "^7.22.9", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-object-rest-spread": "^7.22.5", + "@babel/plugin-transform-runtime": "^7.22.9", + "@babel/preset-env": "^7.22.9", + "@babel/preset-react": "^7.22.5", + "@babel/runtime": "^7.22.6", + "assert": "^2.0.0", + "babel-loader": "^9.1.3", "babel-plugin-add-module-exports": "^1.0.2", - "coffee-loader": "^0.9.0", - "coffeescript": "^1.12.7", + "browserify-zlib": "^0.2.0", + "buffer": "^6.0.3", + "coffee-loader": "^4.0.0", + "coffeescript": "2.6.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.12.0", + "domain-browser": "^4.22.0", + "events": "^3.3.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", "pnp-webpack-plugin": "^1.7.0", - "ts-loader": "8.4.0", - "tsconfig-package": "npm:tsconfig@^7.0.0", - "tsconfig-paths-webpack-plugin": "^3.3.0", - "webpack": "^4.44.2" + "process": "^0.11.10", + "punycode": "^2.3.0", + "querystring-es3": "^0.2.1", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "timers-browserify": "^2.0.12", + "ts-loader": "9.4.4", + "tsconfig-aliased-for-wbip": "npm:tsconfig@^7.0.0", + "tsconfig-paths-webpack-plugin": "^3.5.2", + "tty-browserify": "^0.0.1", + "url": "^0.11.1", + "util": "^0.12.5", + "vm-browserify": "^1.1.2", + "webpack": "^5.88.2" }, "devDependencies": { "@cypress/webpack-preprocessor": "0.0.0-development", "@types/mocha": "^8.0.2", - "@types/webpack": "^4.41.21", + "@types/webpack": "^5.28.1", "chai": "^4.2.0", "fs-extra": "^9.1.0", "mocha": "^8.1.1", diff --git a/npm/webpack-batteries-included-preprocessor/test/fixtures/mjs_spec.mjs b/npm/webpack-batteries-included-preprocessor/test/fixtures/mjs_spec.mjs index 94cd40e59259..babd0da4930f 100644 --- a/npm/webpack-batteries-included-preprocessor/test/fixtures/mjs_spec.mjs +++ b/npm/webpack-batteries-included-preprocessor/test/fixtures/mjs_spec.mjs @@ -1,3 +1,8 @@ import { expect } from 'chai' +// make sure built in resolves correctly in mjs through the provide plugin, including process & buffer +process.env.foo = 'bar' + +const buffer = new Buffer('foo'); + expect(true).to.be.true diff --git a/npm/webpack-batteries-included-preprocessor/test/fixtures/node_builtins_spec.js b/npm/webpack-batteries-included-preprocessor/test/fixtures/node_builtins_spec.js index 1e07fbe075d7..f68fcea839b0 100644 --- a/npm/webpack-batteries-included-preprocessor/test/fixtures/node_builtins_spec.js +++ b/npm/webpack-batteries-included-preprocessor/test/fixtures/node_builtins_spec.js @@ -19,7 +19,10 @@ expect(require('net')).to.be.eql({}) expect(require('os')).to.be.an('object').and.have.property('platform') expect(require('path')).to.be.an('object').and.have.property('join') expect(require('perf_hooks')).to.eql({}) -expect(require('punycode')).to.be.an('object').and.have.property('encode') +const punycode = require('punycode') + +expect(typeof punycode).to.equal('object') +expect(punycode).to.have.property('encode') expect(require('querystring')).to.be.an('object').and.have.property('parse') expect(require('readline')).to.be.eql({}) expect(require('repl')).to.be.eql({}) diff --git a/npm/webpack-dev-server/CHANGELOG.md b/npm/webpack-dev-server/CHANGELOG.md index 475259e463d9..66217c1173b7 100644 --- a/npm/webpack-dev-server/CHANGELOG.md +++ b/npm/webpack-dev-server/CHANGELOG.md @@ -1,3 +1,26 @@ +# [@cypress/webpack-dev-server-v3.6.1](https://github.com/cypress-io/cypress/compare/@cypress/webpack-dev-server-v3.6.0...@cypress/webpack-dev-server-v3.6.1) (2023-09-07) + +# [@cypress/webpack-dev-server-v3.6.0](https://github.com/cypress-io/cypress/compare/@cypress/webpack-dev-server-v3.5.3...@cypress/webpack-dev-server-v3.6.0) (2023-09-07) + + +### Features + +* **webpack-dev-server:** update the generated tsconfig path for angular CT ([#27723](https://github.com/cypress-io/cypress/issues/27723)) ([264a118](https://github.com/cypress-io/cypress/commit/264a118e4858ea6bc401d71895b09f656a4dc938)) + +# [@cypress/webpack-dev-server-v3.5.3](https://github.com/cypress-io/cypress/compare/@cypress/webpack-dev-server-v3.5.2...@cypress/webpack-dev-server-v3.5.3) (2023-08-29) + + +### Bug Fixes + +* allow cypress config.port to override devServer.port for proxying assets ([f82fdf0](https://github.com/cypress-io/cypress/commit/f82fdf026eeab125a2b974e4257a7ac5e33640eb)) + +# [@cypress/webpack-dev-server-v3.5.2](https://github.com/cypress-io/cypress/compare/@cypress/webpack-dev-server-v3.5.1...@cypress/webpack-dev-server-v3.5.2) (2023-08-04) + + +### Bug Fixes + +* **cypress/webpack-dev-server:** correct path for `indexHtmlFile` ([#27320](https://github.com/cypress-io/cypress/issues/27320)) ([53fd537](https://github.com/cypress-io/cypress/commit/53fd537a0486caedc7faccacff7c6433ebc2601f)) + # [@cypress/webpack-dev-server-v3.5.1](https://github.com/cypress-io/cypress/compare/@cypress/webpack-dev-server-v3.5.0...@cypress/webpack-dev-server-v3.5.1) (2023-07-18) diff --git a/npm/webpack-dev-server/README.md b/npm/webpack-dev-server/README.md index 91a641e5be2b..0715bcddbcff 100644 --- a/npm/webpack-dev-server/README.md +++ b/npm/webpack-dev-server/README.md @@ -68,6 +68,7 @@ We then merge the sourced config with the user's webpack config, and layer on ou | --------------------------- | ------- | | <= v1 | <= v9 | | >= v2 | >= v10 | +| >= v4 | >= v13 | ## License diff --git a/npm/webpack-dev-server/cypress/e2e/angular.cy.ts b/npm/webpack-dev-server/cypress/e2e/angular.cy.ts index 8cbbd0ba816a..0b4e7997e26b 100644 --- a/npm/webpack-dev-server/cypress/e2e/angular.cy.ts +++ b/npm/webpack-dev-server/cypress/e2e/angular.cy.ts @@ -15,7 +15,7 @@ for (const project of WEBPACK_ANGULAR) { context(project, () => { beforeEach(() => { cy.scaffoldProject(project) - cy.openProject(project) + cy.openProject(project, ['--component']) }) describe('configuration handling', () => { diff --git a/npm/webpack-dev-server/cypress/e2e/create-react-app.cy.ts b/npm/webpack-dev-server/cypress/e2e/create-react-app.cy.ts index 39697b10dbb5..615b7e7499e6 100644 --- a/npm/webpack-dev-server/cypress/e2e/create-react-app.cy.ts +++ b/npm/webpack-dev-server/cypress/e2e/create-react-app.cy.ts @@ -14,7 +14,7 @@ for (const project of WEBPACK_REACT) { describe(`Working with ${project}`, () => { beforeEach(() => { cy.scaffoldProject(project) - cy.openProject(project) + cy.openProject(project, ['--component']) cy.startAppServer('component') }) diff --git a/npm/webpack-dev-server/cypress/e2e/next.cy.ts b/npm/webpack-dev-server/cypress/e2e/next.cy.ts index 177e0871be32..c36c72f31bc3 100644 --- a/npm/webpack-dev-server/cypress/e2e/next.cy.ts +++ b/npm/webpack-dev-server/cypress/e2e/next.cy.ts @@ -14,7 +14,7 @@ for (const project of WEBPACK_REACT) { describe(`Working with ${project}`, () => { beforeEach(() => { cy.scaffoldProject(project) - cy.openProject(project) + cy.openProject(project, ['--component']) cy.startAppServer('component') }) diff --git a/npm/webpack-dev-server/cypress/e2e/nuxt.cy.ts b/npm/webpack-dev-server/cypress/e2e/nuxt.cy.ts index 0621d60c4339..1820ae184379 100644 --- a/npm/webpack-dev-server/cypress/e2e/nuxt.cy.ts +++ b/npm/webpack-dev-server/cypress/e2e/nuxt.cy.ts @@ -16,7 +16,7 @@ for (const project of PROJECTS) { describe(`Working with ${project}`, () => { beforeEach(() => { cy.scaffoldProject(project) - cy.openProject(project) + cy.openProject(project, ['--component']) cy.startAppServer('component') }) diff --git a/npm/webpack-dev-server/cypress/e2e/react.cy.ts b/npm/webpack-dev-server/cypress/e2e/react.cy.ts index 049096b0c98a..a4f625ab4b60 100644 --- a/npm/webpack-dev-server/cypress/e2e/react.cy.ts +++ b/npm/webpack-dev-server/cypress/e2e/react.cy.ts @@ -17,7 +17,7 @@ for (const project of WEBPACK_REACT) { describe(`Working with ${project}`, () => { beforeEach(() => { cy.scaffoldProject(project) - cy.openProject(project, ['--config-file', 'cypress-webpack.config.ts']) + cy.openProject(project, ['--config-file', 'cypress-webpack.config.ts', '--component']) cy.startAppServer('component') }) diff --git a/npm/webpack-dev-server/cypress/e2e/vue-cli.cy.ts b/npm/webpack-dev-server/cypress/e2e/vue-cli.cy.ts index 312ec87c9c7d..5b0b32bc7313 100644 --- a/npm/webpack-dev-server/cypress/e2e/vue-cli.cy.ts +++ b/npm/webpack-dev-server/cypress/e2e/vue-cli.cy.ts @@ -14,7 +14,7 @@ for (const project of PROJECTS) { describe(`Working with ${project}`, () => { beforeEach(() => { cy.scaffoldProject(project) - cy.openProject(project) + cy.openProject(project, ['--component']) cy.startAppServer('component') }) diff --git a/npm/webpack-dev-server/cypress/e2e/webpack-dev-server.cy.ts b/npm/webpack-dev-server/cypress/e2e/webpack-dev-server.cy.ts index 06e85369ea81..b8609bf52a3b 100644 --- a/npm/webpack-dev-server/cypress/e2e/webpack-dev-server.cy.ts +++ b/npm/webpack-dev-server/cypress/e2e/webpack-dev-server.cy.ts @@ -3,7 +3,7 @@ describe('Config options', () => { it('supports supportFile = false', () => { cy.scaffoldProject('webpack5_wds4-react') - cy.openProject('webpack5_wds4-react', ['--config-file', 'cypress-webpack-no-support.config.ts']) + cy.openProject('webpack5_wds4-react', ['--config-file', 'cypress-webpack-no-support.config.ts', '--component']) cy.startAppServer('component') cy.visitApp() @@ -12,9 +12,20 @@ describe('Config options', () => { cy.get('.passed > .num').should('contain', 1) }) + it('supports nested config', () => { + cy.scaffoldProject('webpack-react-nested-config') + cy.openProject('webpack-react-nested-config', ['--config-file', 'cypress/cypress.config.js', '--component']) + cy.startAppServer('component') + + cy.visitApp() + cy.contains('foo.cy.js').click() + cy.waitForSpecToFinish() + cy.get('.passed > .num').should('contain', 1) + }) + it('supports @cypress/webpack-dev-server', () => { cy.scaffoldProject('webpack5_wds4-react') - cy.openProject('webpack5_wds4-react', ['--config-file', 'cypress-webpack-dev-server-function.config.ts']) + cy.openProject('webpack5_wds4-react', ['--config-file', 'cypress-webpack-dev-server-function.config.ts', '--component']) cy.startAppServer('component') cy.visitApp() @@ -25,7 +36,7 @@ describe('Config options', () => { it('supports webpackConfig as an async function', () => { cy.scaffoldProject('webpack5_wds4-react') - cy.openProject('webpack5_wds4-react', ['--config-file', 'cypress-webpack-dev-server-async-config.config.ts']) + cy.openProject('webpack5_wds4-react', ['--config-file', 'cypress-webpack-dev-server-async-config.config.ts', '--component']) cy.startAppServer('component') cy.visitApp() @@ -42,7 +53,7 @@ describe('Config options', () => { it('recompiles with new spec and custom indexHtmlFile', () => { cy.scaffoldProject('webpack5_wds4-react') - cy.openProject('webpack5_wds4-react', ['--config-file', 'cypress-webpack-dev-server-custom-index.config.ts']) + cy.openProject('webpack5_wds4-react', ['--config-file', 'cypress-webpack-dev-server-custom-index.config.ts', '--component']) cy.startAppServer('component') cy.visitApp() @@ -57,4 +68,15 @@ describe('Config options', () => { cy.contains('New.cy.js').click() cy.waitForSpecToFinish({ passCount: 2 }) }) + + it('supports loading assets via relative urls', () => { + cy.scaffoldProject('webpack-dev-server-relative') + cy.openProject('webpack-dev-server-relative', ['--component']) + cy.startAppServer('component') + + cy.visitApp() + cy.contains('relative-url.cy.jsx').click() + cy.waitForSpecToFinish() + cy.get('.passed > .num').should('contain', 1) + }) }) diff --git a/npm/webpack-dev-server/package.json b/npm/webpack-dev-server/package.json index 7811a10e445d..4153d03eab2b 100644 --- a/npm/webpack-dev-server/package.json +++ b/npm/webpack-dev-server/package.json @@ -30,6 +30,7 @@ "webpack-merge": "^5.4.0" }, "devDependencies": { + "@types/node": "18.17.5", "@types/proxyquire": "^1.3.28", "@types/speed-measure-webpack-plugin": "^1.3.4", "@types/webpack-dev-server-3": "npm:@types/webpack-dev-server@^3", diff --git a/npm/webpack-dev-server/src/devServer.ts b/npm/webpack-dev-server/src/devServer.ts index 675328144e22..1dbb5d729292 100644 --- a/npm/webpack-dev-server/src/devServer.ts +++ b/npm/webpack-dev-server/src/devServer.ts @@ -64,8 +64,11 @@ export function devServer (devServerConfig: WebpackDevServerConfig): Promise { const result = await devServer.create(devServerConfig) as DevServerCreateResult + // @ts-expect-error + const { port } = result.server?.options + if (result.version === 3) { - const srv = result.server.listen(0, '127.0.0.1', () => { + const srv = result.server.listen(port || 0, '127.0.0.1', () => { const port = (srv.address() as AddressInfo).port debug('Component testing webpack server 3 started on port %s', port) diff --git a/npm/webpack-dev-server/src/helpers/angularHandler.ts b/npm/webpack-dev-server/src/helpers/angularHandler.ts index 03d004646525..59d9e2ff0e4d 100644 --- a/npm/webpack-dev-server/src/helpers/angularHandler.ts +++ b/npm/webpack-dev-server/src/helpers/angularHandler.ts @@ -154,15 +154,15 @@ export async function generateTsConfig (devServerConfig: AngularWebpackDevServer include: includePaths, }, null, 2) - const tsConfigPath = path.join(await getTempDir(), 'tsconfig.json') + const tsConfigPath = path.join(await getTempDir(path.basename(projectRoot)), 'tsconfig.json') await fs.writeFile(tsConfigPath, tsConfigContent) return tsConfigPath } -export async function getTempDir (): Promise { - const cypressTempDir = path.join(tmpdir(), 'cypress-angular-ct') +export async function getTempDir (projectName: string): Promise { + const cypressTempDir = path.join(tmpdir(), 'cypress-angular-ct', projectName) await fs.ensureDir(cypressTempDir) diff --git a/npm/webpack-dev-server/src/helpers/nextHandler.ts b/npm/webpack-dev-server/src/helpers/nextHandler.ts index ebd747cbea8a..9a3d4cc7e00e 100644 --- a/npm/webpack-dev-server/src/helpers/nextHandler.ts +++ b/npm/webpack-dev-server/src/helpers/nextHandler.ts @@ -239,6 +239,7 @@ function checkSWC ( // "resolvedNodePath" is only set when using the user's Node.js, which is required to compile Next.js with SWC optimizations // If it is not set, they have either explicitly set "nodeVersion" to "bundled" or are are using Cypress < 9.0.0 where it was set to "bundled" by default + // @ts-expect-error nodeVersion has been removed as of 13.0.0 however this plugin can be used with many versions of cypress if (hasSWCLoader && cypressConfig.nodeVersion === 'bundled') { throw new Error(`Cypress cannot compile your Next.js application when "nodeVersion" is set to "bundled". Please remove this option from your Cypress configuration file.`) } diff --git a/npm/webpack-dev-server/src/loader.ts b/npm/webpack-dev-server/src/loader.ts index 35e27396f25c..6008adbb3cfd 100644 --- a/npm/webpack-dev-server/src/loader.ts +++ b/npm/webpack-dev-server/src/loader.ts @@ -18,7 +18,7 @@ const makeImport = (file: Cypress.Cypress['spec'], filename: string, chunkName: const magicComments = chunkName ? `/* webpackChunkName: "${chunkName}" */` : '' return `"${filename}": { - shouldLoad: () => decodeURI(document.location.pathname).includes("${file.absolute}"), + shouldLoad: () => new URLSearchParams(document.location.search).get("specPath") === "${file.absolute}", load: () => import("${file.absolute}" ${magicComments}), absolute: "${file.absolute.split(path.sep).join(path.posix.sep)}", relative: "${file.relative.split(path.sep).join(path.posix.sep)}", @@ -33,7 +33,7 @@ const makeImport = (file: Cypress.Cypress['spec'], filename: string, chunkName: * @returns {Record} * { * "App.spec.js": { - * shouldLoad: () => document.location.pathname.includes("cypress/component/App.spec.js"), + * shouldLoad: () => (new URL(document.location)).searchParams.get("specPath") === "cypress/component/App.spec.js", * load: () => { * return import("/Users/projects/my-app/cypress/component/App.spec.js" \/* webpackChunkName: "spec-0" *\/) * }, diff --git a/npm/webpack-dev-server/src/makeDefaultWebpackConfig.ts b/npm/webpack-dev-server/src/makeDefaultWebpackConfig.ts index e251968c59b5..28726ece76c3 100644 --- a/npm/webpack-dev-server/src/makeDefaultWebpackConfig.ts +++ b/npm/webpack-dev-server/src/makeDefaultWebpackConfig.ts @@ -17,6 +17,7 @@ export function makeCypressWebpackConfig ( const { devServerConfig: { cypressConfig: { + port, projectRoot, devServerPublicPathRoute, supportFile, @@ -43,6 +44,8 @@ export function makeCypressWebpackConfig ( }, } = config + const webpackDevServerPort = port ?? undefined + debug(`Using HtmlWebpackPlugin version ${htmlWebpackPluginVersion} from ${htmlWebpackPluginImportPath}`) const optimization: Record = { @@ -78,7 +81,7 @@ export function makeCypressWebpackConfig ( }, plugins: [ new (HtmlWebpackPlugin as typeof import('html-webpack-plugin-5'))({ - template: indexHtmlFile, + template: indexHtmlFile ? path.join(projectRoot, indexHtmlFile) : undefined, // Angular generates all of it's scripts with diff --git a/packages/app/src/debug/DebugFailedTest.cy.tsx b/packages/app/src/debug/DebugFailedTest.cy.tsx index 9433597d1e03..924435f8a653 100644 --- a/packages/app/src/debug/DebugFailedTest.cy.tsx +++ b/packages/app/src/debug/DebugFailedTest.cy.tsx @@ -36,6 +36,8 @@ const instance1: TestResults['instance'] = { groupId: '123', status: 'FAILED', hasScreenshots: true, + hasReplay: true, + replayUrl: 'https://cloud.cypress.io/projects/123/runs/456/overview/789/replay', screenshotsUrl: 'https://cloud.cypress.io/projects/123/runs/456/overview/789/screenshots', hasStdout: true, stdoutUrl: 'https://cloud.cypress.io/projects/123/runs/456/overview/789/stdout', @@ -116,7 +118,7 @@ describe('', () => { assertRowContents(testResult) cy.findByTestId('test-group').realHover() - cy.findByTestId('debug-artifacts').should('be.visible').children().should('have.length', 3) + cy.findByTestId('debug-artifacts').should('be.visible').children().should('have.length', 4) cy.findByTestId('debug-artifacts').children().each((artifact) => { cy.wrap(artifact).find('a').should('have.attr', 'href') .and('match', /utm_medium/) @@ -163,7 +165,7 @@ describe('', () => { cy.findByTestId('debug-artifacts').should('not.exist') cy.findAllByTestId('grouped-row').should('have.length', 2) cy.findAllByTestId('grouped-row').first().realHover() - cy.findAllByTestId('debug-artifacts').first().should('be.visible').children().should('have.length', 3) + cy.findAllByTestId('debug-artifacts').first().should('be.visible').children().should('have.length', 4) cy.percySnapshot() }) @@ -205,6 +207,7 @@ describe('', () => { hasStdout: false, hasScreenshots: false, hasVideo: false, + hasReplay: false, } render({ ...testResult, instance: artifactFreeInstance }) @@ -221,5 +224,21 @@ describe('', () => { render({ ...testResult, instance: { ...artifactFreeInstance, hasVideo: true } }) cy.findByTestId('debug-artifacts').children().should('have.length', 1) cy.findByTestId('PLAY-button').should('exist') + + render({ ...testResult, instance: { ...artifactFreeInstance, hasReplay: true } }) + cy.findByTestId('debug-artifacts').children().should('have.length', 1) + cy.findByTestId('REPLAY-button').should('exist') + + render({ ...testResult, instance: instance1 }) + cy.findByTestId('debug-artifacts').children() + .should('have.length', 4) + .first() + .should('have.attr', 'data-cy', 'artifact--REPLAY') + .next() + .should('have.attr', 'data-cy', 'artifact--TERMINAL_LOG') + .next() + .should('have.attr', 'data-cy', 'artifact--IMAGE_SCREENSHOT') + .next() + .should('have.attr', 'data-cy', 'artifact--PLAY') }) }) diff --git a/packages/app/src/debug/DebugPageHeader.cy.tsx b/packages/app/src/debug/DebugPageHeader.cy.tsx index 20a5b574ebb2..b5de9ddd2260 100644 --- a/packages/app/src/debug/DebugPageHeader.cy.tsx +++ b/packages/app/src/debug/DebugPageHeader.cy.tsx @@ -43,11 +43,11 @@ describe('', { cy.findByTestId('debug-results').should('be.visible') - cy.findByTestId('debug-runNumber-FAILED') + cy.findByTestId('runNumber-status-FAILED') .should('have.text', '#432') .children().should('have.length', 2) - cy.findByTestId('debug-flaky-badge') + cy.findByTestId('runResults-flakyBadge') .should('not.exist') defaults.forEach((obj) => { @@ -73,7 +73,7 @@ describe('', { }, }) - cy.findByTestId('debug-flaky-badge') + cy.findByTestId('runResults-flakyBadge') .contains(defaultMessages.specPage.flaky.badgeLabel) cy.findByTestId('total-flaky-tests') @@ -97,7 +97,7 @@ describe('', { }, }) - cy.findByTestId(`debug-runNumber-${status}`).should('be.visible') + cy.findByTestId(`runNumber-status-${status}`).should('be.visible') }) }) diff --git a/packages/app/src/debug/DebugPageHeader.vue b/packages/app/src/debug/DebugPageHeader.vue index 020eaffac4be..ee5f734d598b 100644 --- a/packages/app/src/debug/DebugPageHeader.vue +++ b/packages/app/src/debug/DebugPageHeader.vue @@ -51,12 +51,12 @@
  • - - @@ -92,7 +92,7 @@ v-if="debug.createdAt" data-cy="debug-header-createdAt" > - diff --git a/packages/app/src/debug/DebugRunNavigation.vue b/packages/app/src/debug/DebugRunNavigation.vue index ff2a1c4a260f..7bd9be4e92d2 100644 --- a/packages/app/src/debug/DebugRunNavigation.vue +++ b/packages/app/src/debug/DebugRunNavigation.vue @@ -38,12 +38,12 @@