Wzorzec Obiektów Stron
Wersja 5 WebdriverIO została zaprojektowana z myślą o obsłudze wzorca Obiektów Stron (Page Object Pattern). Dzięki wprowadzeniu zasady "elementy jako obywatele pierwszej kategorii", możliwe jest teraz budowanie dużych zestawów testów przy użyciu tego wzorca.
Do tworzenia obiektów stron nie są wymagane żadne dodatkowe pakiety. Okazuje się, że czyste, nowoczesne klasy zapewniają wszystkie niezbędne funkcje, których potrzebujemy:
- dziedziczenie między obiektami stron
- leniwe ładowanie elementów
- enkapsulacja metod i akcji
Celem używania obiektów stron jest oddzielenie informacji o stronie od faktycznych testów. Idealnie byłoby przechowywać wszystkie selektory lub specyficzne instrukcje, które są unikalne dla danej strony, w obiekcie strony, abyś nadal mógł uruchamiać swoje testy po całkowitym przeprojektowaniu strony.
Tworzenie Obiektu Strony
Na początek potrzebujemy głównego obiektu strony, który nazywamy Page.js. Będzie on zawierał ogólne selektory lub metody, które odziedziczą wszystkie obiekty stron.
// Page.js
export default class Page {
constructor() {
this.title = 'My Page'
}
async open (path) {
await browser.url(path)
}
}
Zawsze będziemy export-ować instancję obiektu strony i nigdy nie tworzyć tej instancji w teście. Ponieważ piszemy testy end-to-end, zawsze traktujemy stronę jako bezstanową konstrukcję—tak samo jak każde żądanie HTTP jest bezstanową konstrukcją.
Oczywiście przeglądarka może przechowywać informacje o sesji i dlatego może wyświetlać różne strony na podstawie różnych sesji, ale nie powinno to mieć odzwierciedlenia w obiekcie strony. Tego rodzaju zmiany stanu powinny znajdować się w rzeczywistych testach.
Zacznijmy testować pierwszą stronę. Do celów demonstracyjnych używamy strony The Internet stworzonej przez Elemental Selenium jako „królika doświadczalnego". Spróbujmy zbudować przykład obiektu strony dla strony logowania.
Pobieranie selektorów za pomocą get
Pierwszym krokiem jest napisanie wszystkich ważnych selektorów, które są wymagane w naszym obiekcie login.page, jako funkcji getter:
// login.page.js
import Page from './page'
class LoginPage extends Page {
get username () { return $('#username') }
get password () { return $('#password') }
get submitBtn () { return $('form button[type="submit"]') }
get flash () { return $('#flash') }
get headerLinks () { return $$('#header a') }
async open () {
await super.open('login')
}
async submit () {
await this.submitBtn.click()
}
}
export default new LoginPage()
Definiowanie selektorów w funkcjach getter może wyglądać trochę dziwnie, ale jest naprawdę użyteczne. Te funkcje są oceniane gdy uzyskujesz dostęp do właściwości, a nie gdy generujesz obiekt. Dzięki temu zawsze żądasz elementu przed wykonaniem na nim akcji.