Visuelle QA als CI-Pipeline-Stufe
Ich habe letzten Monat einen PR gemergt. Das Code-Review sah gut aus. Tests bestanden. Dann öffnete ich die Seite auf meinem Handy und die Seitenleiste war komplett kaputt.
Die Lösung war trivial—eine fehlende Media Query. Der Bug war offensichtlich, sobald man sich tatsächlich die mobile Ansicht ansah. Niemand tat es.
Also fügte ich eine Pipeline-Stufe hinzu, die hinschaut.
Ich öffne ein GitHub-Issue, das sagt:
Implementiere die Option Manuelle Eingabe zum Hinzufügen von Clients. Beim Klicken öffnet sich ein breites Slide-over-Drawer mit einem Formular zum Erstellen eines neuen Clients.
Einen Commit später landet der PR mit über 30 Screenshots, die beweisen, dass jeder Zustand in jedem Viewport funktioniert. Null manuelles Testen. Der einzige Aufwand war das Schreiben der Feature-Beschreibung.
Das Konzept
Bei jedem Push zu einem PR führt ein GitHub Actions Workflow aus:
- Startet einen Docker Compose Stack (Django + Postgres) vom PR-Branch
- Führt Migrationen aus und erstellt einen Testbenutzer
- Übergibt die lokale URL an Claude Code mit Playwright MCP (headless Chromium)
- Testet interaktive Elemente basierend auf dem PR-Diff
- Erstellt Screenshots jedes Zustands in drei Viewports
- Postet die Ergebnisse als PR-Kommentar
Claude Code steuert den Browser. Docker Compose stellt die App bereit. GitHub Actions verbindet alles. Reviewer sehen Funktionsnachweise, ohne lokal etwas auszuführen.
%%{init: {"flowchart": {"subGraphTitleMargin": {"top": 3, "bottom": 10}}} }%%
graph TD
A["PR Push"] --> B
subgraph GHA["GitHub Actions Runner"]
B["Checkout + Docker Compose"] --> C["Migrationen + Test-Daten"]
C --> Agent
subgraph Agent["Claude Code + Playwright"]
direction LR
D["PR Diff lesen"] --> E["Dateien → URLs mappen"]
E --> F["Login + Navigation"]
F --> G["Screenshot ×3 Viewports"]
end
end
Agent --> H["PR-Kommentar"]
style GHA fill:transparent,stroke:#888
style Agent fill:transparent,stroke:#888
Der Workflow selbst ist unkompliziert:
name: UI Screenshots
on:
pull_request:
types: [opened, synchronize]
jobs:
screenshots:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
# ... Docker Compose Setup, Migrationen, Testbenutzer-Erstellung ...
- name: Start services
run: |
docker compose -f docker-compose.local.yml up -d --wait
- name: Install Playwright
run: npx playwright install --with-deps chromium
- name: Run Claude for Screenshots
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
claude_args: >-
--allowed-tools
"mcp__playwright__*,
Bash(gh pr diff:*),
Bash(gh pr comment:*),
Read,Glob,Grep"
prompt: |
You are a visual QA agent. Your job is to visually
verify a UI deployment.
PR: ${{ github.event.pull_request.number }}
The Django app is running at http://localhost:8001
1. Run `gh pr diff` to find changed templates/views
2. Map changed files to URLs — only test pages
affected by this push
3. Login, then screenshot each page at three viewports:
1440x900, 1024x768, 640x1136
4. Save screenshots with descriptive filenames
5. Post a PR comment with:
- Each test performed with pass/fail
- Any visual issues found
- Total screenshots captured
Die Viewport-Matrix
| Gerät | Größe | Warum |
|---|---|---|
| Desktop | 1440×900 | Standard-Laptop |
| Tablet | 1024×768 | iPad Hochformat |
| Mobil | 640×1136 | iPhone SE |
Jeder interaktive Zustand wird in allen drei erfasst. Eine Seitenleisten-Komponente erzeugt 12+ Screenshots:
- Seitenladen (geschlossen) — 3 Viewports
- Trigger-Klick — 3 Viewports
- Vollständig geöffnet — 3 Viewports
- Schließ-Animation — 3 Viewports
Multipliziert mit hellen/dunklen Themes schauen Sie auf 24 Screenshots für eine Komponente. Das ist der Punkt. Erschöpfender visueller Nachweis als CI-Artefakt.
Was Es Tatsächlich Ausgibt
Hier ist echte Ausgabe von einem PR, der eine manuelle Eingabeseite hinzufügte. Der Agent postet einen PR-Kommentar mit einer strukturierten Zusammenfassung, Screenshots in jedem Viewport und einer Test-Checkliste:

