Een snelstartgids voor het schrijven van end-to-end tests met jest-puppeteer
Dit artikel biedt een snelle gids voor het schrijven van efficiënte end-to-end tests met jest-puppeteer, met de nadruk op het installatieproces, vaak gebruikte API's en praktische testsituaties, waarbij een eenvoudige takenlijst-app als voorbeeld wordt gebruikt.
Als onderdeel van onze toewijding aan het waarborgen van de kwaliteit van Logto en voortdurende verbetering, gebruiken we jest-puppeteer voor end-to-end geautomatiseerde tests. Dit stelt ons in staat om snel voort te bouwen op de ontwikkeling van Logto zonder onderbrekingen.
In dit artikel delen we onze ervaring met het schrijven van efficiënte jest-puppeteer testscripts met behulp van een eenvoudige takenlijst-app als voorbeeld. Ons doel is om jou snel aan de slag te helpen met het schrijven van jest-puppeteer testcode voor je eigen projecten.
Inleiding tot end-to-end testen met jest-puppeteer
End-to-end testen is een manier om ervoor te zorgen dat je applicatie correct werkt vanuit het perspectief van de gebruiker. Om dit te bereiken, gebruiken we twee essentiële tools: Jest en Puppeteer.
Jest is een populair JavaScript testframework dat een gebruiksvriendelijke API biedt voor het schrijven van tests en beweringen. Het wordt veel gebruikt voor unit- en integratietesten.
Puppeteer is een Node.js bibliotheek ontwikkeld door het Chrome-team die een hoog niveau API biedt voor het besturen van headless Chrome of Chromium browsers. Dit maakt het een ideale keuze voor het automatiseren van browserinteracties in end-to-end tests.
jest-puppeteer is een Jest-preset die end-to-end testen met Puppeteer mogelijk maakt. Het biedt een eenvoudige API voor het starten van nieuwe browserinstanties en het interactief omgaan met webpagina's via hen.
Nu je een basisbegrip hebt van de essentiële tools, laten we de opzet van je testomgeving in duiken.
De testomgeving instellen
Het instellen van je testomgeving voor end-to-end testen met jest-puppeteer is een eenvoudig proces dat uit drie hoofd stappen bestaat:
- Installeer afhankelijkheden
In je project (of maak een nieuw project aan), open de terminal en voer het volgende uit:
Ga vervolgens naar de node_modules/puppeteer
en installeer Chromium (dat nodig is voor Puppeteer):
- Configureer Jest
Vervolgens moet je Jest configureren om naadloos samen te werken met Puppeteer.
Creëer een Jest-configuratiebestand (bijv. jest.config.js
) in de rootmap van je project, als je er nog geen hebt. In dit configuratiebestand specificeer je jest-puppeteer als een preset:
Je kunt andere Jest-instellingen in dit bestand aanpassen indien nodig. Voor meer informatie over het aanpassen van Jest-configuraties, raadpleeg de Jest-configuratie.
- Schrijf je tests
Maak testbestanden in je project, meestal genaamd met de .test.js
extensie. Jest zal deze testbestanden automatisch ontdekken en uitvoeren.
Hier is een voorbeeld uit de Jest doc:
Voer vervolgens het commando uit om de test te uitvoeren:
Door deze drie stappen te volgen, heb je een goed geconfigureerde testomgeving voor het uitvoeren van end-to-end tests met jest-puppeteer.
Let op: dit is slechts een basisvoorbeeld. Voor meer gedetailleerde informatie over het configureren van een omgeving, raadpleeg de relevante documentatie:
Veel gebruikte API's
In de komende stappen zullen we vertrouwen op de API's die worden aangeboden door Jest, Puppeteer en jest-puppeteer om ons bij onze tests te helpen.
Jest biedt primair API's voor het organiseren van tests en het bevestigen van verwachte resultaten. Je kunt de specifieke details in de documentatie verkennen.
De API's van Puppeteer zijn primair ontworpen voor interactie met browsers, en hun ondersteuning voor testen is misschien niet zo eenvoudig. Je kunt de Puppeteer documentatie raadplegen om de functionaliteiten te begrijpen die het biedt. In onze volgende testvoorbeelden zullen we enkele veelvoorkomende gebruiksscenario's behandelen.
Omdat de API's van Puppeteer oorspronkelijk niet zijn ontworpen voor testen, kan het gebruik ervan voor het schrijven van tests uitdagend zijn. Om het schrijven van Puppeteer-tests te vereenvoudigen, bevat jest-puppeteer een ingebouwde bibliotheek genaamd expect-puppeteer
. Het biedt een reeks beknopte en gebruiksvriendelijke API's. De bibliotheek wordt gedetailleerd beschreven in zijn documentatie, die verschillende nuttige functies introduceert, zoals getoond in de onderstaande voorbeelden:
In de volgende voorbeelden zullen we de API's van deze bibliotheken combineren om onze testsituaties te voltooien.
Nu is het tijd om te beginnen met het leren schrijven van testcode met onze eenvoudige takenlijst-app.
De eenvoudige takenlijst-app
Stel dat we een eenvoudige takenlijst-app hebben die draait op http://localhost:3000
, de belangrijkste HTML-code voor deze app is als volgt:
Bij het uitvoeren van end-to-end testen willen we de volgende scenario's bestrijken:
- Wanneer we de URL van de app openen, zouden de app en zijn gegevens correct moeten laden.
- De controleknop van het item moet klikbaar zijn.
- Het klikken op een externe link in de itemnotities moet de link in een nieuw tabblad openen.
- Een item via het formulier kunnen toevoegen.
Later zullen we testcode schrijven om deze scenario's te valideren.
Verwacht dat de app en zijn gegevens zijn geladen
We beschouwen dat de app succesvol is geladen wanneer aan de volgende voorwaarden is voldaan:
- Een element met de ID "app" moet op de pagina bestaan na toegang tot de URL van de app.
- De gegevens binnen de app moeten correct worden weergegeven.
Dus we hebben de volgende testcode geschreven:
In de code:
page.goto
is gelijk aan het invoeren van "http://localhost:3000" in de browser, zodat je naar elke URL kunt navigeren.page.waitForSelector
wordt gebruikt om te wachten op een specifieke CSS-selector die overeenkomt met een bepaald element, met een standaard wachttijd van 30 seconden.expect(page).toMatchElement
is van deexpect-puppeteer
bibliotheek, het is vergelijkbaar metpage.waitForSelector
, maar het ondersteunt ook het matchen van de tekst binnen een element. Bovendien is de standaardtimeout voortoMatchElement
slechts 500ms.
Het lijkt op het eerste gezicht perfect, maar wanneer je deze test uitvoert en naar een CI-omgeving inzet, mislukt het af en toe na meerdere uitvoeringen. De foutmelding geeft aan:
Op basis van de foutinformatie en het feit dat deze test meestal slaagt, kunnen we afleiden dat de gegevens die door de app worden opgevraagd mogelijk niet altijd binnen de eerste 500ms na het laden van de app worden geretourneerd. Daarom willen we wachten tot de gegevens zijn geladen voordat we de bewering uitvoeren.
Er zijn doorgaans twee veelvoorkomende benaderingen om dit te bereiken:
- Verhoog de wachttijd van de bewering
Uit het foutbericht kunnen we zien dat de standaardwachttijd voor toMatchElement
is ingesteld op 500ms. We kunnen de wachttijd verhogen door de optie timeout
aan de functie toe te voegen als volgt:
Deze benadering kan de kans op mislukte tests enigszins verminderen, maar lost het probleem niet helemaal op, omdat we niet zeker weten hoeveel tijd nodig is om de gegevens op te halen.
Daarom gebruiken we deze benadering alleen wanneer we zeker zijn van de benodigde wachttijd, zoals in scenario's als "een tooltip verschijnt na het zweven boven een element gedurende meer dan 2 seconden.”
- Wacht tot het netwerkverzoek is voltooid voordat je een bewering doet
Dit is de juiste benadering. Hoewel we misschien niet weten hoe lang het dataverzoek zal duren, is wachten op het voltooien van het netwerkverzoek altijd een veilige keuze. Op dit punt kunnen we page.waitForNavigation({ waitUntil: 'networkidle0' })
gebruiken om te wachten tot de netwerkverzoeken zijn voltooid:
Op deze manier, voordat we de bewering voor de App en zijn geladen gegevens uitvoeren, kunnen we ervoor zorgen dat onze netwerkverzoeken al zijn voltooid. Dit zorgt ervoor dat de test consequent de juiste resultaten oplevert.
Verwacht om op een specifieke knop te klikken
Vervolgens testen we de functionaliteit van het klikken op de controleknop binnen een item.
In de voorbeeldapp hebben we opgemerkt dat alle items dezelfde structuur hebben. Hun controleknoppen hebben de CSS-selector li[class$=item] > button
, en de knoptekst is altijd "Check". Dit betekent dat we niet direct kunnen specificeren op welke controleknop van het item we willen klikken. We hebben dus een nieuwe oplossing nodig.
Stel dat we op de controleknop van het "Lees Logto aan de slag document" item willen klikken. We kunnen dit in twee stappen opsplitsen:
- Eerst, verkrijg een referentie naar dat specifieke item.
- Klik vervolgens op de controleknop binnen dat item.
Zoals te zien is in de code, gebruiken we de toMatchElement
functie om het item te matchen met de itemName
ingesteld op "Lees Logto aan de slag document". Vervolgens gebruiken we de readDocItem
referentie om te klikken op de knop met de tekstinhoud 'Check' eronder.
Het is belangrijk op te merken dat bij het verkrijgen van de readDocItem
, de CSS-selector die wordt gebruikt is li[class$=item]:has(div[class$=itemName])
. Deze selector matcht het root li
-element van het item, niet het itemName
erin, omdat we van plan zijn om later op de button
onder de li
-tag te klikken.
Het gebruik van expect(readDocItem).toClick
is vergelijkbaar met toMatchElement
. In de voorbeeldcode geven we { text: 'Check' }
door om verder de textContent
van de button te matchen. Je kunt echter beslissen of je de tekstinhoud van de button wilt matchen op basis van je behoeften.
Verwacht dat een externe link wordt geopend in een nieuw tabblad
Vervolgens willen we testen of we een externe link in een nieuw tabblad kunnen openen wanneer erop wordt geklikt binnen de itemnotities.
In de voorbeeldapp hebben we ontdekt dat het "Lees Logto aan de slag document" item een externe link naar de Logto-documentatie binnen de notities bevat. Hier is onze testcode:
In de code gebruiken we toClick
om op de link binnen itemNotes
te klikken.
Vervolgens gebruiken we browser.waitForTarget
om een nieuw geopend tabblad te vangen met de URL "https://docs.logto.io/docs/tutorials/get-started."
Nadat je het tabblad hebt verkregen, gebruiken we target.page()
om een instantie van de Logto doc-pagina te krijgen en verder te controleren of de pagina is geladen.
Vergeet ook niet om de nieuw geopende pagina te sluiten na het voltooien van onze test.
Verwacht een item te maken via het formulier
Nu willen we de functionaliteit van het toevoegen van een item testen.
We moeten de itemnaam en itemnotities in het formulier invullen, op de "Toevoegen" knop klikken en controleren of de inhoud die we hebben toegevoegd in de lijst verschijnt:
Je zult merken dat we de expect(page).toFill(inputSelector, content)
functie gebruiken om de inhoud van het formulier in te vullen. Deze functie vervangt alle inhoud in de input door de content
.
Als je enkele tekens aan de input wilt toevoegen zonder de bestaande inhoud te vervangen, kun je page.type(selector, content)
gebruiken om de gewenste inhoud direct toe te voegen aan de input.
Echter, wanneer we veel velden hebben om in ons formulier in te vullen, is het niet handig om toFill
meerdere keren aan te roepen. In dit geval kunnen we de volgende benadering gebruiken om alle inhoud in één keer in te vullen:
De verstrekte objectkey is het name-atribuut van het inputelement.
Samenvatting
We hebben een eenvoudig voorbeeld behandeld om veelvoorkomende testvereisten en bijbehorende technieken voor het schrijven van code te introduceren bij het gebruik van jest-puppeteer voor end-to-end testen. We hopen dat dit je kan helpen om snel de basisprincipes van het schrijven van jest-puppeteer testcode onder de knie te krijgen.