PHPUnit vérifie qu’une fonction retourne la bonne valeur. Les tests E2E vérifient qu’un parcours utilisateur aboutit au bon résultat. Aucun des deux ne détecte qu’une mise à jour de thème a discrètement décalé un bouton de quinze pixels, ou qu’une modification de theme.json a changé la couleur de fond d’une section entière. Les tests de régression visuelle comblent ce vide, en comparant automatiquement des captures d’écran entre deux versions d’un site.
Nous utilisons ce type de test depuis plusieurs mois sur des projets de thèmes complexes, avec deux outils qui répondent à des besoins différents : BackstopJS, en autonomie complète sur notre propre infrastructure, et Percy, en service cloud intégré à la CI. Voici comment nous les avons mis en place, et ce qui distingue vraiment les deux approches.
Le principe de la comparaison visuelle
Le fonctionnement est le même quel que soit l’outil : une première exécution capture des captures d’écran de référence sur un ensemble de pages définies. À chaque exécution suivante, de nouvelles captures sont prises dans les mêmes conditions, puis comparées pixel par pixel aux références. Si la différence dépasse un seuil de tolérance configuré, le test échoue et affiche les zones exactes qui diffèrent, généralement mises en évidence en rouge sur une image de différence.
BackstopJS : autonomie complète
BackstopJS s’installe entièrement en local ou sur votre propre infrastructure CI, sans dépendance à un service tiers payant. La configuration se fait dans un fichier backstop.json qui liste les scénarios à capturer :
{
"scenarios": [
{
"label": "Page d'accueil",
"url": "https://staging.mon-client.fr/",
"selectors": [ "document" ],
"delay": 500
},
{
"label": "Fiche produit",
"url": "https://staging.mon-client.fr/produit/exemple/",
"selectors": [ ".mon-fiche-produit" ],
"delay": 500
}
],
"viewports": [
{ "label": "mobile", "width": 375, "height": 667 },
{ "label": "desktop", "width": 1440, "height": 900 }
],
"misMatchThreshold": 0.1
}
La commande backstop reference génère les captures de référence, et backstop test exécute la comparaison lors des exécutions suivantes :
npx backstop reference
npx backstop test

Percy : un service cloud intégré à la CI
Percy fonctionne différemment : le SDK capture les pages pendant l’exécution de votre suite de tests existante (souvent combinée à Playwright ou Cypress), puis envoie les captures au service cloud de Percy, qui effectue la comparaison, l’hébergement des images de référence, et propose une interface de revue collaborative pour approuver ou refuser un changement visuel détecté.
const { percySnapshot } = require( '@percy/playwright' );
test( 'capture visuelle de la page d\'accueil', async ( { page } ) => {
await page.goto( 'https://staging.mon-client.fr/' );
await percySnapshot( page, 'Page d\'accueil' );
} );
L’intérêt principal de Percy par rapport à BackstopJS : la revue des changements visuels se fait dans une interface pensée pour la collaboration, où un designer ou un chef de projet peut approuver ou rejeter chaque différence détectée sans avoir accès au dépôt de code, ce qui change concrètement le flux de validation sur des projets avec plusieurs parties prenantes non techniques.
Calibrer le seuil de tolérance
Le réglage le plus délicat, quel que soit l’outil, reste le seuil de tolérance aux différences. Un seuil trop bas fait échouer le test au moindre pixel d’anti-aliasing différent d’un rendu de police à l’autre, ce qui génère du bruit et finit par décrédibiliser la suite entière. Un seuil trop haut laisse passer de vraies régressions visibles.
| Situation | Seuil recommandé |
|---|---|
| Page à contenu texte simple, peu d’images | 0.1 % (strict) |
| Page avec polices web et rendu variable selon le navigateur | 0.2 à 0.5 % |
| Page avec contenu dynamique (carrousel, date affichée) | Exclure la zone plutôt que d’augmenter le seuil global |
Pièges rencontrés sur nos projets
- Des captures effectuées avant la fin du chargement des polices web, produisant un faux positif systématique sur le premier passage.
- Du contenu réellement dynamique, comme une date affichée en pied de page ou un carrousel avec rotation automatique, qui rend chaque capture différente de la précédente sans qu’il s’agisse d’une régression.
- Des captures de pleine page sur un site avec du contenu chargé en lazy load, où une partie de l’image reste vide selon le moment exact de la capture.
La solution la plus fiable pour le contenu dynamique consiste à masquer ou figer ces zones avant la capture (une classe CSS temporaire, ou l’exclusion explicite d’un sélecteur dans la configuration de l’outil), plutôt que de relâcher le seuil de tolérance global, qui finirait par masquer aussi de vraies régressions.
Sur nos projets, nous réservons la régression visuelle aux gabarits qui comptent vraiment pour le client : page d’accueil, fiche produit, tunnel de commande. Multiplier les scénarios sur des pages secondaires alourdit la maintenance sans apporter de valeur proportionnelle.
En résumé
Les tests de régression visuelle détectent une catégorie de bugs invisible aux tests fonctionnels classiques : ce qui a changé à l’écran sans que le code métier n’ait bougé. BackstopJS convient à une équipe technique qui souhaite garder la main complète sur son infrastructure, quand Percy apporte un flux de revue collaborative précieux dès que des profils non techniques doivent valider les changements visuels. Dans les deux cas, calibrer le seuil de tolérance et isoler le contenu réellement dynamique reste la clé pour garder une suite fiable et exploitée dans la durée.