11. Playwright Testing and Screenshot Proof

11. Playwright Testing and Screenshot Proof

Why screenshot proof matters

A feature can pass a code review while still failing visually, responsively, or in a real browser. Playwright should verify both behavior and visual output. Its visual comparison API can create a baseline on first run and compare later runs with toHaveScreenshot().1

Generate and review screenshots in the same browser/OS configuration used for baselines. Rendering can vary across operating systems, browser versions, fonts, hardware, and headless settings.1

Test surfaces

Surface Screenshots
Public home Desktop and mobile, banner, featured products, chat launcher
Category/search Filtered results, empty state, product cards
Product detail Gallery, stock state, reviews, add-to-bag
Bag/checkout Empty bag, populated bag, validation, quote, error
Confirmation/track Safe order confirmation and tracking states
Admin overview Metrics, alerts, responsive sidebar
Admin catalogue Table, editor, media, validation
Admin order Timeline, payment state, status action, confirmation dialog
Admin assistant Loading, grounded answer, error/fallback, permission scope

Screenshot naming map

screenshots/
  storefront-home.desktop.png
  storefront-home.mobile.png
  storefront-search-filtered.desktop.png
  storefront-product-detail.mobile.png
  storefront-checkout-validation.desktop.png
  admin-overview.desktop.png
  admin-order-payment-unknown.desktop.png
  admin-assistant-grounded.desktop.png
  admin-assistant-unauthorized.mobile.png

Each screenshot should have a matching test name and a short evidence note. Never include real customer names, phone numbers, addresses, payment references, secrets, session cookies, or signed URLs in screenshots.

Playwright setup example

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  use: {
    baseURL: process.env.BASE_URL ?? 'http://127.0.0.1:8787',
    trace: 'retain-on-failure',
    screenshot: 'only-on-failure',
  },
  projects: [
    { name: 'chromium-desktop', use: { ...devices['Desktop Chrome'] } },
    { name: 'chromium-mobile', use: { ...devices['iPhone 13'] } },
  ],
});

Functional test examples

import { test, expect } from '@playwright/test';

test('customer sees verified product cards in chat', async ({ page }) => {
  await page.goto('/');
  await page.getByRole('button', { name: /chat/i }).click();
  await page.getByRole('textbox', { name: /message/i }).fill('I need a gentle cleanser');
  await page.getByRole('button', { name: /send/i }).click();
  await expect(page.getByTestId('chat-product-card').first()).toBeVisible();
  await expect(page.getByTestId('chat-message').last()).not.toContainText('api_key');
});

test('admin route rejects anonymous access', async ({ request }) => {
  const response = await request.post('/api/admin/chat', {
    data: { messages: [{ role: 'user', content: 'Show low stock' }] },
  });
  expect([401, 403]).toContain(response.status());
});

Visual proof examples

import { test, expect } from '@playwright/test';

test('home visual baseline', async ({ page }) => {
  await page.goto('/');
  await expect(page).toHaveScreenshot('storefront-home.desktop.png', {
    animations: 'disabled',
    caret: 'hide',
    maxDiffPixels: 120,
  });
});

Use a screenshot stylesheet or stable fixtures to hide timestamps, rotating banners, random visitor IDs, analytics widgets, and external provider content. Update a baseline only after a human reviews the diff.

Mapping proof

A screenshot is proof only when it maps to a requirement. Maintain a mapping table:

Requirement Test Screenshot/evidence
Public customer cannot see admin content customer-no-admin.spec.ts customer-safe-navigation.desktop.png
Product card uses current server data product-card-price.spec.ts storefront-product-detail.mobile.png
Admin metrics show range/source admin-overview.spec.ts admin-overview.desktop.png
Order unknown state is visible admin-order-status.spec.ts admin-order-payment-unknown.desktop.png
Customer chat avoids internal sources chat-boundary.spec.ts admin-assistant-unauthorized.mobile.png
Keyboard focus is visible accessibility.spec.ts Focus trace and screenshot

CI sequence

pnpm install --frozen-lockfile
pnpm test
npx playwright install --with-deps chromium
BASE_URL=https://staging.example.test npx playwright test

Do not put production credentials in CI logs. Use CI secret storage and a scrubbed staging dataset. Upload traces and screenshots only when they contain no private data. Keep approved baseline images in the repository or secure artifact store according to the project’s policy.

References