Svenska
  • test
  • enden-till-ände test
  • integrationstest
  • utveckling
  • produktivitet
  • jest
  • puppeteer

En snabbguide till att skriva end-to-end tester med jest-puppeteer

Den här artikeln ger en snabbguide för att skriva effektiva end-to-end tester med jest-puppeteer, med fokus på installationsprocessen, vanliga API:er och praktiska testsituationer med hjälp av en enkel att-göra-app som exempel.

Yijun
Yijun
Developer

Som en del av vårt engagemang för att säkerställa kvaliteten på Logto och kontinuerlig förbättring, använder vi jest-puppeteer för end-to-end automatiserad testning. Detta gör att vi snabbt kan iterera på Logtos utveckling utan störningar.

I denna artikel delar vi med oss av vår erfarenhet av att skriva effektiva jest-puppeteer testskript med en enkel att-göra-app som exempel. Vårt mål är att hjälpa dig att snabbt komma igång med att skriva jest-puppeteer testkod för dina egna projekt.

Introduktion till end-to-end testning med jest-puppeteer

End-to-end testning är ett sätt att säkerställa att din applikation fungerar korrekt ur användarens perspektiv. För att uppnå detta använder vi två viktiga verktyg: Jest och Puppeteer.

Jest är ett populärt JavaScript testningsramverk som erbjuder ett användarvänligt API för att skriva tester och assertioner. Det används flitigt för enhets- och integrationstestning.

Puppeteer är ett Node.js-bibliotek utvecklat av Chrome-teamet som tillhandahåller ett hög nivå API för att kontrollera headless Chrome eller Chromium webbläsare. Detta gör det till ett idealiskt val för att automatisera webbläsarinteraktioner i end-to-end tester.

jest-puppeteer är ett Jest-presett som möjliggör end-to-end testning med Puppeteer. Det erbjuder ett enkelt API för att starta nya webbläsarinstanser och interagera med webbsidor genom dem.

Nu när du har en grundläggande förståelse av de viktiga verktygen, låt oss dyka in i att ställa in din testmiljö.

Ställa in din testmiljö

Att ställa in din testmiljö för end-to-end testning med jest-puppeteer är en enkel process som innefattar tre huvudsteg:

  1. Installera beroenden

I ditt projekt (eller skapa ett nytt projekt), öppna terminalen och kör:

Gå sedan till node_modules/puppeteer och installera Chromium (som behövs för Puppeteer):

  1. Konfigurera Jest

Nästa steg är att konfigurera Jest för att fungera sömlöst med Puppeteer.

Skapa en Jest-konfigurationsfil (t.ex., jest.config.js) i ditt projekts rotkatalog om du inte redan har en. I den här konfigurationsfilen anger du jest-puppeteer som ett preset:

Du kan anpassa andra Jest-inställningar i denna fil efter behov. För mer information om hur du anpassar Jest-konfigurationer, vänligen hänvisa till Jest-konfiguration.

  1. Skriv dina tester

Skapa testfiler i ditt projekt, vanligtvis namngivna med .test.js-ändelsen. Jest kommer automatiskt upptäcka och köra dessa testfiler.

Här är ett exempel från Jest-dokumentationen:

Kör sedan kommandot för att köra testet:

Genom att följa dessa tre steg kommer du att ha en välkonfigurerad testmiljö för att genomföra end-to-end tester med jest-puppeteer.

Observera dock att detta bara är ett grundläggande exempel. För mer detaljerad information om miljökonfiguration, vänligen hänvisa till relevant dokumentation:

Vanligt använda API:er

I de kommande stegen kommer vi att förlita oss på API:er som tillhandahålls av Jest, Puppeteer och jest-puppeteer för att hjälpa oss i våra tester.

Jest erbjuder huvudsakligen API:er för att organisera tester och hävda förväntade resultat. Du kan utforska de specifika detaljerna i dokumentationen.

