From 7c7462646423041b9ae0a6b850789ae0e90b9198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 20:10:03 +0200 Subject: [PATCH] Post visual diff images as PR comment on failure When visual tests fail on a PR, upload each diff PNG to GitHub's CDN via the issue assets endpoint and post a comment with the images embedded inline. Also fixes the artifact upload path to point at .vitest-attachments/ where the actual/diff files live. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 61fa59e..545de4e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -138,14 +138,48 @@ jobs: run: pnpm exec playwright install-deps chromium - name: Run visual regression tests + id: visual-tests run: pnpm --filter @trails-cool/planner test:visual + - name: Post diff comment on PR + if: failure() && steps.visual-tests.outcome == 'failure' && github.event_name == 'pull_request' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + diffs=$(find apps/planner/.vitest-attachments -name "*-diff-*.png" 2>/dev/null | sort) + if [ -z "$diffs" ]; then exit 0; fi + + body="## Visual regression failures"$'\n\n' + body+="| Test | Diff (reference → actual) |"$'\n' + body+="|------|--------------------------|"$'\n' + + for diff in $diffs; do + # Upload image to GitHub's CDN via the issue assets endpoint + response=$(curl -sf -X POST \ + -H "Authorization: Bearer $GH_TOKEN" \ + -H "Content-Type: image/png" \ + -H "Accept: application/json" \ + --data-binary @"$diff" \ + "https://uploads.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/assets?name=$(basename $diff)") + url=$(echo "$response" | jq -r '.url // empty') + name=$(basename "$diff" | sed 's/-diff-chromium-linux\.png//' | sed 's/-/ /g') + if [ -n "$url" ]; then + body+="| \`$name\` | ![$name]($url) |"$'\n' + else + body+="| \`$name\` | *(upload failed)* |"$'\n' + fi + done + + body+=$'\n'"Run \`pnpm --filter @trails-cool/planner test:visual:update\` to regenerate snapshots if the change is intentional." + + gh pr comment ${{ github.event.pull_request.number }} --body "$body" + - name: Upload screenshots on failure if: failure() uses: actions/upload-artifact@v7 with: name: visual-snapshots-diff - path: apps/planner/app/**/__screenshots__/ + path: apps/planner/.vitest-attachments/ retention-days: 7 e2e: