Skip to main content

Merging Shard Reports

When running Playwright tests in parallel using sharding, each shard generates its own TestRelic report. You can merge these reports into a single comprehensive report.

Why Merge Reports?

Sharding is a powerful feature in Playwright that distributes tests across multiple workers or machines for faster execution:

# Run tests across 4 shards
npx playwright test --shard=1/4 # Machine 1
npx playwright test --shard=2/4 # Machine 2
npx playwright test --shard=3/4 # Machine 3
npx playwright test --shard=4/4 # Machine 4

Each shard produces its own analytics report. Merging them gives you:

  • A complete view of all tests across all shards
  • Unified timeline showing all navigations
  • Aggregated summary statistics
  • Single file for analysis and visualization

CLI Method

Use the TestRelic CLI to merge reports:

npx testrelic merge shard-1.json shard-2.json shard-3.json -o merged-report.json

CLI Options

npx testrelic merge <input-files...> [options]

Options:
-o, --output <path> Output file path (required)
-h, --help Display help

Example

npx testrelic merge \
./test-results/shard-1/analytics.json \
./test-results/shard-2/analytics.json \
./test-results/shard-3/analytics.json \
-o ./test-results/merged-analytics.json

Programmatic Method

Merge reports from Node.js code:

import { mergeReports } from '@testrelic/playwright-analytics/merge';

await mergeReports(
[
'./test-results/shard-1/analytics.json',
'./test-results/shard-2/analytics.json',
'./test-results/shard-3/analytics.json',
],
{
output: './test-results/merged-analytics.json'
}
);

API

async function mergeReports(
inputPaths: string[],
options: { output: string }
): Promise<void>

Parameters:

  • inputPaths — Array of file paths to shard reports
  • options.output — Output path for merged report

Returns: Promise that resolves when merge is complete

Throws: Error if any input file is invalid or merge fails

Merged Report Structure

The merged report combines data from all shards:

{
"schemaVersion": "1.0.0",
"testRunId": "original-run-id",
"startedAt": "2026-02-07T10:00:00.000Z", // Earliest start time
"completedAt": "2026-02-07T10:15:00.000Z", // Latest completion time
"totalDuration": 900000, // Sum of all shard durations
"summary": {
"total": 100, // Sum of all tests
"passed": 95,
"failed": 3,
"flaky": 2,
"skipped": 0
},
"ci": { /* Same CI metadata */ },
"timeline": [
/* Combined timeline from all shards, sorted by visitedAt */
]
}

Merge Behavior

  • Timeline — All navigation entries are combined and sorted chronologically by visitedAt
  • Summary — Test counts are aggregated across shards
  • Duration — Total duration is the sum of all shard durations
  • TimestampsstartedAt is the earliest, completedAt is the latest
  • Test Run ID — Preserved from the first shard (all shards should have the same ID)
  • CI Metadata — Taken from the first shard

CI/CD Integration

GitHub Actions

name: Test with Sharding

on: [push]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
shard: [1, 2, 3, 4]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
- run: npx playwright install
- run: npx playwright test --shard=${{ matrix.shard }}/4
- uses: actions/upload-artifact@v3
with:
name: shard-${{ matrix.shard }}-report
path: test-results/analytics-timeline.json

merge:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
path: artifacts
- run: |
npx testrelic merge \
artifacts/shard-1-report/analytics-timeline.json \
artifacts/shard-2-report/analytics-timeline.json \
artifacts/shard-3-report/analytics-timeline.json \
artifacts/shard-4-report/analytics-timeline.json \
-o merged-analytics.json
- uses: actions/upload-artifact@v3
with:
name: merged-report
path: merged-analytics.json

Validation

After merging, TestRelic validates the merged report to ensure:

  • Schema version compatibility
  • Timeline chronological order
  • Summary statistics correctness
  • No duplicate test entries

If validation fails, the merge operation will throw an error with details.

Was this doc helpful?