Deterministic Placeholder Images for Visual Regression Testing

Published March 10, 2026

Visual regression tests only work when the baseline is stable. The moment a test pulls a real image from an external server, you introduce latency, potential 404s, and content that changes without warning. Deterministic placeholder fixtures give your test suite a foundation that never shifts — the same pixel grid, the same labels, the same file hash on every run.

The cost of non-deterministic test images

A single changing image in a visual baseline can invalidate an entire screenshot comparison. Playwright, Cypress, and Percy all work by diffing pixels between a stored baseline and the current run. If the baseline was captured with one image and the current run loads a different one — even a visually similar one — the diff will flag it.

This creates a noise problem: engineers spend time triaging diffs that are not caused by code changes. Over time, teams start ignoring diffs or increasing the tolerance threshold until real regressions slip through. Deterministic fixtures eliminate this class of false positive entirely.

What makes an image fixture deterministic

A deterministic fixture is any image file that is:

1. Committed to version control (not fetched at test time) 2. Generated from a stable, reproducible process 3. Named and sized to match the component it represents

Placeholder images satisfy all three conditions. You generate them once from a known configuration, commit the files, and reference them by path in your test setup. The pixel output is always identical because the generator is pure — same input produces same output every time.

Generating a fixture pack for your test suite

Start by listing the image sizes your test suite uses. Open your test files or your component library and collect every unique width×height combination that an `<img>` tag, `background-image`, or `<Image>` component expects.

Paste the list into PlacePack — one size per line in the format `WxH` or `label:WxH`. Add a text template like `{label} {w}×{h}` so filenames are self-documenting. Download the ZIP, extract it into a `__fixtures__/` directory, and update your test setup to load images from there.

Covering multiple UI states in one pack

Most components have several visual states: default, loading, error, and success. Each state might use a different image with different sizing or coloring. Rather than maintaining multiple fixture directories, use per-item color overrides in PlacePack to encode state meaning into the image itself.

For example, use a neutral slate color for default states, amber for loading or warning states, and red for error states. When a Playwright screenshot shows a red placeholder, you immediately know which component state is being exercised without reading the test name.

Playwright test using fixture images

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

test("card renders in error state", async ({ page }) => {
  await page.goto("/card?state=error");
  // image loaded from __fixtures__/card_error_320x180.png
  await expect(page).toHaveScreenshot("card-error.png");
});

Integrating with Percy and Chromatic

Percy and Chromatic both compare rendered pages against stored snapshots. When those pages contain dynamic images, every deploy risks producing a new baseline. Switching to fixture images means the image layer of your baseline never changes unless you explicitly regenerate the fixtures.

To integrate, replace any dynamic image sources in your test environment with references to the fixture files. In a Next.js app you might do this with an environment variable that swaps the image base URL. In a React app using MSW you can intercept image requests and respond with the fixture blobs.

Versioning and updating fixtures

Treat placeholder fixtures like any other generated asset: check them into version control and review changes in pull requests. When a component's dimensions change, regenerate only the affected sizes, commit the updated files, and approve the new baseline in Percy or Chromatic.

Store the PlacePack share URL in your project documentation so any team member can reproduce or extend the fixture set without guessing the original configuration.

FAQ — Frequently asked questions

Does PlacePack output pixel-identical images on every generate?
Yes for SVG (the output is deterministic markup). For PNG, the rasterization uses a fixed algorithm with no random elements, so the same input always produces the same file.
Can I use fixtures with Cypress component testing?
Yes. Place the fixture files in the Cypress fixtures directory and reference them with cy.fixture() or by setting the image src directly in your component mount.
How many fixture images can I generate at once?
PlacePack supports up to 100 rows per session. For larger suites, split by feature area and generate multiple packs, each stored in its own subdirectory.

Related guides

Ready to generate placeholder images?

Open the generator with the right preset pre-loaded and download your pack in seconds.