-
Notifications
You must be signed in to change notification settings - Fork 1.2k
149 lines (136 loc) · 6.24 KB
/
Copy pathvisual.yml
File metadata and controls
149 lines (136 loc) · 6.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
name: Visual Regression
# Untrusted measure job. Runs the visual-regression Playwright suite against the
# committed baselines and, when snapshots differ, produces an artifact with the
# candidate (accepted-state) baselines plus diff images. This workflow runs with
# a read-only token and never comments or pushes. The companion workflows handle
# that with elevated permissions, isolated from PR-authored code:
# - "Visual Regression — Report" (workflow_run) posts the sticky comment.
# - "Visual Regression — Apply" commits accepted baselines when a maintainer
# comments /accept-baselines on the PR.
#
# Baselines are Linux/chromium PNGs regenerated here on the CI runner, so they
# always match the environment they're diffed in. Contributors do NOT commit
# baselines by hand (macOS PNGs would never match); the /accept-baselines flow
# commits the correct Linux baselines for them.
on:
pull_request:
branches: [main]
paths:
- "packages/admin/**"
- "packages/core/**"
- "e2e/**"
- "playwright.config.ts"
- ".github/workflows/visual.yml"
- "pnpm-lock.yaml"
- "package.json"
permissions:
contents: read
jobs:
measure:
name: Measure
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm locale:extract
env:
EMDASH_PSEUDO_LOCALE: "1"
- run: pnpm run --filter emdash... build
env:
EMDASH_PSEUDO_LOCALE: "1"
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: playwright-${{ hashFiles('pnpm-lock.yaml') }}
- run: pnpm exec playwright install --with-deps chromium
if: steps.playwright-cache.outputs.cache-hit != 'true'
- name: Run visual regression
id: run
env:
EMDASH_VISUAL: "1"
EMDASH_PSEUDO_LOCALE: "1"
run: |
set +e
pnpm exec playwright test visual-regression --reporter=line
code=$?
set -e
echo "exit=$code" >> "$GITHUB_OUTPUT"
echo "Playwright exited with $code"
# Always record PR metadata so the Report workflow can upsert *or* clear
# the sticky comment. Candidate baselines + diff images are added only
# when the regenerated baselines actually differ from the committed ones.
# A non-zero exit alone is not drift: a flaky render can fail the diff
# check on the first pass yet regenerate byte-identical baselines under
# --update-snapshots, and an infra failure exits non-zero without
# regenerating anything. Both leave the snapshots dir git-clean, so we
# decide drift from `git status`, not from the exit code.
- name: Collect result
id: collect
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
RUN_EXIT: ${{ steps.run.outputs.exit }}
SNAP_DIR: e2e/tests/visual-regression.spec.ts-snapshots
run: |
mkdir -p visual-out
echo "$PR_NUMBER" > visual-out/pr-number
echo "$HEAD_SHA" > visual-out/head-sha
if [ "$RUN_EXIT" = "0" ]; then
echo "false" > visual-out/has-drift
echo "has_drift=false" >> "$GITHUB_OUTPUT"
echo "No visual drift."
exit 0
fi
# Copy the diff/actual/expected triptychs Playwright writes on failure.
mkdir -p visual-out/diff
if [ -d test-results ]; then
find test-results -type f \
\( -name '*-diff.png' -o -name '*-actual.png' -o -name '*-expected.png' \) \
-exec cp {} visual-out/diff/ \;
fi
# Regenerate the accepted-state baselines (the candidates the Apply
# workflow commits verbatim on accept). These are Linux/chromium PNGs.
EMDASH_PSEUDO_LOCALE=1 EMDASH_VISUAL=1 pnpm exec playwright test visual-regression --update-snapshots --reporter=line || true
# Real drift == the regeneration changed tracked baselines or added
# new ones. Untracked new files count (bootstrap: a PR that adds a
# page has no committed baseline yet). A clean tree means the failure
# did not correspond to a stable pixel difference -- treat it as flake
# or infra and keep the check green with a warning.
if [ -z "$(git status --porcelain -- "$SNAP_DIR")" ]; then
echo "false" > visual-out/has-drift
echo "has_drift=false" >> "$GITHUB_OUTPUT"
echo "::warning::Visual suite exited non-zero but regenerated baselines are identical to the committed ones (flaky render or infra failure, not a UI diff)."
exit 0
fi
# Stage the candidate baselines for the Report/Apply workflows.
mkdir -p visual-out/candidates
if [ -d "$SNAP_DIR" ]; then
cp -r "$SNAP_DIR/." visual-out/candidates/
fi
echo "true" > visual-out/has-drift
echo "has_drift=true" >> "$GITHUB_OUTPUT"
echo "Visual drift detected — candidates and diff images staged for the Report workflow."
- name: Upload artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: visual-regression
path: visual-out/
retention-days: 7
if-no-files-found: error
# Make the check red so a UI PR gets a visible signal. This does not, by
# itself, block merge -- keep it out of required checks until the false-
# diff rate is near zero, then promote it.
- name: Fail on drift
if: steps.collect.outputs.has_drift == 'true'
run: |
echo "::error::Visual snapshots changed. Review the diff in the sticky comment; a maintainer comments /accept-baselines to accept the new baselines."
exit 1