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.
📖 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
| Reporter | Output | Best for |
|---|---|---|
list | One line per test with status and time | Local runs (default when no reporter is set) |
line | A single updating line, failures printed in full | Large suites in a terminal |
dot | One character per test | CI logs (default on CI when no reporter is set) |
html | Interactive web report in playwright-report/ | Humans: debugging, sharing results |
json | Full results as JSON | Dashboards, custom tooling |
junit | JUnit XML | Jenkins, Azure DevOps, GitLab test tabs |
github | Annotations on the failing lines in GitHub | GitHub Actions |
blob | Raw results for merging | Sharded 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.stepgroups, 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:
listplushtmlthat opens on failure. - In CI: a compact terminal reporter (
dotorline),htmluploaded as an artifact,junitfor the CI test tab, andgithubannotations on GitHub. - Keep reports out of Git (
playwright-report/andtest-results/are already in the default.gitignore). - Use tags, annotations and
test.stepso reports explain themselves. - Attach screenshots, videos and traces only for failures to keep reports small.
📝 Assignment
- Run your suite with
--reporter=list,--reporter=lineand--reporter=dotand compare the output. - Configure
list,html(open: 'on-failure') andjunittogether, run the suite, and find all three outputs. - Add a tag, an
issueannotation, twotest.stepblocks and a JSON attachment to one test, then view it in the HTML report. - Add the JSON reporter and read the number of passed tests from the file with a small Node script.
- Write the
SummaryReporterabove, register it, and print the three slowest tests. - Bonus: run the suite as two shards with
--reporter=bloband 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
- 🎭 Allure Report Integration
- 🎭 Parallel Execution, Workers and Sharding
- 🎭 Trace Viewer Step by Step
- 🎭 Playwright Tutorial with TypeScript
🎬 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”