QA Visual como Etapa del Pipeline de CI
Fusioné un PR el mes pasado. La revisión de código se veía bien. Los tests pasaron. Luego abrí el sitio en mi teléfono y la barra lateral estaba completamente rota.
La solución fue trivial—faltaba una media query. El bug era obvio una vez que realmente mirabas la vista móvil. Nadie lo hizo.
Así que añadí una etapa del pipeline que mira.
Abro un issue de GitHub que dice:
Implementar la opción de Entrada Manual para añadir clientes. Al hacer clic, abre un drawer deslizante ancho con un formulario para crear un nuevo cliente.
Un commit después, el PR llega con más de 30 capturas de pantalla que prueban que cada estado funciona en cada viewport. Cero pruebas manuales. El único esfuerzo fue escribir la descripción de la funcionalidad.
El Concepto
En cada push a un PR, un workflow de GitHub Actions:
- Inicia un stack de Docker Compose (Django + Postgres) desde la rama del PR
- Ejecuta migraciones e inserta un usuario de prueba
- Entrega la URL local a Claude Code con Playwright MCP (Chromium headless)
- Ejercita elementos interactivos basándose en el diff del PR
- Captura cada estado en tres viewports
- Publica los resultados como comentario del PR
Claude Code controla el navegador. Docker Compose proporciona la aplicación. GitHub Actions lo une todo. Los revisores ven pruebas de funcionalidad sin ejecutar nada localmente.
%%{init: {"flowchart": {"subGraphTitleMargin": {"top": 3, "bottom": 10}}} }%%
graph TD
A["Push al PR"] --> B
subgraph GHA["GitHub Actions Runner"]
B["Checkout + Docker Compose"] --> C["Migraciones + Datos de Prueba"]
C --> Agent
subgraph Agent["Claude Code + Playwright"]
direction LR
D["Leer Diff del PR"] --> E["Mapear Archivos → URLs"]
E --> F["Login + Navegar"]
F --> G["Captura ×3 Viewports"]
end
end
Agent --> H["Comentario del PR"]
style GHA fill:transparent,stroke:#888
style Agent fill:transparent,stroke:#888
El workflow en sí es directo:
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
# ... Configuración de Docker Compose, migraciones, creación de usuario de prueba ...
- 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
La Matriz de Viewports
| Dispositivo | Tamaño | Por Qué |
|---|---|---|
| Escritorio | 1440×900 | Laptop estándar |
| Tablet | 1024×768 | iPad retrato |
| Móvil | 640×1136 | iPhone SE |
Cada estado interactivo se captura en los tres. Un componente de barra lateral genera más de 12 capturas de pantalla:
- Carga de página (cerrado) — 3 viewports
- Click del trigger — 3 viewports
- Completamente abierto — 3 viewports
- Animación de cierre — 3 viewports
Multiplica por temas claro/oscuro y estás mirando 24 capturas de pantalla para un componente. Ese es el punto. Prueba visual exhaustiva como artefacto de CI.
Lo Que Realmente Produce
Aquí está la salida real de un PR que añadió una página de entrada manual. El agente publica un comentario del PR con un resumen estructurado, capturas de pantalla en cada viewport, y una lista de verificación de tests:

Debajo de ese resumen, el agente agrega capturas de pantalla de cada estado que ejercitó. Aquí está la vista de escritorio—lista de clientes con datos, más el drawer de Añadir Cliente abierto:

El agente probó:
- Estado de formulario vacío
- Formulario con errores de validación (falta el campo de nombre requerido)
- Envío exitoso del formulario
- Renderizado de lista de clientes con datos
- Fallbacks de avatar cuando no hay imagen
- Transiciones de abrir/cerrar modal
- Los tres viewports
Omití estados individuales de enfoque de campo para este PR—rendimientos decrecientes en un formulario simple. El agente puede hacerlo, pero 50 capturas de pantalla de inputs de texto recibiendo enfoque no es señal útil.
El comentario del PR se convierte en un registro de cambios visual. Cada ejecución de prueba termina con una lista de verificación:

Seis meses después, puedo mirar cualquier PR y ver exactamente cómo se veía la UI cuando se desplegó.
El Manifiesto de Pruebas
El prompt en el workflow arriba es genérico — funciona para cualquier PR. La especificidad viene del diff mismo. El agente lee gh pr diff, descubre qué plantillas y vistas cambiaron, mapea esas a URLs, y decide qué probar.
Para un componente de formulario, eso significa que ejercitará:
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
No se necesita plan de prueba manual. El agente infiere la superficie de prueba de los cambios de código.
Por Qué Capturas de Pantalla en Comentarios de PR
Las capturas de pantalla en línea en el comentario del PR tienen algunas ventajas:
- Visibles — los revisores las ven sin hacer clic en artefactos
- Contextuales — justo al lado del diff que están revisando
- Comparables — cada push actualiza el comentario, así que ves antes/después
- Auditables — el historial de comentarios muestra qué se probó en cada commit
Qué Captura Esto
Bugs reales capturados en la primera semana:
- Dropdown recortado por padre con
overflow: hidden(solo visible en tablet) - Texto de botón invisible en modo oscuro (variable CSS incorrecta)
- Etiquetas de formulario desalineadas en iPhone (problema de flexbox gap)
- Estado hover atascado después de touch (necesitaba
@media (hover: hover)) - Fondo del modal no cubriendo el viewport completo en tablet horizontal
Cada uno de estos pasó la revisión de código. Cada uno era obvio en las capturas de pantalla.
El Costo
Ejecutar Claude con Playwright MCP en CI toma 2-4 minutos dependiendo de cuántos estados necesitan pruebas. Para un PR típico tocando un componente, son alrededor de 90 segundos.
Compara con: desplegar a producción y enterarse por los usuarios que el layout móvil está roto. No tiene precio.
El Cambio
El QA visual siempre ha sido el cuello de botella. Puedes automatizar tests unitarios, tests de integración, incluso flujos end-to-end — pero alguien todavía tiene que mirar la UI. Eso ha sido cierto durante décadas.
Ya no es cierto. Los agentes con navegadores no solo ejecutan scripts. Interpretan, navegan, interactúan y juzgan. La superficie de prueba no está codificada — se infiere del cambio. Cada PR obtiene cobertura visual exhaustiva que ningún proceso manual podría igualar.
Esto cambia QE de una puerta a una garantía. No “¿alguien lo revisó?” sino “el pipeline lo revisó, aquí está la prueba”. Cada PR, cada push, cada viewport. El rol de QE no desaparece. Se mueve upstream. En lugar de ejecutar planes de prueba, estás definiendo qué debería importarle al agente. En lugar de capturar bugs, estás diseñando el sistema que los captura.