# Screenshot comparisons

> Compare a page or element with a saved image and review visual changes in the report.

Source: https://rehearsal.dev/retest/docs/guides/screenshots

Use screenshot comparisons when a test needs to catch changes in a page's appearance. You review and save a reference image, called a baseline, then compare later screenshots against it pixel by pixel.

## Compare a saved task

First bring the page to the state you want to keep. An ordinary check before the screenshot prevents a loading state from becoming your reference image.

```ts filename="tests/tasks.retest.ts"
import { expect, test } from '@rehearsal-labs/retest'

test('shows a saved task', async ({ page }) => {
  await page.goto('/')
  await page.getByTestId('task-title').fill('Release checklist')
  await page.getByTestId('save-task').click()
  await expect(page.getByTestId('saved-task')).toHaveText('Release checklist')

  await expect(page).toHaveScreenshot('saved-task')
  await expect(page.getByTestId('saved-task')).toHaveScreenshot('saved-title')
})
```

The first screenshot compares the viewport; the second compares the saved title's box. An element must be visible and already inside the viewport because screenshot checks do not scroll it into view.

## Create and update baselines

With no baseline, the check fails and leaves a candidate image in the run folder. Retest never makes the first run pass by accepting its own picture. Write baselines explicitly when you are ready to review them.

```sh
npx retest run tests/tasks.retest.ts --update-screenshots
```

The flag writes the baselines reached by the selected tests, replacing previous images. Those screenshot checks pass, and the report counts the baselines written. Review the images before committing them with your tests, then run again without the flag.

```sh
npx retest run tests/tasks.retest.ts
```

Baselines live beside the test file. For this example on Chrome on an Apple silicon Mac, the page baseline has this path:

```text
tests/__screenshots__/tasks.retest.ts/saved-task-chromium-darwin-arm64.png
```

Each engine, operating system and processor architecture has its own image. Targets using the same engine share it, so use different screenshot names when those targets intentionally show different layouts.

Retest removes an optional `.png` ending before validating the screenshot name. Use only lowercase letters, digits, dots, underscores and hyphens, starting with a letter or digit. The name has at most 100 characters; invalid names fail with `usage`.

## Wait for a stable image

The screenshot check needs stable pixels.

For a comparison, the captured pixels must stay the same for at least 100 milliseconds. Retest then compares them and keeps trying until they match or the assertion budget ends. Writing a baseline requires a full second of unchanged pixels.

Retest does not stop animations or hide the text caret. A moving page can fail because its pictures never settle, so prepare a stable state in your app before the check. A loading state that lasts a second can still become a baseline if you do not wait for the content.

## Allow small differences

By default, no counted pixel may differ. If a small variation is acceptable, set a pixel count or a fraction of the image, keeping the limit small enough to catch the change you care about.

```ts
await expect(page).toHaveScreenshot('saved-task', {
  maxDiffPixels: 50,
  maxDiffPixelRatio: 0.001,
})
```

When both limits are present, both must hold. `threshold`, which defaults to 0.2, controls how far a pixel's colour can change before it counts as different. Pixels recognised as anti-aliased edges do not count, so this check can miss a colour change along a thin edge.

Screenshot checks have no masks and no `.not` form. Keep changing content out of the state you compare, or use [Layout checks](https://rehearsal.dev/retest/docs/guides/layout-checks.md) for a specific rule that needs no baseline.

## Review a failure

A mismatch leaves the expected image, the actual image and a difference image under `artifacts/` in the run folder. The terminal names those files, and the HTML report shows them side by side. Changed pixels appear in red in the difference image.

The failure also gives the number and fraction of pixels that differed. A page image with the wrong dimensions or device scale fails immediately; a damaged baseline reports `setup_failed`. Recreate baselines in the environment where you will compare them, using the same viewport and scale.

## Platform support

For Chromium-family targets, Retest was checked with `chrome()` and `chromium({ executablePath })`.

| Target | Page comparison | Element comparison |
| --- | --- | --- |
| Chrome and Chromium | Supported | Supported |
| Firefox | Supported | `unsupported` |
| WebKit | Supported | `unsupported` |
| Electron and native apps | `unsupported` | `unsupported` |

A Chromium-family popup can also be compared as a page. Element screenshots inside frames are `unsupported`. See [Browsers](https://rehearsal.dev/retest/docs/platforms/browsers.md) for the supported browser builds and platforms.

> [!WARNING]
> **Screenshots contain page pixels**
>
> Text redaction does not hide secrets in images. An app with `pixels: { web: { screenshots: 'never' } }`, or a session whose pixels are withheld during secret entry, refuses a screenshot comparison with `unsupported`. See [Recordings and evidence](https://rehearsal.dev/retest/docs/guides/recordings-and-evidence.md).

## Next steps

- [Layout checks](https://rehearsal.dev/retest/docs/guides/layout-checks.md): Check overlap and clipped text without keeping a baseline.
- [Recordings and evidence](https://rehearsal.dev/retest/docs/guides/recordings-and-evidence.md): Open the report and understand what a run keeps.
- [Test API](https://rehearsal.dev/retest/docs/reference/test-api.md): Look up screenshot comparison options.
