microsoft/playwright

18 workflows · maturity 50% · 8 patterns · GitHub ↗

Security 10.28/100

Practices

✓ Matrix✓ Permissions○ Security scan○ AI review○ Cache✓ Concurrency○ Reusable workflows

Detected patterns

Security dimensions

permissions
2.8
security scan
0
supply chain
0
secret handling
7.5
harden runner
0

Workflows (18)

copilot-setup-steps .github/workflows/copilot-setup-steps.yml
Triggers
workflow_dispatch
Runs on
ubuntu-latest
Jobs
copilot-setup-steps
Commands
  • npm ci
  • npm run build
  • npx playwright install --with-deps
View raw YAML
name: "Copilot Setup Steps"
on: workflow_dispatch
jobs:
  copilot-setup-steps:
    runs-on: ubuntu-latest

    permissions:
      contents: read

    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
        with:
          node-version: "22"
      - run: npm ci
      - run: npm run build
      - run: npx playwright install --with-deps
create_test_report .github/workflows/create_test_report.yml
Triggers
workflow_run
Runs on
ubuntu-latest
Jobs
merge-reports
Actions
azure/login
Commands
  • npm ci
  • npm run build
  • npx playwright merge-reports --config .github/workflows/merge.config.ts ./all-blob-reports
  • REPORT_DIR='run-${{ github.event.workflow_run.id }}-${{ github.event.workflow_run.run_attempt }}-${{ github.sha }}' azcopy cp --recursive "./playwright-report/*" "https://mspwblobreport.blob.core.windows.net/\$web/$REPORT_DIR" REPORT_URL="https://mspwblobreport.z1.web.core.windows.net/$REPORT_DIR/index.html" echo "Report url: $REPORT_URL" echo "reportUrl=$REPORT_URL" >> "$GITHUB_OUTPUT"
View raw YAML
name: Publish Test Results
on:
  workflow_run:
    workflows: ["tests 1", "tests 2", "tests others", "MCP"]
    types:
      - completed
jobs:
  merge-reports:
    permissions:
      pull-requests: write
      checks: write
      statuses: write
      id-token: write   # This is required for OIDC login (azure/login) to succeed
      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
    steps:
    - uses: actions/checkout@v6
    - uses: actions/setup-node@v6
      with:
        node-version: 20
    - run: npm ci
      env:
        ELECTRON_SKIP_BINARY_DOWNLOAD: 1
    - 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:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        NODE_OPTIONS: --max-old-space-size=8192
        HTML_REPORT_URL: 'https://mspwblobreport.z1.web.core.windows.net/run-${{ github.event.workflow_run.id }}-${{ github.event.workflow_run.run_attempt }}-${{ github.sha }}/index.html'

    - name: Azure Login
      uses: azure/login@v2
      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 HTML report to Azure
      id: upload-report
      run: |
        REPORT_DIR='run-${{ github.event.workflow_run.id }}-${{ github.event.workflow_run.run_attempt }}-${{ github.sha }}'
        azcopy cp --recursive "./playwright-report/*" "https://mspwblobreport.blob.core.windows.net/\$web/$REPORT_DIR"
        REPORT_URL="https://mspwblobreport.z1.web.core.windows.net/$REPORT_DIR/index.html"
        echo "Report url: $REPORT_URL"
        echo "reportUrl=$REPORT_URL" >> "$GITHUB_OUTPUT"
      env:
        AZCOPY_AUTO_LOGIN_TYPE: AZCLI

    - name: Publish Report URL as Commit Status
      uses: actions/github-script@v8
      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.reportUrl }}',
            context: 'HTML Report (${{ github.event.workflow_run.name }})',
          });
dependabot_rebuild .github/workflows/dependabot_rebuild.yml
Triggers
pull_request
Runs on
ubuntu-latest
Jobs
rebuild
Commands
  • npm ci
  • npm run build
  • git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" if [[ -n "$(git status --porcelain)" ]]; then git add . git commit -m "chore: update generated files after dependency update" git push origin HEAD:${{ github.head_ref }} # Pushing with GITHUB_TOKEN does not retrigger workflow runs, see: # https://docs.github.com/en/actions/concepts/security/github_token#when-github_token-triggers-workflow-runs # Close and reopen the PR to fire a pull_request reopened event, which # retriggers infra.yml on the new commit. gh pr close ${{ github.event.pull_request.number }} # Remove labels after closing to avoid triggering bots that may rerun CI. gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels -X DELETE gh pr reopen ${{ github.event.pull_request.number }} else echo "No generated files changed, nothing to commit." fi
View raw YAML
name: "dependabot"
on:
  pull_request:
    branches:
      - main

