Skip to main content
Back to blog

Run Playwright Tests in Azure DevOps Pipeline: Complete Guide

Complete guide to running Playwright tests in Azure DevOps CI/CD pipelines. Covers YAML configuration, browser installation, parallel execution, test sharding, HTML report publishing, and debugging failed tests.

InnovateBits4 min read
Share

Playwright integrates cleanly with Azure DevOps — it produces JUnit XML output natively, captures screenshots and traces on failure, and supports parallel execution across multiple agents. This guide covers a production-ready Playwright pipeline configuration.


Basic Playwright pipeline

# azure-pipelines.yml
trigger:
  branches:
    include: [main]
 
pr:
  branches:
    include: [main]
 
pool:
  vmImage: ubuntu-latest
 
steps:
  - task: NodeTool@0
    inputs:
      versionSpec: '20.x'
    displayName: Setup Node.js
 
  - script: npm ci
    displayName: Install npm packages
 
  - script: npx playwright install --with-deps
    displayName: Install Playwright browsers
 
  - script: npx playwright test
    displayName: Run Playwright tests
    env:
      BASE_URL: $(STAGING_URL)
 
  - task: PublishTestResults@2
    displayName: Publish results
    inputs:
      testResultsFormat: JUnit
      testResultsFiles: playwright-results/results.xml
      testRunTitle: Playwright — $(Build.BuildNumber)
    condition: always()
 
  - task: PublishPipelineArtifact@1
    displayName: Upload HTML report
    inputs:
      targetPath: playwright-report
      artifact: playwright-report
    condition: always()

playwright.config.ts for CI

import { defineConfig, devices } from '@playwright/test'
 
export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,      // Fail if test.only left in code
  retries: process.env.CI ? 2 : 0,   // Retry twice in CI
  workers: process.env.CI ? 4 : undefined,
  reporter: [
    ['junit', { outputFile: 'playwright-results/results.xml' }],
    ['html', { outputFolder: 'playwright-report', open: 'never' }],
    ['list'],
  ],
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
    trace: 'on-first-retry',     // Capture traces on retry
    screenshot: 'only-on-failure',
    video: 'on-first-retry',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox',  use: { ...devices['Desktop Firefox'] } },
  ],
})

Multi-stage pipeline with sharding

For large test suites, split tests across multiple agents using Playwright's built-in sharding:

trigger:
  branches:
    include: [main]
 
pool:
  vmImage: ubuntu-latest
 
stages:
  - stage: Test
    jobs:
      # Run 4 shards in parallel
      - job: Shard1
        displayName: Tests shard 1/4
        steps:
          - template: templates/playwright-steps.yml
            parameters:
              shardIndex: 1
              shardTotal: 4
 
      - job: Shard2
        displayName: Tests shard 2/4
        steps:
          - template: templates/playwright-steps.yml
            parameters:
              shardIndex: 2
              shardTotal: 4
 
      - job: Shard3
        displayName: Tests shard 3/4
        steps:
          - template: templates/playwright-steps.yml
            parameters:
              shardIndex: 3
              shardTotal: 4
 
      - job: Shard4
        displayName: Tests shard 4/4
        steps:
          - template: templates/playwright-steps.yml
            parameters:
              shardIndex: 4
              shardTotal: 4
 
      # Merge results from all shards
      - job: MergeReports
        displayName: Merge and publish reports
        dependsOn: [Shard1, Shard2, Shard3, Shard4]
        condition: always()
        steps:
          - task: NodeTool@0
            inputs:
              versionSpec: '20.x'
          - script: npm ci
          - task: DownloadPipelineArtifact@2
            inputs:
              artifact: shard-results
              targetPath: all-results
          - script: npx playwright merge-reports --reporter=html all-results
            displayName: Merge HTML reports
          - task: PublishPipelineArtifact@1
            inputs:
              targetPath: playwright-report
              artifact: merged-playwright-report

Template templates/playwright-steps.yml:

parameters:
  - name: shardIndex
    type: number
  - name: shardTotal
    type: number
 
steps:
  - task: NodeTool@0
    inputs:
      versionSpec: '20.x'
  - script: npm ci
  - script: npx playwright install --with-deps chromium
  - script: |
      npx playwright test \
        --shard=${{ parameters.shardIndex }}/${{ parameters.shardTotal }} \
        --reporter=blob
    displayName: Playwright shard ${{ parameters.shardIndex }}/${{ parameters.shardTotal }}
    env:
      BASE_URL: $(STAGING_URL)
  - task: PublishPipelineArtifact@1
    inputs:
      targetPath: blob-report
      artifact: shard-results
    condition: always()

Viewing test results and traces

After the pipeline runs:

  1. Click the pipeline run → Tests tab
  2. See all tests with pass/fail status, duration, error messages
  3. Click a failed test to see the failure message
  4. Download the playwright-report artifact → open index.html
  5. In the HTML report, click a failed test → view screenshot, video, and trace

Playwright trace viewer:

Download the trace file (.zip) from the failed test, then run:

npx playwright show-trace trace.zip

The trace viewer shows every action, network request, and DOM state — invaluable for diagnosing failures that don't reproduce locally.


Common errors and fixes

Error: Error: browserType.launch: Executable doesn't exist at /root/.cache/ms-playwright/... Fix: Add npx playwright install --with-deps chromium before the test step. The --with-deps flag installs OS-level dependencies (libgtk, etc.) needed on Ubuntu.

Error: Tests fail with "Target page, context or browser has been closed" Fix: Tests are timing out and Playwright force-closes the browser. Increase the timeout in playwright.config.ts or add explicit waits (await page.waitForLoadState('networkidle')).

Error: ENOENT: no such file or directory, open 'playwright-results/results.xml' Fix: Add mkdir -p playwright-results before running tests, or configure the output directory in playwright.config.ts to match what PublishTestResults expects.

Error: Playwright tests pass in the pipeline but HTML report is empty Fix: The reporter array in playwright.config.ts must include the HTML reporter. The open: 'never' option is important in CI — without it, Playwright tries to open a browser which fails on headless agents.

Error: Shard jobs all pass but MergeReports fails to find artifacts Fix: All shard jobs must upload their blob reports to the same artifact name. When using DownloadPipelineArtifact@2, ensure the artifact name matches exactly what the shard jobs upload.

Free newsletter

Stay ahead in AI-driven QA

Get practical tutorials on test automation, AI testing, and quality engineering — straight to your inbox. No spam, unsubscribe any time.

Discussion

Sign in with GitHub to comment · powered by Giscus