Help Center/Automation & CI/CD/Your test framework

Playwright Test Reports: HTML, JUnit XML, and Uploading to TestCollab

Create Playwright HTML and JUnit reports, map tests to TestCollab cases, and upload results with screenshots, videos, and traces.

On this page

Playwright can create a readable HTML report for debugging and JUnit XML for CI tools. Generate both in the same run, put a TestCollab case ID such as [TC-42] in each test title, and upload the JUnit file with @testcollab/cli.

For CLI installation, authentication, and test-plan options, see TestCollab CLI: Install and First Run.

Choose a Playwright reporter

Playwright includes several reporters. You can configure more than one, so a single test run serves both people and automation.

Reporter Best use Persistent file?
list Readable, detailed progress in a local terminal or shorter CI run No
line Compact progress that rewrites one terminal line No
html Interactive inspection of failures, steps, screenshots, and traces for one run Yes
junit Machine-readable results for CI systems and TestCollab Yes, when an output file is configured

What the HTML report does not provide

The Playwright HTML report is excellent for diagnosing one run. In CI, it remains in the job workspace unless you publish it as an artifact. Even when retained, it is still a run-specific report rather than a shared test-management record.

Uploading JUnit results to TestCollab adds team-wide execution history, build and release traceability, and one plan where manual and automated cases can be reviewed together. Keep the HTML report for debugging and use TestCollab for the durable testing record.

Prerequisites

  • A project that runs tests with @playwright/test.
  • A TestCollab project and a test plan containing the automated cases.
  • A TestCollab API token available as TESTCOLLAB_TOKEN.
  • Each result-producing Playwright test named with its TestCollab case ID.

Configure HTML and JUnit reporters

Configure the reporters in playwright.config.ts. The example also retains evidence for failures so Playwright can name it in the JUnit report.

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

export default defineConfig({
  reporter: [
    ['list'],
    ['html', {
      outputFolder: 'playwright-report',
      open: 'never'
    }],
    ['junit', {
      outputFile: 'test-results/results.xml'
    }]
  ],
  use: {
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
    trace: 'retain-on-failure'
  }
});

If you do not want to edit the configuration file, select JUnit on the command line and set its output filename through the environment:

PLAYWRIGHT_JUNIT_OUTPUT_NAME=results.xml \
  npx playwright test --reporter=junit

Do not use Playwright's --output option to name the XML file. That option selects the test artifact directory, not the JUnit report path.

Name Playwright tests with [TC-42] markers

Place the TestCollab test case ID in the individual test title:

import { test, expect } from '@playwright/test';

test('[TC-42] customer can sign in', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill('customer@example.com');
  await page.getByLabel('Password').fill('valid-password');
  await page.getByRole('button', { name: 'Sign in' }).click();
  await expect(page).toHaveURL(/dashboard/);
});

The CLI recognizes [TC-42], TC-42, id-42, and testcase-42, case-insensitively. The marked case must be present in the target plan and assigned to the user whose API token uploads the results.

Upload screenshots, videos, and traces

Playwright's JUnit reporter writes an [[ATTACHMENT|path]] line for each screenshot, video, and trace recorded for a test. tc report reads those markers and attaches the files to that test case's execution. No extra marker code is required.

<testcase name="[TC-42] customer can sign in">
  <failure message="Expected dashboard URL" />
  <system-out>
[[ATTACHMENT|test-results/customer-can-sign-in/test-failed-1.png]]
[[ATTACHMENT|test-results/customer-can-sign-in/trace.zip]]
  </system-out>
</testcase>

Keep the report and its artifact files in the same job until tc report finishes. Relative paths may resolve from the current working directory or the JUnit file's directory. TestCollab accepts up to 10 files per case and 10 MB per file. Missing, oversized, or extra files produce warnings and are skipped without failing the result upload.

Upload the Playwright JUnit report

export TESTCOLLAB_TOKEN="your-token"

npx @testcollab/cli report \
  --project 123 \
  --test-plan-id 456 \
  --format junit \
  --result-file ./test-results/results.xml

Replace 123 and 456 with your TestCollab project and test plan IDs.

Complete GitHub Actions workflow

The following workflow creates a test plan from a CI tag, runs Playwright, uploads JUnit results to TestCollab, and keeps the HTML report as a GitHub artifact. Store TESTCOLLAB_TOKEN as a repository secret and the three numeric IDs as repository variables.

name: Playwright tests

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    env:
      TESTCOLLAB_TOKEN: ${{ secrets.TESTCOLLAB_TOKEN }}
      TC_PROJECT_ID: ${{ vars.TC_PROJECT_ID }}
      TC_CI_TAG_ID: ${{ vars.TC_CI_TAG_ID }}
      TC_ASSIGNEE_ID: ${{ vars.TC_ASSIGNEE_ID }}
    steps:
      - name: Check out repository
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright browsers
        run: npx playwright install --with-deps

      - name: Create TestCollab test plan
        run: |
          npx @testcollab/cli createTestPlan \
            --project "$TC_PROJECT_ID" \
            --ci-tag-id "$TC_CI_TAG_ID" \
            --assignee-id "$TC_ASSIGNEE_ID"

      - name: Run Playwright tests
        run: npx playwright test

      - name: Upload Playwright results to TestCollab
        if: always()
        run: |
          source tmp/tc_test_plan
          npx @testcollab/cli report \
            --project "$TC_PROJECT_ID" \
            --test-plan-id "$TESTCOLLAB_TEST_PLAN_ID" \
            --format junit \
            --result-file ./test-results/results.xml

      - name: Upload Playwright HTML report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-html-report
          path: playwright-report/
          if-no-files-found: warn
          retention-days: 14

The result and artifact steps use if: always(), so a Playwright assertion failure is still recorded. The failed Playwright step continues to make the job fail.

Use the EU region

Add this option to every TestCollab CLI command for an EU account:

--api-url https://api-eu.testcollab.io

Migrating from the legacy Playwright plugin

New integrations should use Playwright's built-in JUnit reporter and tc report. This avoids framework-specific TestCollab plugin code and uses the same result path as every other JUnit-capable runner. Existing customers maintaining the retired approach can consult Playwright integration (legacy plugin) while migrating.

Troubleshooting

No JUnit file is created

Confirm the configured reporter includes junit and uses outputFile, or set PLAYWRIGHT_JUNIT_OUTPUT_NAME when selecting the reporter on the command line.

A Playwright test is not matched

Open test-results/results.xml and check that the <testcase name> contains the correct [TC-42] marker. Then confirm that case is in the target plan.

An attachment is skipped

Read the warning in the CLI log. Verify the file still exists when tc report runs, is no larger than 10 MB, and is one of the first 10 attachments named for that case.

Results are not uploaded after a failure

Keep test execution and result upload in separate CI steps, and put if: always() on the upload. The reporter normally writes the XML before Playwright returns its failure exit code.

Last updated 2026-08-26.