Détecter les bugs d'interface avec les tests de régression visuelle
Le visual regression testing avec Playwright et Vitest détecte les bugs UI que les tests unitaires et E2E manquent, avec baselines, flakiness et CI.
Les tests de régression visuelle détectent les modifications non intentionnelles de l’interface en affichant votre composant ou votre page dans un navigateur contrôlé, en capturant une capture d’écran et en la comparant pixel par pixel avec une image de référence approuvée — tout écart dépassant un seuil configurable fait échouer le test et signale la modification pour examen humain. Cette approche détecte une catégorie de bugs que les tests unitaires et les tests de bout en bout ne peuvent structurellement pas voir : un bouton qui déclenche correctement son gestionnaire de clic mais qui s’affiche dans la mauvaise couleur, se décale de douze pixels, ou disparaît derrière une superposition modale.
C’est le type de régression qui se glisse dans un refactoring CSS et casse silencieusement la mise en page en production. Vos tests passent, le build est au vert, et c’est un utilisateur qui découvre que le bouton de validation est désormais masqué par une bannière de cookies. Cet article montre comment combler cette lacune avec des outils natifs aux frameworks — les assertions de capture d’écran intégrées à Playwright et les tests visuels en mode navigateur de Vitest — sans service payant, puis aborde le contrôle de la flakiness et la configuration CI qui distinguent une suite utile d’une suite bruyante.
Points clés à retenir
- Les tests de régression visuelle comparent une capture d’écran rendue avec une référence approuvée ; tout écart dépassant un seuil configurable fait échouer le test, détectant les bugs de couleur, de position et de contexte d’empilement que les tests fonctionnels laissent passer.
expect(page).toHaveScreenshot()de Playwright est intégré et gratuit, et il désactive déjà les animations par défaut (animations: 'disabled') et effectue des tentatives automatiques jusqu’à ce que deux captures d’écran consécutives correspondent — inutile d’utiliserwaitForTimeout.- La plupart des cas de flakiness proviennent de quatre sources : les animations CSS, le chargement tardif des polices web, le contenu dynamique, et l’anti-aliasing sous-pixel qui varie selon le GPU et le système d’exploitation — chacun dispose d’un correctif spécifique, pas d’un seuil plus permissif.
- Épinglez votre CI à une image Docker Playwright spécifique (
mcr.microsoft.com/playwright:v1.61.0-noble), car le rendu des polices diffère selon les systèmes d’exploitation et produirait autrement des faux positifs. - Vitest 4.x a ajouté la régression visuelle native via
toMatchScreenshot()dans le mode navigateur stable, offrant aux utilisateurs de Vitest un chemin natif sans quitter leur runner existant.
Qu’est-ce que le test de régression visuelle ?
Le test de régression visuelle est une méthode de test qui compare des captures d’écran d’une page web ou d’un composant d’interface avec une image de référence approuvée pour détecter les modifications visuelles non intentionnelles. Le mécanisme est identique quel que soit l’outil : capturer un rendu connu comme correct une première fois, le stocker comme référence, puis à chaque exécution ultérieure capturer une nouvelle capture d’écran et la comparer à cette référence. Un écart dépassant votre seuil fait échouer le test et signale la modification pour qu’un humain l’approuve ou la rejette.
Cette approche se distingue des tests de snapshot. Un test de snapshot sérialise le balisage rendu d’un composant et compare les textes ; un test de régression visuelle compare les pixels réellement rendus. Les snapshots au niveau du balisage passent à côté de tout ce qui est purement visuel — un changement de z-index, un remplacement de jeton de couleur, une police de substitution — car le DOM sérialisé est identique même lorsque ce que voit l’utilisateur ne l’est pas.
Pourquoi les tests unitaires et E2E manquent-ils les bugs visuels ?
Discover how at OpenReplay.com.
Les tests unitaires vérifient qu’un bouton déclenche son gestionnaire onClick ; les tests E2E vérifient que cliquer dessus complète un parcours ; aucun de ces tests ne peut vous dire que le bouton est de la mauvaise couleur, qu’il s’est décalé de douze pixels vers la droite, ou qu’il est masqué par une superposition modale — c’est la lacune que comblent les tests de régression visuelle. La matrice de couverture rend cette frontière explicite :
| Scénario | Unitaire (Jest/Vitest) | E2E (Playwright/Cypress) | Visuel |
|---|---|---|---|
| Le bouton s’affiche dans le DOM | Oui | Partiel | Oui |
Le bouton déclenche onClick | Oui | Oui | Non |
| Le clic complète le parcours | Non | Oui | Non |
| Le bouton est de la bonne couleur | Non | Non | Oui |
| Le bouton est à la bonne position | Non | Non | Oui |
| Le bouton est masqué par une superposition | Non | Non | Oui |
La dernière ligne est celle qui pose problème en production. Considérez un <CheckoutButton> qui fonctionne parfaitement jusqu’à ce que quelqu’un ajoute un <CookieBanner> dont le contexte d’empilement le recouvre :
// CheckoutButton.tsx
export function CheckoutButton({ onCheckout }: { onCheckout: () => void }) {
return (
<button data-testid="checkout" onClick={onCheckout}>
Complete purchase
</button>
);
}
Un test unitaire vérifiant que le gestionnaire de clic se déclenche passe — JSDOM, l’implémentation du DOM utilisée par défaut par Jest et Vitest, ne calcule pas la mise en page ni les contextes d’empilement, et ne peut donc pas savoir que le bouton est recouvert. Une assertion E2E comme await expect(page.getByTestId('checkout')).toBeVisible() passe également, car Playwright considère un élément visible lorsqu’il possède une boîte englobante non vide et n’est pas en display:none — être recouvert par un élément avec un z-index supérieur ne modifie ni l’un ni l’autre. Bien qu’un locator.click() ultérieur puisse détecter l’obstruction via les vérifications d’actionnabilité de Playwright, une assertion de visibilité seule ne le détectera pas. Un diff de capture d’écran, lui, montre la bannière positionnée par-dessus le bouton.
Comment fonctionnent les tests de régression visuelle ?
Le flux de travail est une boucle en cinq étapes : capturer une référence, exécuter après une modification, comparer la nouvelle capture d’écran avec la référence, examiner le diff, puis soit approuver la modification (mettre à jour la référence) soit la rejeter (corriger le code). Playwright concrétise cela via son flux --update-snapshots.
La première fois que vous exécutez un test contenant toHaveScreenshot(), aucune référence n’existe, donc Playwright écrit une image de référence. Une fois cette référence examinée et commitée, les exécutions suivantes la comparent. Lorsqu’une modification visuelle est intentionnelle — un bouton redessiné, un nouveau jeton de couleur — exécutez npx playwright test --update-snapshots, examinez le diff dans le rapport HTML généré, commitez les fichiers .png mis à jour (Git LFS est une pratique courante pour ces références binaires), et la nouvelle capture d’écran devient la référence ; la prochaine exécution CI la compare. L’option --update-snapshots régénère les images de référence en place.
La discipline essentielle consiste à traiter une mise à jour de référence comme une revue de code, et non comme un simple tampon d’approbation. Une référence mise à jour pour « faire passer le test » sans inspecter le diff est la façon dont une vraie régression devient la nouvelle interface acceptée.
Techniques de comparaison et portée des tests
Les outils de régression visuelle utilisent l’une des quatre techniques de comparaison — pixel par pixel, mise en page, basée sur le DOM, ou assistée par IA — et diffèrent dans la région qu’ils capturent. Le moteur de comparaison :
| Technique | Fonctionnement | Compromis |
|---|---|---|
| Pixel par pixel | Compare chaque pixel ; signale toute différence | Précis mais sensible au bruit de l’anti-aliasing et du lissage des polices ; nécessite des seuils |
| Mise en page | Compare la position, la taille et l’espacement des éléments | Ignore le bruit cosmétique des pixels ; ne détecte pas les changements de couleur/texture |
| Basée sur le DOM | Compare le balisage sérialisé, pas les pixels rendus | Détecte les changements structurels ; aveugle aux bugs purement visuels |
| Assistée par IA | La vision par ordinateur signale uniquement les changements perceptibles par l’humain | Réduit les faux positifs ; disponible dans des outils commerciaux spécifiques |
La portée de la capture est un axe distinct. Les tests au niveau des composants isolent un seul bouton, carte ou modal — moins de bruit, révision plus rapide, idéal pour les design systems et Storybook. Les tests au niveau de la page capturent des écrans complets et détectent les problèmes de mise en page dans des parcours réels, au prix d’un contenu plus dynamique et d’une révision plus lente. Une suite pratique utilise les deux : au niveau des composants pour le design system, au niveau de la page pour les parcours critiques.
Sur la comparaison par IA en particulier, le domaine est souvent mal caractérisé. En juin 2026, la comparaison visuelle basée sur l’IA est l’offre payante principale d’Applitools ; Percy ajoute un triage assisté par IA par-dessus la comparaison pixel, tandis que Chromatic utilise une comparaison pixel et Git plutôt que l’IA — et les outils natifs aux frameworks (Playwright, Vitest browser mode) utilisent la comparaison pixel avec des seuils configurables, ce qui est suffisant pour la plupart des équipes si la flakiness est contrôlée en amont.
Comment configurer les tests de régression visuelle avec Playwright ?
Playwright intègre la comparaison de captures d’écran comme assertion native, donc aucune dépendance supplémentaire n’est nécessaire au-delà de @playwright/test. L’assertion est expect(page).toHaveScreenshot(), documentée dans la référence API PageAssertions. Commencez par la configuration :
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
// Organisez les références par navigateur pour éviter les collisions entre captures cross-browser.
snapshotPathTemplate: '{testDir}/__screenshots__/{projectName}/{arg}{ext}',
expect: {
toHaveScreenshot: {
// Autorisez un petit budget de pixels absolus pour le bruit de rendu sous-pixel.
maxDiffPixels: 100,
// Et un budget relatif — 1% de l'image — pour les captures plus grandes.
maxDiffPixelRatio: 0.01,
},
},
use: {
// Viewport fixe : les changements de mise en page responsive invalideraient autrement les références.
viewport: { width: 1280, height: 720 },
},
// Épinglez un seul navigateur pour des références déterministes en CI.
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
});
Deux options portent l’essentiel du poids. Les options maxDiffPixels et maxDiffPixelRatio définissent la tolérance d’écart avant l’échec du test. Elles existent car l’anti-aliasing sous-pixel varie entre les machines — la documentation de Playwright indique directement que « différents systèmes d’exploitation peuvent produire des captures d’écran différentes ». Un seuil de maxDiffPixelRatio: 0.01 absorbe ce bruit sans masquer les vraies régressions.
Un comportement par défaut mérite d’être compris plutôt que configuré : pour l’assertion toHaveScreenshot(), animations est par défaut à 'disabled', ce qui termine les animations CSS finies et fige les infinies avant la capture. Cela diffère de page.screenshot(), où animations est par défaut à 'allow'. Les images intermédiaires de transition sont donc déjà gérées pour l’assertion — vous n’avez pas à définir cette option, vous vous appuyez sur elle.
Un test ressemble à ceci :
// checkout.spec.ts
import { test, expect } from '@playwright/test';
test('checkout button is not obscured', async ({ page }) => {
await page.goto('/checkout');
// Assertion web-first : attend l'élément plutôt qu'un délai fixe.
await expect(page.getByTestId('checkout')).toBeVisible();
await expect(page.getByTestId('checkout')).toHaveScreenshot('checkout-button.png');
});
Limiter la capture d’écran à un locator plutôt qu’à la page entière maintient la région capturée petite et le diff ciblé — c’est exactement ce qui détecte le chevauchement du <CookieBanner> sans avoir à recréer la référence de toute la page à chaque modification sans rapport.
Tests au niveau des composants avec Vitest browser mode
Si votre stack utilise déjà Vitest, la version 4.0 a promu le mode navigateur au statut stable et ajouté la régression visuelle native via toMatchScreenshot(). Il s’agit d’une fonctionnalité de la version 4.x — la branche 2.x ne dispose pas d’une telle assertion — ciblez donc une version ^4.0 au minimum. La configuration utilise le fournisseur Playwright :
// vitest.config.ts
import { defineConfig } from 'vitest/config';
import { playwright } from '@vitest/browser-playwright';
export default defineConfig({
test: {
browser: {
enabled: true,
provider: playwright(),
instances: [{ browser: 'chromium' }],
},
},
});
// Button.visual.test.ts
import { expect, test } from 'vitest';
import { page } from 'vitest/browser';
import { render } from 'vitest-browser-react';
import { CheckoutButton } from './CheckoutButton';
test('checkout button matches baseline', async () => {
render(<CheckoutButton onCheckout={() => {}} />);
// Capturez un locator d'élément spécifique — la documentation de Vitest signale
// la capture de la page entière comme un anti-pattern.
await expect(page.getByTestId('checkout')).toMatchScreenshot();
});
Le fournisseur est la fonction playwright() de @vitest/browser-playwright, passée comme objet — et non la chaîne 'playwright' utilisée dans les versions antérieures. L’import de contexte est vitest/browser. Consultez le guide de migration Vitest avant de mettre à niveau une configuration browser-mode existante, car ces chemins d’import ont changé dans la v4.
Tests au niveau des composants avec les stories Storybook
Si vos composants vivent dans Storybook (actuellement v10.4), vous n’avez pas à tout réécrire pour ajouter une couverture visuelle — réutilisez les stories que vous maintenez déjà. L’ancien pattern jest-image-snapshot avec postVisit dans le test-runner est désormais une approche Node héritée : il ne fonctionne pas dans le mode navigateur basé sur Vitest de Storybook, car jest-image-snapshot dépend de Node.js.
L’équivalent gratuit et local actuel consiste à intégrer une story dans un test Vitest browser-mode avec l’API portable stories de Storybook (composeStories) et d’utiliser le même toMatchScreenshot() de la configuration Vitest ci-dessus :
// CheckoutButton.visual.test.tsx
import { expect, test } from 'vitest';
import { page } from 'vitest/browser';
import { render } from 'vitest-browser-react';
import { composeStories } from '@storybook/react-vite';
import * as stories from './CheckoutButton.stories';
// Composez la story avec ses args, décorateurs et annotations de projet,
// afin que le test rende exactement le même état de composant que votre story décrit.
const { Primary } = composeStories(stories);
test('CheckoutButton matches its story baseline', async () => {
render(<Primary />);
// Limitez la portée à l'élément, pas à la page entière.
await expect(page.getByTestId('checkout')).toMatchScreenshot();
});
Cela maintient une source de vérité unique — la story — pour les états rendus du composant et sa référence visuelle. Deux mises en garde importantes. L’assertion s’exécute dans un test Vitest browser-mode autonome, et non via l’addon Storybook Vitest, qui ne prend pas en charge toMatchScreenshot (il lève une erreur Invalid Chai property: toMatchScreenshot) ; l’addon gère les tests d’interaction et d’accessibilité, pas les diffs de pixels. Et le produit de test visuel first-party de Storybook est Chromatic, un service cloud payant, qui est la voie à suivre si vous souhaitez des références cross-browser hébergées et un flux de révision géré plutôt que de stocker les références dans votre dépôt.
Pourquoi mes tests visuels échouent-ils constamment ?
La plupart des cas de flakiness dans les tests visuels proviennent de quatre sources : les animations CSS produisant des images intermédiaires de transition, les polices web se chargeant après le déclenchement de la capture d’écran, le contenu dynamique (horodatages, avatars, compteurs) qui diffère légitimement entre les exécutions, et l’anti-aliasing sous-pixel qui varie selon le GPU et le système d’exploitation — chacun nécessite un correctif spécifique, pas un seuil plus permissif. Augmenter maxDiffPixels pour réduire le bruit aveugle également la suite aux vraies régressions, ce qui va à l’encontre de l’objectif.
Un helper de stabilisation traite les sources contrôlables avant le déclenchement de la capture d’écran :
// prepare-page.ts
import { Page } from '@playwright/test';
export async function preparePageForScreenshot(page: Page) {
// 1. Forcez les animations et transitions à une durée nulle par mesure de précaution
// (toHaveScreenshot les désactive déjà, mais page.screenshot
// et les états intermédiaires visibles en bénéficient aussi).
await page.addStyleTag({
content: `*, *::before, *::after {
animation-duration: 0s !important;
transition-duration: 0s !important;
}`,
});
// 2. Attendez les polices web. document.fonts.ready se résout quand le chargement
// des polices se stabilise, évitant le reflow de la police de substitution qui décale le texte.
await page.waitForFunction(() => document.fonts.ready.then(() => true));
// 3. Attendez que toutes les images aient fini de se charger.
await page.waitForFunction(() =>
Array.from(document.images).every((img) => img.complete)
);
// 4. Neutralisez le contenu dynamique plutôt que de le mocker partout.
await page.locator('[data-dynamic]').evaluateAll((els) =>
els.forEach((el) => ((el as HTMLElement).style.visibility = 'hidden'))
);
}
L’étape 2 s’appuie sur document.fonts.ready, qui retourne une Promise se résolvant une fois que les opérations de chargement des polices et de mise en page du document sont terminées — le signal correct pour « les polices sont affichées », bien plus fiable qu’une attente fixe.
Notez ce que ce helper ne fait délibérément pas : il n’appelle jamais page.waitForTimeout(). Le guide des bonnes pratiques de Playwright déconseille les délais fixes (« Ne jamais attendre un timeout en production »). L’alternative évidente, waitForLoadState('networkidle'), est également déconseillée — la documentation de Playwright indique de « s’appuyer sur des assertions web pour évaluer la disponibilité à la place ». L’approche correcte consiste à utiliser des assertions web-first et des attentes d’éléments explicites, et toHaveScreenshot() effectue déjà des tentatives automatiques jusqu’à ce que deux captures d’écran consécutives correspondent, ce qui absorbe à lui seul la plupart du bruit de timing résiduel.
Pour les régions genuinement dynamiques que vous souhaitez garder visibles mais ignorer, l’option mask de Playwright accepte un tableau de locators et peint chacun avec une boîte pleine avant la comparaison :
await expect(page).toHaveScreenshot('dashboard.png', {
mask: [page.getByTestId('last-login'), page.locator('img[data-avatar]')],
});
C’est plus propre que les manipulations CSS de visibilité car la région masquée occupe toujours son espace dans la mise en page, donc la mise en page environnante est comparée exactement telle qu’elle s’affiche.
Comment exécuter des tests visuels en CI sans faux positifs ?
Le rendu des polices diffère entre Ubuntu, macOS et Alpine Linux même à la même version de navigateur, donc une référence capturée sur le MacBook d’un développeur produira des faux positifs lorsqu’elle sera comparée à une capture d’écran prise dans un runner Ubuntu de GitHub Actions — épinglez votre CI à une image Docker officielle spécifique mcr.microsoft.com/playwright:v1.61.0-noble pour éliminer cette variable. Les tags flottants comme :latest ne sont plus publiés pour ces images, donc un tag de version épinglé est obligatoire, pas optionnel.
La règle pratique qui en découle : générez les références à l’intérieur du même conteneur que celui utilisé par la CI. Une référence capturée localement sur un système d’exploitation différent est la source la plus courante de diffs spécifiques à la CI. Générez les références en CI (ou dans le conteneur épinglé localement) et commitez-les.
Pour les références elles-mêmes, Git LFS est une pratique courante — les fichiers PNG sont binaires et gonflent le dépôt avec le temps. Une entrée dans .gitattributes les route vers Git LFS :
tests/**/__screenshots__/** filter=lfs diff=lfs merge=lfs -text
Examinez les diffs de références dans les pull requests exactement comme vous examinez le code. Lorsqu’un test visuel échoue en CI, téléchargez le rapport HTML de Playwright comme artefact de build afin que les réviseurs puissent ouvrir le diff côte à côte. Une modification approuvée est un commit de référence délibéré dans la même PR que le code qui l’a causée — jamais un commit séparé « fix the tests » qui dissimule ce qui a changé.
Que faut-il tester, et que faut-il laisser de côté ?
Testez les composants et les parcours où une modification visuelle vous coûterait quelque chose — un bouton de validation cassé, une navigation effondrée, un composant de design system utilisé sur 40 pages ; évitez les tableaux de bord très dynamiques et les widgets tiers où le contenu change légitimement à chaque rendu. Le coût d’un test visuel est le temps de révision à chaque diff, alors investissez-le là où une régression est coûteuse et le rendu est stable.
Bons candidats : les composants de design system, les parcours de conversion critiques (authentification, validation de commande), la navigation, les états d’erreur et vides, et les points de rupture responsive. Mauvais candidats : les tableaux de bord en temps réel, le contenu généré par les utilisateurs, les emplacements publicitaires et les intégrations tierces que vous ne contrôlez pas — ceux-ci produisent des diffs constants qui entraînent les réviseurs à approuver sans regarder, le pire résultat possible.
Là où les tests visuels s’arrêtent : la production
Les tests de régression visuelle valident l’interface par rapport à des références contrôlées en CI, mais la production s’affiche sur de vrais appareils, avec des viewports non contrôlés, des polices qui peuvent ne pas se charger, et des scripts tiers qui reformatent la page — le session replay reconstruit et rejoue la session enregistrée, de sorte qu’une rupture de mise en page qui a échappé à votre suite de tests apparaît dans les enregistrements des sessions affectées.
Votre matrice de tests épingle un viewport et un navigateur ; un utilisateur sur un ordinateur portable 1366×768 avec une police web dont le chargement a expiré et une locale qui allonge chaque libellé rencontre une mise en page que vos références n’ont jamais décrite. Les tests visuels constituent une prévention à la frontière de la PR ; le session replay est une détection à la frontière de la production. Ils couvrent des modes de défaillance différents et sont complémentaires, pas redondants.
Comment choisir un outil de test de régression visuelle ?
Les outils de régression visuelle se répartissent en trois catégories — les runners natifs aux frameworks, les services cloud et les outils auto-hébergés — et le choix correspond aux besoins de l’équipe plutôt qu’aux listes de fonctionnalités. Les runners natifs aux frameworks — Playwright et Vitest browser mode — sont gratuits, s’exécutent dans votre CI existante et stockent les références dans votre dépôt ; le compromis est que vous gérez vous-même les références et la cohérence entre environnements. Les services cloud comme Percy et Chromatic gèrent le stockage des références et les flux de révision et proposent des niveaux gratuits (Percy inclut 5 000 captures d’écran par mois ; les plans payants de Chromatic démarrent à 179 $/mois), au prix d’une dépendance externe. Les options auto-hébergées comme BackstopJS maintiennent tout en interne avec plus de configuration. Pour une équipe qui exécute déjà Playwright ou Vitest en CI, la voie native ne coûte rien de plus et est suffisante si la flakiness est contrôlée en amont.
La voie native aux frameworks comble la catégorie de bugs que les tests fonctionnels ne peuvent structurellement pas voir, sans nouveau fournisseur et sans coût récurrent. Commencez par ajouter une assertion toHaveScreenshot() à votre composant le plus critique — le bouton de validation, la navigation principale — générez la référence dans le même conteneur que celui utilisé par votre CI, et traitez le premier diff d’échec comme une revue de code plutôt que comme un test à faire taire.
Questions fréquentes
Quelle est la différence entre les tests de régression visuelle et les tests de snapshot ?
Les tests de snapshot sérialisent le balisage rendu d'un composant en texte et comparent cette chaîne, tandis que les tests de régression visuelle comparent les pixels réellement rendus de la capture d'écran. Les snapshots au niveau du balisage passent à côté de tout ce qui est purement visuel, comme un changement de z-index, un remplacement de jeton de couleur ou une police de substitution, car le DOM sérialisé reste identique même lorsque ce que voit l'utilisateur ne l'est pas. La régression visuelle détecte les bugs purement visuels que les diffs de snapshot ne peuvent structurellement pas détecter.
Pourquoi mon test visuel passe-t-il localement mais échoue-t-il en CI ?
Le rendu des polices et l'anti-aliasing sous-pixel diffèrent entre les systèmes d'exploitation, donc une référence capturée sur un ordinateur portable macOS produit des faux positifs lorsqu'elle est comparée à une capture d'écran prise dans un runner Ubuntu de GitHub Actions. La solution est de générer les références à l'intérieur du même conteneur épinglé que celui utilisé par votre CI, comme l'image Docker officielle mcr.microsoft.com/playwright:v1.61.0-noble, plutôt que de commiter des références capturées sur un système d'exploitation différent. Les références inter-environnements sont la source la plus courante de diffs spécifiques à la CI.
Ai-je besoin d'un service payant comme Percy ou Applitools pour faire des tests de régression visuelle ?
Non. Playwright intègre la comparaison de captures d'écran comme assertion native via expect(page).toHaveScreenshot(), et Vitest 4.x a ajouté la régression visuelle native via toMatchScreenshot() dans le mode navigateur stable, tous deux gratuits et s'exécutant dans votre CI existante avec des références stockées dans votre dépôt. Les services payants comme Percy et Chromatic ajoutent le stockage des références et des flux de révision hébergés, et Applitools ajoute la comparaison basée sur l'IA, mais la comparaison pixel native aux frameworks avec des seuils configurables est suffisante pour la plupart des équipes si la flakiness est contrôlée en amont.
Dois-je capturer la page entière ou un seul composant dans un test visuel ?
Limitez la capture d'écran à un locator d'élément spécifique plutôt qu'à la page entière dans la mesure du possible. La capture au niveau des composants maintient le diff ciblé, réduit le bruit, accélère la révision et évite de recréer la référence de toute la page à chaque modification sans rapport. La documentation de Vitest elle-même signale la capture de la page entière comme un anti-pattern. Réservez la capture au niveau de la page pour les parcours de bout en bout critiques comme la validation de commande, où les interactions de mise en page entre éléments importent, et utilisez des tests au niveau des composants pour les éléments de design system et les interfaces isolées.