npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@alex_neo/playwright-azure-reporter

v1.20.0

Published

Playwright Azure Reporter

Readme

Playwright Azure Reporter

GitHub npm (scoped) npm npm

A Playwright reporter that publishes test results to Azure DevOps Test Plans.

Table of Contents

Quick Start

Install the package:

npm install @alex_neo/playwright-azure-reporter

Add the reporter to your playwright.config.ts:

import { defineConfig } from '@playwright/test';
import type { AzureReporterOptions } from '@alex_neo/playwright-azure-reporter';

export default defineConfig({
  reporter: [
    ['list'],
    [
      '@alex_neo/playwright-azure-reporter',
      {
        orgUrl: 'https://dev.azure.com/your-organization-name',
        token: process.env.AZURE_TOKEN,
        planId: 44,
        projectName: 'SampleProject',
        publishTestResultsMode: 'testRun',
      } as AzureReporterOptions,
    ],
  ],
});

Each test must reference an existing Azure DevOps test case ID. See Defining Test Case IDs for all supported formats.

Defining Test Case IDs

You must link each test to an existing test case in Azure DevOps before running tests. There are three ways to do this.

In Test Title

Wrap test case IDs in square brackets inside the test name:

  • [1] Test name - single test case
  • [1,2,3] Test name - multiple test cases
  • [1, 2, 3] Test name [4] another [5][6] combined - mixed formats
test.describe('Test suite', () => {
  test('[1] First Test', () => {
    expect(true).toBe(true);
  });

  test('[10,11,12] Multiple test cases', () => {
    expect(true).toBe(true);
  });
});

Using Tags

Use Playwright's tag syntax with the format @[ID]:

test.describe('Test suite', () => {
  test('Test name', {
    tag: ['@[1]', '@smoke', '@slow'],
  }, () => {
    expect(true).toBe(true);
  });
});

The @ prefix is required by Playwright. Non-ID tags (like @smoke) are ignored by the reporter.

Using Annotations

Use Playwright's annotation API with testCaseIdZone: 'annotation':

test('Test case', {
  annotation: { type: 'TestCase', description: '12345' },
}, () => {
  expect(true).toBe(true);
});

See Test Case ID Matching for advanced matching patterns with annotations.

Configuration

Required Options

| Option | Type | Description | |--------|------|-------------| | orgUrl | string | Full URL for your organization. Example: https://dev.azure.com/your-organization-name | | projectName | string | Name of your Azure DevOps project | | planId | number | ID of the test plan (from the test plan URL: planId=4) |

Note: Some APIs (e.g. ProfileApi) must be hit at the deployment level: https://vssps.dev.azure.com/{yourorgname}

General Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | isDisabled | boolean | false | Disable the reporter entirely | | environment | string | undefined | Prefix for test run names (e.g. 'QA') | | logging | boolean | false | Enable debug logging | | testRunTitle | string | 'Playwright Test Run' | Title for newly created test runs | | testRunConfig | object | undefined | Extra data passed when creating a test run. See API docs |

Authentication

The reporter supports three authentication methods:

Personal Access Token (PAT) - Default

{
  token: 'your-personal-access-token',
  authType: 'pat' // Optional, this is the default
}

Access Token

{
  token: 'your-access-token',
  authType: 'accessToken'
}

Azure Managed Identity

{
  token: 'not-used', // Token field is required but ignored for managedIdentity
  authType: 'managedIdentity',
  applicationIdURI: '499b84ac-1321-427f-aa17-267ca6975798/.default'
}

When to use each:

  • PAT: Personal Access Token from Azure DevOps. Suitable for most use cases.
  • Access Token: OAuth access token. Suitable for CI/CD environments with token-based authentication.
  • Managed Identity: Azure environments with managed identity. Uses DefaultAzureCredential supporting Azure CLI, managed identity, environment variables, etc.

For more examples, see Authentication Examples.

Required Token Scopes

| Scope | Access | Purpose | |-------|--------|---------| | Test Management | Read & Write | Creating/updating test runs, publishing results, uploading attachments | | Work Items | Read & Write | Marking test cases as automated (only if autoMarkTestCasesAsAutomated is enabled) | | Project and Team | Read | Accessing project information |

Alternatively, use a token with Full access scope.

Note: If your token lacks Work Items write permissions but autoMarkTestCasesAsAutomated is enabled, the reporter will log errors for automation updates but continue publishing test results normally.

Publishing Modes

Control how and when test results are sent to Azure DevOps with publishTestResultsMode:

| Mode | Default | Description | |------|---------|-------------| | 'testResult' | Yes | Results published after each test completes, in parallel with test execution | | 'testRun' | | Results batched and published at the end of the test run | | 'testRunADO' | | Updates existing results in an Azure DevOps test run (requires isExistingTestRun: true and testRunId) |

Note: In testRun mode, if the same test case ID appears in multiple tests, only the last result is kept.

Existing Test Runs

