level 07 / reporting-and-artifacts

Reporting & Artifact Management

Configure Playwright reporters and manage test artifacts in CI pipelines.

Built-In Reporters

// playwright.config.ts
export default defineConfig({
  reporter: [
    ['html', { outputFolder: 'playwright-report', open: 'on-failure' }],
    ['junit', { outputFile: 'test-results/results.xml' }],
    ['json', { outputFile: 'test-results/results.json' }],
    ['line'],    // compact console output
    ['dot'],     // minimal dots per test
  ],
});

Mix reporters: reporter: [['html'], ['junit']]

HTML Reporter

The HTML reporter produces a self-contained index.html with:

  • Pass/fail counts per file and test
  • Error messages with stack traces
  • Screenshots on failure (if configured)
  • Video recordings (if configured)
  • Traces (if configured — opens in Trace Viewer)
# View report locally
npx playwright show-report playwright-report/

# Generate for specific test run
npx playwright test --reporter=html

Trace Viewer

Traces capture the full test execution — DOM snapshots, network calls, console logs, screenshots at each action:

// playwright.config.ts
use: {
  trace: 'on-first-retry',      // capture on first retry
  // 'on'                       // always capture
  // 'off'                      // never capture
  // 'retain-on-failure'        // keep only on failure
}
# Open a trace file
npx playwright show-trace test-results/auth-login/trace.zip

Allure Reporter

Rich third-party reporter with history, trends, and categories:

npm install --save-dev allure-playwright
reporter: [['allure-playwright', {
  detail: true,
  outputFolder: 'allure-results',
  suiteTitle: false,
}]],
# Generate and open Allure report
npx allure generate allure-results --clean
npx allure open

CI Artifact Management

GitHub Actions

- uses: actions/upload-artifact@v4
  if: always()
  with:
    name: playwright-report-${{ github.run_id }}
    path: |
      playwright-report/
      test-results/**/*.zip       # traces
    retention-days: 30

Artifact Naming Strategy

playwright-report-<run-id>/        # unique per run — no collisions
test-results-shard-1/              # per shard on matrix runs
allure-report-<branch>-<sha>/      # branch + commit for traceability

Custom Reporter

// reporters/slack-reporter.ts
import { Reporter, TestCase, TestResult } from '@playwright/test/reporter';

class SlackReporter implements Reporter {
  private failed: string[] = [];

  onTestEnd(test: TestCase, result: TestResult) {
    if (result.status === 'failed') {
      this.failed.push(test.title);
    }
  }

  async onEnd() {
    if (this.failed.length > 0) {
      await fetch(process.env.SLACK_WEBHOOK!, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          text: `❌ ${this.failed.length} test(s) failed:\n${this.failed.join('\n')}`,
        }),
      });
    }
  }
}

export default SlackReporter;
// playwright.config.ts
reporter: [['html'], ['./reporters/slack-reporter.ts']],

Reporter Selection by Environment

reporter: process.env.CI
  ? [
      ['blob'],                          // for shard merging
      ['github'],                        // PR annotations
      ['junit', { outputFile: 'results.xml' }],
    ]
  : [
      ['html', { open: 'on-failure' }],  // opens browser on failure
      ['line'],                          // compact console
    ],