Visual-Regression-Testing im Hyvä-Theme etablieren
AI generated
Hyvä
phtml
Hyvä Theme · Testing & CI
Visual-Regression-Testing im Hyvä-Theme etablieren
Wie unbeabsichtigte Layout-Verschiebungen nach einem CSS-Refactoring automatisiert auffallen, statt erst beim Kunden

Ein funktionaler Test bestätigt, dass ein Button klickbar bleibt und ein Formular absendet, sagt aber nichts darüber aus, ob dieselbe Interaktion nach einem Tailwind-Refactoring plötzlich zwei Pixel verschoben oder mit falschem Kontrast dargestellt wird. Dieser Artikel zeigt, wie Visual-Regression-Testing mit Playwright-Screenshots oder Percy als eigene Test-Ebene im Hyvä-Theme aufgebaut wird, welche Seiten für den Testumfang tatsächlich sinnvoll sind, und wie dynamische Inhalte wie Preise und Datumsangaben Snapshots nicht länger verfälschen.

10 Min. Lesezeit Percy Playwright Snapshot-Testing

1. Warum Visual-Regression-Testing eine eigene Test-Ebene neben funktionalen Tests braucht

Funktionale End-to-End-Tests prüfen, ob eine Interaktion das erwartete Ergebnis liefert, etwa ob ein Klick auf Warenkorb hinzufügen tatsächlich einen Artikel im Mini-Cart erscheinen lässt. Sie prüfen aber grundsätzlich nicht, wie diese Interaktion aussieht, weshalb ein Tailwind-Refactoring, das versehentlich eine Utility-Klasse wie px-4 in p-4 ändert und dadurch ein Layout verschiebt, in der funktionalen Testsuite unbemerkt bleibt, solange der Button weiterhin klickbar ist.

Visual-Regression-Testing schließt genau diese Lücke, indem es einen Referenz-Screenshot einer Seite oder Komponente mit einem neuen Screenshot nach einer Codeänderung pixelweise oder perzeptuell vergleicht und jede signifikante Abweichung markiert. Für ein Tailwind-lastiges Theme wie Hyvä, in dem sich CSS-Änderungen besonders leicht unbeabsichtigt auf entfernte Stellen im Markup auswirken können, ist diese zusätzliche Ebene kein Luxus, sondern ein notwendiges Sicherheitsnetz.

2. Werkzeugwahl: Playwright-Screenshots gegen Percy abwägen

Playwrights eingebaute toHaveScreenshot()-Assertion vergleicht Bilder pixelweise gegen eine im Repository gespeicherte Baseline und benötigt keinen externen Dienst, wodurch sie ohne zusätzliche Kosten läuft und vollständig unter eigener Kontrolle bleibt. Der Nachteil ist, dass Baselines je nach Betriebssystem und Schriftrendering leicht unterschiedlich ausfallen können, weshalb Screenshots konsequent im selben Docker-Image erzeugt werden müssen, das auch die CI-Pipeline verwendet.

Percy dagegen ist ein Cloud-Dienst, der einen perzeptuellen statt rein pixelbasierten Vergleich vornimmt und dadurch weniger anfällig für minimale Rendering-Unterschiede ist, gleichzeitig aber laufende Kosten und eine Abhängigkeit von einem externen Anbieter mit sich bringt. Für ein einzelnes, überschaubares Theme-Projekt ist der pixelbasierte Playwright-Ansatz häufig ausreichend, während Percy sich für größere Teams mit einem etablierten Review-Workflow für visuelle Diffs stärker lohnt.


// playwright.config.ts
export default defineConfig({
  expect: {
    toHaveScreenshot: {
      maxDiffPixelRatio: 0.01,
      animations: 'disabled',
    },
  },
  projects: [
    { name: 'visual-chromium', use: { browserName: 'chromium' } },
  ],
});

3. Sinnvolle Seiten-Auswahl für den Testumfang treffen

Der größte Fehler beim Einstieg in Visual-Regression-Testing ist, jede einzelne Produktseite eines Katalogs mit tausenden Artikeln zu erfassen, obwohl die meisten Produktseiten dasselbe Template und damit dieselbe potenzielle Fehlerquelle teilen. Sinnvoller ist eine kleine, bewusst kuratierte Menge an Templates: eine Produktdetailseite mit und ohne Sonderpreis, eine Kategorieseite mit aktiver Facettennavigation, ein Warenkorb mit mehreren Artikeln, ein einzelner Checkout-Schritt und die CMS-Startseite.

