Wie man Visual Regression Testing implementiert. Playwright Screenshots, Percy, Chromatic, Pixel-Vergleich und Strategien für Design Systems.
Einführung in Visual Testing¶
Visual Regression Testing automatisiert die Erkennung unbeabsichtigter Änderungen an Ihrer Benutzeroberfläche. Anstatt nach jeder Änderung jede Komponente und Seite manuell zu überprüfen, erfassen visuelle Tests Screenshots und vergleichen sie mit Referenzbildern, um visuelle Regressionen zu identifizieren.
Wichtige Vorteile: - Automatisierte UI-Verifizierung - Visuelle Fehler vor der Produktion erkennen - Design-System-Konsistenz - Sicherstellen, dass Komponenten über Updates hinweg korrekt aussehen - Cross-Browser-Testing - Darstellung in verschiedenen Browsern verifizieren - Regressionsprävention - Unbeabsichtigte Änderungen frühzeitig erkennen
Playwright Visual Testing¶
Playwright bietet integrierte Visual-Testing-Funktionen:
import { test, expect } from '@playwright/test';
test('homepage visual test', async ({ page }) => {
await page.goto('/');
// Wait for content to load
await page.waitForSelector('[data-testid="hero-section"]');
// Take screenshot and compare
await expect(page).toHaveScreenshot('homepage.png');
});
test('component visual test', async ({ page }) => {
await page.goto('/components/button');
// Screenshot specific element
const button = page.locator('[data-testid="primary-button"]');
await expect(button).toHaveScreenshot('primary-button.png');
});
Playwright für Visual Testing konfigurieren:
// playwright.config.js
module.exports = {
testDir: './tests',
use: {
// Global settings
viewport: { width: 1280, height: 720 },
screenshot: 'only-on-failure',
},
projects: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
// Visual testing specific settings
video: 'retain-on-failure',
},
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
expect: {
// Visual comparison settings
threshold: 0.2, // 20% difference threshold
mode: 'strict',
},
};
Cloud Visual Testing Services¶
Percy von BrowserStack¶
import Percy from '@percy/playwright';
const percy = new Percy();
test('percy visual test', async ({ page }) => {
await page.goto('/');
// Capture for Percy
await percy.screenshot(page, 'Homepage');
// Multiple viewports
await percy.screenshot(page, 'Homepage Mobile', {
widths: [375, 768, 1280]
});
});
Chromatic (Storybook)¶
// chromatic.yml (GitHub Actions)
name: Chromatic
on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
- run: npm run build-storybook
- uses: chromaui/action@v1
with:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
Best Practices¶
1. Stabile Testumgebung¶
test.beforeEach(async ({ page }) => {
// Animationen für konsistente Screenshots deaktivieren
await page.addStyleTag({
content: `
*, *::before, *::after {
animation-duration: 0s !important;
animation-delay: 0s !important;
transition-duration: 0s !important;
transition-delay: 0s !important;
}
`
});
// Dynamische Inhalte mocken
await page.route('/api/timestamp', route => {
route.fulfill({
json: { timestamp: '2023-01-01T00:00:00Z' }
});
});
});
2. Komponentenebene Testing¶
test.describe('Button Component', () => {
test('primary button states', async ({ page }) => {
await page.goto('/storybook/button');
// Verschiedene Zustände testen
const states = ['default', 'hover', 'disabled', 'loading'];
for (const state of states) {
await page.locator(`[data-state="${state}"]`).click();
await expect(page.locator('.button-demo')).toHaveScreenshot(`button-${state}.png`);
}
});
});
3. Responsive Testing¶
const viewports = [
{ width: 375, height: 667 }, // Mobile
{ width: 768, height: 1024 }, // Tablet
{ width: 1280, height: 720 }, // Desktop
];
for (const viewport of viewports) {
test(`responsive design ${viewport.width}x${viewport.height}`, async ({ page }) => {
await page.setViewportSize(viewport);
await page.goto('/');
await expect(page).toHaveScreenshot(`homepage-${viewport.width}w.png`);
});
}
4. Umgang mit dynamischen Inhalten¶
test('page with dynamic content', async ({ page }) => {
// API-Antworten mocken
await page.route('/api/user', route => {
route.fulfill({
json: {
name: 'Test User',
avatar: 'https://example.com/static-avatar.jpg'
}
});
});
// Zeitstempel ausblenden oder mocken
await page.locator('[data-testid="timestamp"]').evaluate(el => {
el.textContent = '2023-01-01 12:00:00';
});
await expect(page).toHaveScreenshot();
});
Integration mit CI/CD¶
# GitHub Actions
name: Visual Tests
on: [push, pull_request]
jobs:
visual-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
- run: npm run build
- run: npx playwright install
- run: npx playwright test --reporter=html
- name: Upload test results
uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
Visual Regression Testing ist essenziell für die Aufrechterhaltung der UI-Qualität im großen Maßstab. Beginnen Sie mit kritischen User Journeys, erstellen Sie Baseline-Screenshots und erweitern Sie die Abdeckung schrittweise auf Komponentenebene-Tests für Ihr Design System.