E2E Testing In Angular 2 From Zero To Hero (Final Part)
Kära framtida mästare i Angular 2 E2E Testing.
Det här är det. I slutet av den här lektionen kommer du äntligen att ha alla verktyg för att skapa funktionella tester för dina Angular 2-applikationer. Inga fler ursäkter:
Vi kommer först att bekanta oss med Locators, sedan kommer vi att se hur häftiga Page Objects kan vara, följt av hur man hanterar asynkronitet och slutligen den enklaste delen som är att trigga Actions.
Om du inte har grunderna rätt, gå dit annars kommer du att vara lite vilse.
Locators
En om inte den viktigaste saken i E2E-testning är att hitta de element som du vill testa i din vy. Oftast kommer du att ställa dig själv frågan ”varför kan jag inte hitta det här **** elementet?” följt av ett ”oooohhhhhhh”.
Det finns många sätt att göra detta på. De flesta av dem beror på ditt program. För att hitta dina element kommer du att använda en rad Locators. För det mesta kan du hitta dina element genom att:
- Klassnamn.
- Id.
- Model.
- Binding.
För de kommande testerna kommer vi att använda denna mall.html:
<div class="parent2"> <div class="parent1"> <div class="nested-class" style="color:blue;"> I am a nested element </div> </div></div>
Låt oss fokusera på nested-class och nested-id.
By Class:
Vi tar här vårt element med element(by.css(selector)) och sedan testar vi om det finns eller inte.
By Id:
it("should find the nested id", () => { let elem = element(by.id("nested-id")); expect(elem.getText()).toBe("I am a nested element");});
Vi tar här vårt element med hjälp av element(by.id(elem-id)) och sedan testar vi om det finns eller inte.
Följande lokaliserare är mycket användbara i AngularJS, men de är ännu inte implementerade i Angular 2, så håll dem bara vid sidan om för tillfället.
By Model:
it("should find the model", () => { let elem = element(by.model("modelToFind")); expect(elem.isPresent()).toBeTruthy();});
By Bindings:
it("should find the binding", () => { let elem = element(by.model("bindingToFind")); expect(elem.isPresent()).toBeTruthy();});
För att felsöka dina tester kan du bara lägga till ”browser.pause()” i ditt test, du kommer att kunna köra alla tidigare instruktioner och stoppa var du vill.
När den når din paus kommer du att få en skärm som liknar den här:
Som du kan se i den här bilden, för att komma in i förarsätet måste du skriva repl.
Nu låt oss säga att du inte har något test och att du bara vill leka runt med Protractor. Du kan bara skriva i din terminal:
protractor --elementExplorer
Om du har några problem med din sökväg kan du skriva:
./node_modules/protractor/bin/elementexplorer.js
Ingen anledning att skriva repl den här gången, använd bara webbläsarobjektet och du är redo att segla!
Page Objects
Hur är det om du har tester som delar samma scenario? Ska du kopiera och klistra in din kod överallt? Vad händer om scenariot ändras? Nu måste du gå igenom alla filer och göra ändringarna.
Det är här som Pages Objects blir mycket användbara. Skriv en gång, dela överallt!
Ett sidobjekt är ett objekt som innehåller element och scenarier för en sida.
Först ett mycket enkelt Page Object:
export class HomePage { nestedClass; constructor() { this.nestedClass = element(by.css(".nested-class")); }}
Därefter använder vi det i vårt test:
Vi importerar Page Object, skapar en instans och använder sedan dess egenskap.
Asynkrona äventyr
Nu, mina vänner, kan du komma åt alla element på din sida! Jag menar nästan :).
Det kommer att finnas några specialfall.
Om du hade (o)tur nog att arbeta med jQuery måste du vara bekant med document.ready().
På grund av JavaScript:s asynkrona natur kommer det att finnas fall där du kommer att försöka få tillgång till ett element innan det ännu har dykt upp på sidan.
För att hantera detta måste du använda en funktion i Protractor för att vänta på att ditt element ska vara redo innan du letar efter det.
Här är ett exempel som visar en knapp efter att en timeout har löpt ut.
Först klassen som innehåller timeout:
export class Home { isHidden = true; triggerTimeOut = ((){ setTimeout(() => this.isHidden = false, 2250) })}
Därefter template.html:
Vi har här en knapp som utlöser vår timeout, när timeouten löper ut visas texten.
Här är testerna.
Vi hittar vår knapp, klickar på den, försöker hitta vår text MEN vi förväntar oss att den inte är närvarande.
Och här är hur vi hanterar detta fall ;).
Vi använder ”browser.wait” kombinerat med ”browser.isElementPresent” som testar vår Locator. Efter 5 sekunder utförs resten av koden. Glöm inte att sätta en timer här, annars kommer dina tester att blockeras för alltid!
Så om ett av dina element ska vara här men du inte kan få tag på det, borde din magkänsla säga dig att komma ihåg vad du just har läst här.
Actions
Nu när du har ditt värdefulla element har du gjort 90 % av arbetet!
Om du inte kan hitta det är det antingen så att din applikation inte fungerar som den ska (det är därför vi testar) eller så måste du bli bättre på att testa och spendera mindre tid på Pokemon GO med att jaga dratinis i närheten av en flod klockan 01.00 på morgonen (vi har alla varit med om det …).
Låt oss fortsätta med de åtgärder som du kan använda på ett element. Här är de:
Vi använder Protractor som bygger på WebDriver. Om du behöver mer avancerade åtgärder kan du ta en titt på vad som finns tillgängligt här.
Låt oss testa några av dem.
För template.html:
<input type="text" />
Vi ska leka lite med textinmatningen. Snabbfråga, vad gör det här testet (läs inte beskrivningen)?
Lösning: Vi hämtar vår inmatning, skriver ”Some text” i den, testar att värdet är inställt, rensar det och testar slutligen att värdet är tomt.
Slutgiltigt kan vi fråga oss själva vad som är det bästa sättet att utlösa åtgärder? Den här länken visar en av bristerna med att använda JavaScript istället för WebDriver.
Säkerligen är det mer kompakt att skriva i JavaScript, men det kommer med vissa risker!
Du kan göra vad du vill med ett element. Det bästa sättet att testa det är att använda de matchers som finns tillgängliga. Varför? För att de är eleganta och ligger nära det mänskliga språket, exempel:
expect(apples.length !== 0).toBe(true);
expect(apples).not.toBeEmpty();
Slutsats
Det här var det sista inlägget i den här serien, just nu har du 90 % av kunskaperna för att testa dina Angular 2-applikationer. Du kommer att få de övriga 10 % genom erfarenhet. Kom ihåg att först hämta dina element med hjälp av Locators, sedan sätta den som kan replikeras i ett Page Object, om du inte kan hitta ditt element och du är säker på att det finns här, kan det vara kanske för att det inte har dykt upp ännu och du måste hantera asynkroniteten. Slutligen testar du **** för dina element med Actions.