Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If Playwright runs in Azure Pipelines but the Tests tab is empty, the usual cause is an output mismatch: Playwright produced terminal text or an HTML report, while Azure’s publisher was looking for JUnit XML. Configure Playwright’s JUnit reporter, point PublishTestResults@2 at the exact XML path, and run that task with condition: succeededOrFailed() so failed tests are still uploaded.

Why Playwright results do not appear in Azure DevOps

Playwright can write several different report types. The interactive report in playwright-report is an HTML site, and the list or line reporter writes human-readable console output. Neither is the XML data source that Azure DevOps uses for entries in the Tests tab.

You need two separate outputs:

  • JUnit XML: consumed by PublishTestResults@2 and displayed as test runs, suites, outcomes and durations in Azure DevOps.
  • HTML report: retained as a pipeline artifact so developers can open Playwright’s traces, steps and screenshots.

A successful Playwright command therefore does not prove that a publish task has anything to upload. The reporter must create a file, and the task’s search folder and filename pattern must match it exactly.

Known-good configuration

1. Configure the JUnit reporter

Add a JUnit reporter to playwright.config.ts. The output path below is relative to the agent workspace and is deliberately the same path used by the pipeline task.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { defineConfig } from '@playwright/test';

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

The JUnit reporter creates test-results/e2e-junit-results.xml. The HTML reporter creates the separate playwright-report directory. If your project already has other reporters, keep them, but do not remove JUnit when Azure test reporting is required.

2. Publish the XML and HTML outputs in Azure Pipelines

This pipeline installs browser dependencies, runs the tests, publishes JUnit results, and stores the HTML report as a pipeline artifact.

- script: npm ci

- script: npx playwright install --with-deps

- script: npx playwright test
  env:
    CI: 'true'

- task: PublishTestResults@2
  displayName: Publish test results
  inputs:
    searchFolder: 'test-results'
    testResultsFormat: 'JUnit'
    testResultsFiles: 'e2e-junit-results.xml'
    mergeTestResults: true
    failTaskOnFailedTests: true
    testRunTitle: 'Playwright end-to-end tests'
  condition: succeededOrFailed()

- task: PublishPipelineArtifact@1
  inputs:
    targetPath: playwright-report
    artifact: playwright-report
    publishLocation: pipeline
  condition: succeededOrFailed()

testResultsFormat: 'JUnit' tells Azure how to parse the file. searchFolder is the directory in which the task searches, while testResultsFiles is the filename or glob inside that directory. mergeTestResults: true allows matching files to be combined into one run. failTaskOnFailedTests: true makes the publish task reflect failing tests; it does not hide their results.

The succeededOrFailed() condition is important. Without it, a failed Playwright command can prevent the following tasks from running, leaving you with no test data and no HTML diagnostics.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make the paths agree

Relative paths are resolved in the agent’s workspace. A path that looks correct in a local shell may differ in a monorepo, a template, or a job that changes directories. Use one explicit directory and filename in both files:

Component Value in this example
Playwright JUnit output test-results/e2e-junit-results.xml
Azure search folder test-results
Azure file pattern e2e-junit-results.xml
HTML artifact directory playwright-report

If you change the reporter filename, update testResultsFiles at the same time. If the tests run from a subdirectory, either keep both paths relative to that working directory or use a consistent workspace-relative arrangement.

Diagnose the failure in order

1. Check that JUnit is actually enabled

Inspect playwright.config.ts and the test command for a command-line override such as --reporter=list or --reporter=line. A command-line reporter override can replace the configured reporter and prevent XML creation. Run the same command used by the pipeline, not a different local command.

2. List the agent’s files immediately after the test command

Add a temporary diagnostic step before publishing. On a Linux agent:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
- script: |
    pwd
    find . -maxdepth 3 -type f -print | sort
    ls -la test-results || true
  displayName: Inspect Playwright outputs
  condition: succeededOrFailed()

On a Windows agent, use PowerShell:

- powershell: |
    Get-Location
    Get-ChildItem -Recurse -File -Depth 3 | Sort-Object FullName
    Get-ChildItem -Force .test-results -ErrorAction SilentlyContinue
  displayName: Inspect Playwright outputs
  condition: succeededOrFailed()

Compare the actual path and case-sensitive filename with the task inputs. This catches a missing directory, a different working directory, and names such as e2e-junit-results.xml versus e2e-junit-result.xml.

3. Make missing files fail loudly while debugging

Temporarily add the supported diagnostic inputs below:

- task: PublishTestResults@2
  inputs:
    searchFolder: 'test-results'
    testResultsFormat: 'JUnit'
    testResultsFiles: 'e2e-junit-results.xml'
    failTaskOnMissingResultsFile: true
    failTaskOnFailureToPublishResults: true
  condition: succeededOrFailed()