jobs:
  rebuild:
    name: update generated files
    runs-on: ubuntu-latest
    if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'microsoft/playwright'
    permissions:
      contents: write
      pull-requests: write
    steps:
      - uses: actions/checkout@v6
        with:
          ref: ${{ github.head_ref }}
          token: ${{ secrets.GITHUB_TOKEN }}

      - uses: actions/setup-node@v6
        with:
          node-version: 20

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Add generated files to the PR
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          if [[ -n "$(git status --porcelain)" ]]; then
            git add .
            git commit -m "chore: update generated files after dependency update"
            git push origin HEAD:${{ github.head_ref }}
            # Pushing with GITHUB_TOKEN does not retrigger workflow runs, see:
            # https://docs.github.com/en/actions/concepts/security/github_token#when-github_token-triggers-workflow-runs
            # Close and reopen the PR to fire a pull_request reopened event, which
            # retriggers infra.yml on the new commit.
            gh pr close ${{ github.event.pull_request.number }}
            # Remove labels after closing to avoid triggering bots that may rerun CI.
            gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels -X DELETE
            gh pr reopen ${{ github.event.pull_request.number }}
          else
            echo "No generated files changed, nothing to commit."
          fi
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
infra .github/workflows/infra.yml
Triggers
push, pull_request
Runs on
ubuntu-24.04, ubuntu-latest
Jobs
doc-and-lint, lint-snippets
Commands
  • npm ci
  • npm run build
  • npx playwright install --with-deps
  • npm run lint
  • if [[ -n $(git status -s) ]]; then echo "ERROR: tree is dirty after npm run build:" git diff exit 1 fi
  • node utils/check_audit.js
  • npm ci
  • pip install -r utils/doclint/linting-code-snippets/python/requirements.txt
View raw YAML
name: "infra"

on:
  push:
    branches:
      - main
      - release-*
  pull_request:
    branches:
      - main
      - release-*

env:
  ELECTRON_SKIP_BINARY_DOWNLOAD: 1

jobs:
  doc-and-lint:
    name: "docs & lint"
    runs-on: ubuntu-24.04
    steps:
    - uses: actions/checkout@v6
    - uses: actions/setup-node@v6
      with:
        node-version: 20
    - 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@v6
    - uses: actions/setup-node@v6
      with:
        node-version: 20
    - uses: actions/setup-python@v6
      with:
        python-version: '3.11'
    - uses: actions/setup-dotnet@v5
      with:
        dotnet-version: 8.0.x
    - uses: actions/setup-java@v5
      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
pr_check_client_side_changes .github/workflows/pr_check_client_side_changes.yml
Triggers
push
Runs on
ubuntu-24.04
Jobs
check
Actions
actions/create-github-app-token
View raw YAML
name: "Check client side changes"
on:
  push:
    branches:
      - main
    paths:
      - 'docs/src/api/**/*'
      - 'packages/playwright-core/src/client/**/*'
      - 'packages/playwright-core/src/utils/isomorphic/**/*'
      - 'packages/playwright/src/matchers/matchers.ts'
      - 'packages/protocol/src/protocol.yml'
