QA Visuelle comme Étape du Pipeline CI

J’ai fusionné une PR le mois dernier. La revue de code était bonne. Les tests ont réussi. Puis j’ai ouvert le site sur mon téléphone et la barre latérale était complètement cassée.

La correction était triviale—une media query manquante. Le bug était évident dès qu’on regardait réellement la vue mobile. Personne ne l’a fait.

Alors j’ai ajouté une étape du pipeline qui regarde.

J’ouvre une issue GitHub qui dit :

Implémenter l’option d’Entrée Manuelle pour ajouter des clients. Lorsqu’elle est cliquée, ouvre un tiroir coulissant large avec un formulaire pour créer un nouveau client.

Un commit plus tard, la PR arrive avec plus de 30 captures d’écran prouvant que chaque état fonctionne dans chaque viewport. Zéro test manuel. Le seul effort a été d’écrire la description de la fonctionnalité.

Le Concept

À chaque push vers une PR, un workflow GitHub Actions :

  1. Démarre une stack Docker Compose (Django + Postgres) depuis la branche de la PR
  2. Exécute les migrations et insère un utilisateur de test
  3. Passe l’URL locale à Claude Code avec Playwright MCP (Chromium headless)
  4. Teste les éléments interactifs en se basant sur le diff de la PR
  5. Capture chaque état dans trois viewports
  6. Publie les résultats comme commentaire de la PR

Claude Code contrôle le navigateur. Docker Compose fournit l’application. GitHub Actions relie le tout. Les réviseurs voient la preuve de la fonctionnalité sans exécuter quoi que ce soit localement.

%%{init: {"flowchart": {"subGraphTitleMargin": {"top": 3, "bottom": 10}}} }%%
graph TD
    A["Push PR"] --> B

    subgraph GHA["GitHub Actions Runner"]
        B["Checkout + Docker Compose"] --> C["Migrations + Données de Test"]
        C --> Agent

        subgraph Agent["Claude Code + Playwright"]
            direction LR
            D["Lire Diff PR"] --> E["Mapper Fichiers → URLs"]
            E --> F["Connexion + Navigation"]
            F --> G["Capture ×3 Viewports"]
        end
    end

    Agent --> H["Commentaire PR"]

    style GHA fill:transparent,stroke:#888
    style Agent fill:transparent,stroke:#888

Le workflow lui-même est simple :

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

      # ... Configuration Docker Compose, migrations, création utilisateur de test ...

      - 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 Matrice de Viewports

AppareilTaillePourquoi
Bureau1440×900Ordinateur portable standard
Tablette1024×768iPad portrait
Mobile640×1136iPhone SE

Chaque état interactif est capturé sur les trois. Un composant de barre latérale génère plus de 12 captures d’écran :

Multipliez par les thèmes clair/sombre et vous regardez 24 captures d’écran pour un composant. C’est le but. Preuve visuelle exhaustive comme artefact CI.

Ce Que Ça Produit Réellement

Voici la sortie réelle d’une PR qui a ajouté une page d’entrée manuelle. L’agent publie un commentaire de PR avec un résumé structuré, des captures d’écran à chaque viewport et une liste de vérification des tests :

Issue GitHub créée par l’agent de QA visuelle

Sous ce résumé, l’agent ajoute des captures d’écran de chaque état qu’il a testé. Voici la vue bureau—liste de clients avec données, plus le tiroir Ajouter Client ouvert :

Vue bureau : liste de clients et tiroir Ajouter Client à 1440x900

L’agent a testé :

J’ai sauté les états de focus des champs individuels pour cette PR—rendements décroissants sur un formulaire simple. L’agent peut le faire, mais 50 captures d’écran d’entrées de texte recevant le focus ne sont pas un signal utile.

Le commentaire de la PR devient un changelog visuel. Chaque exécution de test se termine par une liste de vérification :

Liste de vérification des Tests Effectués avec tous les éléments réussis

Dans six mois, je peux regarder n’importe quelle PR et voir exactement à quoi ressemblait l’UI quand elle a été livrée.

Le Manifeste de Test

Le prompt dans le workflow ci-dessus est générique — il fonctionne pour n’importe quelle PR. La spécificité vient du diff lui-même. L’agent lit gh pr diff, découvre quels templates et vues ont changé, les mappe aux URLs et décide quoi tester.

Pour un composant de formulaire, cela signifie qu’il testera :

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

Aucun plan de test manuel nécessaire. L’agent déduit la surface de test à partir des changements de code.

Pourquoi des Captures d’Écran dans les Commentaires de PR

Les captures d’écran en ligne dans le commentaire de la PR ont quelques avantages :

  1. Visibles — les réviseurs les voient sans cliquer sur les artefacts
  2. Contextuelles — juste à côté du diff qu’ils examinent
  3. Comparables — chaque push met à jour le commentaire, donc vous voyez avant/après
  4. Auditables — l’historique des commentaires montre ce qui a été testé à chaque commit

Ce Que Ça Attrape

Bugs réels attrapés la première semaine :

Chacun d’eux a passé la revue de code. Chacun était évident dans les captures d’écran.

Le Coût

Exécuter Claude avec Playwright MCP en CI prend 2-4 minutes selon le nombre d’états à tester. Pour une PR typique touchant un composant, c’est environ 90 secondes.

Comparez avec : déployer en production et apprendre des utilisateurs que la mise en page mobile est cassée. Inestimable.

Le Changement

La QA visuelle a toujours été le goulot d’étranglement. Vous pouvez automatiser les tests unitaires, les tests d’intégration, même les flux de bout en bout — mais quelqu’un doit toujours regarder l’UI. C’est vrai depuis des décennies.

Ce n’est plus vrai. Les agents avec navigateurs n’exécutent pas seulement des scripts. Ils interprètent, naviguent, interagissent et jugent. La surface de test n’est pas codée en dur — elle est déduite du changement. Chaque PR obtient une couverture visuelle exhaustive qu’aucun processus manuel ne pourrait égaler.

Cela change le QE d’une porte à une garantie. Pas “quelqu’un l’a-t-il vérifié” mais “le pipeline l’a vérifié, voici la preuve”. Chaque PR, chaque push, chaque viewport. Le rôle de QE ne disparaît pas. Il se déplace en amont. Au lieu d’exécuter des plans de test, vous définissez ce dont l’agent devrait se soucier. Au lieu d’attraper des bugs, vous concevez le système qui les attrape.