Régression visuelle : dérive ou véritable défaut ?
Diagnostiquez une régression visuelle avec des changements contrôlés de police, de fenêtre et d’échelle. Séparez tolérance de couleur et budget de pixels différents.
BotBrowser Team
Vous voulez la documentation structurée pour Documentation ?
Cet article fait partie de la bibliothèque éditoriale. Pour les étapes de configuration, la référence et les mises à jour continues, passez directement à la section docs.
Un échec de test de régression visuelle signifie qu’une comparaison ne respecte pas les règles configurées. Il n’en identifie pas la cause. Un fichier de police, une version du navigateur, une fenêtre ou un moteur graphique différents peuvent déplacer les pixels sans changement du code applicatif. BotBrowser fournit des inventaires de polices et des contrôles de rendu issus des profils pour favoriser la cohérence entre plateformes, mais il ne garantit pas des pixels de glyphes identiques entre moteurs, ne juge pas la validité du CSS et ne choisit pas les tolérances des captures.
Résumé
- Comparez les dimensions et les paramètres de rendu avant de calculer ou d’accepter une différence de pixels.
- La tolérance de couleur détermine quels pixels sont différents. Un nombre ou une proportion autorisée détermine la quantité de différences ainsi classées qui peut être acceptée.
- Une exécution contrôlée de Chrome standard a séparé police, fenêtre, échelle et CSS. Un budget généreux comme une tolérance de couleur généreuse ont accepté un changement CSS délibéré.
- Des résultats répétés identiques établissent une répétabilité pour les paramètres enregistrés. Ils ne prouvent pas que l’interface, la police ou la référence sont correctes.
Sommaire
- Séparer une comparaison échouée de sa cause
- Vérifier quatre sources de dérive
- Reproduire un seul changement à la fois
- Lire les résultats des captures contrôlées
- Choisir séparément tolérance de couleur et budget
- Décider entre restaurer examiner et actualiser
- Questions fréquentes sur la régression visuelle
Séparer une comparaison échouée de sa cause
Commencez par les dimensions des deux images décodées. Une capture deux fois plus large et deux fois plus haute contient quatre fois plus de positions de pixels. La comparer directement à la petite image ne produit pas un décompte ordinaire entre positions correspondantes. La réduire introduit un rééchantillonnage et une nouvelle source de différences. Classez d’abord cette incompatibilité de dimensions ; adoptez une normalisation explicite seulement si elle appartient au contrat prévu du test.
Comparez ensuite le relevé de capture : version de l’exécutable, système d’exploitation, mode de rendu, viewport en pixels CSS, deviceScaleFactor, polices disponibles et révision de l’application. Une étiquette de conteneur est utile, mais une étiquette modifiable ne prouve pas à elle seule que tous ces paramètres sont inchangés. Conservez la version résolue du navigateur et l’identité des fichiers de police avec la référence. Un échec avec des paramètres différents demande une autre investigation qu’un échec avec des paramètres identiques.
Examinez alors la localisation des différences. Des changements suivant les caractères suggèrent une question de police ou de composition ; un rectangle isolé suggère une modification locale de style ou de contenu ; des différences étendues peuvent impliquer la disposition, l’échelle ou un paramètre commun. Ce sont des indices, pas des diagnostics. Une nouvelle étiquette produit aussi des différences textuelles, et une substitution de police peut déplacer la mise en page bien au-delà des glyphes.
Les vérifications de capture couvrent déjà la préparation et ses métadonnées. Déclarez ces paramètres au lieu de traiter l’assertion d’image comme un détecteur de disponibilité de l’application. Playwright attend que deux captures consécutives soient identiques avant de comparer la dernière à la référence. Deux images stables peuvent néanmoins montrer un tableau vide, une police de remplacement ou une erreur de chargement. La condition propre à l’application doit désigner l’état réellement attendu.
Séparez trois questions dans le compte rendu : les paramètres étaient-ils comparables, quelles zones ont changé et la nouvelle interface est-elle acceptable ? Les deux premières sont des mesures. La troisième exige le contrat applicatif ou une revue de conception. Actualiser automatiquement la référence ne répond à aucune ; cela change seulement l’image utilisée lors des comparaisons futures.
Vérifier quatre sources de dérive
Version du navigateur et mode de capture
Fixez l’exécutable ayant produit la référence, au-delà de la version de la bibliothèque d’automatisation. Une mise à jour de cette dernière peut sélectionner un autre navigateur fourni, tandis que le navigateur du système peut évoluer indépendamment. Relevez la version réelle lors de la capture. Si la référence vient d’une autre version, exécutez l’ancienne révision applicative dans le nouveau navigateur avant d’attribuer la différence au code.
Enregistrez aussi le mode avec ou sans fenêtre. La documentation Playwright cite notamment le système, sa version, ses paramètres, le matériel, l’alimentation et le mode sans fenêtre parmi les influences sur le rendu. Cet avertissement justifie le contrôle de l’environnement ; il ne démontre pas qu’un de ces facteurs explique une capture particulière. Un essai apparié entre deux versions est nécessaire pour examiner une mise à jour. L’exécution contrôlée présentée plus bas ne change pas de version du navigateur.
Fichiers de police et état de chargement
Un nom de famille CSS est une demande, pas la preuve du fichier ayant dessiné chaque glyphe. La police peut manquer, être en cours de chargement ou ne pas contenir un caractère. Un remplacement différent peut modifier les formes, les largeurs et les retours à la ligne. Enregistrez les fichiers fournis et vérifiez un texte représentatif après résolution des promesses de chargement concernées. Attendre une police ne crée pas un glyphe qu’elle ne possède pas.
document.fonts.ready concerne le chargement des polices et la mise en page du document. Cette promesse ne signifie pas que tout contenu ou toute requête future a déjà été lancé. Si l’application insère ensuite une autre zone, attendez son état de disponibilité avant de la capturer. Après une modification volontaire de police, laissez la disposition se recalculer avant l’image suivante. Comparer l’ancienne image à une capture antérieure à l’application de la nouvelle police confond chronologie et choix typographique.
Les contrôles de polices de BotBrowser décrivent inventaire et rendu issus des profils sans garantir une sortie identique pour chaque glyphe. Les polices de l’hôte restent pertinentes lorsque le mode choisi autorise leur substitution ou utilise les polices réelles du système. Un inventaire déclaré et une politique de comparaison répondent donc à deux problèmes différents ; aucun ne rend l’autre superflu.
Fenêtre et facteur d’échelle
La largeur de la fenêtre modifie la disposition adaptative et le retour à la ligne. Le facteur d’échelle modifie la relation entre coordonnées CSS et pixels de l’image. Relevez les deux plutôt que de remplacer la taille de fenêtre par la largeur de la capture. Une capture de page entière peut également grandir parce que le document grandit, même si sa fenêtre reste fixe.
Vérifiez les valeurs observées dans la page en plus des options demandées à l’automatisation. Une référence et une image actuelle produites avec deux largeurs CSS doivent d’abord être classées comme incompatibilité géométrique. Augmenter le nombre de pixels différents autorisés ne restaure pas la disposition de la référence. Si plusieurs fenêtres correspondent à des projets volontaires, conservez des références et des identifiants de projet distincts.
Moteur graphique et rendu de l’hôte
Une valeur GPU déclarée ne prouve pas qu’un même rastériseur a dessiné l’image. Les rastériseurs logiciels et les chemins graphiques de l’hôte peuvent produire des pixels différents pour des opérations équivalentes. La documentation du moteur graphique Linux de BotBrowser distingue explicitement ces moteurs et leurs résultats. Le nom du moteur de rendu ne suffit pas à établir la provenance d’une référence exacte.
Conservez la configuration graphique lorsque l’environnement l’expose, et évitez de mélanger des références issues de types d’exécuteurs différents. Si un pilote ou un moteur a changé, effectuez un essai apparié en conservant application, polices et géométrie. L’expérience suivante ne modifie aucun pilote et ne prouve aucune cause GPU. Elle montre comment classer une modification connue avant d’assouplir une tolérance.
Reproduire un seul changement à la fois
Utilisez une page qui vous appartient, un contenu fixe, deux fichiers de police locaux et aucune requête externe. Capturez une référence, puis créez des groupes séparés ne changeant que la police choisie, la largeur de fenêtre, le facteur d’échelle ou une couleur CSS connue. Répétez chaque groupe dans de nouveaux processus. Le changement CSS est un témoin positif : il confirme que la comparaison peut révéler une modification applicative introduite volontairement.
L’exécution comprenait cinq groupes de trois lancements indépendants, soit 15 tâches. Un seul ensemble global avait une limite demandée de 20 et une limite effective de 15, puisque seulement 15 tâches existaient. L’hôte Ubuntu disposait de 32 cœurs et d’une mémoire disponible suffisante avant le lancement ; il utilisait le service existant :88. Le maximum observé était de 15 navigateurs actifs simultanément. Il s’agit d’un essai borné, pas d’une recommandation pour toute machine.
Téléchargez le script autonome de reproduction et le JSON de l’exécution enregistrée. Le script demande Linux, Node 20 ou ultérieur, Chrome standard, Playwright Core, Python avec Pillow, deux fichiers TTF locaux et le service existant xvfb-88.service. Il n’installe rien. Affectez les quatre variables de chemin à ces dépendances, puis exécutez :
DISPLAY=:88 node visual-regression-baseline-drift.mjs \
--browser "$CHROME_BIN" --playwright-root "$PLAYWRIGHT_ROOT" \
--font-a "$FONT_A" --font-b "$FONT_B" \
--workers 20 --out /tmp/visual-regression-result.json
Le script sert la page fixe et ses polices sur la boucle locale, enregistre les groupes et vérifie la fermeture des processus. Il conserve les images et les répertoires temporaires pour inspection. Son mode --self-test vérifie les cas limites avant tout lancement. Les décomptes ci-dessous appartiennent à cette exécution ; d’autres fichiers de police peuvent donner d’autres quantités sans invalider la méthode.
Le schéma de capture sépare la disponibilité de la page de la comparaison. Remplacez le sélecteur applicatif par un état réellement implémenté dans la page que vous contrôlez :
import { chromium } from 'playwright';
import { writeFile } from 'node:fs/promises';
const browser = await chromium.launch({ headless: false });
try {
const context = await browser.newContext({
viewport: { width: 1280, height: 900 },
deviceScaleFactor: 1,
});
const page = await context.newPage();
await page.goto('http://127.0.0.1:4173/fixture');
await page.locator('[data-ready="true"]').waitFor();
await page.evaluate(async () => {
await document.fonts.ready;
await new Promise(resolve =>
requestAnimationFrame(() => {
requestAnimationFrame(resolve);
})
);
});
const manifest = await page.evaluate(() => ({
viewport: [innerWidth, innerHeight],
devicePixelRatio,
fontStatus: document.fonts.status,
}));
manifest.browserVersion = browser.version();
await page.screenshot({ path: 'capture.png', animations: 'disabled' });
await writeFile('capture.json', JSON.stringify(manifest, null, 2));
} finally {
await browser.close();
}
L’exemple capture une preuve ; il ne compare pas les images et ne définit pas le serveur de test. Une capture seule ne restitue ni la version du navigateur, ni les fichiers fournis, ni la condition fonctionnelle attendue. Ajoutez ces informations au relevé de référence au lieu de les déduire des pixels. Désactiver les animations retire une source de mouvement nommée, mais ne fige ni données vivantes, ni horloge, ni temporisateurs applicatifs.
Pour la police, gardez texte, largeurs et navigateur fixes et changez seulement la police fournie sélectionnée. Pour la géométrie, gardez contenu et polices fixes et changez la fenêtre ou l’échelle. Pour le témoin CSS, modifiez uniquement la déclaration de couleur connue. Si plusieurs paramètres changent ensemble, conservez ce fait et classez le résultat comme comparaison de configurations ; ne le présentez pas comme un effet causal isolé.
Lire les résultats des captures contrôlées
Chrome standard a indiqué la version d’exécution 154.0.8037.57 dans les 15 tâches. L’image de référence mesurait 1280 × 900 ; chaque groupe était cohérent sur ses trois lancements. La comparaison décodait les PNG en octets RGBA. Un pixel était différent lorsque le plus grand écart absolu entre canaux dépassait la tolérance entière choisie. Cette règle exacte est illustrative ; elle ne correspond pas à la règle perceptuelle pixelmatch de Playwright.
| Groupe | Dimensions | Pixels modifiés en comparaison exacte | Interprétation |
|---|---|---|---|
| Répétitions de référence | 1280 × 900 | 0 | Les paramètres contrôlés se sont répétés dans cette exécution. |
| Police sélectionnée modifiée | 1280 × 900 | 26,962, environ 2.34% | Les écarts sont restés dans la zone liée au texte. |
| Largeur de fenêtre modifiée | 1024 × 900 | Non calculé | L’incompatibilité de dimensions a été classée d’abord. |
| Facteur d’échelle modifié | 2560 × 1800 | Non calculé | Les dimensions d’échantillonnage différaient. |
| Couleur CSS connue modifiée | 1280 × 900 | 9,600, environ 0.83% | Les écarts sont restés dans le bloc prévu. |
Le bloc CSS occupait 120 × 80 pixels, soit une aire de 9,600 pixels. Le canal volontairement modifié présentait un écart de 8. Avec une tolérance de canal de 0, tous ces pixels étaient comptés. Un budget de 10,000 acceptait pourtant l’image. Porter la tolérance illustrative à 16 faisait tomber le décompte à zéro. Ces valeurs montrent deux façons distinctes d’accepter un changement connu ; elles ne constituent pas des réglages de production proposés.
Le groupe de police a changé 26,962 pixels à l’intérieur de la zone textuelle enregistrée, sans écart à l’extérieur. Cela soutient l’attribution dans cette page volontairement limitée. Une vraie application peut modifier largement sa disposition après substitution d’une police ; la restriction à cette zone n’est donc pas un détecteur général. Le témoin CSS était lui aussi simple : une propriété de disposition aurait pu affecter presque toute la page plutôt qu’un seul rectangle.
Chaque tâche a chargé seulement sa page et sa ressource de police locales. Le relevé conserve géométrie observée, disponibilité des polices, provenance du navigateur et comparaisons. La vérification finale n’a trouvé aucun navigateur ni processus de tâche restant. Cela établit la fin de l’exécution bornée, pas la présence des mêmes polices ou du même environnement graphique chez le lecteur. Le script reproductible et sa sortie sont conservés avec les preuves de l’expérience.
Choisir séparément tolérance de couleur et budget
Les options documentées de comparaison d’images séparent l’écart perceptuel de couleur autorisé à une position du total de différences accepté. maxDiffPixels exprime un nombre acceptable de pixels classés différents ; maxDiffPixelRatio exprime une proportion de la surface totale. Ces réglages agissent sur des parties distinctes du calcul. Modifier l’un n’équivaut pas à modifier l’autre, et les valeurs d’un autre algorithme ne sont pas interchangeables.
| Réglage ou action | Question traitée | Défaut susceptible d’être masqué |
|---|---|---|
| Tolérance de couleur par pixel | L’écart de couleur est-il suffisant pour compter ce pixel ? | Une petite modification volontaire de couleur sur un composant important. |
| Nombre maximal de pixels différents | Combien de différences classées l’image peut-elle contenir ? | Une icône absente ou une commande modifiée restant sous le budget. |
| Proportion maximale différente | Quelle fraction de l’image peut changer ? | Un défaut fixe occupant une fraction moindre d’une page plus longue. |
| Nouvelle image de référence | Quelle référence les comparaisons futures utiliseront-elles ? | Toute modification involontaire acceptée sans regarder l’image. |
Une proportion dépend de la surface. Une même commande absente représente une fraction plus faible d’une longue page que d’un recadrage du composant. Un budget en nombre n’a pas ce dénominateur, mais il ignore toujours le sens de la zone. Aucune métrique ne sait si les pixels appartiennent à une ombre, à un prix ou à un bouton de paiement désactivé. Choisissez la zone d’intérêt dans le contrat du test, pas après un échec pour obtenir son acceptation.
Construisez la politique à partir de répétitions enregistrées dans l’environnement prévu et de modifications applicatives connues devant rester détectables. Gardez les deux types d’exemples. Si un réglage accepte le défaut CSS connu, sa capacité à calmer un bruit bénin ne le rend pas adapté. Examinez l’image des différences et décidez entre comparer un composant plus petit et stable, stabiliser un autre paramètre ou conserver le réglage strict.
Ne reportez pas la tolérance entière de canal de 16 dans le réglage perceptuel de Playwright. Échelles et significations diffèrent. Ne prenez pas davantage les 10,000 pixels comme configuration modèle : ce budget avait été fixé avant l’exécution pour montrer qu’une quantité autorisée peut absorber le témoin connu de 9,600 pixels. Un budget défendable doit être lié aux dimensions, à la région et aux changements précis que l’assertion doit refuser.
Décider entre restaurer examiner et actualiser
Si les dimensions diffèrent de façon inattendue, rétablissez d’abord viewport, deviceScaleFactor et aire de capture prévues. Si les polices ou le navigateur diffèrent, déterminez si le changement d’environnement était voulu. Corrigez la dérive accidentelle ; pour une mise à jour volontaire, comparez l’ancienne révision applicative dans les deux environnements avant d’approuver une nouvelle référence. Séparez autant que possible migration d’environnement et évolution fonctionnelle.
Si les paramètres concordent mais qu’une région stable change encore, examinez la révision applicative et l’état capturé : styles, texte, données et résultats de chargement. La décision entre configuration et divergence de pixels dans Grid traite l’attribution entre nœuds. Une assertion locale doit conserver cette distinction sans prétendre qu’un relevé identique prouve un rendu identique.
Actualisez une référence après acceptation de la zone modifiée et enregistrement de l’environnement générateur. Gardez l’ancienne image dans l’historique, la différence courante, le motif d’acceptation et les paramètres ayant produit le remplacement. Une commande d’actualisation écrit une sortie ; elle ne révise pas le produit. L’exclure de la récupération automatique évite qu’un défaut durable devienne la référence acceptée du lendemain.
Lors d’une mise à jour volontaire du navigateur, vérifiez du texte représentatif, les commandes et la disposition en plus de la différence globale. Un faible pourcentage peut masquer un défaut local important ; un pourcentage élevé peut provenir de bords de caractères sans conséquence. Une tolérance exprime une politique après compréhension de ces distinctions. Elle ne décide pas si le produit doit conserver le changement.
Questions fréquentes sur la régression visuelle
Une même empreinte de capture prouve-t-elle l’absence de défaut ?
Non. Des octets identiques établissent l’égalité de cette capture. Les deux images peuvent avoir la même mauvaise police, le même contenu absent ou les mêmes données anciennes. Ajoutez les vérifications sémantiques pertinentes, par exemple l’état de la commande ou la condition de données chargées.
Tous les exécuteurs doivent-ils partager une référence ?
Seulement si c’est le contrat voulu et si les paramètres concernés sont contrôlés. Des projets de navigateurs, rendus de plateformes ou fenêtres différents peuvent justifier des références distinctes. Attribuer une référence à chaque accident cacherait la dérive : classez la différence avant d’ajouter une famille.
Un profil déclaré remplace-t-il les relevés de polices et de GPU ?
Non. Les contrôles de profil décrivent des surfaces sélectionnées ; les pixels dépendent aussi du texte et du chemin de rendu réels. Notez le mode de police et les hypothèses graphiques ; le nom du profil ne garantit pas des pixels identiques entre hôtes.
Sources
- Playwright: Visual comparisons, dépendance à l’environnement et options de comparaison.
- Playwright: SnapshotAssertions, tolérance de couleur, nombre et proportion de pixels.
- Playwright: PageAssertions.toHaveScreenshot, captures successives et animations.
- MDN: Document.fonts, chargement et disponibilité des polices.
- BotBrowser: Cross-platform profiles, paramètres déclarés et limites de l’hôte.
- BotBrowser: Font controls, inventaire, modes et limites du rendu.
- BotBrowser: Linux GPU backend, chemins logiciels et différences de pixels.
Conclusion pratique
Un échec de capture demande des dimensions comparables, des paramètres enregistrés et une différence examinée avant une tolérance plus large. Séparez la tolérance classant chaque pixel du budget total et vérifiez les deux avec un changement connu que le test doit refuser. Acceptez une nouvelle référence après revue du changement d’interface et de son environnement générateur.
Articles Connexes
Captures fiables avec un navigateur headless
DémarrageÉcrire un rapport de bug navigateur reproductible
EmpreinteValider la confidentialité selon le backend de rendu
ComparaisonQue change un navigateur antidétection ?
DémarrageTrier une régression après une mise à jour du navigateur
EmpreintePropriétés de l'écran et du viewport pour le responsive design
Exécutez la même vérification dans BotBrowser
Chargez un profil, gardez dans le navigateur les signaux que vous venez de lire, puis confirmez le résultat sur votre propre machine avant le déploiement.