Skip to main content

Advanced

Shard merging

Run Playwright shards in parallel, collect their JSON output, and merge everything into a single PDF in a final job, without re-running any tests.

How it works

  1. Each shard runs with --reporter=json and writes a JSON results file.
  2. The JSON files are uploaded as CI artifacts.
  3. A merge job downloads all shard artifacts and points the shardResults reporter option at them (a glob or an explicit path array).
  4. The reporter reads those files instead of live test events, merges them in-memory, and renders a single PDF.

The merge job only runs the PDF renderer; it does not execute any tests. Chrome is launched once.

Reporter config for the merge job

In the merge job, run the reporter in merge mode by pointing the shardResults option at the collected JSON files. It accepts a glob or an explicit array; wiring it to an env var keeps one config serving both the shard jobs and the merge job.

ts
// playwright.config.tsreporter: [['@reportforge/playwright-pdf', {  // set only in the merge job, e.g. SHARD_RESULTS_GLOB=results/shard-*.json  shardResults: process.env.SHARD_RESULTS_GLOB,  // or explicit: shardResults: ['results/shard-1.json', 'results/shard-2.json'],  outputFile: 'reports/{date}-{branch}-{status}.pdf',  template: 'detailed',}]]

When shardResults is set, the reporter reads those JSON files instead of collecting live test events; live results are ignored. The merge job can run against a dummy spec with a single skipped test, since it only renders the PDF.

GitHub Actions: full workflow

# .github/workflows/test.ymljobs:  test:    strategy:      matrix:        shard: [1, 2, 3, 4]    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4      - uses: actions/setup-node@v4        with: { node-version: 22 }      - run: npm ci      - run: npx playwright test --shard=${{ matrix.shard }}/4 --reporter=json        env:          PLAYWRIGHT_JSON_OUTPUT_NAME: results/shard-${{ matrix.shard }}.json      - uses: actions/upload-artifact@v4        if: always()        with:          name: shard-${{ matrix.shard }}          path: results/shard-${{ matrix.shard }}.json  merge-report:    needs: test    if: always()    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4      - uses: actions/setup-node@v4        with: { node-version: 22 }      - run: npm ci      - name: Install Chrome        run: |          wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | \            sudo gpg --dearmor -o /usr/share/keyrings/google-chrome.gpg          echo "deb [arch=amd64 signed-by=/usr/share/keyrings/google-chrome.gpg] \            http://dl.google.com/linux/chrome/deb/ stable main" | \            sudo tee /etc/apt/sources.list.d/google-chrome.list          sudo apt-get update -qq && sudo apt-get install -y google-chrome-stable      - uses: actions/download-artifact@v4        with:          pattern: shard-*          merge-multiple: true          path: results      - run: npx playwright test --reporter=@reportforge/playwright-pdf tests/dummy.spec.ts        env:          PUPPETEER_EXECUTABLE_PATH: /usr/bin/google-chrome-stable          RF_LICENSE_KEY: ${{ secrets.RF_LICENSE_KEY }}          SHARD_RESULTS_GLOB: results/shard-*.json      - uses: actions/upload-artifact@v4        if: always()        with:          name: playwright-pdf-report          path: reports/*.pdf

Known limitation

History trending (historyFile) is not supported in merge mode. The history JSON is written after a merge run but the trend chart will only show the merged run as a single data point, not per-shard history. Run history tracking on your staging or nightly full (non-sharded) run instead.

Timed-out tests keep their own count in merged reports, so the KPI cards and charts match what a single-run report shows. When the JSON report carries config.workers or config.metadata.playwrightVersion, the environment panel reflects them; both are optional and older files merge unchanged.