Diese Auswahl deckt jedes im Theme vorhandene Layout-Muster mindestens einmal ab, ohne die Pipeline mit hunderten nahezu identischen Screenshots zu überladen, die im Zweifel ohnehin gemeinsam kippen, wenn sich eine gemeinsam genutzte Komponente wie die Produktkarte ändert. Neue Seiten-Typen, etwa ein neu eingeführtes Landingpage-Layout, werden erst dann ergänzt, wenn sie tatsächlich ein eigenständiges Muster darstellen, nicht bei jeder neuen URL.

4. Dynamische Inhalte wie Preise und Datumsangaben zuverlässig maskieren

Ein Preis, der sich durch eine automatische Rabattregel zwischen zwei Testläufen ändert, oder ein relatives Datum wie vor drei Tagen in einer Produktbewertung, sorgt dafür, dass ein Screenshot-Vergleich fälschlicherweise als Regression markiert wird, obwohl sich am Layout selbst nichts verändert hat. Playwrights mask-Option in toHaveScreenshot() erlaubt es, genau diese Bereiche über einen Selektor gezielt mit einem einfarbigen Block zu überdecken, statt den gesamten Screenshot unzuverlässig zu machen.

Percy verfolgt denselben Gedanken über percy-css-Regeln, die vor der Aufnahme des Screenshots bestimmte Elemente ausblenden oder mit einer festen Ersatzfarbe füllen. In beiden Fällen bleibt der eigentliche Layout-Bereich, in dem der Preis oder das Datum steht, weiterhin Teil des Vergleichs, sodass ein tatsächlicher Layout-Fehler an dieser Stelle nach wie vor erkannt wird, während der sich ständig ändernde Inhalt selbst keine falschen Alarme mehr auslöst.


await expect(page).toHaveScreenshot('pdp-rucksack-classic.png', {
  mask: [
    page.locator('[data-testid="product-price"]'),
    page.locator('[data-testid="review-date"]'),
  ],
  maxDiffPixelRatio: 0.01,
});

5. Deterministische Testdaten als Grundlage stabiler Snapshots

Maskierung allein löst nicht jedes Problem, denn ein Preis, der sich zwischen zwei Testläufen von einer zwei- auf eine dreistellige Zahl ändert, kann trotz Maskierung eine minimal andere Textbreite und damit ein leicht verschobenes Layout in benachbarten Elementen erzeugen. Ein dediziertes Fixture-Produkt mit einem fest hinterlegten, niemals durch Rabattregeln veränderten Preis vermeidet dieses Problem an der Wurzel, statt es nachträglich mit Masken zu kaschieren.

Für den Katalog empfiehlt sich deshalb ein kleiner, klar als Testdaten markierter Satz von Produkten, der über ein eigenes CLI-Kommando vor jedem Visual-Test-Lauf reproduzierbar neu angelegt wird, statt sich auf zufällig vorhandene Produktionsdaten oder manuell gepflegte Staging-Inhalte zu verlassen, die sich über die Zeit unbemerkt verändern können.

6. Web-Fonts und Lazy-Loading als versteckte Flakiness-Quelle

Ein Screenshot, der aufgenommen wird, bevor eine Web-Font vollständig geladen ist, zeigt kurzzeitig die Fallback-Schrift des Betriebssystems mit einer anderen Zeichenbreite, wodurch Zeilenumbrüche an unerwarteten Stellen entstehen und der Vergleich fehlschlägt, obwohl kein echter Fehler vorliegt. Ein await page.evaluate(() => document.fonts.ready) vor jedem Screenshot stellt sicher, dass tatsächlich die finale Schrift gerendert wurde.

Ebenso führt Lazy-Loading von Produktbildern dazu, dass ein Bild zum Zeitpunkt des Screenshots noch als grauer Platzhalter erscheint, wenn es sich außerhalb des initial sichtbaren Bereichs befindet. Ein kurzes Scrollen über die gesamte Seite vor der eigentlichen Aufnahme sowie das Deaktivieren von CSS-Transitions über die animations-Option verhindern, dass der Zeitpunkt der Aufnahme selbst zur Fehlerquelle wird.

7. Einen Approval-Workflow für echte visuelle Änderungen etablieren

Nicht jede erkannte Abweichung ist ein Fehler. Eine bewusste Design-Änderung, etwa ein größerer Abstand zwischen Produktkarten nach einem Redesign, führt zu Recht zu einem visuellen Diff, der aber akzeptiert und nicht behoben werden soll. Playwright löst das über das Kommando --update-snapshots, das die neue Aufnahme als neue Baseline übernimmt und damit im selben Commit wie die Codeänderung landet, statt in einer separaten, leicht zu vergessenden Aktion.

