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:

  1. Inicia un stack de Docker Compose (Django + Postgres) desde la rama del PR
  2. Ejecuta migraciones e inserta un usuario de prueba
  3. Entrega la URL local a Claude Code con Playwright MCP (Chromium headless)
  4. Ejercita elementos interactivos basándose en el diff del PR
  5. Captura cada estado en tres viewports
  6. 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

DispositivoTamañoPor Qué
Escritorio1440×900Laptop estándar
Tablet1024×768iPad retrato
Móvil640×1136iPhone SE

Cada estado interactivo se captura en los tres. Un componente de barra lateral genera más de 12 capturas de pantalla:

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:

Issue de GitHub creado por el agente de QA visual

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:

Vista de escritorio: lista de clientes y drawer de Añadir Cliente en 1440x900

El agente probó:

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:

Lista de verificación de Pruebas Realizadas con todos los elementos pasando

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:

  1. Visibles — los revisores las ven sin hacer clic en artefactos
  2. Contextuales — justo al lado del diff que están revisando
  3. Comparables — cada push actualiza el comentario, así que ves antes/después
  4. Auditables — el historial de comentarios muestra qué se probó en cada commit

Qué Captura Esto

Bugs reales capturados en la primera semana:

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.