1. Baseline governance β who updates what, when
Baselines are the source of truth. An auto-update culture is a compromised source of truth.
Problem: Tests fail, someone runs --update-snapshots, greens ship β with whatever UI drift happened to be in that run. A month later, the baseline shows an 8-pixel logo shift nobody noticed. Tomorrow a real regression hides the same way.
// playwright.config.ts β explicit baseline strategy
export default defineConfig({
expect: {
toHaveScreenshot: {
// Default threshold β strict for critical flows
maxDiffPixelRatio: 0.01,
animations: 'disabled',
caret: 'hide',
},
},
});
// CI flow β baselines are ONLY updated on an explicit branch + PR
// .github/workflows/visual.yml
jobs:
visual:
steps:
- run: pnpm playwright test --project=visual
# NO --update-snapshots here
- if: failure()
uses: actions/upload-artifact@v4
with:
name: visual-diffs
path: test-results/
# Separate workflow: manually triggered, updates baselines, opens PR
update-baselines:
if: github.event_name == 'workflow_dispatch'
steps:
- run: pnpm playwright test --project=visual --update-snapshots
- uses: peter-evans/create-pull-request@v5
with:
title: 'chore: update visual baselines'
branch: visual-baseline-update
body: 'Review each changed snapshot before approving.'Rule of thumb: No one auto-updates baselines on CI. Baseline updates go through a dedicated PR that a human reviews diff-by-diff. This is the ONE concession that makes visual regression actually useful in a team.