Puppeteers API:er är främst utformade för att interagera med webbläsare, och deras stöd för testning är kanske inte lika enkelt. Du kan hänvisa till Puppeteer-dokumentationen för att förstå de funktioner den tillhandahåller. I våra efterföljande testexempel kommer vi att täcka några vanliga användningsfall.

Eftersom Puppeteers API:er inte ursprungligen utformades för testning kan det vara utmanande att använda dem för att skriva tester. För att förenkla processen att skriva Puppeteer-tester innehåller jest-puppeteer ett inbäddat bibliotek kallat expect-puppeteer. Det erbjuder en uppsättning korta och användarvänliga API:er. Biblioteket beskrivs i sin dokumentation, som introducerar olika nyttiga funktioner, som visas i exemplen nedan:

I följande exempel kommer vi att kombinera de API:er som tillhandahålls av dessa bibliotek för att slutföra våra testscenarion.

Nu är det dags att börja lära sig hur man skriver testkod med hjälp av vår enkla att-göra-app.

Den enkla att-göra-appen

Anta att vi har en enkel att-göra-app som körs på http://localhost:3000, den huvudsakliga HTML-koden för denna app är som följer:

När vi utför end-to-end-testning strävar vi efter att täcka följande scenarier:

  1. När vi öppnar appens URL ska appen och dess data laddas korrekt.
  2. Kontrollknappen i objektet ska gå att klicka på.
  3. Klicka på en extern länk inuti objektanteckningarna ska öppna länken i en ny flik.
  4. Kan lägga till ett objekt från formuläret.

Senare kommer vi att skriva testkod för att validera dessa scenarier.

Förvänta dig att appen och dess data har laddats

Vi anser att appen har laddats framgångsrikt när följande villkor är uppfyllda:

  1. Ett element med ID:t "app" bör finnas på sidan efter att man har öppnat appens URL.
  2. Datat inuti appen bör vara korrekt renderad.

Så vi har skrivit följande testkod:

I koden:

  • page.goto är motsvarande att skriva "http://localhost:3000" i webbläsaren, så att du kan navigera till vilken URL som helst.
  • page.waitForSelector används för att vänta på att en specifik CSS-selektor ska matcha ett visst element, med en default väntetid på 30 sekunder.
  • expect(page).toMatchElement kommer från expect-puppeteer lib, Det är liknande page.waitForSelector, men det stöder också att matcha texten inom ett element. Dessutom är standardtimeouten för toMatchElement endast 500 ms.

Det kan verka perfekt vid första anblicken, men när vi kör detta test och distribuerar det till en CI-miljö misslyckas det ibland efter flera körningar. Felmeddelandet indikerar:

Baserat på felinformationen och det faktum att detta test passerar oftast, kan vi dra slutsatsen att datan som begärs av appen kanske inte alltid returneras inom de första 500 ms efter att appen laddas. Därför vill vi vänta på att datan ska laddas innan vi gör påståendet.

Vanligtvis finns det två vanliga metoder för att uppnå detta:

  1. Öka assertions väntetid

Från felmeddelandet kan vi se att standardväntetiden för toMatchElement är inställd på 500 ms. Vi kan öka väntetiden genom att lägga till timeout-alternativet till funktionen på detta sätt:

Den här metoden kan minska förekomsten av misslyckade tester till viss del, men den löser inte helt problemet eftersom vi inte kan veta säkert hur mycket tid som behövs för att datan ska hämtas.

Därför använder vi bara denna metod när vi är säkra på den nödvändiga väntetiden, som i scenarion som "en tooltip visas efter att ha svävat över ett element i mer än 2 sekunder.”

  1. Vänta på att nätverksförfrågan ska slutföras innan du gör en assertion