jobs:
  check:
    name: Check
    runs-on: ubuntu-24.04
    if: github.repository == 'microsoft/playwright'
    steps:
      - uses: actions/checkout@v6
      - uses: actions/create-github-app-token@v2
        id: app-token
        with:
          app-id: ${{ vars.PLAYWRIGHT_APP_ID }}
          private-key: ${{ secrets.PLAYWRIGHT_PRIVATE_KEY }}
          repositories: |
            playwright
            playwright-python
            playwright-java
            playwright-dotnet
      - name: Create GitHub issue
        uses: actions/github-script@v8
        with:
          github-token: ${{ steps.app-token.outputs.token }}
          script: |
            const currentPlaywrightVersion = require('./package.json').version.match(/\d+\.\d+/)[0];
            const { data } = await github.rest.git.getCommit({
              owner: context.repo.owner,
              repo: context.repo.repo,
              commit_sha: context.sha,
            });
            const commitHeader = data.message.split('\n')[0];
            const prMatch = commitHeader.match(/#(\d+)/);
            const formattedCommit = prMatch 
              ? `https://github.com/microsoft/playwright/pull/${prMatch[1]}`
              : `https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${context.sha} (${commitHeader})`;

            const title = '[Ports]: Backport client side changes for ' + currentPlaywrightVersion;
            for (const repo of ['playwright-python', 'playwright-java', 'playwright-dotnet']) {
              const { data: issuesData } = await github.rest.search.issuesAndPullRequests({
                q: `is:issue is:open repo:microsoft/${repo} in:title "${title}"`
              })
              let issueNumber = null;
              let issueBody = '';
              if (issuesData.total_count > 0) {
                issueNumber = issuesData.items[0].number
                issueBody = issuesData.items[0].body
              } else {
                const { data: issueCreateData } = await github.rest.issues.create({
                  owner: context.repo.owner,
                  repo: repo,
                  title,
                  body: 'Please backport client side changes: \n',
                });
                issueNumber = issueCreateData.number;
                issueBody = issueCreateData.body;
              }
              const newBody = issueBody.trimEnd() + `
              - [ ] ${formattedCommit}`;
              const data = await github.rest.issues.update({
                owner: context.repo.owner,
                repo: repo,
                issue_number: issueNumber,
                body: newBody
              })
            }
publish_release .github/workflows/publish_release.yml
Triggers
workflow_dispatch, schedule, push, release
Runs on
ubuntu-24.04, ubuntu-24.04
Jobs
publish-npm-and-driver, publish-trace-viewer
Actions
azure/login, actions/create-github-app-token
Commands
  • npm install -g npm@latest
  • npm ci
  • npm run build
  • node utils/build/update_canary_version.js --alpha --commit-timestamp utils/publish_all_packages.sh --alpha
  • node utils/build/update_canary_version.js --alpha --today-date utils/publish_all_packages.sh --alpha
  • node utils/build/update_canary_version.js --beta --commit-timestamp utils/publish_all_packages.sh --beta
  • utils/publish_all_packages.sh --release
  • utils/build/build-playwright-driver.sh utils/build/upload-playwright-driver.sh
View raw YAML
name: "publish release - npm, driver, trace viewer"

on:
  workflow_dispatch:
  schedule:
    - cron: "10 5 * * *"
  push:
    branches:
      - release-*
  release:
    types: [published]

env:
  ELECTRON_SKIP_BINARY_DOWNLOAD: 1

jobs:
  publish-npm-and-driver:
    name: "publish NPM and driver"
    runs-on: ubuntu-24.04
    if: github.repository == 'microsoft/playwright'
    permissions:
      id-token: write  # This is required for OIDC login (azure/login, NPM publish) to succeed
      contents: read   # This is required for actions/checkout to succeed
    environment: allow-publish-driver-to-cdn # This is required for OIDC login (azure/login)
    steps:
    - uses: actions/checkout@v6
    - uses: actions/setup-node@v6
      with:
        node-version: 20
        registry-url: 'https://registry.npmjs.org'
    # Ensure npm 11.5.1 or later is installed (for OIDC npm publishing)
    - name: Update npm
      run: npm install -g npm@latest
    - 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

    - name: Azure Login
      uses: azure/login@v2
      with:
        client-id: ${{ secrets.AZURE_PW_CDN_CLIENT_ID }}
        tenant-id: ${{ secrets.AZURE_PW_CDN_TENANT_ID }}
        subscription-id: ${{ secrets.AZURE_PW_CDN_SUBSCRIPTION_ID }}
    - name: build & publish driver
      env:
        AZ_UPLOAD_FOLDER: ${{ github.event_name == 'release' && 'driver' || 'driver/next' }}
      run: |
        utils/build/build-playwright-driver.sh
        utils/build/upload-playwright-driver.sh

  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@v6
    - uses: actions/setup-node@v6
      with:
        node-version: 20
    - uses: actions/create-github-app-token@v2
      id: app-token
      with:
        app-id: ${{ vars.PLAYWRIGHT_APP_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 }}
publish_release_docker .github/workflows/publish_release_docker.yml
Triggers
workflow_dispatch, release
Runs on
ubuntu-22.04
Jobs
publish-docker-release
Actions
docker/setup-qemu-action, azure/login
Commands
  • npm ci
  • npm run build
  • az acr login --name playwright
  • ./utils/docker/publish_docker.sh stable
View raw YAML
name: "publish release - Docker"

on:
  workflow_dispatch:
  release:
    types: [published]

env:
  ELECTRON_SKIP_BINARY_DOWNLOAD: 1

jobs:
  publish-docker-release:
    name: "publish to DockerHub"
    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
    if: github.repository == 'microsoft/playwright'
    environment: allow-publishing-docker-to-acr
    steps:
    - uses: actions/checkout@v6
    - uses: actions/setup-node@v6
      with:
        node-version: 20
        registry-url: 'https://registry.npmjs.org'
    - name: Set up Docker QEMU for arm64 docker builds
      uses: docker/setup-qemu-action@v4
      with:
        platforms: arm64
    - run: npm ci
    - run: npm run build
    - name: Azure Login
      uses: azure/login@v2
      with:
        client-id: ${{ secrets.AZURE_DOCKER_CLIENT_ID }}
        tenant-id: ${{ secrets.AZURE_DOCKER_TENANT_ID }}
        subscription-id: ${{ secrets.AZURE_DOCKER_SUBSCRIPTION_ID }}
    - name: Login to ACR via OIDC
      run: az acr login --name playwright
    - run: ./utils/docker/publish_docker.sh stable
roll_browser_into_playwright perms .github/workflows/roll_browser_into_playwright.yml
Triggers
repository_dispatch
Runs on
ubuntu-24.04
Jobs
roll
Actions
actions/create-github-app-token
Commands
  • npm ci
  • npm run build
  • npx playwright install-deps
  • ./utils/roll_browser.js $BROWSER $REVISION $BROWSER_VERSION npm run build
  • BRANCH_NAME="roll-into-pw-${BROWSER}/${REVISION}" echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT git fetch origin $BRANCH_NAME:$BRANCH_NAME || true if git show-ref --verify --quiet refs/heads/$BRANCH_NAME; then echo "exists=1" >> $GITHUB_OUTPUT echo "branch $BRANCH_NAME already exists, exiting" exit 0 fi echo "exists=0" >> $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 "feat(${BROWSER}): roll to r${REVISION}" git push origin $BRANCH_NAME --force
View raw YAML
name: Roll Browser into Playwright

on:
  repository_dispatch:
    types: [roll_into_pw]

env:
  ELECTRON_SKIP_BINARY_DOWNLOAD: 1
  BROWSER: ${{ github.event.client_payload.browser }}
  REVISION: ${{ github.event.client_payload.revision }}
  BROWSER_VERSION: ${{ github.event.client_payload.browserVersion }}

permissions:
  contents: write

concurrency: 
  group: 'roll-browser-into-playwright-${{ github.event.client_payload.browser }}-${{ github.event.client_payload.revision }}'

jobs:
  roll:
    runs-on: ubuntu-24.04
    steps:
    - uses: actions/checkout@v6
    - uses: actions/setup-node@v6
      with:
        node-version: 20
    - run: npm ci
    - run: npm run build
    - name: Install dependencies
      run: npx playwright install-deps
    - name: Roll to new revision
      run: |
        ./utils/roll_browser.js $BROWSER $REVISION $BROWSER_VERSION
        npm run build
    - name: Prepare branch
      id: prepare-branch
      run: |
        BRANCH_NAME="roll-into-pw-${BROWSER}/${REVISION}"
        echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT

        git fetch origin $BRANCH_NAME:$BRANCH_NAME || true
        if git show-ref --verify --quiet refs/heads/$BRANCH_NAME; then
          echo "exists=1" >> $GITHUB_OUTPUT
          echo "branch $BRANCH_NAME already exists, exiting"
          exit 0
        fi
        echo "exists=0" >> $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 "feat(${BROWSER}): roll to r${REVISION}"
        git push origin $BRANCH_NAME --force
    - uses: actions/create-github-app-token@v2
      id: app-token
      with:
        app-id: ${{ vars.PLAYWRIGHT_APP_ID }}
        private-key: ${{ secrets.PLAYWRIGHT_PRIVATE_KEY }}
    - name: Create Pull Request
      uses: actions/github-script@v8
      if: ${{ steps.prepare-branch.outputs.exists == '0' }}
      with:
        github-token: ${{ steps.app-token.outputs.token }}
        script: |
          const response = await github.rest.pulls.create({
            owner: 'microsoft',
            repo: 'playwright',
            head: 'microsoft:${{ steps.prepare-branch.outputs.BRANCH_NAME }}',
            base: 'main',
            title: 'feat(${{ env.BROWSER }}): roll to r${{ env.REVISION }}',
          });
          await github.rest.issues.addLabels({
            owner: 'microsoft',
            repo: 'playwright',
            issue_number: response.data.number,
            labels: ['CQ1'],
          });
roll_nodejs .github/workflows/roll_nodejs.yml
Triggers
workflow_dispatch, schedule
Runs on
ubuntu-22.04
Jobs
trigger-nodejs-roll
Actions
actions/create-github-app-token
Commands
  • node utils/build/update-playwright-node.mjs
  • 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
View raw YAML
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@v6
      - uses: actions/setup-node@v6
        with:
          node-version: 20
      - 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@v2
        id: app-token
        with:
          app-id: ${{ vars.PLAYWRIGHT_APP_ID }}
          private-key: ${{ secrets.PLAYWRIGHT_PRIVATE_KEY }}
      - name: Create Pull Request
        if: ${{ steps.prepare-branch.outputs.HAS_CHANGES == '1' }}
        uses: actions/github-script@v8
        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',
            });
