Playwright Plugin
The @pxdiff/playwright package integrates pxdiff into Playwright tests. Take screenshots during tests and get instant diff results against baselines.
Installation
Section titled “Installation”npm install --save-dev @pxdiff/playwrightPeer dependency: @playwright/test >= 1.40
1. Global Setup
Section titled “1. Global Setup”Create a global setup file that initializes the pxdiff session:
import { pxdiffSetup } from "@pxdiff/playwright/setup";
export default function setup(): void { pxdiffSetup();}This generates a PXDIFF_SESSION_ID to group all screenshots from the test run into a single capture and diff. It won’t overwrite an existing value.
2. Create a Test Fixture
Section titled “2. Create a Test Fixture”Extend Playwright’s test with pxdiff:
import { test as base } from "@playwright/test";import { createPxdiffFixture } from "@pxdiff/playwright";
export const test = base.extend( createPxdiffFixture({ suite: "my-app", }));
export { expect } from "@playwright/test";3. Configure Playwright
Section titled “3. Configure Playwright”Reference the global setup in your Playwright config:
import { defineConfig } from "@playwright/test";
export default defineConfig({ globalSetup: "./global-setup.ts", // ...});4. Set Environment Variables
Section titled “4. Set Environment Variables”export PXDIFF_API_KEY=pxd_your_key_hereUse the toMatchPxdiff matcher on Page or Locator instances:
import { test, expect } from "./fixtures";
test("homepage visual regression", async ({ page }) => { await page.goto("/");
// Full-page screenshot await expect(page).toMatchPxdiff("homepage");
// Component screenshot const header = page.locator("header"); await expect(header).toMatchPxdiff("header");
// With options await expect(page).toMatchPxdiff("homepage-mobile", { viewport: { width: 375, height: 812 }, ignoreSelectors: [".dynamic-timestamp"], });});createPxdiffFixture(options?)
Section titled “createPxdiffFixture(options?)”Creates a Playwright fixture that initializes pxdiff context for each test.
| Option | Type | Default | Description |
|---|---|---|---|
suite | string | "playwright" | Suite name for grouping snapshots |
blocking | boolean | true | Whether changed snapshots fail the test |
apiUrl | string | PXDIFF_API_URL or "https://pxdiff.com" | API URL |
git.branch | string | (auto-detected) | Git branch override |
git.commit | string | (auto-detected) | Git commit override |
local | boolean | (auto-detected) | Local mode (from PXDIFF_LOCAL or absence of CI) |
autoApprove | boolean | (auto-detected) | From PXDIFF_AUTO_APPROVE |
toMatchPxdiff(name, options?)
Section titled “toMatchPxdiff(name, options?)”Custom matcher for visual regression assertions.
await expect(page).toMatchPxdiff("snapshot-name", options);await expect(locator).toMatchPxdiff("component-name", options);| Option | Type | Default | Description |
|---|---|---|---|
blocking | boolean | (from fixture) | Override blocking mode for this snapshot |
threshold | number | Custom diff threshold (0–1) | |
viewport | object | { width, height } — set viewport before screenshot | |
fullPage | boolean | false | Capture full page instead of viewport |
mask | Locator[] | Locators to mask before screenshot | |
ignoreSelectors | string[] | CSS selectors to hide via visibility: hidden | |
maxDiffPixelRatio | number | Max acceptable diff ratio (0–1). Pass if below this | |
animations | string | "disabled" to freeze animations | |
timeout | number | Screenshot timeout in ms | |
waitForNetworkIdle | boolean | true | Wait for network idle before taking the screenshot |
path | string[] | Display hierarchy path for tree grouping in review UI |
Ignore Selectors
Section titled “Ignore Selectors”Elements matching ignoreSelectors are hidden with visibility: hidden before the screenshot is taken. The CSS is cleaned up immediately after.
In addition, elements with data-pxdiff="ignore" or data-chromatic="ignore" attributes are always hidden:
<span data-pxdiff="ignore">Dynamic content here</span>Pass/Fail Logic
Section titled “Pass/Fail Logic”The matcher determines pass/fail as follows:
- Pass: unchanged, new, auto-approved, within
maxDiffPixelRatio, non-blocking mode, or CI mode (soft-fail) - Fail: changed snapshots exceeding the threshold in blocking mode
In CI mode (when PXDIFF_SESSION_ID is set and not local), the matcher always passes but includes diff information in the test annotations. The pxdiff GitHub check run reports the overall result.
Test Annotations
Section titled “Test Annotations”Each toMatchPxdiff call attaches a pxdiff annotation to the test with the diff result. This makes results visible in Playwright’s HTML report.
CI Integration
Section titled “CI Integration”With pxdiff run
Section titled “With pxdiff run”The recommended approach for CI is to wrap your Playwright tests with pxdiff run:
- name: Visual Regression run: pxdiff run -- npx playwright test env: PXDIFF_API_KEY: ${{ secrets.PXDIFF_API_KEY }}This creates a GitHub check run, groups all screenshots into one session, and reports results back to the PR.
Standalone
Section titled “Standalone”You can also run Playwright tests without pxdiff run. Screenshots are still uploaded and diffed individually:
- name: Visual Tests run: npx playwright test env: PXDIFF_API_KEY: ${{ secrets.PXDIFF_API_KEY }}Environment Variables
Section titled “Environment Variables”| Variable | Description |
|---|---|
PXDIFF_API_KEY | (required) API authentication key |
PXDIFF_API_URL | API base URL (default: https://pxdiff.com) |
PXDIFF_SESSION_ID | Session ID for grouping (set by pxdiffSetup() or pxdiff run) |
PXDIFF_LOCAL | Set to true for local development mode |
PXDIFF_AUTO_APPROVE | Set to true to auto-approve all changes |
PXDIFF_BRANCH | Override git branch detection |
PXDIFF_COMMIT | Override git commit detection |