Unter dieser Zusammenfassung fügt der Agent Screenshots jedes getesteten Zustands hinzu. Hier ist die Desktop-Ansicht—Client-Liste mit Daten, plus geöffnetes Client-Hinzufügen-Drawer:

Der Agent testete:
- Leerer Formular-Zustand
- Formular mit Validierungsfehlern (fehlendes erforderliches Namensfeld)
- Erfolgreiche Formular-Übermittlung
- Client-Listen-Rendering mit Daten
- Avatar-Fallbacks ohne Bild
- Modal-Öffnen/Schließen-Übergänge
- Alle drei Viewports
Ich übersprung einzelne Feld-Fokus-Zustände für diesen PR—abnehmende Erträge bei einem einfachen Formular. Der Agent kann es tun, aber 50 Screenshots von Texteingaben, die Fokus erhalten, sind kein nützliches Signal.
Der PR-Kommentar wird zu einem visuellen Changelog. Jeder Testlauf endet mit einer Checkliste:

In sechs Monaten kann ich jeden PR anschauen und genau sehen, wie die UI aussah, als sie ausgeliefert wurde.
Das Test-Manifest
Der Prompt im obigen Workflow ist generisch — er funktioniert für jeden PR. Die Spezifität kommt vom Diff selbst. Der Agent liest gh pr diff, findet heraus, welche Templates und Views sich geändert haben, mappt diese zu URLs und entscheidet, was zu testen ist.
Für eine Formular-Komponente bedeutet das, er wird testen:
component: ClientForm
states:
- empty form
- filled form (valid data)
- validation error (submit without name)
- submitting (loading state)
- success (confirmation)
interactions:
- submit empty form (trigger validation)
- fill all fields, submit
- verify client appears in list after submit
Kein manueller Testplan nötig. Der Agent leitet die Testoberfläche aus den Code-Änderungen ab.
Warum Screenshots in PR-Kommentaren
Inline-Screenshots im PR-Kommentar haben einige Vorteile:
- Sichtbar — Reviewer sehen sie ohne zu Artefakten durchzuklicken
- Kontextuell — direkt neben dem Diff, den sie reviewen
- Vergleichbar — jeder Push aktualisiert den Kommentar, sodass Sie vorher/nachher sehen
- Auditierbar — die Kommentarhistorie zeigt, was bei jedem Commit getestet wurde
Was Das Fängt
Echte Bugs in der ersten Woche gefangen:
- Dropdown durch
overflow: hiddenElternteil abgeschnitten (nur auf Tablet sichtbar) - Button-Text im Dark Mode unsichtbar (falsche CSS-Variable)
- Formular-Labels auf iPhone falsch ausgerichtet (Flexbox-Gap-Problem)
- Hover-Zustand nach Touch hängen geblieben (brauchte
@media (hover: hover)) - Modal-Hintergrund deckt nicht den vollständigen Viewport auf Landscape-Tablet ab
Jeder davon bestand das Code-Review. Jeder war in den Screenshots offensichtlich.
Die Kosten
Claude mit Playwright MCP in CI auszuführen dauert 2-4 Minuten, abhängig davon, wie viele Zustände getestet werden müssen. Für einen typischen PR, der eine Komponente berührt, sind es etwa 90 Sekunden.
Vergleichen Sie mit: in Produktion deployen und von Benutzern erfahren, dass das mobile Layout kaputt ist. Unbezahlbar.
Die Verschiebung
Visuelle QA war immer der Engpass. Sie können Unit-Tests automatisieren, Integrationstests, sogar End-to-End-Flows — aber jemand muss immer noch auf die UI schauen. Das war jahrzehntelang wahr.
Es ist nicht mehr wahr. Agenten mit Browsern führen nicht nur Skripte aus. Sie interpretieren, navigieren, interagieren und beurteilen. Die Testoberfläche ist nicht hardcodiert — sie wird aus der Änderung abgeleitet. Jeder PR erhält erschöpfende visuelle Abdeckung, die kein manueller Prozess erreichen könnte.
Dies ändert QE von einem Tor zu einer Garantie. Nicht “hat es jemand überprüft”, sondern “die Pipeline hat es überprüft, hier ist der Beweis”. Jeder PR, jeder Push, jeder Viewport. Die QE-Rolle verschwindet nicht. Sie bewegt sich upstream. Anstatt Testpläne auszuführen, definieren Sie, was dem Agenten wichtig sein sollte. Anstatt Bugs zu fangen, entwerfen Sie das System, das sie fängt.