> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Détectez les régressions visuelles avant chaque PR

export const UseCaseHero = ({title, description, prompt, category, features, devinUrl, agent, intent, playbookId, type}) => {
  const encodedPrompt = encodeURIComponent(prompt || '');
  const tag = 'docs-use-case-gallery';
  const utm = 'utm_source=docs&utm_medium=use-case-gallery&utm_campaign=hero-cta';
  const agentParams = (agent ? '&agent=' + agent : '') + (intent ? '&intent=' + intent : '') + (playbookId ? '&playbookId=' + playbookId : '');
  const devinHref = type === 'schedule' ? 'https://app.devin.ai/settings/schedules/create?' + utm + agentParams + (prompt ? '&prompt=' + encodedPrompt : '') : type === 'review' ? 'https://app.devin.ai/review?' + utm : agent === 'ada' ? 'https://app.devin.ai/search?' + utm + '&noSubmit=true' + (prompt ? '&prompt=' + encodedPrompt : '') : devinUrl ? devinUrl.includes('?') ? devinUrl + '&' + utm + agentParams : devinUrl + '?' + utm + agentParams : prompt ? 'https://app.devin.ai/?tags=' + tag + '&' + utm + agentParams + '&prompt=' + encodedPrompt : 'https://app.devin.ai/?' + utm + agentParams;
  const buttonLabel = type === 'schedule' ? 'Schedule in Devin ↗' : type === 'review' ? 'Set Up Devin Review ↗' : agent === 'advanced' ? 'Try in Devin ↗' : agent === 'dana' ? 'Try in Dana ↗' : agent === 'ada' ? 'Try in Ask Devin ↗' : 'Try in Devin ↗';
  const featureList = features ? features.split(',').map(f => f.trim()) : [];
  return <div className="uc-hero">
      <div className="uc-hero-inner">
        <div className="uc-hero-left">
          <h1 className="uc-hero-title">{title}</h1>
          <p className="uc-hero-desc">{description}</p>
          <div>
            <a href={devinHref} target="_blank" rel="noopener noreferrer" className="try-in-devin-btn">
              {buttonLabel}
            </a>
          </div>
        </div>
        <div className="uc-hero-meta">
          <div className="uc-meta-item">
            <span className="uc-meta-label">Author</span>
            <span className="uc-meta-value">Cognition</span>
          </div>
          <div className="uc-meta-item">
            <span className="uc-meta-label">Category</span>
            <span className="uc-meta-value">{category}</span>
          </div>
          {featureList.length > 0 && <div className="uc-meta-item">
              <span className="uc-meta-label">Features</span>
              <span className="uc-meta-value">{featureList.join(', ')}</span>
            </div>}
        </div>
      </div>
    </div>;
};

export const PromptBlock = ({children, type, agent, intent, playbookId}) => {
  var utm = 'utm_source=docs&utm_medium=use-case-gallery&utm_campaign=prompt-block';
  var tag = 'docs-use-case-gallery';
  var agentParams = (agent ? '&agent=' + agent : '') + (intent ? '&intent=' + intent : '') + (playbookId ? '&playbookId=' + playbookId : '');
  var label = type === 'schedule' ? 'Schedule in Devin' : type === 'playbook' ? 'Create Playbook' : type === 'knowledge' ? 'Add to Knowledge' : agent === 'advanced' ? 'Try in Devin' : agent === 'dana' ? 'Try in Dana' : agent === 'ada' ? 'Try in Ask Devin' : 'Try in Devin';
  var buildUrl = function (text) {
    var encoded = encodeURIComponent(text);
    if (type === 'schedule') return 'https://app.devin.ai/settings/schedules/create?' + utm + agentParams + '&prompt=' + encoded;
    if (type === 'playbook') return 'https://app.devin.ai/settings/playbooks/create?' + utm + '&body=' + encoded;
    if (type === 'knowledge') return 'https://app.devin.ai/knowledge?' + utm + '&body=' + encoded;
    if (agent === 'ada') return 'https://app.devin.ai/search?' + utm + '&noSubmit=true&prompt=' + encoded;
    return 'https://app.devin.ai/?tags=' + tag + '&' + utm + agentParams + '&prompt=' + encoded;
  };
  const ref = React.useRef(null);
  const [href, setHref] = React.useState('#');
  React.useEffect(() => {
    if (!ref.current) return;
    var codeEl = ref.current.querySelector('pre code');
    if (codeEl) {
      var text = codeEl.textContent.trim();
      if (text) setHref(buildUrl(text));
    }
    var header = ref.current.querySelector('[data-component-part="code-block-header"]');
    if (header && !header.querySelector('.prompt-block-devin-link')) {
      var link = document.createElement('a');
      link.href = href;
      link.target = '_blank';
      link.rel = 'noopener noreferrer';
      link.className = 'prompt-block-devin-link';
      link.style.cssText = 'display:inline-flex;align-items:center;gap:6px;text-decoration:none;color:#fff;font-size:11px;font-weight:500;padding:4px 10px;border-radius:6px;white-space:nowrap;background:#317CFF;transition:background 0.2s;margin-left:8px;';
      link.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg> ' + label;
      link.onmouseenter = function () {
        link.style.background = '#2968D9';
      };
      link.onmouseleave = function () {
        link.style.background = '#317CFF';
      };
      header.appendChild(link);
    }
    var existingLink = ref.current.querySelector('.prompt-block-devin-link');
    if (existingLink && href !== '#') existingLink.href = href;
  });
  return <div className="prompt-block" ref={ref}>{children}</div>;
};