roll_stable_test_runner .github/workflows/roll_stable_test_runner.yml
Triggers
workflow_dispatch, schedule
Runs on
ubuntu-24.04
Jobs
trigger-roll
Actions
actions/create-github-app-token
Commands
  • npm install @playwright/test@next VERSION=$(node -e "console.log(require('./package.json').dependencies['@playwright/test'].replace('^', ''))") echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
  • 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
View raw YAML
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@v6
      - uses: actions/setup-node@v6
        with:
          node-version: 22
      - 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@v2
        id: app-token
        with:
          app-id: ${{ vars.PLAYWRIGHT_APP_ID }}
          private-key: ${{ secrets.PLAYWRIGHT_PRIVATE_KEY }}
      - name: Create Pull Request
        if: ${{ steps.prepare-branch.outputs.HAS_CHANGES == '1' }}
        uses: actions/github-script@v8
        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 }}',
            });
tests_bidi matrix .github/workflows/tests_bidi.yml
Triggers
workflow_dispatch, pull_request, schedule
Runs on
ubuntu-24.04
Jobs
test_bidi
Matrix
channel, exclude, exclude.channel, exclude.isPullRequest, isPullRequest→ ${{ github.event_name == 'pull_request' }}, True, bidi-chromium, moz-firefox-nightly
Actions
azure/login
Commands
  • npm ci
  • npm run build
  • npx playwright install ffmpeg
  • npx playwright install --with-deps chromium
  • echo "BIDI_FFPATH=$(npx -y @puppeteer/browsers install firefox@nightly | tail -n1 | sed 's/^[^ ]* *//')" >> "$GITHUB_ENV"
  • xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run biditest -- --retries=${{ matrix.isPullRequest && 2 || 0 }} --project=${{ matrix.channel }}*
  • 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"
