Playwright Reporters and the HTML Report: Complete Guide

Test results are only useful if people can read them. In this lesson you will configure Playwright’s built-in reporters, get the most from the HTML report, produce JUnit and JSON for CI tools, merge sharded reports and write your own reporter.

Advertisement

📖 What You’ll Learn: what reporters do, every built-in reporter, configuring several reporters, local vs CI setups, the HTML report features, tags, annotations and attachments, merging blob reports from shards, third-party reporters, and writing a custom reporter.


📊 What Is a Reporter?

A reporter decides how Playwright presents test results: lines in the terminal, an interactive HTML page, a JUnit XML file for Jenkins, or a JSON file for your own dashboard. You can use several reporters at once, for example readable terminal output plus an HTML report plus JUnit XML for CI.


🧰 Built-in Reporters

ReporterOutputBest for
listOne line per test with status and timeLocal runs (default when no reporter is set)
lineA single updating line, failures printed in fullLarge suites in a terminal
dotOne character per testCI logs (default on CI when no reporter is set)
htmlInteractive web report in playwright-report/Humans: debugging, sharing results
jsonFull results as JSONDashboards, custom tooling
junitJUnit XMLJenkins, Azure DevOps, GitLab test tabs
githubAnnotations on the failing lines in GitHubGitHub Actions
blobRaw results for mergingSharded runs across machines

Choose one on the command line:

npx playwright test --reporter=list
npx playwright test --reporter=dot
npx playwright test --reporter=line,html

⚙️ Configure Reporters in playwright.config.ts

import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: [
    ['list'],                                                    // terminal
    ['html', { outputFolder: 'playwright-report', open: 'never' }], // HTML report
    ['junit', { outputFile: 'results/junit.xml' }],              // for CI test tabs
    ['json', { outputFile: 'results/results.json' }],            // for dashboards
  ],
});

A common pattern is different reporters locally and in CI:

reporter: process.env.CI
  ? [['dot'], ['github'], ['html', { open: 'never' }], ['junit', { outputFile: 'results/junit.xml' }]]
  : [['list'], ['html', { open: 'on-failure' }]],

The HTML open option accepts 'always', 'never' or 'on-failure' (the default opens the report automatically only when tests fail locally).


🌐 The HTML Report in Depth

npx playwright show-report                       # open the last report
npx playwright show-report my-report-folder      # open a report from another folder
npx playwright show-report --port 9323           # choose the port

What you get:

  • Summary of passed, failed, flaky and skipped tests, with filters and search.
  • Results grouped by file and project (browser).
  • Tags and annotations shown on each test (tags, annotations).
  • Every step, including test.step groups, hooks and fixtures, with durations.
  • Errors with code snippets, screenshots, videos and traces (screenshots and videos, Trace Viewer).
  • Attachments you added with testInfo.attach().

The report is a static website. You can zip it, upload it as a CI artifact, or publish it to any static hosting so the whole team can open it in a browser.

Add useful information to the report

test('checkout', {
  tag: '@smoke',
  annotation: { type: 'issue', description: 'https://jira.example.com/browse/QA-42' },
}, async ({ page }, testInfo) => {
  await test.step('open the cart', async () => {
    // ...
  });
  await testInfo.attach('order-details', { body: JSON.stringify({ orderId: 123 }), contentType: 'application/json' });
});

🧩 Merge Reports from Sharded Runs

When you split a suite across several CI machines with --shard, each machine produces a blob report. Merge them into one HTML report:

# on each machine
npx playwright test --shard=1/3 --reporter=blob
# after all shards finish, with all blob-report folders copied into one folder
npx playwright merge-reports --reporter html ./all-blob-reports

The full CI setup is in parallel execution and sharding and GitHub Actions.


🧑‍🔧 Third-Party Reporters

The community offers many reporters. The most popular in QA teams is Allure, with history, trends and categories; see Allure report integration. Others integrate with test management tools and dashboards. Install them from npm and add them to the reporter array like built-in ones.


✍️ Write Your Own Reporter

A custom reporter is a class with optional hooks. This one prints a short summary and the slowest tests:

// reporters/summary-reporter.ts
import type { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult } from '@playwright/test/reporter';

class SummaryReporter implements Reporter {
  private durations: { title: string; ms: number }[] = [];

  onBegin(config: FullConfig, suite: Suite) {
    console.log('Starting ' + suite.allTests().length + ' tests');
  }

  onTestEnd(test: TestCase, result: TestResult) {
    this.durations.push({ title: test.title, ms: result.duration });
    if (result.status === 'failed') console.log('FAILED: ' + test.title);
  }

  onEnd(result: FullResult) {
    const slowest = [...this.durations].sort((a, b) => b.ms - a.ms).slice(0, 3);
    console.log('Finished with status: ' + result.status);
    slowest.forEach(t => console.log('  slow: ' + t.title + ' (' + t.ms + ' ms)'));
  }
}

export default SummaryReporter;
// playwright.config.ts
reporter: [['list'], ['./reporters/summary-reporter.ts']],

Custom reporters are useful for sending results to Slack or Teams, updating a test management tool, or enforcing rules such as “fail the build if any test took longer than 60 seconds”.


✅ Reporting Best Practices

  • Locally: list plus html that opens on failure.
  • In CI: a compact terminal reporter (dot or line), html uploaded as an artifact, junit for the CI test tab, and github annotations on GitHub.
  • Keep reports out of Git (playwright-report/ and test-results/ are already in the default .gitignore).
  • Use tags, annotations and test.step so reports explain themselves.
  • Attach screenshots, videos and traces only for failures to keep reports small.

📝 Assignment

  1. Run your suite with --reporter=list, --reporter=line and --reporter=dot and compare the output.
  2. Configure list, html (open: 'on-failure') and junit together, run the suite, and find all three outputs.
  3. Add a tag, an issue annotation, two test.step blocks and a JSON attachment to one test, then view it in the HTML report.
  4. Add the JSON reporter and read the number of passed tests from the file with a small Node script.
  5. Write the SummaryReporter above, register it, and print the three slowest tests.
  6. Bonus: run the suite as two shards with --reporter=blob and merge them into one HTML report.

❓ FAQ

🤔 How do I generate an HTML report in Playwright?

Add reporter: 'html' (or ['html', { open: 'never' }]) in the config and run the tests. Open it with npx playwright show-report.

🤔 How do I use multiple reporters in Playwright?

Pass an array: reporter: [['list'], ['html'], ['junit', { outputFile: 'results.xml' }]].

🤔 How do I get JUnit XML results for Jenkins?

Add ['junit', { outputFile: 'results/junit.xml' }] to the reporters and point Jenkins’ JUnit plugin at that file. See Playwright with Jenkins.

🤔 How do I merge Playwright reports from shards?

Run each shard with --reporter=blob, collect the blob-report folders, then run npx playwright merge-reports --reporter html <folder>.

🤔 Can I create a custom reporter in Playwright?

Yes. Implement the Reporter interface from @playwright/test/reporter (onBegin, onTestEnd, onEnd and more) and add the file path to the reporter array.


🎯 Next Steps

🎬 Watch the full Playwright tutorial series on YouTube!

Subscribe to SqaToolsByDY • Practice on sqatools.in

2 thoughts on “Playwright Reporters and the HTML Report: Complete Guide”

Leave a Comment