Detta är rätt metod. Även om vi kanske inte vet hur länge datan kommer att ta, är det alltid ett säkert val att vänta på att nätverksförfrågan ska avslutas. Vid denna punkt kan vi använda page.waitForNavigation({ waitUntil: 'networkidle0' }) för att vänta på att nätverksförfrågningarna ska slutföras:

På detta sätt kan vi innan vi utför påståendet för Appen och dess laddade data säkerställa att våra nätverksförfrågningar redan har avslutats. Detta säkerställer att testet konsekvent ger rätt resultat.

Förvänta dig att klicka på en specifik knapp

Nästa test är att se om det går att klicka på check-knappen inuti ett objekt.

I exempelappen har vi märkt att alla objekt delar samma struktur. Deras check-knappar har CSS-selectorn li[class$=item] > button, och knappens text är alltid "Check". Detta innebär att vi inte direkt kan specificera vilken items check-knapp vi ska klicka på. Därför behöver vi en ny lösning.

Anta att vi vill klicka på check-knappen för "Läsa Logto kom igång-dokumentet" objektet. Vi kan dela upp detta i två steg:

  1. Först få en referens till det specifika objektet.
  2. Sedan klicka på check-knappen inuti det objektet.

Som visas i koden använder vi funktionen toMatchElement för att matcha objektet med itemName inställt på "Läsa Logto kom igång-dokumentet". Sedan använder vi referensen readDocItem för att klicka på knappen med textinnehållet 'Check' som finns under den.

Det är viktigt att notera att när vi får readDocItem, är CSS-selectorn som används li[class$=item]:has(div[class$=itemName]). Denna selektor matchar rot li elementet i objektet, inte itemName inuti det, eftersom vi har för avsikt att klicka på button under li taggen senare.

Användningen av expect(readDocItem).toClick är liknande toMatchElement. I exempel-koden skickar vi { text: 'Check' } för att ytterligare matcha textContent av knappen. Dock kan du välja om du vill matcha textinnehållet i knappen baserat på dina behov.

Förvänta dig att en extern länk öppnas i en ny flik

Nästa test är att se om det går att öppna en extern länk i en ny flik när man klickar på den inom anteckningarna.

I exempelappen har vi funnit att "Läsa Logto kom igång-dokumentet" objektet har en extern länk till Logto-dokumentet inom sina anteckningar. Här är vår testkod:

I koden utnyttjar vi toClick för att klicka på länken inom itemNotes.

Därefter använder vi browser.waitForTarget för att fånga en nyligen öppnad flik med URL:en "https://docs.logto.io/docs/tutorials/get-started."

Efter att ha erhållit fliken använder vi target.page() för att få en instans av Logto-dokumentets sida och kontrollera ytterligare om sidan har laddats.

Kom också ihåg att stänga den nyöppnade sidan efter att testet har slutförts.

Förvänta dig att skapa ett objekt från formuläret

Nu vill vi testa funktionen att lägga till ett objekt.

Vi behöver fylla i objektets namn och anteckningar i formuläret, klicka på "Add"-knappen och kontrollera om innehållet vi lagt till visas i listan:

Du kommer att märka att vi använder funktionen expect(page).toFill(inputSelector, content) för att fylla i formulärinnehållet. Denna funktion ersätter allt innehåll i inmatningen med content.

Om du vill lägga till några tecken till inmatningen utan att ersätta det befintliga innehållet kan du använda page.type(selector, content) för att direkt lägga till önskat innehåll till inmatningen.

Men när vi har många fält att fylla i vår form är det inte bekvämt att kalla toFill flera gånger. I detta fall kan vi använda följande metod för att fylla i allt innehåll i en kallelse:

Det angivna objektnyckeln är name-attributet för input-elementet.

Sammanfattning

Vi har täckt ett enkelt exempel för att introducera vanliga testkrav och motsvarande kodskrivningstekniker vid användning av jest-puppeteer för end-to-end testning. Vi hoppas att det kan hjälpa dig snabbt greppa grunderna för att skriva jest-puppeteer testkod.