View raw YAML
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@v6
      if: github.event_name != 'workflow_dispatch'
    - uses: actions/checkout@v6
      if: github.event_name == 'workflow_dispatch'
      with:
        ref: ${{ github.event.inputs.ref }}
    - uses: actions/setup-node@v6
      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: |
        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@v7
      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@v7
      with:
        name: json-report-${{ matrix.channel }}
        path: test-results/report.json
        retention-days: 7

    - name: Azure Login
      if: ${{ !cancelled() && github.ref == 'refs/heads/main' }}
      uses: azure/login@v2
      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
tests_components matrix .github/workflows/tests_components.yml
Triggers
push, pull_request
Runs on
${{ matrix.os }}
Jobs
test_components
Matrix
include, include.node-version, include.os, node-version, os→ 20, 22, 24, macos-latest, ubuntu-latest, windows-latest
Commands
  • npm ci
  • npm run build
  • npx playwright install --with-deps
  • npm run ct
View raw YAML
name: "components"

on:
  push:
    branches:
      - main
      - release-*
  pull_request:
    paths-ignore:
      - 'browser_patches/**'
      - 'docs/**'
      - 'packages/playwright-core/src/server/bidi/**'
      - 'packages/playwright-core/src/tools/**'
      - 'tests/bidi/**'
      - 'tests/mcp/**'
    branches:
      - main
      - release-*

env:
  FORCE_COLOR: 1
  ELECTRON_SKIP_BINARY_DOWNLOAD: 1

jobs:
  test_components:
    name: ${{ matrix.os }} - Node.js ${{ matrix.node-version }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        node-version: [20]
        include:
          - os: ubuntu-latest
            node-version: 22
          - os: ubuntu-latest
            node-version: 24
    runs-on: ${{ matrix.os }}
    steps:
    - uses: actions/checkout@v6
    - uses: actions/setup-node@v6
      with:
        node-version: ${{ matrix.node-version }}
    - run: npm ci
    - run: npm run build
    - run: npx playwright install --with-deps
    - run: npm run ct
tests_mcp matrix .github/workflows/tests_mcp.yml
Triggers
push, pull_request
Runs on
${{ matrix.os }}
Jobs
test_mcp
Matrix
os, shardIndex, shardTotal→ 1, 2, macos-latest, ubuntu-latest, windows-latest
View raw YAML
name: MCP

on:
  push:
    branches:
      - main
      - release-*
  pull_request:
    paths-ignore:
      - 'browser_patches/**'
      - 'docs/**'
      - 'packages/playwright-core/src/server/bidi/**'
      - 'tests/bidi/**'
    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
  ELECTRON_SKIP_BINARY_DOWNLOAD: 1
  DEBUG: pw:mcp:error

jobs:
  test_mcp:
    name: ${{ matrix.os }} - ${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
    # 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, windows-latest]
        shardIndex: [1, 2]
        shardTotal: [2]
    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@v6
    - uses: ./.github/actions/run-test
      with:
        node-version: "22"
        command: npm run test-mcp -- --shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
        bot-name: "mcp-${{ matrix.os }}"
        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 }}
tests_others matrix .github/workflows/tests_others.yml
Triggers
push, pull_request
Runs on
${{ matrix.os }}, ubuntu-22.04, ubuntu-22.04, ${{ matrix.os }}
Jobs
test_stress, test_clock_frozen_time_linux, test_clock_frozen_time_test_runner, test_electron
Matrix
clock, os→ frozen, macos-latest, realtime, ubuntu-latest, windows-latest
Commands
  • npm ci
  • npm run build
  • npx playwright install --with-deps
  • npm run stest contexts -- --project=chromium
  • npm run stest browsers -- --project=chromium
  • npm run stest frames -- --project=chromium
  • npm run stest contexts -- --project=webkit
  • npm run stest browsers -- --project=webkit
View raw YAML
name: tests others

on:
  push:
    branches:
      - main
      - release-*
  pull_request:
    paths-ignore:
      - 'browser_patches/**'
      - 'docs/**'
      - 'packages/playwright-core/src/server/bidi/**'
      - 'tests/bidi/**'
    types: [ labeled ]
    branches:
      - main
      - release-*

env:
  FORCE_COLOR: 1
  ELECTRON_SKIP_BINARY_DOWNLOAD: 1