Percy bietet dafür eine eigene Weboberfläche, in der ein Reviewer jeden Diff explizit als akzeptiert oder abgelehnt markiert, bevor der zugehörige Merge-Request gemergt werden darf. Unabhängig vom gewählten Werkzeug sollte diese Entscheidung immer von einer Person getroffen werden, die den fachlichen Kontext der Änderung kennt, nicht automatisiert oder pauschal von der Pipeline selbst.

8. Visual Tests in die CI-Pipeline integrieren, ohne sie auszubremsen

Weil Visual Tests naturgemäß langsamer sind als reine Funktionstests, da für jede geprüfte Seite ein vollständiger Screenshot gerendert und verglichen werden muss, lohnt sich ein eigener, parallel laufender Pipeline-Job statt einer Integration in die ohnehin schon laufende funktionale Testsuite. Dieser Job kann zusätzlich nur auf Merge-Requests laufen, die tatsächlich Änderungen an .phtml- oder CSS-Dateien enthalten, statt bei jedem einzelnen Commit im gesamten Repository.

Für sehr große Themes lohnt sich außerdem eine Sharding-Strategie, bei der die kuratierte Seitenliste auf mehrere parallele Runner aufgeteilt wird, sodass die Gesamtlaufzeit auch bei einer wachsenden Zahl an Snapshot-Seiten überschaubar bleibt und Visual-Regression-Testing nicht zum limitierenden Faktor der gesamten Pipeline wird.

9. Praxisbeispiel: die Kategorieseite mit Facettennavigation visuell absichern

Eine Kategorieseite mit geöffnetem Facetten-Panel ist ein besonders lohnendes Ziel für Visual-Regression-Testing, weil sie viele unterschiedliche Hyvä-Komponenten gleichzeitig kombiniert: Filter-Checkboxen, Preis-Slider, Sortier-Dropdown und die Produktkarten-Grid-Struktur. Ein einziger Screenshot deckt damit potenzielle Layout-Fehler in mehreren Komponenten gleichzeitig ab, statt für jede Komponente einen isolierten Test zu benötigen.

Wichtig ist, den Screenshot erst nach dem vollständigen Öffnen des Facetten-Panels und nach Abschluss der zugehörigen Alpine-Transition aufzunehmen, damit das Bild denselben, tatsächlich für Nutzer sichtbaren Endzustand abbildet, den auch ein manueller Test sehen würde, statt einen willkürlichen Zwischenzustand während der Animation festzuhalten.


test('Kategorieseite mit geoeffneten Facetten bleibt visuell stabil', async ({ page }) => {
  await page.goto('/damen/jacken.html');
  await page.evaluate(() => (window as any).__alpineReady);
  await page.locator('[data-testid="filter-toggle"]').click();
  await page.locator('[data-testid="filter-panel"]').waitFor({ state: 'visible' });
  await page.evaluate(() => document.fonts.ready);

  await expect(page).toHaveScreenshot('plp-jacken-facetten-offen.png', {
    mask: [page.locator('[data-testid="product-price"]')],
    fullPage: true,
  });
});
Werkzeug Vergleichsart Kosten Gut geeignet für
Playwright toHaveScreenshot Pixelbasiert, lokale Baseline Keine externen Kosten Kleinere Teams mit eigener CI-Infrastruktur
Percy Perzeptueller Cloud-Vergleich Laufende Abo-Kosten Größere Teams mit etabliertem Review-Workflow
Chromatic Komponentenbasiert über Storybook Laufende Abo-Kosten Teams mit vorhandener Storybook-Struktur
Manueller Vergleich Visuelle Prüfung durch eine Person Zeitaufwand statt Lizenzkosten Einzelne, seltene Design-Freigaben

Mironsoft

Hyvä-Theme-Entwicklung und Luma-Migration

Noch auf Luma unterwegs oder ein Hyvä-Theme, das nicht rund läuft?

Wir entwickeln Hyvä-Themes für Magento von Grund auf oder migrieren bestehende Luma-Shops sauber, mit Tailwind CSS, Alpine.js und ohne unnötiges JavaScript-Gepäck.

Luma-zu-Hyvä-Migration

Bestehenden Shop strukturiert und ohne Funktionsverlust auf Hyvä umstellen.

