Janne Göbel
Frontend-Dev
02.08.2024 | 5 min Lesezeit
Das Testen von React-Komponenten war für mich schon immer ein "Pain Point" im Arbeitsalltag. Mit meinem Einstieg in das Testing mit "Jest" und der "React Testing Library" entstand der Wunsch, das Testen von Komponenten attraktiver zu gestalten. Tests mit dem simulierten Jest-DOM ohne Browser-Features werfen jedoch die Frage nach dem Sinn solcher Tests auf. Die Performance der Tests ist nicht berauschend, und das Entwicklererlebbnis ist wenig immersiv ohne Testoberfläche mit visueller Darstellung der Komponenten. Dies kann zu einer falschen Sicherheit führen. Dennoch hat Jest nach wie vor seine Daseinsberechtigung: Gerade für das Testen von reinem JavaScript- bzw. TypeScript-Code bietet es eine solide Performance, ist gut nachvollziehbar und stellt nützliche Tools bereit. Sobald jedoch der Jest-DOM ins Spiel kommt, verabschieden sich diese Nachvollziehbarkeit und die Developer-Experience. Vor diesem Hintergrund habe ich mich auf die Suche nach einer Alternative für das UI-Komponenten-Testing begeben.
Wenn man sich mit Komponententests auseinandersetzt, stößt man unweigerlich auf zwei Frameworks: "Playwright" und "Cypress". Beide sind vor allem für das End-to-End-Testing bekannt, bieten jedoch mittlerweile auch ein Component-Testing-Feature an. Das Schöne daran ist, dass die Komponententests auf die jeweilige UI des Frameworks zugreifen, sodass man endlich sieht, was man gerade testet. Wer nun denkt, dass Komponententests mit diesen Frameworks ein Spaziergang am Strand sind, den muss ich leider enttäuschen. Das Component-Testing von Playwright befindet sich noch im experimentellen Status, und die Dokumentation ist in beiden Fällen lückenhaft. Doch mit etwas Debugging und Trial-and-Error kann man damit fertig werden und mit dem Testen beginnen.
Nach einer Erprobungsphase mit beiden Frameworks entschied ich mich für Playwright. Die Möglichkeit, Tests und Test-Suiten sowohl parallel als auch einzeln auszuführen, ist besonders praktisch. Starten kann man den oder die gewünschten Tests ganz einfach über den Explorer, der zusätzlich noch die Beschreibung/Titel des Tests beinhaltet. Zudem ist die Syntax der Tests der von Jest und der React Testing Library sehr ähnlich, was den Umstieg erleichtert. Besonders hervorzuheben ist die UI, die auf einem realen Browser basiert und "Cross-Browser-Testing" für alle gängigen Browser ermöglicht. Dies sorgt für realistische Testergebnisse. Das Herz der Testing-UI bilden ein Test-Explorer und die Visualisierung der Komponente. Ohne Probleme kann man durch Klicks im Test-Explorer zu einzelnen Schritten des Tests springen und überprüfen, was zu jedem Zeitpunkt optisch mit der Komponente geschieht.
Ein absolutes Highlight und Game-Changer ist der "Locator": Durch einen Klick auf das gewünschte Element wird der am besten geeignete "Selector" vorgeschlagen.
Playwright-Tests sind zudem sehr gut nachzuvollziehen, da sie sehr sprechend sind. Hier ein Beispiel für ein IP-Eingabefeld. Ziel des Tests ist es, zu überprüfen, wie die Komponente mit ungültigen Eingaben umgeht. Im Fall einer IP sollte jedes Oktett eine Zahl zwischen 0 und 255 sein und keine Buchstaben oder Sonderzeichen enthalten.
test("only accepts valid inputs", async ({ mount }) => {
// Komponente wird eingefügt
const component = await mount(<IpInput />);
// Das erste Eingabefeld wird selektiert
const firstOctet = await component.getByRole("textbox").first();
// User-Interaktionen und ungültige Eingaben werden nachgestellt
await firstOctet.press("2");
await firstOctet.press("5");
await firstOctet.press("a");
await firstOctet.press("6");
await firstOctet.press("5");
// Der Wert des ersten Eingabefelds wird kontrolliert
expect(firstOctet).toHaveText("255");
});
Neben der UI bietet Playwright ebenfalls die Möglichkeit, Tests in der Konsole auszuführen. Das Schöne daran ist, dass hier mit gängigen Browsern getestet werden kann, wodurch Bugs und Browser-Limitations schnell sichtbar gemacht werden. Dieses Konsolenskript kann zusätzlich in CI-Pipelines eingebunden werden, um die Zusammenarbeit im Team zu verbessern und Fehler zu vermeiden bzw. frühzeitig zu erkennen. Gerade für die CI-Pipeline bietet Playwright in seiner Konfiguration extrem hilfreiche Funktionen. So kann zum Beispiel die Anzahl der "Retries" in der CI anders gesetzt werden als lokal, was den Charme hat, dass Tests in der CI mehrmals durchlaufen werden, bevor die Pipeline wirklich fehlschlägt. Zudem kann hier auch das Load-Balancing auf verschiedene "Worker" für die CI deaktiviert werden. Man kann auch aus verschiedenen Arten von Reports wählen, um gegebenenfalls entweder detaillierte oder simple Ausgaben zu erhalten.
// Retries nur in CI
retries: process.env.CI ? 2 : 0,
// Limit auf einen Worker in CI
workers: process.env.CI ? 1 : undefined,
// HTML Test-Report lokal
reporter: process.env.CI ? "list" : [["html"], ["list"]],
Alles in allem macht das Testing mit Playwright einen entwicklerorientierten Eindruck, zumindest löst es einige Probleme vor denen man beim Komponenttesting mit bspw. Jest steht. Um ehrlich zu sein hat das Testing mit der UI sogar ein wenig Spaß gemacht. Tests und Testfälle sind nachvaollziehbar und mögliche Probleme innerhalb einer Komponente werden besser sichtbar. Die Playwright Testoberfläche gestaltet den Prozess spielerisch, und der Locator macht Work-Arounds wie Test-IDs obsolet. Zudem sieht man neben einer Fehlermeldung in der Konsole auch, was zu diesem Zeitpunkt mit der Komponente schiefläuft. Über das Testen in der CLI kann man Testläufe ganz einfach in den Entwicklungsprozess einbinden, und eine Integration der Tests in die CI-Pipeline dient als Sicherheitsmaßnahme bei Kollaborationen und Pull-Requests. Deshalb kann ich jedem den Blick in Richtung Playwright nur empfehlen, jedenfalls möchte es in meinem Entwickleralltag nicht mehr missen.