jobs:
  test_stress:
    name: Stress - ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    steps:
    - uses: actions/checkout@v6
    - uses: actions/setup-node@v6
      with:
        node-version: 20
    - run: npm ci
    - run: npm run build
    - run: npx playwright install --with-deps
    - run: npm run stest contexts -- --project=chromium
      if: ${{ !cancelled() }}
    - run: npm run stest browsers -- --project=chromium
      if: ${{ !cancelled() }}
    - run: npm run stest frames -- --project=chromium
      if: ${{ !cancelled() }}
    - run: npm run stest contexts -- --project=webkit
      if: ${{ !cancelled() }}
    - run: npm run stest browsers -- --project=webkit
      if: ${{ !cancelled() }}
    - run: npm run stest frames -- --project=webkit
      if: ${{ !cancelled() }}
    - run: npm run stest contexts -- --project=firefox
      if: ${{ !cancelled() }}
    - run: npm run stest browsers -- --project=firefox
      if: ${{ !cancelled() }}
    - run: npm run stest frames -- --project=firefox
      if: ${{ !cancelled() }}
    - run: npm run stest heap -- --project=chromium
      if: ${{ !cancelled() }}

  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@v6
    - uses: ./.github/actions/run-test
      with:
        node-version: 20
        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 }}

  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@v6
    - uses: ./.github/actions/run-test
      with:
        node-version: 20
        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@v6
    - 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:
        browsers-to-install: chromium
        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 }}
      env:
        ELECTRON_SKIP_BINARY_DOWNLOAD:
tests_primary matrix .github/workflows/tests_primary.yml
Triggers
push, pull_request
Runs on
${{ matrix.os }}, ${{ matrix.os }}, ${{ matrix.os }}, ubuntu-latest, ${{ matrix.os }}
Jobs
test_linux, test_linux_chromium_tot, test_test_runner, test_vscode_extension, test_package_installations
Matrix
browser, include, include.browser, include.node-version, include.os, include.shardIndex, include.shardTotal, include.shardWeights, node-version, os, shardIndex, shardTotal, shardWeights→ 1, 2, 20, 22, 24, 3, 44:33:23, 58:42, chromium, firefox, macos-latest, ubuntu-22.04, ubuntu-22.04-arm, ubuntu-latest, webkit, windows-latest
Commands
  • npm ci
  • npm run build
  • npx playwright install chromium
  • git clone https://github.com/microsoft/playwright-vscode.git
  • git rev-parse HEAD
  • node -e "const p = require('./package.json'); delete p.devDependencies['@playwright/test']; fs.writeFileSync('./package.json', JSON.stringify(p, null, 2));"
  • npm ci && npm run build
  • npm run test
View raw YAML
name: "tests 1"

on:
  push:
    branches:
      - main
      - release-*
  pull_request:
    paths-ignore:
      - 'browser_patches/**'
      - 'docs/**'
      - 'packages/playwright-core/src/server/bidi/**'
      - 'packages/playwright-core/src/tools/**'
      - 'tests/bidi/**'
      - '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
  ELECTRON_SKIP_BINARY_DOWNLOAD: 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@v6
    - 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_linux_chromium_tot:
    name: ${{ matrix.os }} (chromium tip-of-tree)
    environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-22.04]
    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@v6
    - uses: ./.github/actions/run-test
      with:
        browsers-to-install: chromium-tip-of-tree
        command: npm run test -- --project=chromium-*
        bot-name: "${{ matrix.os }}-chromium-tip-of-tree"
        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: chromium-tip-of-tree

  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: [20]
        shardIndex: [1, 2]
        shardTotal: [2]
        shardWeights: ['58:42']
        include:
          - os: windows-latest
            node-version: 20
            shardIndex: 1
            shardTotal: 3
            shardWeights: '44:33:23'
          - os: windows-latest
            node-version: 20
            shardIndex: 2
            shardTotal: 3
            shardWeights: '44:33:23'
          - os: windows-latest
            node-version: 20
            shardIndex: 3
            shardTotal: 3
            shardWeights: '44:33:23'
          - os: ubuntu-latest
            node-version: 22
            shardIndex: 1
            shardTotal: 2
            shardWeights: '58:42'
          - os: ubuntu-latest
            node-version: 22
            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'
    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@v6
    - 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_CHANNEL: firefox-beta
        PWTEST_SHARD_WEIGHTS: ${{ matrix.shardWeights }}

  test_vscode_extension:
    name: VSCode Extension
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v6
    - uses: actions/setup-node@v6
      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@v6
    - 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
        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 }}
