# How to send Playwright test results to a test management tool

Export JUnit XML and import it after the tests, or register a reporter in playwright.config. JUnit XML works with almost any tool; a dedicated reporter also keeps every retry, nested steps, screenshots and traces.

- Canonical URL: https://probara.net/blog/send-playwright-results-to-test-management/
- Published: 2026-11-09T15:00:56.000Z
- Updated: 2026-11-09T15:01:15.144Z
- Author: Probara
- Category: Test management

You can send Playwright results to a test management tool in two ways: have Playwright write a JUnit XML file and import it in a later CI step, or register a reporter in `playwright.config` that sends the results while the tests run. JUnit XML works with almost any tool, but it carries no steps and usually one outcome per test. A dedicated reporter keeps every retry attempt, the nested `test.step` tree, and the screenshots, videos and traces Playwright produced.

## What are the two ways to report Playwright results?

Every integration between Playwright and a test management tool is either a file you upload after the run or a reporter that runs inside it. The difference decides what reaches the tool and how much setup you own.


|                             | JUnit XML and an import step                  | A dedicated reporter                                |
| --------------------------- | --------------------------------------------- | --------------------------------------------------- |
| Where it runs               | A CI step after `npx playwright test`         | Inside Playwright's main process                    |
| What Playwright needs       | The built-in `junit` reporter                 | A reporter package listed in `playwright.config`    |
| Steps (`test.step`)         | None: the format has no steps                 | Nested, with status, duration and error             |
| Retried tests               | One result per test, with its final outcome   | Every attempt as its own result                     |
| Screenshots, videos, traces | Only files the import step can find           | Sent with the result they belong to                 |
| Works with other tools      | Almost any CI or test tool reads JUnit XML    | Only the tool the reporter was written for          |
| Extra failure point         | The import step must run even when tests fail | None: the reporter runs as part of the test command |


