IKivan-kozenko -aqa
Try yourself as a QA tester
All topics·Intermediate·9 / 27

Reporters

My CI config always uses two reporters simultaneously: 'dot' for terminal output (quiet, one char per test) and 'blob' when sharding for later merging. Locally I use 'html' so failures open automatically in the browser with traces attached. The 'github' reporter adds inline annotations to PR diffs — worth adding if the team reviews failures directly in GitHub.

Which reporter to use and when

Reporters can be combined; use blob on sharded CI runs and merge-reports to produce one HTML report from all shards

The default is list locally and dot on CI. I usually override CI to use dot explicitly to avoid the verbose list output. You can combine reporters — the config takes an array, so I get terminal output AND a file simultaneously.

ts
// playwright.config.ts — два репортери одночасно
export default defineConfig({
  reporter: [
    ['list'],
    ['json', { outputFile: 'test-results.json' }],
  ],
})
ts
// playwright.config.ts — різні репортери для CI і локально
export default defineConfig({
  reporter: process.env.CI ? 'dot' : 'list',
})

Terminal reporters — list, line, dot

list — one line per test, shows time. Good for local runs with <100 tests. line — one line for the last running test, updates in place. Good for large suites where you just want to see progress. dot — one character per test. · = pass, F = fail, × = fail+retry pending, ± = flaky (passed after retry). I use dot on CI to keep logs readable.

bash
npx playwright test --reporter=dot
Running 124 tests using 6 workers
······F·············±···T···········

HTML reporter — the one I use for debugging

The HTML report is a self-contained web page with all test results, traces, screenshots, and videos. By default it opens automatically when tests fail. I set open: 'never' on CI (no browser to open) and open: 'on-failure' locally.

To view the last report: npx playwright show-report. To view a downloaded CI artifact zip: npx playwright show-report playwright-report.zip.

ts
// playwright.config.ts
export default defineConfig({
  reporter: [
    ['html', {
      open: process.env.CI ? 'never' : 'on-failure',
      outputFolder: 'playwright-report',
    }],
  ],
})
bash
# Відкрити останній звіт
npx playwright show-report

# Відкрити конкретну теку
npx playwright show-report my-report

# Відкрити zip з CI артефакту
npx playwright show-report playwright-report.zip

Blob reporter — for sharded CI runs

The blob reporter saves raw test data (results, traces, screenshots) to a zip file. Its entire purpose is sharding: each shard produces a blob, you download all blobs, then merge them into one HTML report. Without blob you'd have 4 separate HTML reports with no way to combine them.

ts
// playwright.config.ts — blob для CI (шардованих запусків)
export default defineConfig({
  reporter: process.env.CI ? 'blob' : 'html',
})
bash
# Після скачування всіх blob-артефактів в ./all-blob-reports
npx playwright merge-reports --reporter html ./all-blob-reports

CI integrations — GitHub annotations, JUnit for Azure

The github reporter adds failure annotations directly to the PR diff — clicking on a failure in the GitHub Actions summary takes you to the failing line of code. I combine it with dot so I get both annotation and terminal output.

JUnit reporter produces XML output that Azure DevOps, Jenkins, and similar tools can import into their test dashboards. I use it when the team wants to see trend data in their CI tool rather than opening the Playwright HTML report.

ts
// playwright.config.ts — GitHub-анотації + термінальний вивід
export default defineConfig({
  reporter: process.env.CI
    ? [['github'], ['dot']]
    : 'list',
})
ts
// playwright.config.ts — JUnit для Azure DevOps / Jenkins
export default defineConfig({
  reporter: [
    ['junit', { outputFile: 'test-results/e2e-junit-results.xml' }],
    ['dot'],
  ],
})

Custom reporters

When built-in reporters aren't enough — for example when I need to post test results to Slack or write to a custom database — I implement the Reporter interface. The key methods are onTestEnd (called after every test) and onEnd (called when the run finishes).

ts
// my-reporter.ts
import type { Reporter, TestCase, TestResult, FullResult } from '@playwright/test/reporter'

class MyReporter implements Reporter {
  onTestEnd(test: TestCase, result: TestResult) {
    if (result.status === 'failed') {
      console.log(`FAIL: ${test.title} — ${result.error?.message}`)
    }
  }

  onEnd(result: FullResult) {
    console.log(`Run finished: ${result.status}`)
  }
}

export default MyReporter
ts
// playwright.config.ts
export default defineConfig({
  reporter: ['./my-reporter.ts'],
})