-
Notifications
You must be signed in to change notification settings - Fork 20
154 lines (127 loc) · 5.15 KB
/
Copy pathvisual-regression.yml
File metadata and controls
154 lines (127 loc) · 5.15 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
150
151
152
153
154
name: Visual Regression
on:
pull_request:
branches: [main]
paths:
- "src/**"
- "tests/visual/**"
- ".github/workflows/visual-regression.yml"
concurrency:
group: visual-regression-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
env:
NODE_VERSION: 20
jobs:
visual-regression:
name: Visual Regression Tests
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install chromium --with-deps
- name: Build app
run: npm run build
- name: Start dev server
run: npm run dev &
env:
CI: true
- name: Wait for server
run: npx wait-on http://localhost:3000 --timeout 120000
- name: Run visual regression tests
id: visual
run: npx playwright test --config=playwright.visual.config.ts --workers=50%
continue-on-error: true
- name: Generate visual report
if: always()
run: |
npx tsx -e "
const { collectEntries, generateReport } = require('./tests/visual/reportGenerator');
const fs = require('node:fs');
const entries = collectEntries();
const html = generateReport(entries);
fs.writeFileSync('visual-report.html', html);
// Write a machine-readable summary to a temp file for the PR comment step
const summary = { pass: 0, fail: 0, skip: 0, entries: [] as Record<string,unknown>[] };
for (const e of entries) {
if (e.status === 'fail') summary.fail++;
else if (e.status === 'pass') summary.pass++;
else if (e.status === 'skip') summary.skip++;
summary.entries.push({ route: e.route, viewport: e.viewport, diffRatio: (e.diffRatio * 100).toFixed(3), status: e.status });
}
fs.writeFileSync('visual-summary.json', JSON.stringify(summary));
console.log('Report and summary generated.');
"
- name: Upload diff artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: visual-diffs
path: tests/visual/diffs/
retention-days: 30
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v4
with:
name: visual-screenshots
path: tests/visual/results/
retention-days: 30
- name: Upload HTML report
if: always()
uses: actions/upload-artifact@v4
with:
name: visual-report
path: visual-report.html
retention-days: 30
- name: Post PR comment
if: github.event_name == 'pull_request' && always()
continue-on-error: true
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ ! -f visual-summary.json ]; then
echo "No visual-summary.json found — skipping PR comment."
exit 0
fi
SUMMARY_FILE="visual-pr-comment.md"
echo "## 🖼️ Visual Regression Results" > $SUMMARY_FILE
echo "" >> $SUMMARY_FILE
echo "| Route / Component | Viewport | Diff Ratio | Status |" >> $SUMMARY_FILE
echo "|---|---|---|---|" >> $SUMMARY_FILE
npx tsx -e "
const fs = require('node:fs');
const data = JSON.parse(fs.readFileSync('visual-summary.json', 'utf8'));
for (const e of data.entries) {
const icon = e.status === 'pass' ? '✅' : e.status === 'fail' ? '❌' : '⚠️';
console.log('| ' + e.route + ' | ' + e.viewport + ' | ' + e.diffRatio + '% | ' + icon + ' ' + e.status.toUpperCase() + ' |');
}
// Output totals as a special key-value format
console.log('__TOTALS__pass=' + data.pass + ',fail=' + data.fail + ',skip=' + data.skip);
" > /tmp/visual-table.md
# Extract totals line and table content
TOTALS=$(grep '__TOTALS__' /tmp/visual-table.md | head -1)
grep -v '__TOTALS__' /tmp/visual-table.md >> $SUMMARY_FILE
# Parse totals
PASS=$(echo "$TOTALS" | sed -n 's/.*pass=\([0-9]*\).*/\1/p')
FAIL=$(echo "$TOTALS" | sed -n 's/.*fail=\([0-9]*\).*/\1/p')
SKIP=$(echo "$TOTALS" | sed -n 's/.*skip=\([0-9]*\).*/\1/p')
echo "" >> $SUMMARY_FILE
echo "📊 **Summary:** ${PASS:-0} passed, ${FAIL:-0} failed, ${SKIP:-0} skipped" >> $SUMMARY_FILE
echo "" >> $SUMMARY_FILE
echo "📎 [View workflow artifacts](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $SUMMARY_FILE
gh pr comment ${{ github.event.pull_request.number }} --body-file $SUMMARY_FILE || echo "Could not post PR comment (may be a fork PR)."
- name: Stop dev server
if: always()
run: kill $(lsof -t -i:3000) 2>/dev/null || true
- name: Fail on visual regressions
if: steps.visual.outcome == 'failure'
run: exit 1