The rows for steps and retries follow how Probara records each route ([Probara docs: CI integrations](https://docs.probara.net/en/developers/ci-integrations/)); check your own tool's import documentation for the same two rows. Playwright lets you list several reporters at once, so either choice keeps the terminal output and the HTML report ([Playwright: Reporters](https://playwright.dev/docs/test-reporters)).

## Option 1: export JUnit XML and import it after the tests

JUnit XML is the portable route: Playwright writes the file, and a separate CI step uploads it. Playwright's built-in `junit` reporter writes the file named in its `outputFile` option, or the name in the `PLAYWRIGHT_JUNIT_OUTPUT_NAME` environment variable ([Playwright: Reporters](https://playwright.dev/docs/test-reporters)):

```ts
// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: [['list'], ['junit', { outputFile: 'reports/junit.xml' }]],
});
```

The import step then posts that file to your tool, and it must run when tests fail. A failing test fails the test step, so in GitHub Actions the import step needs `if: always()`; without it, a red build is exactly the one that never gets reported ([Probara docs: CLI](https://docs.probara.net/en/developers/cli/)).

```yaml
- name: Report to Probara
  if: always()
  run: npx @probara/cli import junit reports/junit.xml
  env:
    PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
    PROBARA_PROJECT: SHOP
```

What you give up is structure. JUnit XML has a suite, a test case and a failure message; it has no steps ([Probara docs: CI integrations](https://docs.probara.net/en/developers/ci-integrations/)). BrowserStack's Test Management import of Playwright JUnit XML, for example, takes the file, a project name and a run name, and its sample report contains only suites, test cases and failures ([BrowserStack docs](https://www.browserstack.com/docs/test-management/upload-reports-cli/frameworks/playwright)). Some JUnit options also change the file: `includeProjectInTestName` prefixes each test name with the Playwright project, which changes how a tool that matches by name sees the test.

## Option 2: register a reporter that sends results during the run

A dedicated reporter is a package you add to the `reporter` array of `playwright.config`; it receives the run through Playwright's reporter API and sends it to the tool. That API exposes far more than JUnit XML: each `TestStep` has a title, a duration in milliseconds, the error it threw, and its child steps ([Playwright: TestStep](https://playwright.dev/docs/api/class-teststep)).

```ts
// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: [['list'], ['@probara/playwright-reporter', { projectId: 'SHOP' }]],
});
```

The result in the tool can then show where a test failed, not only that it failed: the nested step that timed out, its error, and the screenshot taken in it.

![A failed Playwright result in Probara with its nested automation steps, the step that timed out and its TimeoutError](https://app.probara.net/__assets/blog/01M70D6TQMASMBNE1SKDGAP6DJ.webp)

The trade-offs are lock-in and versions. A reporter is written for one tool, so switching tools means switching packages, and it has its own minimum versions of Node.js and `@playwright/test`. Pin it in `package.json` so an update never changes a pipeline by surprise.

## How does each Playwright test find its test case?

A test reaches the right test case either because it names the case or because the tool recognises it by a key built from the test itself. Pick one rule for the whole suite before the first upload, because it decides whether history accumulates on one case or scatters across duplicates.

- **Name the case.** Put the case id in the test, as an annotation or in the title. Playwright annotations have a `type` and a `description` and are available to the reporter API, so they work with any reporter ([Playwright: Annotations](https://playwright.dev/docs/test-annotations)):
  ```ts
  test('pays with a card', {
    annotation: { type: 'probara_case', description: 'SHOP-12' },
  }, async ({ page }) => {
    // ...
  });
  ```
- **Let a key match it.** Tools that match by key build it from the file and the title path, for example `checkout.spec.ts > checkout > pays with a card` ([Probara docs: linking tests to cases](https://docs.probara.net/en/developers/ci-integrations/playwright/linking/)).

Use ids when the cases already exist, written by hand or imported. Use keys when the automated tests are the source of truth and you want the tool to create a case for each new test. With keys, renaming a test, a `describe` block or a file creates a new case, because the key changes; with an id, renames are free.

## How do retries and sharding change what gets reported?

Retries and sharding are the two settings that most often make a test management tool disagree with Playwright. They need a decision, not a default.

**Retries.** Playwright does not retry by default. With `retries` set, it labels a test *flaky* when it failed on the first run and passed on a retry, and *failed* when it failed every attempt ([Playwright: Retries](https://playwright.dev/docs/test-retries)). If the tool only receives the final outcome, a flaky test looks like a clean pass and the evidence is gone. Send every attempt when you can; our guide on [how to find flaky tests](https://probara.net/blog/how-to-find-flaky-tests/) shows what to do with that history.

**Sharding.** `npx playwright test --shard=1/4` runs a quarter of the suite per machine, and by default each shard would report as its own run. Playwright's answer is the `blob` reporter: each shard writes a blob report, and `npx playwright merge-reports` combines them into one report afterwards ([Playwright: Sharding](https://playwright.dev/docs/test-sharding)). You can merge straight into your tool's reporter:

```bash
npx playwright merge-reports --reporter @probara/playwright-reporter ./all-blob-reports
```

The alternative is to create one run first and have every shard report into it, which shows results while shards are still running but needs a final job that closes the run even when shards fail.

## Which one should you choose?

Choose by what you need to see when a test fails, not by which setup is shorter.

1. **Use JUnit XML** when you run several frameworks (pytest, Maven Surefire, Jest) and want one import step for all of them, or when your tool has no Playwright reporter.
2. **Use a dedicated reporter** when Playwright is your main framework and the people triaging failures need the step that broke, the trace and every retry.
3. **Switch from JUnit to a reporter without losing history** only if the reporter builds the same case keys as the JUnit import. Check this with a dry run before the switch; otherwise every test becomes a new case.
4. **Keep Playwright's HTML report** either way. A test management tool holds history across runs; the HTML report is still the fastest way to open one trace.

## Where Probara fits

Probara supports both routes. The [Probara CLI](https://docs.probara.net/en/developers/cli/) imports JUnit XML from any framework with `npx @probara/cli import junit reports/junit.xml`, and [@probara/playwright-reporter](https://docs.probara.net/en/developers/ci-integrations/playwright/) sends each attempt as its own result, with nested steps, screenshots, videos and traces. Both create an automated run named after the CI build, link tests by case id or automation key, create the cases that do not exist yet, and close the run. The reporter builds the same keys as a JUnit import of Playwright's report, so a project can move from one to the other and keep every case ([migrating](https://docs.probara.net/en/developers/ci-integrations/playwright/migrating/)). For sharded pipelines, the [sharding guide](https://docs.probara.net/en/developers/ci-integrations/playwright/sharding/) covers both merging blob reports and sharing one run. Reporting from CI requires a Pro or Enterprise plan, or a trial.

## FAQ

### Can I use the HTML reporter and a test management reporter at the same time?

Yes. Playwright's `reporter` option takes an array, and every reporter in it receives the same run, so you can keep `list`, `html` and a test management reporter together.

### Does Playwright's JUnit XML include retries?

With the `onlyFailures` option, Playwright keeps every attempt of the tests it includes, flaky ones among them, but the file is then limited to unexpected outcomes, flaky and interrupted tests ([Playwright: Reporters](https://playwright.dev/docs/test-reporters)). When Probara imports JUnit XML, it records one result per test and summarizes earlier attempts in the notes when the report keeps them.

### Will a local `npx playwright test` send results to the tool?

That depends on the reporter, so check its documentation. Probara's reporter reads the token from the environment and stays off when no token and project are set, so local runs, and pull requests from forks that get no secrets, send nothing.

### What happens to results when I rename a test?

If the test is linked by case id, the result still lands on the same case. If it is matched by an automation key, the new name builds a new key and the tool creates a new case, so add the case id before renaming.
