In deze blog post ga ik het hebben over mijn overstap van Cucumber/Selenium naar Playwright, voor frontend end-to-end testen van webapplicaties. Als softwareontwikkelaar is het namelijk van belang dat ik alle onderdelen van mijn webapplicaties adequaat test met moderne technologieën.
Waarom frontend testen
Als je enkele van mijn case studies leest, zul je merken dat ik altijd code geautomatiseerd test met verschillende technieken. Iedere onderdeel van een softwareoplossing vereist andere testmethoden en technieken. Zo unittest ik backend code met behulp van JUnit. Voor al het visuele, zoals webapplicaties waar eindgebruikers interactie mee hebben, schrijf ik frontend testen.
Frontend test technieken
Er zijn verschillende manieren waarop je de frontend van je webapplicatie kunt testen. Zo kun je iedere losse component geïsoleerd testen. In mijn geval implementeer ik end-to-end testen voor usecases. Tenminste, als ik aan webapplicaties werk, waar ik in deze blog post vanuit ga.
End-to-end testen zijn testen waarin je de flow van verschillende functionaliteiten langsgaat en controleert of alles verloopt zoals verwacht. Daarbij worden niet alleen succes-scenario's getest, maar ook scenario's waarin het verkeerd gaat. Denk aan een foutief ingevuld formulier — in dat geval verwacht je een foutmelding.
Afgelopen jaren heb ik dit soort testen met Cucumber & Selenium gemaakt.
End-to-end testen met Cucumber
Met Cucumber, een zogenoemde behavior-driven development (BDD) tool, schrijf je de testscenario's in een voor iedereen leesbare taal. Deze taal noemen ze Gherkin, hier zie je zo'n scenario voor TheorieGO:
Gherkin
1Feature: Sign in
2
3 Scenario: Successfully authenticate with username and password
4 Given that I have navigated to the admin portal
5 When I type "admin@example.com" in the field "E-mailadres"
6 And I type "************" in the field "Wachtwoord"
7 And I press the button "Inloggen"
8 Then the "Dashboard - TheorieGO Admin" page should be openedJe kunt in vrij duidelijke taal lezen wat er in het scenario gebeurt en wordt verwacht. Echter, Gherkin stappen werken niet op magische wijze, maar dien je zelf te implementeren.
In zo'n step definition implementeer je het gedrag van de browser en kun je controleren of klopt wat er gebeurt. Dat laatste doe je door middel van assertions, bijv. met de assertions-library Chai.js.
In de volgende code-snippet zie je een voorbeeld van een step definition. Hierin controleer ik of een bepaalde pagina is geopend op basis van de paginatitel:
Typescript
1Then("the {string} page should be opened",
2 async (expectedTitle: string) => {
3 const pageTitle: string = await driver.getTitle();
4 expect(pageTitle).to.equal(expectedTitle);
5 }
6);Eén van de voordelen van het gebruik van deze methode, is dat niet-programmeurs zelf scenario's kunnen schrijven in de Gherkin-syntax.
Nadeel Cucumber voor mij
Omdat ik veelal aan relatief kleine projecten werk, als freelancer, levert deze manier van frontend testen mij veel overhead op. In mijn geval is er geen behoefte aan BDD, of niet-programmeurs die test scenario's hoeven te schrijven.
Het overslaan van de Gherkin-scenario's zal mij dus tijd besparen. Daarnaast had ik behoefte aan bepaalde features die Cucumber, ten tijde van het schrijven van deze blog, niet ondersteunt. Deze zal ik later toelichten.
Op basis van verschillende adviezen, de aangeboden features, de community (& support), het feit dat het open-source en gratis is, heb ik gekozen om Playwright in gebruik te nemen.
Eerste indruk Playwright
Met behulp van de Getting Started docs van Playwright, kun je vrij snel aan de slag. Je krijgt in eerste instantie dan een voorbeeldproject die je als basis kunt gebruiken.
In Playwright testscenario's doe je twee dingen: Acties uitvoeren ("perform actions") en het resultaat controleren (" assert the state against expectations").
Een testscenario zoals ik in het vorige Cucumber voorbeeld heb gegeven, ziet er bijvoorbeeld zo uit:
Typescript
1test.describe('Sign in', () => {
2
3 test('Successfully authenticate with username and password',
4 async ({page}) => {
5 await page.goto('http://localhost:3000/login');
6 await expect(page)
7 .toHaveTitle('Inloggen - TheorieGO Admin');
8
9 await page.getByLabel('E-mailadres')
10 .fill('admin@example.com');
11 await page.getByLabel('Wachtwoord')
12 .fill('************');
13 await page.getByRole('button', {name: 'Inloggen'})
14 .click();
15
16 await expect(page)
17 .toHaveTitle('Dashboard - TheorieGO Admin');
18 });
19
20});Met behulp van allerlei design patterns kunnen scenario's worden geoptimaliseerd. Zoals voor het hergebruiken van (delen van) scenario's of selectors.
In eerste instantie was dit voor mij vrij herkenbaar. Enige verschil ten opzichte van Cucumber was dat ik geen Gherkin stappen hoef te schrijven.
Pluspunten Playwright
Voor de Events Toegangsapp heb ik Playwright als eerst toegepast voor het testen van alle flows van de webapplicatie. Hier volgen een aantal pluspunten die ik had ondervonden.
Expect API
Zoals ik eerder toelichtte, gebruikte ik voorheen Chai.js voor assertions. Met Playwright is dat niet meer nodig, aangezien deze met een ingebouwde assertions API komt.
Voorbeeld:
Typescript
1await expect(page.getByText('Showing 1 to 15 of 100 results'))
2 .toBeVisible();
3await expect(exampleDomElement).toBeVisible();Auto-wait & auto-retrying
Playwright komt met een zogenoemde auto-wait functionaliteit. Als je een actie wilt uitvoeren met een element, dan wacht Playwright totdat dat mogelijk is, ofwel tot het element actionable is. Hierdoor hoef je géén arbitraire delay te gebruiken.
Als je bijvoorbeeld wil klikken op een element, dan controleert Playwright of de locator bestaat, zichtbaar is, stabiel is (niet animerend), events kan ontvangen en enabled is:
Typescript
1await page.getByRole('button', {name: 'Inloggen'}).click();Daarnaast heeft de assertion library ook auto-retrying assertions. Dat zijn assertions die automatisch opnieuw worden geprobeerd, totdat eraan wordt voldaan of er een timeout optreedt:
Typescript
1await expect(exampleDomElement).toBeVisible();Locator API
Het is met Playwright niet nodig om een externe selector-library te gebruiken, zoals Selenium. In plaats daarvan biedt Playwright een hoeveelheid aan ingebouwde locators.
Voorbeeld:
Typescript
1const loginButton: Locator =
2 page.getByRole('button', {name: 'Inloggen'});Code generator & inspector
Met de code generator tool, codegen, kun je flows opnemen of elementen inspecteren om zo de juiste selector te
genereren.

