Visual comparisons
Visual snapshot testing: first run generates the reference, every run after compares pixel-by-pixel. I use it for catching accidental CSS regressions — a layout that looks fine in code but breaks visually. The main challenge is flakiness from dynamic content like timestamps and ads — mask those with stylePath or mask option.
How screenshot comparison works
First run: no reference exists, so Playwright generates it and writes the file to disk. The test fails on the first run — that's expected. Commit the generated file. Every run after that: Playwright takes a fresh screenshot and compares it pixel-by-pixel to the saved reference.
Screenshot files are named with browser and OS in the name: orders-page-1-chromium-darwin.png. That's because rendering differs between browsers and platforms — you need separate references for each. If you run tests on Linux CI but generate references on macOS, the comparison will fail.
Generating and updating references
When the page design changes intentionally, you need to update the reference. Use --update-snapshots to regenerate all references. Review the diff in git before committing — this is the checkpoint where you confirm the change is intentional.
Tolerance — allow minor pixel differences
Anti-aliasing, font rendering, and subpixel differences cause minor pixel variations between runs. I set maxDiffPixelRatio: 0.01 globally — allows 1% of pixels to differ without failing. For individual assertions I use maxDiffPixels when a specific component is known to have micro-rendering differences.
Masking dynamic content — timestamps, avatars, ads
Dynamic content like timestamps, user avatars, or live counters will always differ between runs and make visual tests flaky. Two ways to handle it: mask option (Playwright overlays a colored box) or stylePath (inject CSS that hides elements).
Text snapshots — compare API responses and text content
Beyond screenshots, toMatchSnapshot() works for any text or binary data. I use it for API response structure snapshots — when I want to catch unexpected field changes in an endpoint response.