tests_secondary matrix perms .github/workflows/tests_secondary.yml
Triggers
push, pull_request
Runs on
${{ matrix.os }}, ${{ matrix.os }}, windows-latest, ${{ matrix.os }}, ${{ matrix.os }}, ubuntu-22.04, ${{ matrix.runs-on }}, ${{ matrix.runs-on }}, ${{ matrix.os }}, ${{ matrix.os }}, ${{ matrix.os }}, ubuntu-24.04, ${{ matrix.runs-on }}
Jobs
test_linux, test_mac, test_win, test-package-installations-other-node-versions, headed_tests, transport_linux, tracing_linux, test_chromium_channels, chromium_tot, chromium_tot_headless_shell, firefox_beta, build-playwright-driver, test_channel_chromium
Matrix
browser, channel, exclude, exclude.headed, exclude.os, headed, include, include.browser, include.channel, include.node_version, include.os, include.runs-on, mode, os, runs-on→ , --headed, 20, 22, 24, chrome, chrome-beta, chromium, chromium-tip-of-tree, driver, firefox, macos-14-large, macos-14-xlarge, macos-15-large, macos-15-xlarge, macos-26-xlarge, macos-latest, msedge, msedge-beta, msedge-dev, service, ubuntu-22.04, ubuntu-24.04, ubuntu-latest, webkit, windows-latest
Commands
  • npm install -g yarn@1
  • npm install -g pnpm@8
  • if grep -q "Ubuntu 24" /etc/os-release; then sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 fi
  • npm ci
  • npm run build
  • utils/build/build-playwright-driver.sh
View raw YAML
name: "tests 2"

on:
  push:
    branches:
      - main
      - release-*
  pull_request:
    paths-ignore:
      - 'browser_patches/**'
      - 'docs/**'
      - 'packages/playwright-core/src/server/bidi/**'
      - 'tests/bidi/**'
    types: [ labeled ]
    branches:
      - main
      - release-*

env:
  # Force terminal colors. @see https://www.npmjs.com/package/colors
  FORCE_COLOR: 1
  ELECTRON_SKIP_BINARY_DOWNLOAD: 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_linux:
    name: ${{ matrix.os }} (${{ matrix.browser }})
    environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
    strategy:
      fail-fast: false
      matrix:
        browser: [chromium, firefox, webkit]
        os: [ubuntu-24.04]
    runs-on: ${{ matrix.os }}
    steps:
    - uses: actions/checkout@v6
    - 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_mac:
    name: ${{ matrix.os }} (${{ matrix.browser }})
    environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
    strategy:
      fail-fast: false
      matrix:
        # Intel: *-large
        # Arm64: *-xlarge
        os: [macos-14-large, macos-14-xlarge, macos-15-large, macos-15-xlarge]
        browser: [chromium, firefox, webkit]
        include:
          - os: macos-26-xlarge
            browser: webkit
    runs-on: ${{ matrix.os }}
    steps:
    - uses: actions/checkout@v6
    - 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"
    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@v6
    - 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 }})"
    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: 22
        - os: ubuntu-latest
          node_version: 24
    timeout-minutes: 30
    steps:
    - uses: actions/checkout@v6
    - 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 }}

  headed_tests:
    name: "headed ${{ matrix.browser }} (${{ matrix.os }})"
    environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
    strategy:
      fail-fast: false
      matrix:
        browser: [chromium, firefox, webkit]
        os: [ubuntu-24.04, macos-14-xlarge, windows-latest]
        include:
          # We have different binaries per Ubuntu version for WebKit.
          - browser: webkit
            os: ubuntu-22.04
    runs-on: ${{ matrix.os }}
    steps:
    - uses: actions/checkout@v6
    - uses: ./.github/actions/run-test
      with:
        browsers-to-install: ${{ matrix.browser }} chromium
        command: npm run test -- --project=${{ matrix.browser }}-* --headed
        bot-name: "${{ matrix.browser }}-headed-${{ 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 }}

  transport_linux:
    name: "Transport"
    environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
    strategy:
      fail-fast: false
      matrix:
        mode: [driver, service]
    runs-on: ubuntu-22.04
    steps:
    - uses: actions/checkout@v6
    - uses: ./.github/actions/run-test
      with:
        browsers-to-install: chromium
        command: npm run ctest
        bot-name: "${{ matrix.mode }}"
        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: ${{ matrix.mode }}

  tracing_linux:
    name: Tracing ${{ matrix.browser }} ${{ matrix.channel }}
    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
          - browser: chromium
            runs-on: ubuntu-22.04
            channel: chromium-tip-of-tree
    runs-on: ${{ matrix.runs-on }}
    steps:
    - uses: actions/checkout@v6
    - uses: ./.github/actions/run-test
      with:
        browsers-to-install: ${{ matrix.browser }} chromium ${{ matrix.channel }}
        command: npm run test -- --project=${{ matrix.browser }}-*
        bot-name: "tracing-${{ matrix.channel || 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
        PWTEST_CHANNEL: ${{ matrix.channel }}

  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:
        channel: [chrome, chrome-beta, msedge, msedge-beta, msedge-dev]
        runs-on: [ubuntu-22.04, macos-latest, windows-latest]
    steps:
    - uses: actions/checkout@v6
    - 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 }}

  chromium_tot:
    name: Chromium tip-of-tree ${{ matrix.os }}${{ matrix.headed }}
    environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
    runs-on: ${{ matrix.os  }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-22.04, macos-14-large, windows-latest]
        headed: ['--headed', '']
        exclude:
          # Tested in tests_primary.yml already
          - os: ubuntu-22.04
            headed: ''
    steps:
    - uses: actions/checkout@v6
    - uses: ./.github/actions/run-test
      with:
        browsers-to-install: chromium-tip-of-tree
        command: npm run ctest -- ${{ matrix.headed }}
        bot-name: "chromium-tip-of-tree-${{ matrix.os }}${{ matrix.headed }}"
        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: chromium-tip-of-tree

  chromium_tot_headless_shell:
    name: Chromium tip-of-tree headless-shell-${{ matrix.os }}
    environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
    runs-on: ${{ matrix.os  }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-22.04]
    steps:
    - uses: actions/checkout@v6
    - uses: ./.github/actions/run-test
      with:
        browsers-to-install: chromium-tip-of-tree-headless-shell
        command: npm run ctest
        bot-name: "chromium-tip-of-tree-headless-shell-${{ 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 }}
      env:
        PWTEST_CHANNEL: chromium-tip-of-tree-headless-shell

  firefox_beta:
    name: Firefox Beta ${{ matrix.os }}
    environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
    runs-on: ${{ matrix.os  }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-22.04, windows-latest, macos-latest]
    steps:
    - uses: actions/checkout@v6
    - uses: ./.github/actions/run-test
      with:
        browsers-to-install: firefox-beta chromium
        command: npm run ftest
        bot-name: "firefox-beta-${{ 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 }}
      env:
        PWTEST_CHANNEL: firefox-beta

  build-playwright-driver:
    name: "build-playwright-driver"
    runs-on: ubuntu-24.04
    steps:
    - uses: actions/checkout@v6
    - uses: actions/setup-node@v6
      with:
        node-version: 20
    - run: npm ci
    - run: npm run build
    - run: utils/build/build-playwright-driver.sh

  test_channel_chromium:
    name: Test channel=chromium
    environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
    strategy:
      fail-fast: false
      matrix:
        runs-on: [ubuntu-latest, windows-latest, macos-latest]
    runs-on: ${{ matrix.runs-on }}
    steps:
    - uses: actions/checkout@v6
    - uses: ./.github/actions/run-test
      with:
        # TODO: this should pass --no-shell.
        # However, codegen tests do not inherit the channel and try to launch headless shell.
        browsers-to-install: chromium
        command: npm run ctest
        bot-name: "channel-chromium-${{ 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: chromium
