La comparaison pixel par pixel casse sur des différences sans importance : rendu des polices, anti-aliasing, timestamps dynamiques. Les outils comme Percy et Applitools Eyes utilisent la vision par ordinateur pour comprendre ce qui a changé visuellement plutôt que compter les pixels.
Le problème de la comparaison pixel parfait
// Comparaison de captures d'écran traditionnelle
test('la page d\'accueil s\'affiche correctement', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveScreenshot('homepage.png'); // Échoue sur 1px de différence
});Ça casse pour :
- Les différences de rendu des polices entre OS et versions de navigateur
- Les animations capturées à des frames différents
- Le contenu dynamique (timestamps, noms d'utilisateur, publicités)
- Les variations d'anti-aliasing
- Les différences de position de défilement
Le choix devient : accepter des faux échecs constants, ou relâcher les seuils au point de laisser passer de vrais bugs visuels.
Comment fonctionne le test visuel par IA
Les services de test visuel par IA utilisent la vision par ordinateur et le machine learning pour :
1. Comprendre la mise en page : reconnaître qu'un bouton est un bouton, pas juste des pixels
2. Ignorer les différences sans importance : variations de rendu du texte, légers décalages d'espacement
3. Signaler les changements significatifs : glissements de mise en page, éléments manquants, changements de couleur, contenu qui se chevauche
4. Regrouper les échecs similaires : 50 tests montrant le même bug deviennent un seul problème groupé
L'IA est entraînée sur des milliers de vrais changements UI et apprend quelles différences sont des bugs et lesquelles sont du bruit de rendu.
Percy (BrowserStack)
Percy est l'outil de test visuel par IA le plus établi, acquis par BrowserStack.
Configuration avec Playwright
npm install --save-dev @percy/cli @percy/playwright// tests/visual.spec.ts
import { test } from '@playwright/test';
import percySnapshot from '@percy/playwright';
test('accueil visuel', async ({ page }) => {
await page.goto('/');
await percySnapshot(page, 'Homepage');
});
test('page de connexion visuelle', async ({ page }) => {
await page.goto('/login');
await percySnapshot(page, 'Login Page');
});
test('tableau de bord après connexion', async ({ page }) => {
await page.goto('/login');
await page.fill('[data-testid="email"]', 'user@test.com');
await page.fill('[data-testid="password"]', 'ValidPass1');
await page.click('[data-testid="submit"]');
await page.waitForURL('/dashboard');
await percySnapshot(page, 'Dashboard - Authenticated');
});Lancer Percy
# Définir votre token Percy (depuis app.percy.io)
PERCY_TOKEN=your_token npx percy exec -- npx playwright testAu premier lancement, Percy prend des captures de référence. Les lancements suivants les comparent et l'IA signale les vrais changements visuels pour révision humaine.
Intégration CI
# .github/workflows/visual-tests.yml
- name: Lancer les tests visuels Percy
run: npx percy exec -- npx playwright test tests/visual.spec.ts
env:
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}Percy publie les résultats comme une vérification de PR : les diffs visuels apparaissent directement dans votre pull request GitHub.
Applitools Eyes
Applitools utilise son moteur "Visual AI", plus précis que la comparaison pixel. Il gère les tests responsive et la comparaison au niveau des composants.
npm install --save-dev @applitools/eyes-playwrightimport { test } from '@playwright/test';
import { Eyes, Target, Configuration } from '@applitools/eyes-playwright';
test('régression visuelle', async ({ page }) => {
const eyes = new Eyes();
const configuration = new Configuration();
configuration.setApiKey(process.env.APPLITOOLS_API_KEY!);
eyes.setConfiguration(configuration);
await eyes.open(page, 'My App', 'Homepage Test');
await page.goto('/');
await eyes.check('Homepage', Target.window().fully());
await page.goto('/products');
await eyes.check('Products Page', Target.window().fully());
await eyes.close();
});L'Ultrafast Grid
La fonctionnalité clé d'Applitools : l'Ultrafast Grid rend votre snapshot DOM dans plusieurs navigateurs et viewports simultanément, sans lancer ces navigateurs sur votre machine.
import { VisualGridRunner, BrowserType, DeviceName, ScreenOrientation } from '@applitools/eyes-playwright';
const runner = new VisualGridRunner({ testConcurrency: 5 });
const configuration = new Configuration();
configuration.addBrowser(1280, 800, BrowserType.CHROME);
configuration.addBrowser(1440, 900, BrowserType.FIREFOX);
configuration.addDeviceEmulation(DeviceName.iPhone_12, ScreenOrientation.PORTRAIT);
configuration.addDeviceEmulation(DeviceName.iPad_Pro, ScreenOrientation.LANDSCAPE);Un seul lancement Playwright, des résultats visuels pour 4 configurations navigateur/appareil.
Comparaison de captures d'écran intégrée à Playwright
Playwright intègre une comparaison visuelle basique, sans IA :
// Intégré : comparaison pixel avec seuil configurable
test('capture d\'écran de la page d\'accueil', async ({ page }) => {
await page.goto('/');
// Autoriser jusqu'à 1% de différence pixel
await expect(page).toHaveScreenshot('homepage.png', {
maxDiffPixelRatio: 0.01,
});
// Ou définir un nombre absolu de pixels
await expect(page).toHaveScreenshot('homepage.png', {
maxDiffPixels: 50,
});
});// Masquer le contenu dynamique
await expect(page).toHaveScreenshot('homepage.png', {
mask: [
page.getByTestId('timestamp'),
page.getByTestId('user-avatar'),
page.getByTestId('ad-banner'),
],
});Gérer le contenu dynamique
Le principal défi des tests visuels : le contenu qui change légitimement entre deux lancements.
Masquer les éléments dynamiques
// Percy
await percySnapshot(page, 'Dashboard', {
percyCSS: `
[data-testid="timestamp"] { visibility: hidden; }
[data-testid="user-avatar"] { filter: blur(10px); }
`,
});
// Playwright intégré
await expect(page).toHaveScreenshot({
mask: [
page.locator('[data-testid="timestamp"]'),
page.locator('.ad-container'),
],
});Attendre un état stable
test('test visuel du graphique', async ({ page }) => {
await page.goto('/analytics');
// Attendre la fin des animations
await page.waitForLoadState('networkidle');
await page.waitForTimeout(500); // Marge pour les transitions CSS
// Attendre l'élément qui confirme le chargement des données
await page.waitForSelector('[data-testid="chart-loaded"]');
await percySnapshot(page, 'Analytics Dashboard');
});Figer le temps
// Figer Date pour que les timestamps ne changent pas entre les lancements
await page.addInitScript(() => {
const fixedDate = new Date('2026-01-15T12:00:00Z');
Date.now = () => fixedDate.getTime();
Date = class extends Date {
constructor(...args) {
if (args.length === 0) {
super(fixedDate.getTime());
} else {
super(...args);
}
}
};
});Tests visuels au niveau des composants
Plutôt que des captures pleine page, testez les composants individuellement :
test('test visuel des variantes de bouton', async ({ page }) => {
await page.goto('/storybook/button');
// Tester chaque variante de bouton
const variants = ['primary', 'secondary', 'danger', 'ghost'];
for (const variant of variants) {
await page.click(`[data-story="${variant}"]`);
await percySnapshot(page, `Button - ${variant}`);
}
});Les tests de composants sont plus stables que les captures pleine page : moins de variables, plus facile d'isoler ce qui a changé.
Mettre en place un workflow de tests visuels
1. Création de la référence
Le premier lancement crée les captures de référence. Révisez-les attentivement : n'approuvez que ce qui est visuellement correct.
2. Workflow de PR
- Le développeur fait des modifications
- La CI lance les tests visuels
- Les diffs sont publiés sur la PR
- Le QA ou le développeur révise les diffs
- Approuver les changements attendus (nouvelle fonctionnalité correcte), rejeter les inattendus (bug)
3. Mise à jour des références
Quand l'UI change intentionnellement, les références doivent être mises à jour. Sur Percy, approuvez les diffs dans le dashboard. Sur Playwright, lancez avec le flag --update-snapshots.
npx playwright test --update-snapshotsCommitez les captures mises à jour avec la PR.
Comparatif des coûts
| Outil | Tier gratuit | Payant |
|-------|-------------|--------|
| Playwright intégré | Gratuit (open source) | Gratuit |
| Percy | 5 000 captures/mois | À partir de 99 $/mois |
| Applitools | Essai limité | Tarif personnalisé |
| Chromatic | 5 000 snapshots/mois | À partir de 149 $/mois |
Pour les petits projets, la comparaison intégrée de Playwright avec masquage et réglage des seuils suffit. Pour les équipes qui livrent fréquemment : Percy ou Applitools, la révision des diffs par IA économise des heures de comparaison manuelle.
Tableau récapitulatif
| Approche | Précision | Coût | Idéal pour |
|----------|-----------|------|------------|
| Playwright intégré | Pixel parfait | Gratuit | Pages statiques, environnement contrôlé |
| Percy | IA | À partir de 99 $/mois | Cross-browser, révision en équipe |
| Applitools | Visual AI + grid | Tarif personnalisé | Enterprise, multi-navigateurs |
Quatre règles pour que les tests visuels tiennent la route :
- Masquer le contenu dynamique (timestamps, publicités, avatars)
- Attendre un état stable avant les captures
- Réviser les références avec soin avant approbation
- Regrouper les tests visuels par page ou composant pour faciliter la révision
Les tests visuels par IA ne suppriment pas les faux positifs : ils les réduisent considérablement. Les diffs qui arrivent en révision sont beaucoup plus souvent de vrais problèmes.
→ See also: Tests de Régression Visuelle avec Playwright: toHaveScreenshot sans Applitools | Assertions dans Playwright: Le Guide Complet | Tests Multi-Navigateurs avec Playwright: Chrome, Firefox, Safari