From 75222940e6c19613c219c0f3a2c9018acf0160ae Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Fri, 11 Sep 2026 14:37:09 -0700 Subject: [PATCH 1/2] test(webkit): DO NOT MERGE - webkit GC leak matrix on macos-15-xlarge Diagnostic branch. Runs page-leaks plus a per-operation variant matrix on the one bot that reproduces the r2359 GC regression, to determine whether the failure really is confined to the expect path. All other workflows are removed on this branch so the draft PR runs nothing else. --- .github/workflows/copilot-setup-steps.yml | 17 -- .github/workflows/create_test_report.yml | 133 --------- .github/workflows/infra.yml | 58 ---- .github/workflows/pr-ci-triage.yml | 134 --------- .github/workflows/publish_extension.yml | 76 ----- .github/workflows/publish_release.yml | 83 ------ .github/workflows/roll_nodejs.yml | 53 ---- .github/workflows/roll_stable_test_runner.yml | 58 ---- .github/workflows/tests_bidi.yml | 102 ------- .github/workflows/tests_docker.yml | 158 ---------- .github/workflows/tests_docker_changes.yml | 24 -- .github/workflows/tests_docker_release.yml | 14 - .github/workflows/tests_extension.yml | 56 ---- .github/workflows/tests_mcp.yml | 65 ----- .github/workflows/tests_primary.yml | 261 ----------------- .github/workflows/tests_secondary.yml | 274 ------------------ .github/workflows/tests_webview_simulator.yml | 166 ----------- .github/workflows/triage_linux.yml | 108 ------- .github/workflows/triage_mac.yml | 112 ------- .github/workflows/triage_win.yml | 116 -------- .github/workflows/update_test_results_db.yml | 46 --- .github/workflows/webkit_gc_repro.yml | 32 ++ tests/page/webkit-gc-repro.spec.ts | 136 +++++++++ 23 files changed, 168 insertions(+), 2114 deletions(-) delete mode 100644 .github/workflows/copilot-setup-steps.yml delete mode 100644 .github/workflows/create_test_report.yml delete mode 100644 .github/workflows/infra.yml delete mode 100644 .github/workflows/pr-ci-triage.yml delete mode 100644 .github/workflows/publish_extension.yml delete mode 100644 .github/workflows/publish_release.yml delete mode 100644 .github/workflows/roll_nodejs.yml delete mode 100644 .github/workflows/roll_stable_test_runner.yml delete mode 100644 .github/workflows/tests_bidi.yml delete mode 100644 .github/workflows/tests_docker.yml delete mode 100644 .github/workflows/tests_docker_changes.yml delete mode 100644 .github/workflows/tests_docker_release.yml delete mode 100644 .github/workflows/tests_extension.yml delete mode 100644 .github/workflows/tests_mcp.yml delete mode 100644 .github/workflows/tests_primary.yml delete mode 100644 .github/workflows/tests_secondary.yml delete mode 100644 .github/workflows/tests_webview_simulator.yml delete mode 100644 .github/workflows/triage_linux.yml delete mode 100644 .github/workflows/triage_mac.yml delete mode 100644 .github/workflows/triage_win.yml delete mode 100644 .github/workflows/update_test_results_db.yml create mode 100644 .github/workflows/webkit_gc_repro.yml create mode 100644 tests/page/webkit-gc-repro.spec.ts diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml deleted file mode 100644 index 56781490852bd..0000000000000 --- a/.github/workflows/copilot-setup-steps.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: "Copilot Setup Steps" -on: workflow_dispatch -jobs: - copilot-setup-steps: - runs-on: ubuntu-latest - - permissions: - contents: read - - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: lts/* - - run: npm ci - - run: npm run build - - run: npx playwright install --with-deps diff --git a/.github/workflows/create_test_report.yml b/.github/workflows/create_test_report.yml deleted file mode 100644 index 2716035797788..0000000000000 --- a/.github/workflows/create_test_report.yml +++ /dev/null @@ -1,133 +0,0 @@ -name: Publish Test Results -on: - workflow_run: - workflows: ["tests 1", "tests 2", "tests others", "MCP"] - types: - - completed - -permissions: {} - -jobs: - merge-reports: - permissions: - pull-requests: write - checks: write - statuses: write - contents: read # This is required for actions/checkout to succeed - if: ${{ github.event.workflow_run.event == 'pull_request' || github.event.workflow_run.event == 'push' }} - runs-on: ubuntu-latest - outputs: - pr_number: ${{ steps.pr.outputs.number }} - has_failures: ${{ steps.failures.outputs.has_failures }} - triage_allowed: ${{ steps.pr.outputs.triage_allowed }} - env: - MARKDOWN_OUTPUT_FILE: ${{ github.workspace }}/report.md - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: lts/* - - run: npm ci - - run: npm run build - - - name: Download blob report artifact - uses: ./.github/actions/download-artifact - with: - namePrefix: 'blob-report' - path: 'all-blob-reports' - - - name: Merge reports - run: | - npx playwright merge-reports --config .github/workflows/merge.config.ts ./all-blob-reports - env: - NODE_OPTIONS: --max-old-space-size=8192 - WORKFLOW_RUN_CONCLUSION: ${{ github.event.workflow_run.conclusion }} - - - name: Detect failures - id: failures - run: | - if [ -f "$MARKDOWN_OUTPUT_FILE" ] && grep -qE '\*\*[0-9]+ failed\*\*' "$MARKDOWN_OUTPUT_FILE"; then - echo "has_failures=true" >> "$GITHUB_OUTPUT" - else - echo "has_failures=false" >> "$GITHUB_OUTPUT" - fi - - - name: Upload HTML report - id: upload-report - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - path: playwright-report/index.html - archive: false # Upload as a single, browser-openable file (no zip) - retention-days: 30 - - # The triggering workflow ran on a pull_request event, but workflow_run.pull_requests is - # empty for PRs from forks, so resolve the number from the head ref instead. gh's head - # filter wants "owner:branch" for forks but a bare branch for same-repo PRs. - - name: Resolve PR number and triage allow-list - if: ${{ github.event.workflow_run.event == 'pull_request' }} - id: pr - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - HEAD_REF: ${{ github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch || format('{0}:{1}', github.event.workflow_run.head_repository.owner.login, github.event.workflow_run.head_branch) }} - run: | - NUMBER=$(gh pr view --repo "${{ github.repository }}" "$HEAD_REF" --json number --jq '.number' 2>/dev/null || true) - echo "number=$NUMBER" >> "$GITHUB_OUTPUT" - - AUTHOR=$(gh pr view --repo "${{ github.repository }}" "$HEAD_REF" --json author --jq '.author.login' 2>/dev/null || true) - TRIAGE_ALLOWED=false - case "$AUTHOR" in - app/github-actions|app/microsoft-playwright-automation) - TRIAGE_ALLOWED=true - ;; - *) - if [ -n "$AUTHOR" ]; then - PERM=$(gh api "repos/${{ github.repository }}/collaborators/$AUTHOR/permission" --jq .permission 2>/dev/null || echo none) - case "$PERM" in write|admin) TRIAGE_ALLOWED=true ;; esac - fi - ;; - esac - echo "triage_allowed=$TRIAGE_ALLOWED" >> "$GITHUB_OUTPUT" - - - name: Post report comment to PR - if: ${{ steps.pr.outputs.number }} - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - HTML_REPORT_URL: ${{ steps.upload-report.outputs.artifact-url }} - PR_NUMBER: ${{ steps.pr.outputs.number }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { postReportComment } = require('./tests/config/postReportComment'); - await postReportComment({ - github, - context, - core, - reportFile: process.env.MARKDOWN_OUTPUT_FILE, - prNumber: +process.env.PR_NUMBER, - reportUrl: process.env.HTML_REPORT_URL, - }); - - - name: Publish Report URL as Commit Status - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - script: | - await github.rest.repos.createCommitStatus({ - owner: context.repo.owner, - repo: context.repo.repo, - sha: '${{ github.event.workflow_run.head_sha }}', - state: 'success', - target_url: '${{ steps.upload-report.outputs.artifact-url }}', - context: 'HTML Report (${{ github.event.workflow_run.name }})', - }); - - triage: - needs: merge-reports - if: ${{ needs.merge-reports.outputs.has_failures == 'true' && needs.merge-reports.outputs.pr_number && needs.merge-reports.outputs.triage_allowed == 'true' }} - permissions: - contents: read - actions: read - pull-requests: write - copilot-requests: write - uses: ./.github/workflows/pr-ci-triage.yml - with: - pr_number: ${{ needs.merge-reports.outputs.pr_number }} diff --git a/.github/workflows/infra.yml b/.github/workflows/infra.yml deleted file mode 100644 index 12e120ca1c9ba..0000000000000 --- a/.github/workflows/infra.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: "infra" - -on: - push: - branches: - - main - - release-* - pull_request: - branches: - - main - - release-* - -jobs: - doc-and-lint: - name: "docs & lint" - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: lts/* - - run: npm ci - - run: npm run build - - run: npx playwright install --with-deps - - run: npm run lint - - name: Verify clean tree - run: | - if [[ -n $(git status -s) ]]; then - echo "ERROR: tree is dirty after npm run build:" - git diff - exit 1 - fi - - name: Audit prod NPM dependencies - run: node utils/check_audit.js - continue-on-error: true - lint-snippets: - name: "Lint snippets" - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: lts/* - - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: '3.11' - - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 - with: - dotnet-version: 8.0.x - - uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0 - with: - distribution: 'zulu' - java-version: '21' - - run: npm ci - - run: pip install -r utils/doclint/linting-code-snippets/python/requirements.txt - - run: mvn package - working-directory: utils/doclint/linting-code-snippets/java - - run: node utils/doclint/linting-code-snippets/cli.js diff --git a/.github/workflows/pr-ci-triage.yml b/.github/workflows/pr-ci-triage.yml deleted file mode 100644 index 0b60d35749d68..0000000000000 --- a/.github/workflows/pr-ci-triage.yml +++ /dev/null @@ -1,134 +0,0 @@ -# Reusable CI triage for PR test failures. Callable from other repos -# (e.g. microsoft/playwright-browsers) via workflow_call. -name: PR CI Triage - -on: - workflow_call: - inputs: - pr_number: - description: 'PR number to triage' - required: true - type: string - -permissions: {} - -jobs: - triage: - runs-on: ubuntu-latest - timeout-minutes: 20 - permissions: - contents: read - actions: read - pull-requests: read - copilot-requests: write - outputs: - has_draft: ${{ steps.triage.outputs.has_draft }} - env: - PR_NUMBER: ${{ inputs.pr_number }} - TARGET_REPO: ${{ github.repository }} - GH_TOKEN: ${{ github.token }} - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - repository: microsoft/playwright - ref: main - - - name: Set up Node.js - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: '24' - - - name: Install Copilot CLI - run: npm install -g @github/copilot - - - name: Triage failures with Copilot CLI - id: triage - env: - COPILOT_GITHUB_TOKEN: ${{ github.token }} - run: | - set -euo pipefail - mkdir -p output - PROMPT=$(cat <> "$GITHUB_OUTPUT" - else - echo "has_draft=false" >> "$GITHUB_OUTPUT" - fi - - - name: Add session transcript to job summary - if: ${{ always() }} - run: | - { - echo "## CI triage session transcript (PR #$PR_NUMBER on $TARGET_REPO)" - echo '' - cat output/copilot-session.md 2>/dev/null || echo "(no transcript)" - } >> "$GITHUB_STEP_SUMMARY" - - - name: Upload triage draft - if: ${{ always() }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: ci-triage-${{ inputs.pr_number }} - path: output/triage.md - if-no-files-found: warn - - post: - needs: triage - if: ${{ needs.triage.outputs.has_draft == 'true' }} - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: write - env: - PR_NUMBER: ${{ inputs.pr_number }} - GH_TOKEN: ${{ github.token }} - WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - REPORT_NAME: ${{ github.event.workflow_run.name || github.workflow }} - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - repository: microsoft/playwright - ref: main - - - name: Download triage draft - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: ci-triage-${{ inputs.pr_number }} - path: output - - - name: Post triage comment - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const fs = require('fs'); - const { collapsePreviousComments } = require('./tests/config/postReportComment'); - const sentinel = ``; - const prNumber = +process.env.PR_NUMBER; - await collapsePreviousComments(github, context, prNumber, sentinel); - const triage = fs.readFileSync('output/triage.md', 'utf8'); - const body = `${triage}\n\nTriaged by the Playwright bot - [agent run](${process.env.WORKFLOW_URL})\n${sentinel}\n`; - await github.rest.issues.createComment({ - ...context.repo, - issue_number: prNumber, - body, - }); diff --git a/.github/workflows/publish_extension.yml b/.github/workflows/publish_extension.yml deleted file mode 100644 index d6453d8cd94bc..0000000000000 --- a/.github/workflows/publish_extension.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Publish Extension to Chrome Web Store -on: - workflow_dispatch: - -jobs: - publish-extension-chrome-web-store: - runs-on: ubuntu-latest - environment: allow-publishing-extension-to-cws - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: lts/* - cache: 'npm' - - name: Install dependencies - run: npm ci - - name: Build extension - run: npm run build - - name: Package extension - working-directory: ./packages/extension - run: | - cd dist - zip -r ../extension.zip . - - name: Get access token - id: auth - run: | - ACCESS_TOKEN=$(curl -s -X POST "https://oauth2.googleapis.com/token" \ - -d "client_id=${{ secrets.CHROME_CLIENT_ID }}" \ - -d "client_secret=${{ secrets.CHROME_CLIENT_SECRET }}" \ - -d "refresh_token=${{ secrets.CHROME_REFRESH_TOKEN }}" \ - -d "grant_type=refresh_token" | jq -r '.access_token') - if [ "$ACCESS_TOKEN" = "null" ] || [ -z "$ACCESS_TOKEN" ]; then - echo "Failed to obtain access token" - exit 1 - fi - echo "::add-mask::$ACCESS_TOKEN" - echo "access_token=$ACCESS_TOKEN" >> $GITHUB_OUTPUT - - name: Upload to Chrome Web Store - run: | - RESPONSE=$(curl -s -w "\n%{http_code}" \ - -X PUT "https://www.googleapis.com/upload/chromewebstore/v1.1/items/${{ secrets.CHROME_EXTENSION_ID }}" \ - -H "Authorization: Bearer ${{ steps.auth.outputs.access_token }}" \ - -H "x-goog-api-version: 2" \ - -T ./packages/extension/extension.zip) - HTTP_CODE=$(echo "$RESPONSE" | tail -1) - BODY=$(echo "$RESPONSE" | head -n -1) - echo "$BODY" - if [ "$HTTP_CODE" -ne 200 ]; then - echo "Upload failed with HTTP $HTTP_CODE" - exit 1 - fi - STATUS=$(echo "$BODY" | jq -r '.uploadState') - if [ "$STATUS" != "SUCCESS" ]; then - echo "Upload state: $STATUS" - exit 1 - fi - - name: Publish to Chrome Web Store - run: | - RESPONSE=$(curl -s -w "\n%{http_code}" \ - -X POST "https://www.googleapis.com/chromewebstore/v1.1/items/${{ secrets.CHROME_EXTENSION_ID }}/publish" \ - -H "Authorization: Bearer ${{ steps.auth.outputs.access_token }}" \ - -H "x-goog-api-version: 2" \ - -H "Content-Length: 0") - HTTP_CODE=$(echo "$RESPONSE" | tail -1) - BODY=$(echo "$RESPONSE" | head -n -1) - echo "$BODY" - if [ "$HTTP_CODE" -ne 200 ]; then - echo "Publish failed with HTTP $HTTP_CODE" - exit 1 - fi - STATUS=$(echo "$BODY" | jq -r '.status[0]') - if [ "$STATUS" != "OK" ] && [ "$STATUS" != "PUBLISHED_WITH_FRICTION_WARNING" ]; then - echo "Publish status: $STATUS" - exit 1 - fi - echo "Extension published successfully" diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml deleted file mode 100644 index f78cb6e2c86c7..0000000000000 --- a/.github/workflows/publish_release.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: "publish release - npm, trace viewer" - -on: - workflow_dispatch: - schedule: - - cron: "10 5 * * *" - push: - branches: - - release-* - release: - types: [published] - -jobs: - publish-npm: - name: "publish NPM" - runs-on: ubuntu-24.04 - if: github.repository == 'microsoft/playwright' - permissions: - id-token: write # This is required for OIDC login (NPM publish) to succeed - contents: read # This is required for actions/checkout to succeed - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: lts/* - registry-url: 'https://registry.npmjs.org' - - run: npm ci - - run: npm run build - - - name: "@next: publish with commit timestamp (triggered manually)" - if: contains(github.ref, 'main') && github.event_name == 'workflow_dispatch' - run: | - node utils/build/update_canary_version.js --alpha --commit-timestamp - utils/publish_all_packages.sh --alpha - - name: "@next: publish with today's date (triggered automatically)" - if: contains(github.ref, 'main') && github.event.schedule - run: | - node utils/build/update_canary_version.js --alpha --today-date - utils/publish_all_packages.sh --alpha - - name: "@beta: publish with commit timestamp (triggered automatically)" - if: contains(github.ref, 'release') && github.event_name == 'push' - run: | - node utils/build/update_canary_version.js --beta --commit-timestamp - utils/publish_all_packages.sh --beta - - name: "publish release to NPM" - if: github.event_name == 'release' && github.event.action == 'published' - run: utils/publish_all_packages.sh --release - - publish-trace-viewer: - name: "publish Trace Viewer to trace.playwright.dev" - runs-on: ubuntu-24.04 - if: github.repository == 'microsoft/playwright' - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: lts/* - - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 - id: app-token - with: - client-id: ${{ vars.PLAYWRIGHT_APP_CLIENT_ID }} - private-key: ${{ secrets.PLAYWRIGHT_PRIVATE_KEY }} - repositories: trace.playwright.dev - - name: Deploy Canary - if: contains(github.ref, 'main') && github.event.schedule - run: bash utils/build/deploy-trace-viewer.sh --canary - env: - GH_SERVICE_ACCOUNT_TOKEN: ${{ steps.app-token.outputs.token }} - - name: Deploy Beta - if: contains(github.ref, 'release') && github.event_name == 'push' - run: bash utils/build/deploy-trace-viewer.sh --beta - env: - GH_SERVICE_ACCOUNT_TOKEN: ${{ steps.app-token.outputs.token }} - - name: Deploy Stable - if: github.event_name == 'release' && github.event.action == 'published' - run: bash utils/build/deploy-trace-viewer.sh --stable - env: - GH_SERVICE_ACCOUNT_TOKEN: ${{ steps.app-token.outputs.token }} - - name: Deploy Stable (manually) - if: contains(github.ref, 'release') && github.event_name == 'workflow_dispatch' - run: bash utils/build/deploy-trace-viewer.sh --stable - env: - GH_SERVICE_ACCOUNT_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/roll_nodejs.yml b/.github/workflows/roll_nodejs.yml deleted file mode 100644 index 8fa66e685eea3..0000000000000 --- a/.github/workflows/roll_nodejs.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: "PR: bump driver/Docker Node.js" -on: - workflow_dispatch: - schedule: - # At 10:00am UTC (3AM PST) every tuesday and thursday to roll to new Node.js driver - - cron: "0 10 * * 2,4" -jobs: - trigger-nodejs-roll: - name: Trigger Roll - runs-on: ubuntu-22.04 - if: github.repository == 'microsoft/playwright' - permissions: - contents: write - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: lts/* - - run: node utils/build/update-playwright-node.mjs - - name: Prepare branch - id: prepare-branch - run: | - if [[ "$(git status --porcelain)" == "" ]]; then - echo "there are no changes"; - exit 0; - fi - echo "HAS_CHANGES=1" >> $GITHUB_OUTPUT - BRANCH_NAME="roll-platform-nodejs/$(date +%Y-%b-%d)" - echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT - git config --global user.name microsoft-playwright-automation[bot] - git config --global user.email 203992400+microsoft-playwright-automation[bot]@users.noreply.github.com - git checkout -b "$BRANCH_NAME" - git add . - git commit -m "chore: roll driver/Dockerfile to recent Node.js LTS version" - git push origin $BRANCH_NAME - - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 - id: app-token - with: - client-id: ${{ vars.PLAYWRIGHT_APP_CLIENT_ID }} - private-key: ${{ secrets.PLAYWRIGHT_PRIVATE_KEY }} - - name: Create Pull Request - if: ${{ steps.prepare-branch.outputs.HAS_CHANGES == '1' }} - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ steps.app-token.outputs.token }} - script: | - await github.rest.pulls.create({ - owner: 'microsoft', - repo: 'playwright', - head: 'microsoft:${{ steps.prepare-branch.outputs.BRANCH_NAME }}', - base: 'main', - title: 'chore: roll driver/Dockerfile to recent Node.js LTS version', - }); diff --git a/.github/workflows/roll_stable_test_runner.yml b/.github/workflows/roll_stable_test_runner.yml deleted file mode 100644 index 7dc920a392a96..0000000000000 --- a/.github/workflows/roll_stable_test_runner.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: "PR: bump stable-test-runner" -on: - workflow_dispatch: - schedule: - # At 10:00am UTC (3AM PST) every Monday - - cron: "0 10 * * 1" -jobs: - trigger-roll: - name: Trigger Roll - runs-on: ubuntu-24.04 - if: github.repository == 'microsoft/playwright' - permissions: - contents: write - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: lts/* - - run: | - npm install @playwright/test@next - VERSION=$(node -e "console.log(require('./package.json').dependencies['@playwright/test'].replace('^', ''))") - echo "VERSION=$VERSION" >> $GITHUB_OUTPUT - working-directory: tests/playwright-test/stable-test-runner/ - id: bump - - name: Prepare branch - id: prepare-branch - run: | - if [[ "$(git status --porcelain)" == "" ]]; then - echo "there are no changes"; - exit 0; - fi - echo "HAS_CHANGES=1" >> $GITHUB_OUTPUT - BRANCH_NAME="roll-stable-test-runner/$(date +%Y-%b-%d)" - echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT - git config --global user.name microsoft-playwright-automation[bot] - git config --global user.email 203992400+microsoft-playwright-automation[bot]@users.noreply.github.com - git checkout -b "$BRANCH_NAME" - git add . - git commit -m "test: roll stable-test-runner to ${{ steps.bump.outputs.VERSION }}" - git push origin $BRANCH_NAME - - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 - id: app-token - with: - client-id: ${{ vars.PLAYWRIGHT_APP_CLIENT_ID }} - private-key: ${{ secrets.PLAYWRIGHT_PRIVATE_KEY }} - - name: Create Pull Request - if: ${{ steps.prepare-branch.outputs.HAS_CHANGES == '1' }} - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ steps.app-token.outputs.token }} - script: | - await github.rest.pulls.create({ - owner: 'microsoft', - repo: 'playwright', - head: 'microsoft:${{ steps.prepare-branch.outputs.BRANCH_NAME }}', - base: 'main', - title: 'test: roll stable-test-runner to ${{ steps.bump.outputs.VERSION }}', - }); diff --git a/.github/workflows/tests_bidi.yml b/.github/workflows/tests_bidi.yml deleted file mode 100644 index e70fbd5a00384..0000000000000 --- a/.github/workflows/tests_bidi.yml +++ /dev/null @@ -1,102 +0,0 @@ -name: tests BiDi - -on: - workflow_dispatch: - inputs: - ref: - description: Playwright SHA / ref to test. Use 'refs/pull/PULL_REQUEST_ID/head' to test a PR. Defaults to the current branch. - required: false - default: '' - pull_request: - branches: - - main - paths: - - .github/workflows/tests_bidi.yml - - packages/playwright-core/src/server/bidi/** - - tests/bidi/** - schedule: - # Run every day at midnight - - cron: '0 0 * * *' - -env: - FORCE_COLOR: 1 - -jobs: - test_bidi: - name: BiDi - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - runs-on: ubuntu-24.04 - permissions: - id-token: write # This is required for OIDC login (azure/login) to succeed - contents: read # This is required for actions/checkout to succeed - strategy: - fail-fast: false - matrix: - channel: [bidi-chromium, moz-firefox-nightly] - isPullRequest: - - ${{ github.event_name == 'pull_request' }} - exclude: - - isPullRequest: true - channel: bidi-chromium - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - if: github.event_name != 'workflow_dispatch' - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - if: github.event_name == 'workflow_dispatch' - with: - ref: ${{ github.event.inputs.ref }} - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: 20 - - run: npm ci - - run: npm run build - # Needed for video tests - - run: npx playwright install ffmpeg - - run: npx playwright install --with-deps chromium - - if: matrix.channel == 'moz-firefox-nightly' - run: | - sudo apt-get update - sudo apt-get install -y libavcodec60 - echo "BIDI_FFPATH=$(npx -y @puppeteer/browsers install firefox@nightly | tail -n1 | sed 's/^[^ ]* *//')" >> "$GITHUB_ENV" - - name: Run tests - run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run biditest -- --retries=${{ matrix.isPullRequest && 2 || 0 }} --project=${{ matrix.channel }}* - env: - PWTEST_USE_BIDI_EXPECTATIONS: ${{ matrix.isPullRequest && '1' || '' }} - - name: Upload csv report to GitHub - if: ${{ !cancelled() }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: csv-report-${{ matrix.channel }} - path: test-results/report.csv - retention-days: 7 - - - name: Upload json report to GitHub - if: ${{ !cancelled() }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: json-report-${{ matrix.channel }} - path: test-results/report.json - retention-days: 7 - - - name: Upload parquet report - if: ${{ !cancelled() }} - uses: ./.github/actions/upload-parquet-report - with: - job_name: ${{ matrix.channel }} - - - name: Azure Login - if: ${{ !cancelled() && github.ref == 'refs/heads/main' }} - uses: azure/login@7ddb5af1ef8758cf1353cf3b42f940aee27ba21c # v3.0.2 - with: - client-id: ${{ secrets.AZURE_BLOB_REPORTS_CLIENT_ID }} - tenant-id: ${{ secrets.AZURE_BLOB_REPORTS_TENANT_ID }} - subscription-id: ${{ secrets.AZURE_BLOB_REPORTS_SUBSCRIPTION_ID }} - - - name: Upload report.csv to Azure - if: ${{ !cancelled() && github.ref == 'refs/heads/main' }} - run: | - REPORT_DIR='bidi-reports' - azcopy cp "./test-results/report.csv" "https://mspwblobreport.blob.core.windows.net/\$web/$REPORT_DIR/${{ matrix.channel }}.csv" - echo "Report url: https://mspwblobreport.z1.web.core.windows.net/$REPORT_DIR/${{ matrix.channel }}.csv" - env: - AZCOPY_AUTO_LOGIN_TYPE: AZCLI diff --git a/.github/workflows/tests_docker.yml b/.github/workflows/tests_docker.yml deleted file mode 100644 index 59f7077694a4b..0000000000000 --- a/.github/workflows/tests_docker.yml +++ /dev/null @@ -1,158 +0,0 @@ -name: tests docker - -on: - workflow_call: - -env: - FORCE_COLOR: 1 - -jobs: - test_linux_docker: - name: "Docker ${{ matrix.docker_tag }} ${{ matrix.docker_arch }}" - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - strategy: - fail-fast: false - matrix: - include: - - docker_tag: jammy - docker_arch: amd64 - host_os: ubuntu-22.04 - - docker_tag: jammy - docker_arch: arm64 - host_os: ubuntu-22.04-arm - - docker_tag: noble - docker_arch: amd64 - host_os: ubuntu-22.04 - - docker_tag: noble - docker_arch: arm64 - host_os: ubuntu-22.04-arm - - docker_tag: resolute - docker_arch: amd64 - host_os: ubuntu-22.04 - - docker_tag: resolute - docker_arch: arm64 - host_os: ubuntu-22.04-arm - runs-on: ${{ matrix.host_os }} - permissions: - id-token: write # This is required for OIDC login (azure/login) to succeed - contents: read # This is required for actions/checkout to succeed - steps: - - name: Create ~/.azure directory - run: mkdir -p ~/.azure - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: 22 - env: - PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 - - run: npm ci - - run: npm run build - # Used as a Pull-through cache for the Docker images. Only available on the - # main repo, where the secrets are present; forks fall back to Docker Hub. - - name: Azure Login - if: ${{ github.event_name == 'push' && github.repository == 'microsoft/playwright' }} - uses: azure/login@7ddb5af1ef8758cf1353cf3b42f940aee27ba21c # v3.0.2 - with: - client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - - name: Login to ACR via OIDC - if: ${{ github.event_name == 'push' && github.repository == 'microsoft/playwright' }} - run: az acr login --name playwright - - name: Add Dockerfile cache - if: ${{ github.event_name == 'push' && github.repository == 'microsoft/playwright' }} - run: sed -i 's/FROM ubuntu/FROM playwright.azurecr.io\/cached\/ubuntu/' utils/docker/Dockerfile.${{matrix.docker_tag}} - - run: ./utils/docker/build.sh --${{ matrix.docker_arch }} ${{ matrix.docker_tag }} playwright:localbuild - shell: bash - - name: Launch container - run: | - docker run \ - --rm \ - --name docker-tests \ - --platform linux/${{ matrix.docker_arch }} \ - --user=pwuser \ - --workdir /home/pwuser \ - --env CI \ - --env INSIDE_DOCKER=1 \ - -v ~/.azure:/root/.azure \ - -d \ - -t \ - playwright:localbuild /bin/bash - - name: Copy repository inside docker container - run: | - # Note: we cannot do explicit `git clone` inside container because it requires some smarts to decide if github.sha or - # github.ref should be used for checkout. - # The actions/checkout action already handled this complexity for us, so we'll just copy checkout. - docker cp . docker-tests:/home/pwuser/playwright - docker exec --user root docker-tests chown -R pwuser /home/pwuser/playwright - - # GIT is now picky on directory ownership - # See https://github.blog/2022-04-12-git-security-vulnerability-announced/ - docker exec \ - --user root \ - --workdir /home/pwuser/playwright docker-tests /bin/bash -c ' - git config --global --add safe.directory /home/pwuser/playwright - ' - - name: Run "npm ci" inside docker - run: docker exec --workdir /home/pwuser/playwright docker-tests npm ci - - - name: Run "npm run build" inside docker - run: docker exec --workdir /home/pwuser/playwright docker-tests npm run build - - - name: "Run @smoke tests inside docker" - run: | - docker exec \ - --env GITHUB_RUN_ID \ - --env GITHUB_RUN_ATTEMPT \ - --env GITHUB_WORKFLOW \ - --env GITHUB_EVENT_NAME \ - --env GITHUB_REF \ - --env GITHUB_REF_NAME \ - --env GITHUB_HEAD_REF \ - --env GITHUB_SHA \ - --workdir /home/pwuser/playwright docker-tests xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" npm run test -- --grep "@smoke" - - - name: Azure Login - if: ${{ !cancelled() && github.event_name == 'push' && github.repository == 'microsoft/playwright' }} - uses: azure/login@7ddb5af1ef8758cf1353cf3b42f940aee27ba21c # v3.0.2 - with: - client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - - name: Upload Flakiness dashboard - if: ${{ !cancelled() && github.event_name == 'push' && github.repository == 'microsoft/playwright' }} - run: | - # Flakiness dashboard has to be uploaded from-inside docker container so that it can collect meta information, e.g. arch - # See https://github.com/microsoft/playwright/blob/13b1e52d95df416fdfa7846c8a840aad8df263af/utils/upload_flakiness_dashboard.sh#L71-L86 - docker exec \ - --env GITHUB_REPOSITORY \ - --env GITHUB_REF \ - --env GITHUB_RUN_ID \ - --user root \ - --workdir /home/pwuser/playwright docker-tests /bin/bash -c ' - set -e - # Azure-CLI is needed for upload_flakiness_dashboard.sh script. - curl -sL https://aka.ms/InstallAzureCLIDeb | bash - ./utils/upload_flakiness_dashboard.sh "./test-results/report.json" - ' - - name: Copy blob report from container - if: ${{ !cancelled() && (github.event_name == 'pull_request' || failure()) }} - run: docker cp "docker-tests:/home/pwuser/playwright/blob-report" "./blob-report" - - - name: Upload blob report - if: ${{ !cancelled() && (github.event_name == 'pull_request' || failure()) }} - uses: ./.github/actions/upload-blob-report - with: - report_dir: blob-report - job_name: docker-${{ matrix.docker_tag }}-${{ matrix.docker_arch }} - - - name: Copy parquet report from container - if: ${{ !cancelled() }} - run: docker cp "docker-tests:/home/pwuser/playwright/test-results/test-results.parquet" "./test-results.parquet" || true - - - name: Upload parquet report - if: ${{ !cancelled() }} - uses: ./.github/actions/upload-parquet-report - with: - report_file: test-results.parquet - job_name: docker-${{ matrix.docker_tag }}-${{ matrix.docker_arch }} diff --git a/.github/workflows/tests_docker_changes.yml b/.github/workflows/tests_docker_changes.yml deleted file mode 100644 index 8807d32ae6788..0000000000000 --- a/.github/workflows/tests_docker_changes.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: tests docker (changes) - -on: - push: - branches: - - main - paths: - - 'utils/docker/**' - - '.github/workflows/tests_docker*.yml' - pull_request: - branches: - - main - - release-* - paths: - - 'utils/docker/**' - - '.github/workflows/tests_docker*.yml' - -jobs: - test_linux_docker: - uses: ./.github/workflows/tests_docker.yml - permissions: - id-token: write - contents: read - secrets: inherit diff --git a/.github/workflows/tests_docker_release.yml b/.github/workflows/tests_docker_release.yml deleted file mode 100644 index d9e22f16550a2..0000000000000 --- a/.github/workflows/tests_docker_release.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: tests docker (release) - -on: - push: - branches: - - release-* - -jobs: - test_linux_docker: - uses: ./.github/workflows/tests_docker.yml - permissions: - id-token: write - contents: read - secrets: inherit diff --git a/.github/workflows/tests_extension.yml b/.github/workflows/tests_extension.yml deleted file mode 100644 index bcee6798551ff..0000000000000 --- a/.github/workflows/tests_extension.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: extension - -on: - push: - branches: - - main - - release-* - paths: - - 'packages/playwright-core/src/tools/**' - - '!packages/playwright-core/src/tools/dashboard/**' - - '!packages/playwright-core/src/tools/trace/**' - - 'packages/extension/**' - - 'tests/extension/**' - - '.github/workflows/tests_extension.yml' - pull_request: - branches: - - main - - release-* - paths: - - 'packages/playwright-core/src/tools/**' - - '!packages/playwright-core/src/tools/dashboard/**' - - '!packages/playwright-core/src/tools/trace/**' - - 'packages/extension/**' - - 'tests/extension/**' - - '.github/workflows/tests_extension.yml' - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - FORCE_COLOR: 1 - DEBUG: pw:mcp:error - -jobs: - test_extension: - name: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [macos-latest] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: 22 - - run: npm ci - - run: npm run build - - run: npx playwright install --with-deps chromium - - run: npm run test-extension - - name: Upload parquet report - if: ${{ !cancelled() }} - uses: ./.github/actions/upload-parquet-report - with: - job_name: extension-${{ matrix.os }} diff --git a/.github/workflows/tests_mcp.yml b/.github/workflows/tests_mcp.yml deleted file mode 100644 index 88dc1041c6229..0000000000000 --- a/.github/workflows/tests_mcp.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: MCP - -on: - push: - branches: - - main - - release-* - pull_request: - paths-ignore: - - 'browser_patches/**' - - 'docs/**' - - 'packages/extension/**' - - 'packages/playwright-core/src/server/bidi/**' - - 'tests/bidi/**' - - 'tests/extension/**' - branches: - - main - - release-* - -concurrency: - # For pull requests, cancel all currently-running jobs for this workflow - # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - # Force terminal colors. @see https://www.npmjs.com/package/colors - FORCE_COLOR: 1 - DEBUG: pw:mcp:error - -jobs: - test_mcp: - name: ${{ matrix.os }} - ${{ matrix.project }} - # Used for authentication of flakiness upload - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-latest] - project: [chrome, chromium, firefox, webkit] - include: - - os: windows-latest - project: chrome - - os: windows-latest - project: chromium - - os: windows-latest - project: firefox - - os: windows-latest - project: webkit - - os: windows-latest - project: msedge - runs-on: ${{ matrix.os }} - permissions: - id-token: write # This is required for OIDC login (azure/login) to succeed - contents: read # This is required for actions/checkout to succeed - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: ./.github/actions/run-test - with: - node-version: "22" - command: npm run test-mcp -- --project=${{ matrix.project }} - bot-name: "mcp-${{ matrix.os }}-${{ matrix.project }}" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} diff --git a/.github/workflows/tests_primary.yml b/.github/workflows/tests_primary.yml deleted file mode 100644 index c01376f55ab0e..0000000000000 --- a/.github/workflows/tests_primary.yml +++ /dev/null @@ -1,261 +0,0 @@ -name: "tests 1" - -on: - push: - branches: - - main - - release-* - pull_request: - paths-ignore: - - 'browser_patches/**' - - 'docs/**' - - 'packages/extension/**' - - 'packages/playwright-core/src/server/bidi/**' - - 'packages/playwright-core/src/tools/**' - - 'tests/bidi/**' - - 'tests/extension/**' - - 'tests/mcp/**' - branches: - - main - - release-* - -concurrency: - # For pull requests, cancel all currently-running jobs for this workflow - # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - # Force terminal colors. @see https://www.npmjs.com/package/colors - FORCE_COLOR: 1 - -jobs: - test_linux: - name: ${{ matrix.os }} (${{ matrix.browser }} - Node.js ${{ matrix.node-version }}) - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - strategy: - fail-fast: false - matrix: - browser: [chromium, firefox, webkit] - os: [ubuntu-22.04] - node-version: [20] - include: - - os: ubuntu-22.04 - node-version: 22 - browser: chromium - - os: ubuntu-22.04 - node-version: 24 - browser: chromium - - os: ubuntu-22.04-arm - node-version: 20 - browser: chromium - runs-on: ${{ matrix.os }} - permissions: - id-token: write # This is required for OIDC login (azure/login) to succeed - contents: read # This is required for actions/checkout to succeed - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: ./.github/actions/run-test - with: - node-version: ${{ matrix.node-version }} - browsers-to-install: ${{ matrix.browser }} chromium - command: npm run test -- --project=${{ matrix.browser }}-* - bot-name: "${{ matrix.browser }}-${{ matrix.os }}-node${{ matrix.node-version }}" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - - test_test_runner: - name: Test Runner - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-latest] - node-version: [22] - shardIndex: [1, 2] - shardTotal: [2] - shardWeights: ['58:42'] - include: - - os: windows-latest - node-version: 22 - shardIndex: 1 - shardTotal: 3 - shardWeights: '44:33:23' - - os: windows-latest - node-version: 22 - shardIndex: 2 - shardTotal: 3 - shardWeights: '44:33:23' - - os: windows-latest - node-version: 22 - shardIndex: 3 - shardTotal: 3 - shardWeights: '44:33:23' - - os: ubuntu-latest - node-version: 20 - shardIndex: 1 - shardTotal: 2 - shardWeights: '58:42' - - os: ubuntu-latest - node-version: 20 - shardIndex: 2 - shardTotal: 2 - shardWeights: '58:42' - - os: ubuntu-latest - node-version: 24 - shardIndex: 1 - shardTotal: 2 - shardWeights: '58:42' - - os: ubuntu-latest - node-version: 24 - shardIndex: 2 - shardTotal: 2 - shardWeights: '58:42' - - os: ubuntu-latest - node-version: 26 - shardIndex: 1 - shardTotal: 2 - shardWeights: '58:42' - - os: ubuntu-latest - node-version: 26 - shardIndex: 2 - shardTotal: 2 - shardWeights: '58:42' - runs-on: ${{ matrix.os }} - permissions: - id-token: write # This is required for OIDC login (azure/login) to succeed - contents: read # This is required for actions/checkout to succeed - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: ./.github/actions/run-test - with: - node-version: ${{matrix.node-version}} - command: npm run ttest -- --shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }} - bot-name: "${{ matrix.os }}-node${{ matrix.node-version }}" - shard-index: ${{ matrix.shardIndex }} - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - env: - PWTEST_SHARD_WEIGHTS: ${{ matrix.shardWeights }} - - test_web_components: - name: Web Components - ${{ matrix.package }} - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - permissions: - id-token: write # This is required for OIDC login (azure/login) to succeed - contents: read # This is required for actions/checkout to succeed - strategy: - fail-fast: false - matrix: - package: [html-reporter, web] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: ./.github/actions/run-test - with: - node-version: 20 - browsers-to-install: chromium - command: npm run test-${{ matrix.package }} - bot-name: "web-components-${{ matrix.package }}" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - - test_vscode_extension: - name: VSCode Extension - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: 20 - - run: npm ci - env: - DEBUG: pw:install - - run: npm run build - - run: npx playwright install chromium - - name: Checkout extension - run: git clone https://github.com/microsoft/playwright-vscode.git - - name: Print extension revision - run: git rev-parse HEAD - working-directory: ./playwright-vscode - - name: Remove @playwright/test from extension dependencies - run: node -e "const p = require('./package.json'); delete p.devDependencies['@playwright/test']; fs.writeFileSync('./package.json', JSON.stringify(p, null, 2));" - working-directory: ./playwright-vscode - - name: Build extension - run: npm ci && npm run build - working-directory: ./playwright-vscode - - name: Run extension tests - run: npm run test - working-directory: ./playwright-vscode - env: - PW_TAG: "@vscode-extension" - - name: Upload blob report - if: ${{ !cancelled() && (github.event_name == 'pull_request' || failure()) }} - uses: ./.github/actions/upload-blob-report - with: - report_dir: playwright-vscode/blob-report - job_name: vscode-extension - - test_package_installations: - name: "Installation Test ${{ matrix.os }}" - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - strategy: - fail-fast: false - matrix: - os: - - ubuntu-latest - - macos-latest - - windows-latest - runs-on: ${{ matrix.os }} - timeout-minutes: 45 - permissions: - id-token: write # This is required for OIDC login (azure/login) to succeed - contents: read # This is required for actions/checkout to succeed - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - run: npm install -g yarn@1 - - run: npm install -g pnpm@8 - - name: Setup Ubuntu Binary Installation # TODO: Remove when https://github.com/electron/electron/issues/42510 is fixed - if: ${{ runner.os == 'Linux' }} - run: | - if grep -q "Ubuntu 24" /etc/os-release; then - sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 - fi - shell: bash - - uses: ./.github/actions/run-test - with: - command: npm run itest - node-version: 22 - bot-name: "package-installations-${{ matrix.os }}" - shell: ${{ matrix.os == 'windows-latest' && 'pwsh' || 'bash' }} - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - - test_clock_frozen_time_linux: - name: time library - ${{ matrix.clock }} - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - permissions: - id-token: write # This is required for OIDC login (azure/login) to succeed - contents: read # This is required for actions/checkout to succeed - strategy: - fail-fast: false - matrix: - clock: [frozen, realtime] - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: ./.github/actions/run-test - with: - node-version: 22 - browsers-to-install: chromium - command: npm run test -- --project=chromium-* - bot-name: "${{ matrix.clock }}-time-library-chromium-linux" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - env: - PW_CLOCK: ${{ matrix.clock }} diff --git a/.github/workflows/tests_secondary.yml b/.github/workflows/tests_secondary.yml deleted file mode 100644 index 5622c1bb06b35..0000000000000 --- a/.github/workflows/tests_secondary.yml +++ /dev/null @@ -1,274 +0,0 @@ -name: "tests 2" - -on: - push: - branches: - - main - - release-* - pull_request: - types: [ labeled ] - branches: - - main - - release-* - -env: - # Force terminal colors. @see https://www.npmjs.com/package/colors - FORCE_COLOR: 1 - -permissions: - id-token: write # This is required for OIDC login (azure/login) to succeed - contents: read # This is required for actions/checkout to succeed - -jobs: - test_mac: - name: ${{ matrix.os }} (${{ matrix.browser }}) - if: ${{ github.event_name == 'push' || github.event.label.name == 'CQ1' }} - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - strategy: - fail-fast: false - matrix: - # Intel: *-large - # Arm64: *-xlarge - os: [macos-15-large, macos-15-xlarge] - browser: [chromium, firefox, webkit] - include: - - os: macos-14-xlarge - browser: chromium - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: ./.github/actions/run-test - with: - browsers-to-install: ${{ matrix.browser }} chromium - command: npm run test -- --project=${{ matrix.browser }}-* - bot-name: "${{ matrix.browser }}-${{ matrix.os }}" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - - test_win: - name: "Windows" - if: ${{ github.event_name == 'push' || github.event.label.name == 'CQ1' }} - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - strategy: - fail-fast: false - matrix: - browser: [chromium, firefox, webkit] - runs-on: windows-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: ./.github/actions/run-test - with: - browsers-to-install: ${{ matrix.browser }} chromium - command: npm run test -- --project=${{ matrix.browser }}-* ${{ matrix.browser == 'firefox' && '--workers 1' || '' }} - bot-name: "${{ matrix.browser }}-windows-latest" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - - test-package-installations-other-node-versions: - name: "Installation Test ${{ matrix.os }} (${{ matrix.node_version }})" - if: ${{ github.event_name == 'push' || github.event.label.name == 'CQ1' }} - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-latest - node_version: 20 - - os: ubuntu-latest - node_version: 24 - - os: ubuntu-latest - node_version: 26 - timeout-minutes: 30 - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - run: npm install -g yarn@1 - - run: npm install -g pnpm@8 - - name: Setup Ubuntu Binary Installation # TODO: Remove when https://github.com/electron/electron/issues/42510 is fixed - if: ${{ runner.os == 'Linux' }} - run: | - if grep -q "Ubuntu 24" /etc/os-release; then - sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 - fi - shell: bash - - uses: ./.github/actions/run-test - with: - node-version: ${{ matrix.node_version }} - command: npm run itest - bot-name: "package-installations-${{ matrix.os }}-node${{ matrix.node_version }}" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - - driver_linux: - name: "Driver" - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - strategy: - fail-fast: false - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: ./.github/actions/run-test - with: - browsers-to-install: chromium - command: npm run ctest - bot-name: "driver" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - env: - PWTEST_MODE: driver - - tracing_linux: - name: Tracing ${{ matrix.browser }} - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - strategy: - fail-fast: false - matrix: - include: - - browser: chromium - runs-on: ubuntu-22.04 - - browser: firefox - runs-on: ubuntu-22.04 - # See https://github.com/microsoft/playwright/issues/35586 - - browser: webkit - runs-on: ubuntu-24.04 - runs-on: ${{ matrix.runs-on }} - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: ./.github/actions/run-test - with: - browsers-to-install: ${{ matrix.browser }} chromium - command: npm run test -- --project=${{ matrix.browser }}-* - bot-name: "tracing-${{ matrix.browser }}" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - env: - PWTEST_TRACE: 1 - - test_chromium_channels: - name: Test ${{ matrix.channel }} on ${{ matrix.runs-on }} - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - runs-on: ${{ matrix.runs-on }} - strategy: - fail-fast: false - matrix: - include: - - channel: chrome - runs-on: ubuntu-22.04 - - channel: chrome - runs-on: macos-latest - - channel: chrome - runs-on: windows-latest - - channel: chrome-beta - runs-on: ubuntu-22.04 - - channel: msedge - runs-on: windows-latest - - channel: msedge-dev - runs-on: windows-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: ./.github/actions/run-test - with: - browsers-to-install: ${{ matrix.channel }} - command: npm run ctest - bot-name: ${{ matrix.channel }}-${{ matrix.runs-on }} - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - env: - PWTEST_CHANNEL: ${{ matrix.channel }} - - test_android: - name: Android - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - runs-on: playwright-x64-ubuntu24-64-core - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0 - with: - distribution: 'temurin' - java-version: '21' - - name: Enable KVM group perms - run: | - echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules - sudo udevadm control --reload-rules - sudo udevadm trigger --name-match=kvm - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: 22 - - name: Create Android Emulator - run: utils/avd_recreate.sh - - name: Start Android Emulator - run: utils/avd_start.sh - - uses: ./.github/actions/run-test - with: - browsers-to-install: android - command: npm run atest - bot-name: "android" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - - test_clock_frozen_time_test_runner: - name: time test runner - ${{ matrix.clock }} - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - runs-on: ubuntu-22.04 - permissions: - id-token: write # This is required for OIDC login (azure/login) to succeed - contents: read # This is required for actions/checkout to succeed - strategy: - fail-fast: false - matrix: - clock: [frozen, realtime] - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: ./.github/actions/run-test - with: - node-version: 22 - command: npm run ttest - bot-name: "${{ matrix.clock }}-time-runner-chromium-linux" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - env: - PW_CLOCK: ${{ matrix.clock }} - - test_electron: - name: Electron - ${{ matrix.os }} - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - permissions: - id-token: write # This is required for OIDC login (azure/login) to succeed - contents: read # This is required for actions/checkout to succeed - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Setup Ubuntu Binary Installation # TODO: Remove when https://github.com/electron/electron/issues/42510 is fixed - if: ${{ runner.os == 'Linux' }} - run: | - if grep -q "Ubuntu 24" /etc/os-release; then - sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 - fi - shell: bash - # Prevent stalling when macOS decides to show the reopen windows prompt - # after killing enough Electron processes. See https://github.com/electron/electron/pull/51488. - - name: Turn off the reopen windows prompt on macOS - if: ${{ matrix.os == 'macos-latest' }} - run: defaults write com.github.Electron ApplePersistenceIgnoreState YES - shell: bash - - uses: ./.github/actions/run-test - with: - browsers-to-install: chromium - setup-command: npx install-electron --no - command: npm run etest - bot-name: "electron-${{ matrix.os }}" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} diff --git a/.github/workflows/tests_webview_simulator.yml b/.github/workflows/tests_webview_simulator.yml deleted file mode 100644 index 681594c4d2f8c..0000000000000 --- a/.github/workflows/tests_webview_simulator.yml +++ /dev/null @@ -1,166 +0,0 @@ -name: "tests WebView (iOS Simulator)" - -on: - workflow_dispatch: - pull_request: - paths: - - 'tests/webview/**' - - 'packages/playwright-core/src/server/webkit/webview/**' - - '.github/workflows/tests_webview_simulator.yml' - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - FORCE_COLOR: 1 - -jobs: - test_webview_simulator: - name: "WebView on iOS Simulator (${{ matrix.shard }}/4)" - runs-on: macos-15 - timeout-minutes: 60 - strategy: - fail-fast: false - matrix: - shard: [1, 2, 3, 4] - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: 20 - - - name: Runner environment - run: | - echo "::group::OS / Xcode" - sw_vers - uname -a - xcode-select -p - xcodebuild -version - echo "::endgroup::" - echo "::group::Available iOS runtimes" - xcrun simctl list runtimes - echo "::endgroup::" - echo "::group::Available device types" - xcrun simctl list devicetypes | grep -i 'iPhone\|iPad' | head -40 - echo "::endgroup::" - echo "::group::Network config" - cat /etc/hosts - ifconfig lo0 - echo "::endgroup::" - - - name: Ensure ::1 localhost in /etc/hosts - run: | - if grep -qE '^::1[[:space:]]+localhost' /etc/hosts; then - echo "::1 localhost already present" - else - echo "::1 localhost" | sudo tee -a /etc/hosts - echo "Added ::1 localhost" - fi - echo "--- /etc/hosts after ---" - cat /etc/hosts - - - name: npm ci - run: | - echo "::group::npm ci" - npm ci - echo "::endgroup::" - - - name: npm run build - run: | - echo "::group::npm run build" - npm run build - echo "::endgroup::" - - - name: Install ios-webkit-debug-proxy - run: | - echo "::group::brew install ios-webkit-debug-proxy" - brew install ios-webkit-debug-proxy - which ios_webkit_debug_proxy - ios_webkit_debug_proxy --help 2>&1 | head -40 || true - echo "::endgroup::" - - - name: Boot iOS Simulator - uses: futureware-tech/simulator-action@e89aa8f93d3aec35083ff49d2854d07f7186f7f5 # v5 - with: - # Per wiki/Devices-macos-15.md only iPhone 16/17 series ship pre-installed; iPhone 15 isn't. - model: 'iPhone 16' - os_version: '18.6' - wait_for_boot: true - boot_timeout_seconds: 300 - - - name: Simulator state after boot - run: | - echo "::group::Booted devices" - xcrun simctl list devices booted - echo "::endgroup::" - echo "::group::Simulator processes" - pgrep -lf Simulator || true - pgrep -lf launchd_sim || true - echo "::endgroup::" - - - name: Locate simulator webinspectord socket - run: | - echo "::group::Locating com.apple.webinspectord_sim.socket" - # On modern macOS, ios_webkit_debug_proxy can no longer auto-discover the simulator; - # we have to point -s at the launchd-owned unix socket. - for i in $(seq 1 15); do - SOCK=$(lsof -aUc launchd_sim 2>/dev/null | awk '/com\.apple\.webinspectord_sim\.socket/{print $NF; exit}') - [[ -n "$SOCK" ]] && break - echo "attempt $i: socket not found yet" - sleep 1 - done - if [[ -z "$SOCK" ]]; then - echo "Failed to locate webinspectord_sim.socket" - echo "--- launchd_sim file table ---" - lsof -aUc launchd_sim 2>/dev/null || true - exit 1 - fi - echo "socket: $SOCK" - echo "SIM_WI_SOCKET=unix:$SOCK" >> $GITHUB_ENV - echo "::endgroup::" - - - name: Start ios-webkit-debug-proxy - run: | - echo "::group::Starting proxy (SIM_WI_SOCKET=$SIM_WI_SOCKET)" - ios_webkit_debug_proxy -F -d -s "$SIM_WI_SOCKET" -c "null:9221,:9222-9322" > "$RUNNER_TEMP/iwdp.log" 2>&1 & - PID=$! - echo "IWDP_PID=$PID" >> $GITHUB_ENV - echo "proxy pid=$PID" - sleep 3 - if ! kill -0 "$PID" 2>/dev/null; then - echo "Proxy died immediately. Log:" - cat "$RUNNER_TEMP/iwdp.log" - exit 1 - fi - echo "::endgroup::" - echo "::group::Listening ports" - lsof -nP -iTCP -sTCP:LISTEN | grep -E "9221|9222|ios_webkit" || true - echo "::endgroup::" - - - name: Run WebView tests - run: | - echo "::group::Test run (shard ${{ matrix.shard }}/4)" - npx playwright test --config tests/webview/playwright.config.ts --shard=${{ matrix.shard }}/4 - echo "::endgroup::" - - - name: Stop proxy - if: always() - run: | - [[ -n "$IWDP_PID" ]] && kill "$IWDP_PID" 2>/dev/null || true - # Simulator shutdown is owned by futureware-tech/simulator-action's post step. - - - name: Upload artifacts - if: always() - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: webview-simulator-logs-${{ matrix.shard }} - path: | - ${{ github.workspace }}/test-results/** - if-no-files-found: ignore - - - name: Upload parquet report - if: ${{ !cancelled() }} - uses: ./.github/actions/upload-parquet-report - with: - job_name: webview-simulator-${{ matrix.shard }} diff --git a/.github/workflows/triage_linux.yml b/.github/workflows/triage_linux.yml deleted file mode 100644 index d78876f386fad..0000000000000 --- a/.github/workflows/triage_linux.yml +++ /dev/null @@ -1,108 +0,0 @@ -name: "Issue triage (Linux)" - -on: - # Opt in by applying the "needs-triage-linux" label; re-apply it to trigger another pass. - issues: - types: [labeled] - workflow_dispatch: - inputs: - issue: - description: "Issue number to triage" - required: true - -permissions: {} - -jobs: - triage: - if: >- - github.event_name == 'workflow_dispatch' || - (github.event_name == 'issues' && github.event.label.name == 'needs-triage-linux') - runs-on: ubuntu-latest - timeout-minutes: 20 - permissions: - copilot-requests: write - outputs: - has_draft: ${{ steps.triage.outputs.has_draft }} - env: - ISSUE: ${{ github.event.issue.number || inputs.issue }} - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Set up Node.js - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: lts/* - - - name: Install Copilot CLI - run: npm install -g @github/copilot - - - name: Triage issue with Copilot CLI - id: triage - env: - COPILOT_GITHUB_TOKEN: ${{ github.token }} - run: | - mkdir -p output - PROMPT=$(cat <> "$GITHUB_OUTPUT" - else - echo "has_draft=false" >> "$GITHUB_OUTPUT" - fi - - - name: Add session transcript to job summary - if: always() - run: | - { - echo "## Triage session transcript (issue $ISSUE, Linux)" - echo '' - cat "output/copilot-session.md" 2>/dev/null || echo "(no transcript)" - } >> "$GITHUB_STEP_SUMMARY" - - - name: Upload output - if: always() - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: triage-linux-${{ github.event.issue.number || inputs.issue }} - path: output/triage.md - if-no-files-found: warn - - post: - needs: triage - if: needs.triage.outputs.has_draft == 'true' - runs-on: ubuntu-latest - permissions: - issues: write - env: - ISSUE: ${{ github.event.issue.number || inputs.issue }} - GH_TOKEN: ${{ github.token }} - WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - steps: - - name: Download triage output - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: triage-linux-${{ github.event.issue.number || inputs.issue }} - path: output - - - name: Post triage comment - run: | - printf '\n\nTriaged on Linux by the Playwright bot - [agent run](%s)\n\n' "$WORKFLOW_URL" >> output/triage.md - gh issue comment "$ISSUE" --repo "${{ github.repository }}" --body-file output/triage.md diff --git a/.github/workflows/triage_mac.yml b/.github/workflows/triage_mac.yml deleted file mode 100644 index 0903251f259a6..0000000000000 --- a/.github/workflows/triage_mac.yml +++ /dev/null @@ -1,112 +0,0 @@ -name: "Issue triage (macOS)" - -on: - # Opt in by applying the "needs-triage-mac" label; re-apply it to trigger another pass. - issues: - types: [labeled] - workflow_dispatch: - inputs: - issue: - description: "Issue number to triage" - required: true - -permissions: {} - -jobs: - triage: - if: >- - github.event_name == 'workflow_dispatch' || - (github.event_name == 'issues' && github.event.label.name == 'needs-triage-mac') - runs-on: macos-latest - timeout-minutes: 20 - permissions: - copilot-requests: write - outputs: - has_draft: ${{ steps.triage.outputs.has_draft }} - env: - ISSUE: ${{ github.event.issue.number || inputs.issue }} - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Set up Node.js - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: lts/* - - - name: Install Copilot CLI - run: npm install -g @github/copilot - - - name: Triage issue with Copilot CLI - id: triage - env: - COPILOT_GITHUB_TOKEN: ${{ github.token }} - run: | - mkdir -p output - PROMPT=$(cat <> "$GITHUB_OUTPUT" - else - echo "has_draft=false" >> "$GITHUB_OUTPUT" - fi - - - name: Add session transcript to job summary - if: always() - run: | - { - echo "## Triage session transcript (issue $ISSUE, macOS)" - echo '' - cat "output/copilot-session.md" 2>/dev/null || echo "(no transcript)" - } >> "$GITHUB_STEP_SUMMARY" - - - name: Upload output - if: always() - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: triage-mac-${{ github.event.issue.number || inputs.issue }} - path: output/triage.md - if-no-files-found: warn - - post: - needs: triage - if: needs.triage.outputs.has_draft == 'true' - runs-on: ubuntu-latest - permissions: - issues: write - env: - ISSUE: ${{ github.event.issue.number || inputs.issue }} - GH_TOKEN: ${{ github.token }} - WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - steps: - - name: Download triage output - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: triage-mac-${{ github.event.issue.number || inputs.issue }} - path: output - - - name: Post triage comment - run: | - printf '\n\nTriaged on macOS by the Playwright bot - [agent run](%s)\n\n' "$WORKFLOW_URL" >> output/triage.md - gh issue comment "$ISSUE" --repo "${{ github.repository }}" --body-file output/triage.md diff --git a/.github/workflows/triage_win.yml b/.github/workflows/triage_win.yml deleted file mode 100644 index 146e9ad82956f..0000000000000 --- a/.github/workflows/triage_win.yml +++ /dev/null @@ -1,116 +0,0 @@ -name: "Issue triage (Windows)" - -on: - # Opt in by applying the "needs-triage-win" label; re-apply it to trigger another pass. - issues: - types: [labeled] - workflow_dispatch: - inputs: - issue: - description: "Issue number to triage" - required: true - -permissions: {} - -jobs: - triage: - if: >- - github.event_name == 'workflow_dispatch' || - (github.event_name == 'issues' && github.event.label.name == 'needs-triage-win') - runs-on: windows-latest - timeout-minutes: 20 - permissions: - copilot-requests: write - outputs: - has_draft: ${{ steps.triage.outputs.has_draft }} - env: - ISSUE: ${{ github.event.issue.number || inputs.issue }} - defaults: - run: - # Windows runners default to pwsh; the steps below use bash syntax. - shell: bash - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Set up Node.js - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: lts/* - - - name: Install Copilot CLI - run: npm install -g @github/copilot - - - name: Triage issue with Copilot CLI - id: triage - env: - COPILOT_GITHUB_TOKEN: ${{ github.token }} - run: | - mkdir -p output - PROMPT=$(cat <> "$GITHUB_OUTPUT" - else - echo "has_draft=false" >> "$GITHUB_OUTPUT" - fi - - - name: Add session transcript to job summary - if: always() - run: | - { - echo "## Triage session transcript (issue $ISSUE, Windows)" - echo '' - cat "output/copilot-session.md" 2>/dev/null || echo "(no transcript)" - } >> "$GITHUB_STEP_SUMMARY" - - - name: Upload output - if: always() - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: triage-win-${{ github.event.issue.number || inputs.issue }} - path: output/triage.md - if-no-files-found: warn - - post: - needs: triage - if: needs.triage.outputs.has_draft == 'true' - runs-on: ubuntu-latest - permissions: - issues: write - env: - ISSUE: ${{ github.event.issue.number || inputs.issue }} - GH_TOKEN: ${{ github.token }} - WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - steps: - - name: Download triage output - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: triage-win-${{ github.event.issue.number || inputs.issue }} - path: output - - - name: Post triage comment - run: | - printf '\n\nTriaged on Windows by the Playwright bot - [agent run](%s)\n\n' "$WORKFLOW_URL" >> output/triage.md - gh issue comment "$ISSUE" --repo "${{ github.repository }}" --body-file output/triage.md diff --git a/.github/workflows/update_test_results_db.yml b/.github/workflows/update_test_results_db.yml deleted file mode 100644 index bac2781f69d62..0000000000000 --- a/.github/workflows/update_test_results_db.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: "Update test results DB" -on: - workflow_dispatch: - schedule: - - cron: "0 */3 * * *" - -concurrency: - group: test-results-db - cancel-in-progress: false - -jobs: - update: - name: Update DuckDB - runs-on: ubuntu-22.04 - timeout-minutes: 60 - if: github.repository == 'microsoft/playwright' - permissions: - actions: read - contents: read - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: lts/* - - run: npm ci - - name: Download current database - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: node utils/test-results-db/cli.ts download - - name: Ingest new test results - id: ingest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NODE_OPTIONS: --max-old-space-size=8192 - run: node utils/test-results-db/cli.ts update --lookback-days 7 --concurrency 32 - - name: Truncate to run cap - if: steps.ingest.outputs.imported != '0' - run: node utils/test-results-db/cli.ts truncate --max-runs 2000 - - name: Upload database - if: steps.ingest.outputs.imported != '0' - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: test-results-db - path: utils/test-results-db/test-results.duckdb - retention-days: 7 - overwrite: true diff --git a/.github/workflows/webkit_gc_repro.yml b/.github/workflows/webkit_gc_repro.yml new file mode 100644 index 0000000000000..00b1aeed67aee --- /dev/null +++ b/.github/workflows/webkit_gc_repro.yml @@ -0,0 +1,32 @@ +name: "webkit gc repro" + +# Diagnostic branch only. DO NOT MERGE. +# +# Every other workflow is removed on this branch so a draft PR runs nothing but the WebKit leak +# matrix below, on the one bot that actually reproduces the regression (macos-15-xlarge, arm64). +# pull_request only: a push to a personal fork cannot schedule a larger runner. + +on: + pull_request: + branches: + - main + +permissions: + contents: read + +jobs: + webkit_leaks: + name: webkit-page leaks (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + os: [macos-15-xlarge] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: ./.github/actions/run-test + with: + browsers-to-install: webkit chromium + command: npx playwright test --config=tests/library/playwright.config.ts tests/page/webkit-gc-repro.spec.ts tests/page/page-leaks.spec.ts --project=webkit-page --repeat-each=10 --retries=0 --reporter=line + bot-name: "webkit-gc-repro-${{ matrix.os }}" diff --git a/tests/page/webkit-gc-repro.spec.ts b/tests/page/webkit-gc-repro.spec.ts new file mode 100644 index 0000000000000..e057e0bafb017 --- /dev/null +++ b/tests/page/webkit-gc-repro.spec.ts @@ -0,0 +1,136 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Diagnostic for the WebKit r2359 GC regression. DO NOT MERGE. +// +// `page-leaks.spec.ts` › `expect should not leak` fails ~70% of runs on webkit-macos-15-xlarge +// since the r2359 roll, while the click/fill/waitFor variants next to it are 100% green. This +// file asks whether that asymmetry is real or an artifact of timing, by running the same +// scenario once per locator call and once per equivalent raw-DOM call. +// +// A standalone reduction hit wholesale retention on the waitFor equivalent, which does not fit +// the "expect-specific" story, hence this matrix. The raw-DOM variants run in the main world; +// the locator variants go through the injected script in the utility world. + +import { server as coreServer } from '../../packages/playwright-core/lib/coreBundle'; +const { nullProgress } = coreServer; +import { test, expect } from './pageTest'; + +const COUNT = 25; + +async function weakRefObjects(pageImpl: any, selector: string) { + for (const world of ['main', 'utility']) { + const context = await pageImpl.mainFrame().context(world); + await context.evaluate(selector => { + const elements = document.querySelectorAll(selector); + globalThis.weakRefs = globalThis.weakRefs || []; + for (const element of elements) + globalThis.weakRefs.push(new WeakRef(element)); + }, selector); + } +} + +async function weakRefCount(pageImpl: any): Promise<{ main: number, utility: number }> { + const result = { main: 0, utility: 0 }; + for (const world of ['main', 'utility']) { + await pageImpl.requestGC(nullProgress); + const context = await pageImpl.mainFrame().context(world); + result[world] = await context.evaluate(() => globalThis.weakRefs.filter(r => !!r.deref()).length); + } + return result; +} + +// Same bounds as page-leaks.spec.ts. The failure is wholesale — every ref stays alive, so the +// count jumps straight to 58 — and it is sticky, so a short toPass window is enough and keeps a +// failing run from burning the whole test timeout. +async function checkWeakRefs(pageImpl: any, from: number, to: number) { + await expect(async () => { + const counts = await weakRefCount(pageImpl); + expect(counts.main + counts.utility).toBeGreaterThanOrEqual(from); + expect(counts.main + counts.utility).toBeLessThan(to); + }).toPass({ timeout: 5000 }); +} + +const kVariants = ['expect', 'waitFor', 'click', 'dom-style', 'dom-event', 'dom-both', 'none'] as const; + +for (const variant of kVariants) { + test(`${variant} should not leak`, async ({ page, mode, toImpl }) => { + test.skip(mode !== 'default'); + + await page.setContent(` + + +
+ `); + await weakRefObjects(toImpl(page), 'button'); + + const last = () => page.locator('#buttons > button').last(); + const visit = async () => { + switch (variant) { + case 'expect': + await expect(last()).toBeVisible(); + break; + case 'waitFor': + await last().waitFor(); + break; + case 'click': + await last().click(); + break; + case 'dom-style': + await page.evaluate(() => { + const element = document.querySelector('#buttons > button:last-child')!; + const display = getComputedStyle(element).display; + element.getBoundingClientRect(); + return display; + }); + break; + case 'dom-event': + await page.evaluate(() => { + const element = document.querySelector('#buttons > button:last-child')!; + element.dispatchEvent(new CustomEvent('__mark__', { bubbles: true, cancelable: true, composed: true })); + }); + break; + case 'dom-both': + await page.evaluate(() => { + const element = document.querySelector('#buttons > button:last-child')!; + const display = getComputedStyle(element).display; + element.getBoundingClientRect(); + element.dispatchEvent(new CustomEvent('__mark__', { bubbles: true, cancelable: true, composed: true })); + return display; + }); + break; + case 'none': + break; + } + }; + + for (let i = 0; i < COUNT; ++i) { + await page.evaluate(i => { + const element = document.createElement('button'); + element.textContent = 'dynamic ' + i; + document.getElementById('buttons').appendChild(element); + }, i); + await visit(); + } + + await weakRefObjects(toImpl(page), 'button'); + await page.evaluate(() => { + document.getElementById('buttons').textContent = ''; + }); + + await checkWeakRefs(toImpl(page), 2, COUNT); + }); +} From b8004f673a32f7db279bd0976ce8fb88038cde3d Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Fri, 11 Sep 2026 16:00:36 -0700 Subject: [PATCH 2/2] test(webkit): add no-pre-refs controls to the GC leak matrix First run showed waitFor failing 10/10 here while page-leaks' own waitFor test passed 10/10 on the same bot. The tests differ only in that the expect test registers WeakRefs before the loop as well as after, and every variant here copies that shape. These two controls drop the pre-loop registration to confirm it is a necessary ingredient rather than the assertion path. --- tests/page/webkit-gc-repro.spec.ts | 48 ++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/tests/page/webkit-gc-repro.spec.ts b/tests/page/webkit-gc-repro.spec.ts index e057e0bafb017..1cd954ea88d10 100644 --- a/tests/page/webkit-gc-repro.spec.ts +++ b/tests/page/webkit-gc-repro.spec.ts @@ -17,13 +17,19 @@ // Diagnostic for the WebKit r2359 GC regression. DO NOT MERGE. // // `page-leaks.spec.ts` › `expect should not leak` fails ~70% of runs on webkit-macos-15-xlarge -// since the r2359 roll, while the click/fill/waitFor variants next to it are 100% green. This -// file asks whether that asymmetry is real or an artifact of timing, by running the same -// scenario once per locator call and once per equivalent raw-DOM call. +// since the r2359 roll, while the click/fill/waitFor tests next to it are 100% green. The first +// run of this matrix showed that asymmetry is not about `expect` at all: the `waitFor` variant +// below failed 10/10 while page-leaks' own `waitFor` test passed 10/10, on the same bot, in the +// same job. // -// A standalone reduction hit wholesale retention on the waitFor equivalent, which does not fit -// the "expect-specific" story, hence this matrix. The raw-DOM variants run in the main world; -// the locator variants go through the injected script in the utility world. +// The two tests differ in one thing. The `expect` test registers WeakRefs *before* the loop as +// well as after; click/fill/waitFor only register after. Every variant here copies the `expect` +// test's shape, so `registerBefore` reproduces it and the `-no-pre-refs` variants drop it. If +// those two stay green while their twins fail, the trigger is pre-loop registration plus a +// locator visibility check, not the assertion path. +// +// The raw-DOM variants run in the main world; the locator variants go through the injected +// script in the utility world. import { server as coreServer } from '../../packages/playwright-core/lib/coreBundle'; const { nullProgress } = coreServer; @@ -53,9 +59,10 @@ async function weakRefCount(pageImpl: any): Promise<{ main: number, utility: num return result; } -// Same bounds as page-leaks.spec.ts. The failure is wholesale — every ref stays alive, so the -// count jumps straight to 58 — and it is sticky, so a short toPass window is enough and keeps a -// failing run from burning the whole test timeout. +// Same bounds as page-leaks.spec.ts, and they hold either way: the static buttons leave 8 alive +// with pre-loop registration and 4 without. The failure is wholesale - every ref stays alive, 58 +// or 54 - and it is sticky, so a short toPass window is enough and keeps a failing run from +// burning the whole test timeout. async function checkWeakRefs(pageImpl: any, from: number, to: number) { await expect(async () => { const counts = await weakRefCount(pageImpl); @@ -64,10 +71,24 @@ async function checkWeakRefs(pageImpl: any, from: number, to: number) { }).toPass({ timeout: 5000 }); } -const kVariants = ['expect', 'waitFor', 'click', 'dom-style', 'dom-event', 'dom-both', 'none'] as const; +type Visit = 'expect' | 'waitFor' | 'click' | 'dom-style' | 'dom-event' | 'dom-both' | 'none'; + +const kVariants: { name: string, registerBefore: boolean, visit: Visit }[] = [ + { name: 'expect', registerBefore: true, visit: 'expect' }, + { name: 'waitFor', registerBefore: true, visit: 'waitFor' }, + { name: 'click', registerBefore: true, visit: 'click' }, + { name: 'dom-style', registerBefore: true, visit: 'dom-style' }, + { name: 'dom-event', registerBefore: true, visit: 'dom-event' }, + { name: 'dom-both', registerBefore: true, visit: 'dom-both' }, + { name: 'none', registerBefore: true, visit: 'none' }, + // Identical, minus the pre-loop registration - i.e. exactly how page-leaks.spec.ts shapes the + // click/fill/waitFor tests that stay green. + { name: 'expect-no-pre-refs', registerBefore: false, visit: 'expect' }, + { name: 'waitFor-no-pre-refs', registerBefore: false, visit: 'waitFor' }, +]; for (const variant of kVariants) { - test(`${variant} should not leak`, async ({ page, mode, toImpl }) => { + test(`${variant.name} should not leak`, async ({ page, mode, toImpl }) => { test.skip(mode !== 'default'); await page.setContent(` @@ -75,11 +96,12 @@ for (const variant of kVariants) {
`); - await weakRefObjects(toImpl(page), 'button'); + if (variant.registerBefore) + await weakRefObjects(toImpl(page), 'button'); const last = () => page.locator('#buttons > button').last(); const visit = async () => { - switch (variant) { + switch (variant.visit) { case 'expect': await expect(last()).toBeVisible(); break;