Screenshot APIs
When to Use
Use
toHaveScreenshot()for all VR work. Usepage.screenshot()only when you need a raw buffer for non-test purposes. UsetoMatchSnapshot()only when you already have a buffer and need to diff it.
Decision
| API | Type | Auto-retry stability | Baseline diffing | Use for |
|---|---|---|---|---|
expect(page).toHaveScreenshot() |
Assertion | Yes — waits for two consecutive matching frames | Yes (pixelmatch) | Primary VR API |
expect(buffer).toMatchSnapshot() |
Assertion | No | Yes for images | Generic snapshot; buffer already captured |
page.screenshot() |
Action | No | No | Raw capture; returns Buffer or writes file |
What Makes toHaveScreenshot() "Smart"
- Auto-retry stability check — re-screenshots until two consecutive frames are identical (handles spinners, layout shifts, font swap, lazy-loaded images settling)
- Baseline auto-creation — first run errors with
A snapshot doesn't exist at example.spec.ts-snapshots/example-test-1-chromium-darwin.png, writing actual.— the file is created and committed-ready - Threshold-based comparison — uses pixelmatch with default
threshold: 0.2perceptual color tolerance
Pattern
Minimal VR test
import { test, expect } from '@playwright/test';
test('homepage', async ({ page }) => {
await page.goto('https://playwright.dev');
await expect(page).toHaveScreenshot();
});
Element-level (preferred for components)
await expect(page.locator('.header')).toHaveScreenshot('header.png');
Common Mistakes
- Wrong: Using
page.screenshot()for VR → Right: it produces a file but does no comparison; the test always passes - Wrong: Using
toMatchSnapshot()on a buffer when you wantedtoHaveScreenshot()→ Right: you lose the auto-retry stability check - Wrong: Inconsistent naming —
toHaveScreenshot('thing')vstoHaveScreenshot('Thing.png')→ Right: name consistently; casing produces different baseline filenames