tests_video matrix .github/workflows/tests_video.yml
Triggers
push
Runs on
${{ matrix.os }}
Jobs
video_linux
Matrix
browser, os→ chromium, firefox, ubuntu-22.04, ubuntu-24.04, webkit
View raw YAML
name: "tests Video"

on:
  push:
    branches:
      - main
      - release-*

env:
  # Force terminal colors. @see https://www.npmjs.com/package/colors
  FORCE_COLOR: 1
  ELECTRON_SKIP_BINARY_DOWNLOAD: 1

jobs:
  video_linux:
    name: "Video Linux"
    environment: allow-uploading-flakiness-results
    strategy:
      fail-fast: false
      matrix:
        browser: [chromium, firefox, webkit]
        os: [ubuntu-22.04, 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
    runs-on: ${{ matrix.os }}
    steps:
    - uses: actions/checkout@v6
    - 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 }}
      env:
        PWTEST_VIDEO: 1
trigger_tests .github/workflows/trigger_tests.yml
Triggers
push
Runs on
ubuntu-24.04
Jobs
trigger
Actions
actions/create-github-app-token
Commands
  • curl -X POST \ -H "Accept: application/vnd.github.v3+json" \ -H "Authorization: token ${GH_TOKEN}" \ --data "{\"event_type\": \"playwright_tests\", \"client_payload\": {\"ref\": \"${GITHUB_SHA}\"}}" \ https://api.github.com/repos/microsoft/playwright-browsers/dispatches
View raw YAML
name: "Internal Tests"

on:
  push:
    branches:
      - main
      - release-*

jobs:
  trigger:
    name: "trigger"
    runs-on: ubuntu-24.04
    steps:
    - uses: actions/create-github-app-token@v2
      id: app-token
      with:
        app-id: ${{ vars.PLAYWRIGHT_APP_ID }}
        private-key: ${{ secrets.PLAYWRIGHT_PRIVATE_KEY }}
        repositories: playwright-browsers
    - run: |
        curl -X POST \
          -H "Accept: application/vnd.github.v3+json" \
          -H "Authorization: token ${GH_TOKEN}" \
          --data "{\"event_type\": \"playwright_tests\", \"client_payload\": {\"ref\": \"${GITHUB_SHA}\"}}" \
          https://api.github.com/repos/microsoft/playwright-browsers/dispatches
      env:
        GH_TOKEN: ${{ steps.app-token.outputs.token }}