Trace viewer & HTML report
De Trace Viewer GUI-tool laat je traces van uitgevoerde testen zien. Je kunt per stap in je test flow zien hoe de applicatie eruitzag. Daarnaast kun je uit deze snapshots locators zoeken en inspecteren.
Multi-browser & platform
Eén van de voornaamste selling-points van Playwright is de cross-browser functionaliteit. Je kunt jouw test cases laten draaien op verschillende rendering engines, zoals Chromium, WebKit en/of Firefox.
Via het Playwright configuratie-bestand kun je dit snel instellen.

De testen zullen dan met de verschillende engines worden uitgevoerd.

Visual comparisons
Playwright heeft een ingebouwde functionaliteit waarmee je de visuele staat van de pagina kunt vergelijken met een screenshot. Zulke screenshots kunnen gegenereerd of geüpdatet worden met Playwright.
Als de pagina er visueel niet uitziet zoals verwacht, kun je dat in de trace viewer zien.

Overstap naar Playwright
Hoewel Cucumber (met Selenium) een geschikte framework is voor frontend end-to-end testen, ga ik in toekomstige projecten overstappen naar Playwright.
Wat voor mij de doorslag heeft gegeven zijn de bovengenoemde pluspunten, zoals de trace viewer en ingebouwde cross-browser functionaliteit. Daarnaast is het een steeds vaker gebruikte tool in de industrie en is er een grote community aanwezig voor support.
Naast de benoemde Playwright features uit deze blog post, zijn er nog véél meer. Hier ga ik komende tijd dus zeker mee experimenteren!