To publish results to an existing test run instead of creating a new one:

{
  publishTestResultsMode: 'testRunADO',
  isExistingTestRun: true,
  testRunId: 12345, // or set AZURE_PW_TEST_RUN_ID env variable
}
  • isExistingTestRun [boolean] - Publish to an existing test run without creating/completing it. Default: false.
  • testRunId [number] - ID of the existing test run. Can also be set via AZURE_PW_TEST_RUN_ID env variable. Reporter options take precedence over the env variable.

Note: When using isExistingTestRun, the test run is not completed automatically. You must complete it manually.

Retry Results

Control how retry attempts are published with publishRetryResults:

| Mode | Description | |------|-------------| | 'all' | Every retry attempt is published as a separate test result (default) | | 'last' | Only the final attempt is published. Intermediate failures are skipped |

{
  publishRetryResults: 'last',
  // works with Playwright's retries setting
}

Attachments & Logs

| Option | Type | Default | Description | |--------|------|---------|-------------| | uploadAttachments | boolean | false | Upload attachments (screenshots/video) after each test | | attachmentsType | (string\|RegExp)[] | ['screenshot'] | Filter which attachments to upload by type or name pattern | | uploadLogs | boolean | false | Upload stdout/stderr logs (independent of uploadAttachments) |

Test Point Mapping

testPointMapper

A callback to map tests to specific test configurations (e.g. by browser):

import { TestCase } from '@playwright/test/reporter';
import { TestPoint } from 'azure-devops-node-api/interfaces/TestInterfaces';

{
  testPointMapper: async (testCase: TestCase, testPoints: TestPoint[]) => {
    switch (testCase.parent.project()?.use.browserName) {
      case 'chromium':
        return testPoints.filter((tp) => tp.configuration.id === '3');
      case 'firefox':
        return testPoints.filter((tp) => tp.configuration.id === '4');
      case 'webkit':
        return testPoints.filter((tp) => tp.configuration.id === '5');
      default:
        throw new Error('invalid test configuration!');
    }
  },
  testRunConfig: {
    // Get configuration IDs from:
    // https://dev.azure.com/{organization}/{project}/_apis/test/configurations
    configurationIds: [3, 4, 5],
  },
}

Important: Define testRunConfig.configurationIds and/or testPointMapper, otherwise results are published for all configurations.

rootSuiteId

Restricts test point resolution to a specific suite. Useful when different suites (e.g. smoke, integration) contain the same test case IDs. Can also be set via AZURE_PW_ROOT_SUITE_ID env variable. Reporter options take precedence.

Automation Tests
  - Smoke Tests (suiteId: 5)
    - Test 1 (caseId: 1)
    - Test 2 (caseId: 2)
  - Integration Tests (suiteId: 6)
    - Test 1 (caseId: 1)
    - Test 2 (caseId: 2)

Without rootSuiteId, running smoke tests would also match test points in Integration Tests. Set rootSuiteId: 5 to scope results to Smoke Tests only.

Test Case ID Matching

testCaseIdMatcher

A string, RegExp, or array of either, used to extract test case IDs. Default: /\[([\d,\s]+)\]/

Examples with test titles:

| Test Title | Matcher | Extracted IDs | |-----------|---------|---------------| | Test case @tag1=123 | /@tag1=(\d+)/ | ['123'] | | Test case @TC=123 [@TC=456] | /@TC=(\d+)/ | ['123', '456'] | | Test case test123 TEST456 | [/[a-z]+(\d+)/, /[A-Z]+(\d+)/] | ['123', '456'] |

If an invalid matcher is provided (e.g. a number), an error is thrown: "Invalid testCaseIdMatcher. Must be a string or RegExp.".

testCaseIdZone

Specifies where to look for test case IDs: 'title' (default) or 'annotation'.

  • 'title' - Extracts IDs from the test title and tags
  • 'annotation' - Extracts IDs from test annotations only

Important: When using testCaseIdZone: 'annotation', you must also define testCaseIdMatcher.

When using annotation zone, the matcher works in two steps:

  1. First matcher matches the annotation type (e.g. /(TestCase)/)
  2. Subsequent matchers extract IDs from the annotation description

Annotation examples:

Simple description:

// testCaseIdZone: 'annotation', testCaseIdMatcher: /(TestCase)/
test('Test case', {
  annotation: { type: 'TestCase', description: '12345' },
}, () => { /* ... */ });
// Extracted: ['12345']

Azure DevOps URLs:

// testCaseIdZone: 'annotation', testCaseIdMatcher: [/(Test Case)/, /\/(\d+)/]
test('Test case', {
  annotation: {
    type: 'Test Case',
    description: 'https://dev.azure.com/org/project/_workitems/edit/12345, https://dev.azure.com/org/project/_workitems/edit/54321',
  },
}, () => { /* ... */ });
// Extracted: ['12345', '54321']

Bracketed format:

// testCaseIdZone: 'annotation', testCaseIdMatcher: [/(Test Case)/, /\[([\d,\s]+)\]/]
test('Test case', {
  annotation: { type: 'Test Case', description: '[12345, 67890]' },
}, () => { /* ... */ });
// Extracted: ['12345', '67890']

Test Case Summary

Generate a report of test cases that don't match the test plan. Helps identify missing, misconfigured, or unassigned test cases.

{
  testCaseSummary: {
    enabled: true,
    outputPath: './test-case-summary.md',
    consoleOutput: true,
    publishToRun: true,
  },
}

| Sub-option | Type | Default | Description | |------------|------|---------|-------------| | enabled | boolean | false | Enable summary generation | | outputPath | string | undefined | File path for the summary report | | consoleOutput | boolean | true | Print summary to console | | publishToRun | boolean | false | Upload summary as a Markdown attachment to the ADO test run |

Output channels work independently - enable any combination:

| consoleOutput | outputPath | publishToRun | Result | |:-:|:-:|:-:|--------| | true | - | - | Console only | | true | set | - | Console + file | | - | - | true | ADO attachment only | | true | set | true | All three channels |

When all test cases match, a success message is logged instead.

Note: When publishToRun: true, the attachment is only uploaded if unmatched test points exist. Key summary lines are always logged regardless of the logging setting to ensure CI visibility.

Example output:

# Test Case Summary

Found 1 test(s) with test case IDs that don't match the test plan:

## Tests with No Matching Test Points (1)

- **[777] Test with file output**
  - File: tests/example.spec.ts:3
  - Test Case IDs: [777]

## Recommendations

- Verify test case IDs exist in Azure DevOps test plan 4
- Check that test cases are assigned to configurations: [10, 20] (Firefox, Safari)
- Ensure test cases are included in the test plan suite structure

Auto-Mark as Automated

Automatically update Azure DevOps test case work items to reflect their automation status when tests are executed.

{
  autoMarkTestCasesAsAutomated: {
    enabled: true,
    updateAutomatedTestName: true,
    updateAutomatedTestStorage: true,
  },
}

| Sub-option | Type | Default | Description | |------------|------|---------|-------------| | enabled | boolean | false | Enable automatic marking | | updateAutomatedTestName | boolean | true | Set AutomatedTestName field | | updateAutomatedTestStorage | boolean | true | Set AutomatedTestStorage field | | automatedTestNameFormat | string | 'title' | 'title' or 'titleWithParent' (includes parent suite name) | | automatedTestStoragePath | boolean \| function | false | false: filename only, true: full path, function: custom callback | | automatedTestType | function | undefined | Callback to set AutomatedTestType (e.g. 'Unit Test', 'E2E Test') |

What it does:

  1. Checks each test case's automation status in Azure DevOps
  2. If "Not Automated": sets AutomationStatus to "Automated", updates name/storage/type fields, generates a new AutomatedTestId GUID
  3. If already "Automated": optionally updates name and storage fields if they differ

Advanced example:

{
  autoMarkTestCasesAsAutomated: {
    enabled: true,
    updateAutomatedTestName: true,
    updateAutomatedTestStorage: true,
    automatedTestNameFormat: 'titleWithParent',
    automatedTestStoragePath: (testCase) => {
      // Use relative path from project root
      const parts = testCase.location.file.split('/');
      const idx = parts.indexOf('my-project');
      return idx >= 0 ? parts.slice(idx + 1).join('/') : testCase.location.file;
    },
    automatedTestType: (testCase) => {
      if (testCase.location.file.includes('/e2e/')) return 'End-to-End Test';
      if (testCase.location.file.includes('/integration/')) return 'Integration Test';
      return 'Functional Test';
    },
  },
}

Tip: Use automatedTestNameFormat: 'titleWithParent' to prevent name collisions across suites. Use automatedTestStoragePath callback to avoid exposing absolute paths.

Note: Requires Work Items write permissions. Works in all publishing modes (testResult, testRun, testRunADO).

CI/CD Integration

Environment Variables

| Variable | Description | |----------|-------------| | AZURE_PW_TEST_RUN_ID | Set automatically after the test run is created. Available as process.env.AZURE_PW_TEST_RUN_ID. In testResult mode it's set at the start; in testRun mode at the end; in testRunADO mode it contains the existing run ID. | | AZURE_PW_ROOT_SUITE_ID | Alternative to the rootSuiteId option | | AZUREPWDEBUG | Enable debug logging: '1' = enabled, '0' = disabled (default) |

Azure DevOps Pipeline Example

- script: npx playwright test
  displayName: 'Run Playwright tests'
  name: 'playwright'
  env:
    CI: 'true'
    AZUREPWDEBUG: '1'

# Access the test run ID from subsequent steps (since v1.10.0)
- script: echo $(playwright.AZURE_PW_TEST_RUN_ID)
  displayName: 'Print test run id'

Releases

For detailed information about stable releases, beta releases, and version management, see RELEASES.md.