Skip to content

Screenshot APIs

When to Use

Use toHaveScreenshot() for all VR work. Use page.screenshot() only when you need a raw buffer for non-test purposes. Use toMatchSnapshot() 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"

  1. Auto-retry stability check — re-screenshots until two consecutive frames are identical (handles spinners, layout shifts, font swap, lazy-loaded images settling)
  2. 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
  3. Threshold-based comparison — uses pixelmatch with default threshold: 0.2 perceptual 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 wanted toHaveScreenshot()Right: you lose the auto-retry stability check
  • Wrong: Inconsistent naming — toHaveScreenshot('thing') vs toHaveScreenshot('Thing.png')Right: name consistently; casing produces different baseline filenames

See Also