Custom-Theme-Entwicklung

Individuelles Hyvä-Theme nach Design-Vorgaben von Grund auf umsetzen.

Performance-Optimierung

Core Web Vitals und Ladezeiten im Hyvä-Frontend gezielt verbessern.

10. Zusammenfassung

Visual-Regression-Testing im Hyvä-Theme: Das Wichtigste auf einen Blick

Eigene Test-Ebene

Visual-Regression-Testing erkennt Layout-Fehler, die funktionale Tests grundsätzlich übersehen.

Kuratierte Seitenauswahl

Ein Template pro Layout-Muster reicht aus, nicht jede einzelne Produktseite.

Maskierung plus Fixture-Daten

Preise und Daten werden maskiert, echte Rabattschwankungen durch feste Testprodukte vermieden.

Bewusster Approval-Workflow

Echte Design-Änderungen werden von einer Person akzeptiert, nicht automatisch übernommen.

11. FAQ: Visual-Regression-Testing im Hyvä-Theme: Das Wichtigste auf einen Blick

1Warum reicht eine funktionale Testsuite nicht aus, um Layout-Fehler zu erkennen?
Weil funktionale Tests nur prüfen, ob eine Interaktion das erwartete Ergebnis liefert, nicht wie sie aussieht. Ein Klick bleibt funktional korrekt, selbst wenn ein Tailwind-Refactoring das Layout unbeabsichtigt verschiebt.
2Playwright-Screenshots oder Percy: welches Werkzeug passt besser zu einem einzelnen Theme-Projekt?
Playwrights eingebaute toHaveScreenshot-Assertion ist meist ausreichend und verursacht keine laufenden Kosten. Percy lohnt sich eher für größere Teams mit einem etablierten Review-Workflow für visuelle Diffs.
3Wie viele Seiten sollten in ein Visual-Regression-Setup aufgenommen werden?
Eine kleine, kuratierte Menge, die jedes im Theme vorhandene Layout-Muster mindestens einmal abdeckt, etwa eine Produktdetailseite, eine Kategorieseite mit Facetten, einen Checkout-Schritt und die Startseite, statt jede einzelne Produktseite.
4Wie werden Preise in Screenshots zuverlässig maskiert?
Über die mask-Option von Playwrights toHaveScreenshot beziehungsweise über percy-css-Regeln bei Percy, die den entsprechenden Bereich vor der Aufnahme gezielt mit einem einfarbigen Block überdecken.
5Warum reicht Maskierung allein manchmal nicht aus?
Weil ein Preiswechsel von einer zwei- auf eine dreistellige Zahl trotz Maskierung eine andere Textbreite erzeugen und dadurch benachbarte Elemente leicht verschieben kann. Ein Fixture-Produkt mit festem Preis vermeidet dieses Problem direkt an der Wurzel.
6Wie wird verhindert, dass Web-Fonts einen Screenshot-Vergleich verfälschen?
Über ein document.fonts.ready-Await direkt vor jeder Aufnahme, das sicherstellt, dass tatsächlich die finale Schrift und nicht kurzzeitig eine Fallback-Schrift gerendert wurde.
7Wie geht ein Visual-Test mit lazy geladenen Produktbildern um?
Durch ein kurzes Scrollen über die gesamte Seite vor der eigentlichen Aufnahme, damit alle Bilder außerhalb des initial sichtbaren Bereichs bereits geladen sind und nicht als grauer Platzhalter erscheinen.
8Wer sollte einen erkannten visuellen Diff akzeptieren oder ablehnen?
Immer eine Person mit fachlichem Kontext zur Änderung, etwa über Playwrights --update-snapshots-Kommando im selben Commit oder über Percys Weboberfläche, nie eine automatische, pauschale Entscheidung der Pipeline.
9Wie bleibt eine Visual-Regression-Pipeline auch bei vielen Snapshots schnell?
Über einen eigenen, parallel laufenden Pipeline-Job, der nur bei Änderungen an .phtml- oder CSS-Dateien ausgelöst wird, sowie über eine Sharding-Strategie, die die Seitenliste auf mehrere Runner verteilt.
10Warum eignet sich eine Kategorieseite mit Facettennavigation besonders gut als Visual-Test?
Weil sie mehrere Hyvä-Komponenten gleichzeitig kombiniert, etwa Filter, Preis-Slider, Sortierung und Produktkarten, sodass ein einziger Screenshot potenzielle Layout-Fehler in mehreren Komponenten auf einmal abdeckt.