<UseCaseHero title="Détecter les régressions visuelles avant chaque PR" description="Une compétence de dépôt qui demande à Devin de prendre une capture d’écran de chaque page concernée et de signaler toute casse de mise en page avant d’ouvrir une PR." prompt="Crée une compétence de dépôt dans .agents/skills/visual-regression/visual-regression.md qui indique à Devin comment lancer notre application Next.js, parcourir chaque page affectée par le diff en cours, prendre des captures d’écran aux résolutions desktop et mobile, et signaler tout problème de mise en page — avant d’ouvrir une PR." category="Développement de fonctionnalités" features="Compétences" />

<div className="uc-detail-wrapper">
  <Tip>Vous ne souhaitez pas effectuer cette configuration manuellement ? Collez un lien vers cette page dans une session Devin et demandez-lui de tout configurer pour vous.</Tip>

  <Steps>
    <Step title="Le problème : les bugs CSS échappent aux tests unitaires">
      Votre suite de tests réussit, la CI est au vert et la PR est fusionnée — mais la page de paramètres affiche désormais du texte qui se chevauche sur mobile, et le bouton de validation de commande a disparu derrière un pied de page. Les tests unitaires et les linters ne détectent pas les régressions visuelles, donc le code est déployé en production et un client le signale.

      Une compétence de dépôt résout ce problème. Les compétences sont des fichiers Markdown que vous validez dans `.agents/skills/<your-skill>/` dans n’importe lequel de vos dépôts. Devin voit toutes les compétences dans l’ensemble des dépôts connectés — vous pouvez les déclencher manuellement, ou Devin peut choisir de les déclencher automatiquement lorsqu’il détecte une situation pertinente. Cette compétence indique à Devin exactement comment démarrer votre application, naviguer vers les pages affectées par le diff et en faire des captures d’écran à plusieurs largeurs de viewport — à chaque fois, avant chaque PR.
    </Step>

    <Step title="Ajoutez la compétence « visual-regression » à votre dépôt">
      Effectuez un commit d’un fichier à l’emplacement `.agents/skills/visual-regression/visual-regression.md` qui décrit la checklist de QA manuelle de votre équipe sous forme d’étapes que Devin peut suivre :

      ```markdown theme={null}
      # Vérification de régression visuelle

      ## Description
      Avant d'ouvrir toute pull request (PR), démarrez l'application localement et prenez une capture d'écran de chaque
      page affectée par le diff actuel aux largeurs bureau et mobile.
      Signalez tout problème de mise en page détecté.

      ## Prérequis
      - Docker en cours d'exécution (pour la base de données)
      - Port 3000 disponible

      ## Configuration
      1. Installer les dépendances : `npm install`
      2. Démarrer les services : `docker-compose up -d postgres redis`
      3. Exécuter les migrations : `npx prisma migrate dev`
      4. Initialiser les données de test : `npm run db:seed`
      5. Démarrer le serveur de développement : `npm run dev`
      6. Attendre l'affichage de "Ready on http://localhost:3000" dans le terminal

      ## Vérifications visuelles
      1. Lire le diff git actuel pour identifier les pages affectées
      2. Pour chaque page affectée :
         a. Ouvrir la page dans le navigateur à l'adresse http://localhost:3000/{route}
         b. Capturer à une largeur de 1280 px (bureau)
         c. Redimensionner le navigateur à une largeur de 375 px (mobile)
         d. Capturer à la largeur mobile
         e. Vérifier : chevauchement de texte, éléments masqués derrière d'autres
            éléments, défilement horizontal, boutons ou liens
            inaccessibles, images ou icônes manquantes, erreurs console
      3. Si un problème est détecté, le lister avec l'URL de la page, la largeur
         de la fenêtre d'affichage et une description du problème

      ## Avant d'ouvrir la PR
      1. Exécuter `npm run lint` et corriger les problèmes éventuels
      2. Exécuter `npm test` et confirmer que tous les tests passent
      3. Inclure toutes les captures d'écran dans la description de la PR
      4. Si des problèmes ont été détectés, les lister en haut du corps de la PR
      ```

      Ce fichier est livré avec votre code. Une fois validé, Devin le considère comme une compétence disponible : dès qu'une session interagit avec des fichiers d'interface utilisateur dans ce dépôt, Devin peut déclencher automatiquement les vérifications de régression visuelle, ou vous pouvez les lancer manuellement à tout moment.
    </Step>

    <Step title="Adaptez les contrôles à vos pages">
      Des instructions génériques comme « vérifie que la page s’affiche correctement » produisent des résultats vagues. L’aspect le plus important de cette compétence consiste à dire à Devin à quoi doit ressembler le comportement correct pour chaque partie de votre application.

      Ajoutez à votre compétence des sections spécifiques à chaque route :

      ```markdown theme={null}
      ## Route-Specific Checks

      ### Dashboard (`/dashboard`)
      - The metric cards should display in a 3-column grid on desktop
      - Cards should stack to a single column on mobile
      - The chart should be fully visible without horizontal scroll

      ### Checkout (`/checkout`)
      - The "Place Order" button must be visible without scrolling
        on both desktop and mobile
      - The order summary sidebar should collapse into an accordion on mobile
      - The price breakdown should show subtotal, tax, and total on separate lines

      ### Settings (`/settings`)
      - All form labels should be left-aligned with their inputs
      - The "Save" button must be reachable at the bottom of the form
      - Tab navigation between sections should update the URL hash
      ```

      Devin analyse le diff, identifie quelles routes ont été modifiées et se reporte à la section correspondante ; ainsi, les vérifications sont ciblées plutôt que génériques.
    </Step>

    <Step title="Regardez-le détecter une véritable régression">
      Supposons qu’un ingénieur modifie la grille CSS du tableau de bord en passant de `grid-template-columns: repeat(3, 1fr)` à `repeat(auto-fit, minmax(200px, 1fr))` pour rendre la mise en page responsive. Les tests unitaires passent — aucune logique n’a changé. Mais sur mobile, les cartes débordent désormais du viewport.

      Quand Devin termine la modification de code, il suit automatiquement cette procédure :

      1. **Démarre l’application** — installe les dépendances, lance Docker, exécute les migrations, insère les données, démarre le serveur de développement
      2. **Lit le diff** — voit que `src/components/Dashboard.tsx` a changé, l’associe à la route `/dashboard`
      3. **Fait des captures d’écran à 1280px** — la grille à 3 colonnes s’affiche correctement
      4. **Fait des captures d’écran à 375px** — repère un débordement horizontal : les cartes ne tiennent pas dans le viewport
      5. **Signale le problème** — indique « Horizontal scroll detected on /dashboard at 375px width — metric cards overflow the viewport »
      6. **Corrige le CSS** — ajoute `overflow-x: hidden` et ajuste le minimum de `minmax` à `150px`
      7. **Refait des captures d’écran** — confirme la correction aux deux largeurs
      8. **Ouvre la PR** — inclut des captures avant/après et la correction dans la description

      Vous pouvez observer cela en temps réel via l’onglet du navigateur dans votre [espace de travail de session](/fr/work-with-devin/devin-session-tools).
    </Step>

    <Step title="Extensions pour votre stack">
      Adaptez la compétence pour intégrer des outils supplémentaires et des étapes de vérification spécifiques à votre projet :

      <PromptBlock>
        ```txt Ajouter des vérifications de composants Storybook theme={null}
        Mettez à jour la compétence de régression visuelle pour qu’elle exécute aussi
        `npm run storybook`, ouvre http://localhost:6006 et prenne une capture d’écran
        de chaque story pour les composants modifiés dans le diff en cours. Signalez
        toute story présentant une erreur de rendu ou une zone d’affichage vide.
        ```
      </PromptBlock>

      <PromptBlock>
        ```txt Ajouter une vérification du mode sombre theme={null}
        Mettez à jour la compétence de régression visuelle pour qu’elle bascule aussi
        l’application en mode sombre (cliquez sur le sélecteur de thème en haut à droite)
        et reprenne une capture d’écran de chaque page concernée. Signalez tout texte
        qui devient illisible sur le fond sombre ou tout élément qui perd sa bordure.
        ```
      </PromptBlock>
    </Step>
  </Steps>
</div>