These settings turn a silent “no files found” situation into a visible task failure. Remove or retain them according to how strictly your pipeline should treat missing output after you have corrected the path.

4. Validate that the XML is real JUnit

A zero-byte file, truncated file, or unrelated XML document will not create useful test entries. Open the file in the artifact or print its first lines during diagnosis. It should contain JUnit suites and test cases generated by the Playwright run. Confirm that the test process completed far enough to flush the reporter.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

5. Handle sharded or parallel jobs

Parallel jobs must not overwrite one shared filename. Give each shard a distinct output, for example test-results/e2e-junit-results-$(System.JobAttempt).xml, or generate files in separate shard directories. Point the publisher at a glob such as **/e2e-junit-results-*.xml and keep mergeTestResults: true. First verify that every shard writes its file; a glob cannot publish a file that was never created.

Attachments, screenshots, traces and videos

Configure failure diagnostics in Playwright rather than trying to make the HTML report populate the Tests tab. The example configuration uses screenshot: 'only-on-failure' and trace: 'retain-on-failure'. You can also retain videos according to your project’s normal Playwright settings.

PublishTestResults@2 can associate attachment paths recorded in the JUnit XML. Those paths may be absolute or relative to the XML file. If an attachment is missing, check that the file still exists when the publish task runs and that the recorded path is valid on the build agent. In Azure DevOps, open a failed test and select the Attachments tab to inspect or download associated files. Use the separately published playwright-report artifact for the complete interactive report.

Common symptoms and fixes

Symptom Likely cause Fix
Tests tab is empty, but the console shows passing tests No JUnit reporter, or the publisher is looking in the wrong directory Enable the JUnit reporter and align outputFile, searchFolder and testResultsFiles.
“No files found” from PublishTestResults Filename, case, working directory or glob does not match List files immediately after the test step and copy the actual path into the task inputs.
Results disappear when tests fail The publisher is skipped after a failed test command Add condition: succeededOrFailed() to the publish tasks.
One shard appears, others are missing Shards overwrite one XML file or the pattern matches only one file Use unique per-shard filenames, a recursive glob and mergeTestResults: true.
Publish task runs but shows no useful cases Malformed, empty or non-JUnit XML Inspect the file contents and confirm the JUnit reporter completed and wrote suites and test cases.
HTML report cannot be opened from Tests HTML is not the Azure test-results format Publish playwright-report with PublishPipelineArtifact@1 and open it from the pipeline’s Artifacts section.

Local reproduction before changing YAML

  1. Delete old output directories so a stale XML file cannot mask the problem: rm -rf test-results playwright-report on Linux/macOS, or remove the directories in PowerShell on Windows.
  2. Run the exact CI command: CI=true npx playwright test on a Unix-like shell, or set the equivalent environment variable in PowerShell.
  3. Verify that test-results/e2e-junit-results.xml and playwright-report exist and contain current timestamps.
  4. Only then run the Azure job. If the file exists locally but not on the agent, investigate the agent’s working directory, browser installation, permissions and test command rather than changing the publisher format.

Reliability and maintenance notes

  • Run npm ci from the lockfile so the CI dependency tree is reproducible.
  • Install browsers and operating-system dependencies with npx playwright install --with-deps on agents that do not already contain them.
  • Keep report directories unique per job when multiple jobs publish artifacts; otherwise later steps can overwrite earlier output.
  • Retain the HTML artifact even when JUnit publication succeeds. JUnit gives Azure structured outcomes; the HTML report supplies Playwright’s interactive debugging context.
  • When upgrading Playwright or Azure task versions, recheck the generated filename and task log. The integration depends on the file actually written by your installed reporter, not on the presence of a configuration snippet alone.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your immediate goal is a clean image or PDF of a page rather than running a Playwright browser in the pipeline, ScreenshotNeo provides a single HTTP request. Before capture it accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the outcome with X-Page-Verdict and X-Billed headers. Its MCP server lets Claude, Cursor and other MCP clients call take_screenshot, get_page_info and capture_pdf.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

See the ScreenshotNeo documentation for authentication and all capture options. A direct call looks like this:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://playwright.dev -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://playwright.dev"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://playwright.dev' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Every plan includes the same feature set, including full-page captures with lazy images loaded, CSS-selector element shots, dark mode, device presets or custom viewports, retina scale, PDF controls, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting and an OpenAPI specification. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to start.

Frequently Asked Questions

Can the same JUnit file be published by more than one pipeline task?

It can be discovered by multiple tasks, but doing so may create duplicate runs. Use one publisher for a given XML set, or deliberately separate files and titles when distinct runs are required.

What should I preserve when moving from one Azure agent image to another?

Preserve the reporter output path, the publisher search pattern and the diagnostic settings. Agent image changes can affect browser dependencies and working directories, so verify the generated files on the new image.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.