diff --git a/.circleci/workflows.yml b/.circleci/workflows.yml index 93344e11c8be..091f0bff0468 100644 --- a/.circleci/workflows.yml +++ b/.circleci/workflows.yml @@ -593,7 +593,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|useDurationFormat|useTestingType|SpecPatterns).cy.*' | circleci tests split --total=$CIRCLE_NODE_TOTAL) + TESTFILES=$(find src -regextype posix-extended -name '*.cy.*' -not -regex '.*(FileMatch|PromoAction|SelectorPlayground|useDurationFormat|useTestingType|SpecPatterns|DebugPendingRunCounts).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) @@ -2896,7 +2896,6 @@ linux-x64-contributor-workflow: &linux-x64-contributor-workflow jobs: - node_modules_install - build: - # context: test-runner:env-canary requires: - node_modules_install - check-ts: diff --git a/.github/workflows/report_weekly_app_kpis.yml b/.github/workflows/report_weekly_app_kpis.yml index d9a1a82be7d6..de727b058be5 100644 --- a/.github/workflows/report_weekly_app_kpis.yml +++ b/.github/workflows/report_weekly_app_kpis.yml @@ -96,6 +96,18 @@ jobs: 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 @@ -107,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 }}, ${{ steps.feature-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/update-browser-versions.yml b/.github/workflows/update-browser-versions.yml index b85b8eb89c4e..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: @@ -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/.vscode/launch.json b/.vscode/launch.json index ff2618c4bf7d..2142cdfd3ce2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,6 +8,21 @@ "processId": "${command:PickProcess}", "continueOnAttach": true }, + { + "type": "node", + "request": "attach", + "name": "Attach to port 5566", + "port": 5566, + "continueOnAttach": true, + }, + { + "type": "node", + "request": "attach", + "name": "Attach to Docker", + "port": 5566, + "continueOnAttach": true, + "remoteRoot": "/opt/cypress", + }, { "type": "node", "request": "attach", diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 85ddc536a838..3f562577b436 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -396,6 +396,20 @@ $ yarn add https://cdn.cypress.io/beta/npm/.../cypress.tgz Note that unzipping the Linux binary inside a Docker container onto a mapped volume drive is *slow*. But once this is done you can modify the application resource folder in the local folder `/tmp/test-folder/node_modules/cypress/cypress-cache/3.3.0/Cypress/resources/app` to debug issues. +#### Docker as a performance constrained environment + +Sometimes performance issues are easier to reproduce in performance constrained environments. A docker container can be a good way to simulate this locally and allow for quick iteration. + +In a fresh cypress repository run the following command: + +```shell +docker compose run --service-port dev +``` + +This will spin up a docker container based off cypress/browsers:latest and start up the bash terminal. From here you can yarn install and develop as normal, although slower. It's recommend that you run this in a fresh repo because node modules may differ between an install on your local device and from within a linux docker image. + +Ports 5566 and 5567 are available to attach debuggers to, please note that docker compose run only maps ports if the `--service-port` command is used. + ### Packages Generally when making contributions, you are typically making them to a small number of packages. Most of your local development work will be inside a single package at a time. diff --git a/browser-versions.json b/browser-versions.json index eb4bb16309d3..a123031782e8 100644 --- a/browser-versions.json +++ b/browser-versions.json @@ -1,5 +1,5 @@ { - "chrome:beta": "115.0.5790.13", - "chrome:stable": "114.0.5735.106", + "chrome:beta": "118.0.5993.11", + "chrome:stable": "117.0.5938.88", "chrome:minimum": "64.0.3282.0" } diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index d413af3445ba..6418a505b6e8 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -1,4 +1,12 @@ +## 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_ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000000..83fd12748ddd --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,51 @@ +version: '3' + +services: + dev: + image: cypress/browsers:latest + ports: + # Share debugging ports + - 5566:5566 + - 5567:5567 + environment: + # Use Hist file from shared volume + HISTFILE: /root/hist/.bash_history + # Setup inspect to use the more permissive address when debugging so + # that we can connect to it from ouside the docker container + CYPRESS_DOCKER_DEV_INSPECT_OVERRIDE: '0.0.0.0:5566' + # This disables CI mode which causes cypress to build differently + CI: '' + command: /bin/bash + working_dir: /opt/cypress + volumes: + # Copy Cypress source to docker container + - .:/opt/cypress + - bash-history:/root/hist + watch: + image: cypress/browsers:latest + environment: + # This disables CI mode which causes cypress to build differently + CI: '' + command: yarn watch + working_dir: /opt/cypress + volumes: + # Copy Cypress source to docker container + - .:/opt/cypress + ci: + # This should mirror the image used in workflows.yml + image: cypress/browsers-internal:node18.15.0-chrome114-ff115 + ports: + - 5566:5566 + - 5567:5567 + command: /bin/bash + environment: + HISTFILE: /root/hist/.bash_history + CYPRESS_DOCKER_DEV_INSPECT_OVERRIDE: '0.0.0.0:5566' + working_dir: /opt/cypress + volumes: + - .:/opt/cypress + - bash-history:/root/hist + +# persist terminal history between runs in a virtual volume +volumes: + bash-history: diff --git a/package.json b/package.json index 7caf82b86302..103b98f2fcd1 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "gulp:debug": "node --inspect-brk ./node_modules/.bin/gulp", "dev-debug": "node ./scripts/debug.js dev", "docker": "./scripts/run-docker-local.sh", + "docker-dev": "./scripts/run-docker-local.sh dev", "ensure-deps": "./scripts/ensure-dependencies.sh", "get-next-version": "node scripts/get-next-version.js", "postinstall": "node ./scripts/run-postInstall.js", diff --git a/packages/app/cypress/e2e/debug.cy.ts b/packages/app/cypress/e2e/debug.cy.ts index a5252b99eb56..c2c39129028b 100644 --- a/packages/app/cypress/e2e/debug.cy.ts +++ b/packages/app/cypress/e2e/debug.cy.ts @@ -75,7 +75,7 @@ describe('App - Debug Page', () => { .contains('View in Cypress Cloud') .should('have.attr', 'href', 'https://cloud.cypress.io/projects/7p5uce/runs/2?utm_medium=Debug+Tab&utm_campaign=View+in+Cypress+Cloud&utm_source=Binary%3A+App') - cy.findByTestId('debug-runNumber-PASSED').contains('#2') + cy.findByTestId('runNumber-status-PASSED').contains('#2') cy.findByTestId('debug-commitsAhead').contains('You are 1 commit ahead') cy.findByTestId('metadata').within(() => { @@ -136,7 +136,7 @@ describe('App - Debug Page', () => { cy.findByLabelText('Relevant run had 1 test failure').should('be.visible').contains('1') - cy.findByTestId('debug-runNumber-FAILED').contains('#136') + cy.findByTestId('runNumber-status-FAILED').contains('#136') cy.findByTestId('debug-commitsAhead').contains('You are 1 commit ahead') cy.findByTestId('metadata').within(() => { diff --git a/packages/app/cypress/e2e/runs.cy.ts b/packages/app/cypress/e2e/runs.cy.ts index d89a684b872d..5e6efb766d58 100644 --- a/packages/app/cypress/e2e/runs.cy.ts +++ b/packages/app/cypress/e2e/runs.cy.ts @@ -60,7 +60,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => { cy.visitApp() cy.findByTestId('sidebar-link-runs-page').click() - cy.get('[data-cy="runs-loader"]') + cy.get('[data-cy*="runsSkeleton-"]') cy.get('[data-cy="runs"]') }) }) @@ -103,7 +103,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => { cy.visitApp() moveToRunsPage() - cy.contains('a', 'OVERLIMIT').click() + cy.findByTestId('runNumber-status-OVERLIMIT').click() cy.withCtx((ctx, o) => { expect((ctx.actions.electron.openExternal as SinonStub).lastCall.lastArg).to.contain('http://dummy.cypress.io/runs/4') @@ -666,29 +666,25 @@ describe('App: Runs', { viewportWidth: 1200 }, () => { cy.visitApp() moveToRunsPage() - cy.get('[href^="http://dummy.cypress.io/runs/0"]').first().within(() => { - cy.findByText('fix: make gql work CANCELLED') - cy.get('[data-cy="run-card-icon-CANCELLED"]') + cy.get('[data-cy="runCard-status-CANCELLED"]').first().within(() => { + cy.get('[data-cy="runNumber-status-CANCELLED"]') }) - cy.get('[href^="http://dummy.cypress.io/runs/1"]').first().within(() => { - cy.findByText('fix: make gql work ERRORED') - cy.get('[data-cy="run-card-icon-ERRORED"]') + cy.get('[data-cy="runCard-status-ERRORED"]').first().within(() => { + cy.get('[data-cy="runNumber-status-ERRORED"]') }) - cy.get('[href^="http://dummy.cypress.io/runs/2"]').first().within(() => { - cy.findByText('fix: make gql work FAILED') - cy.get('[data-cy="run-card-icon-FAILED"]') + cy.get('[data-cy="runCard-status-FAILED"]').first().within(() => { + cy.get('[data-cy="runNumber-status-FAILED"]') }) - cy.get('[href^="http://dummy.cypress.io/runs/0"]').first().as('firstRun') + cy.get('[data-cy="runCard-status-CANCELLED"]').first().as('firstRun') cy.get('@firstRun').within(() => { - cy.get('[data-cy="run-card-author"]').contains('John Appleseed') - cy.get('[data-cy="run-card-avatar"]') - cy.get('[data-cy="run-card-branch"]').contains('main') - cy.get('[data-cy="run-card-created-at"]').contains('an hour ago') - cy.get('[data-cy="run-card-duration"]').contains('01:00') + cy.get('[data-cy="runCard-author"]').contains('John Appleseed') + cy.get('[data-cy="runCard-avatar"]') + cy.get('[data-cy="runCard-branchName"]').contains('main') + cy.get('[data-cy="runCard-createdAt"]').contains('01m 00s (an hour ago)') cy.contains('span', 'skipped') cy.get('span').contains('pending') @@ -702,7 +698,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => { cy.visitApp() moveToRunsPage() - cy.get('[data-cy^="runCard-"]').first().click() + cy.get('[data-cy="runNumber-status-CANCELLED"]').first().click() cy.withCtx((ctx) => { expect((ctx.actions.electron.openExternal as SinonStub).lastCall.lastArg).to.contain('http://dummy.cypress.io/runs/0') @@ -765,19 +761,18 @@ describe('App: Runs', { viewportWidth: 1200 }, () => { cy.visitApp() moveToRunsPage() + cy.findByText('fix: using Git data CANCELLED') cy.get('[href^="http://dummy.cypress.io/runs/0"]').first().within(() => { - cy.findByText('fix: using Git data CANCELLED') - cy.get('[data-cy="run-card-icon-CANCELLED"]') + cy.get('[data-cy="runNumber-status-CANCELLED"]') }) - cy.get('[href^="http://dummy.cypress.io/runs/0"]').first().as('firstRun') + cy.get('[data-cy="runCard-status-CANCELLED"]').first().as('firstRun') cy.get('@firstRun').within(() => { - cy.get('[data-cy="run-card-author"]').contains('John Appleseed') - cy.get('[data-cy="run-card-avatar"]') - cy.get('[data-cy="run-card-branch"]').contains('main') - cy.get('[data-cy="run-card-created-at"]').contains('an hour ago') - cy.get('[data-cy="run-card-duration"]').contains('01:00') + cy.get('[data-cy="runCard-author"]').contains('John Appleseed') + cy.get('[data-cy="runCard-avatar"]') + cy.get('[data-cy="runCard-branchName"]').contains('main') + cy.get('[data-cy="runCard-createdAt"]').contains('01m 00s (an hour ago)') cy.contains('span', 'skipped') cy.get('span').contains('pending') @@ -791,7 +786,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => { cy.visitApp() moveToRunsPage() - cy.get('[data-cy^="runCard-"]').first().click() + cy.get('[data-cy="runNumber-status-CANCELLED"]').first().click() cy.withCtx((ctx) => { expect((ctx.actions.electron.openExternal as SinonStub).lastCall.lastArg).to.contain('http://dummy.cypress.io/runs/0') @@ -955,7 +950,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => { const itSkipIfWindows = Cypress.platform === 'win32' ? it.skip : it itSkipIfWindows('should re-query for executing runs', () => { - cy.get('[data-cy="run-card-icon-RUNNING"]').should('have.length', RUNNING_COUNT).should('be.visible') + cy.get('[data-cy="runNumber-status-RUNNING"]').should('have.length', RUNNING_COUNT).should('be.visible') cy.remoteGraphQLIntercept(async (obj) => { await new Promise((resolve) => setTimeout(resolve, 100)) @@ -976,7 +971,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => { }) function completeNext (passed) { - cy.get('[data-cy="run-card-icon-PASSED"]').should('have.length', passed).should('be.visible') + cy.get('[data-cy="runNumber-status-PASSED"]').should('have.length', passed).should('be.visible') if (passed < RUNNING_COUNT) { completeNext(passed + 1) } diff --git a/packages/app/package.json b/packages/app/package.json index c4a45f225676..e2c9505defcf 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -21,7 +21,7 @@ "dependencies": {}, "devDependencies": { "@cypress-design/vue-button": "^0.10.1", - "@cypress-design/vue-icon": "^0.25.0", + "@cypress-design/vue-icon": "^0.26.0", "@cypress-design/vue-statusicon": "^0.5.0", "@cypress-design/vue-tabs": "^0.5.1", "@graphql-typed-document-node/core": "^3.1.0", 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 @@