Powrót do: Praktyczne wprowadzenie do testów automatycznych z Playwright
Bonus: Dostosowanie wzorca POM do standardów TypeScript
Prezentacja
Zmiany
W repozytorium z kodem playwright_automatyzacja_wprowadzenie bazujemy już na nowym, dostosowanym do standardów podejściu 🙂
W najnowszej wersji TypeScript i ES doszły nowe reguły sprawdzające poprawność kodu.
Co ważne – VS Code domyślnie korzysta z nowszych wersji reguł (dla zainteresowanych – ustawienie “JS/TS › Implicit Project Config: Target” – aktualnie ES2022).
O samym ES i konfiguracjach na razie nie musisz więcej wiedzieć, jednak…
Co to dla nas zmienia? 🤔
Aktualnie wskazane jest inicjalizowanie zmiennych w konstruktorze.
Dotychczasowa implementacja – jej wady, zalety i gdzie jest ta niezgodność?
W naszym przypadku oznacza to, że inicjalizację lokatorów musimy przenieść do konstruktora.
W poprzedniej lekcji przyjeliśmy taką implementację w login.page.ts:
import { Page } from '@playwright/test' export class LoginPage { constructor(private page: Page) {} loginInput = this.page.getByTestId('login-input') passwordInput = this.page.getByTestId('password-input') loginButton = this.page.getByTestId('login-button') }
W tym przypadku inicjalizacja lokatorów odbywa się w ciele klasy, zaraz przy definiowaniu właściwości (pól) klasy.
Jaka jest zasada działania?
Gdy tworzymy obiekt strony:
const loginPage = new LoginPage(page)
to wywoływany jest constructor
:
constructor(private page: Page) {}
import { Page } from '@playwright/test' export class LoginPage { constructor(private page: Page) {} }
jest równoważny z takim zapisem:
import { Page } from '@playwright/test' export class LoginPage { page: Page constructor(page: Page) { this.page = page } }
Zauważ, że w tym przypadku musimy mieć w klasie zadeklarowane pole page
!
Następnie po wywołaniu konstruktora inicjalizowane są pola (property/właściwości) w klasie, czyli wszystkie lokatory:
import { Page } from '@playwright/test' export class LoginPage { constructor(private page: Page) {} loginInput = this.page.getByTestId('login-input') passwordInput = this.page.getByTestId('password-input') loginButton = this.page.getByTestId('login-button') }
Inicjalizacja tych zmiennych zadziała, bo wartość page
mamy już przypisaną w konstruktorze 😉
Dlaczego jest to niezgodne z ES2022? 🔍
W wersji ECMAScript 2022 (ES2022) wprowadzono pewne zasady dotyczące inicjalizacji właściwości w klasach. Według tych zasad, jeśli właściwość klasy zależy od innych właściwości lub parametrów konstruktora (takich jak nasz page
), to jej inicjalizacja powinna nastąpić po pełnym zainicjalizowaniu wszystkich tych zależności.
W naszym przypadku właściwości loginInput
, passwordInput
i loginButton
są inicjalizowane bezpośrednio w ciele klasy.
ES2022 obecnie wymaga, aby taka inicjalizacja odbywała się w konstruktorze, gdzie mamy pewność, że wszystkie potrzebne zależności są już dostępne.
Przenosząc inicjalizację lokatorów do konstruktora, zapewniamy, że właściwość page
została już przypisana i możemy bezpiecznie z niej korzystać.
Mimo że nasza poprzednia implementacja działa poprawnie, zmiana w ES2022 ma na celu ujednolicenie podejścia do inicjalizacji właściwości klas, aby zapewnić większą spójność i zgodność ze standardem.
Wymóg inicjalizacji pól w konstruktorze pomaga uniknąć sytuacji, w których właściwości mogłyby być używane przed ich pełnym zainicjalizowaniem, co zmniejsza ryzyko błędów.
Podejście to zyskuje na znaczeniu nie tylko w aplikacjach webowych i testach automatycznych, ale również w bardziej rozbudowanych aplikacjach, gdzie wymagana jest większa stabilność i przewidywalność działania kodu. Ujednolicenie zasad inicjalizacji zmniejsza ryzyko nieoczekiwanych błędów 😉
Zmiany w implementacji
W najnowszej wersji TypeScript musimy wykonać w konstruktorze inicjalizację pól klasy.
Zawartość pliku login.page.ts przyjmie postać:
import { Locator, Page } from '@playwright/test'; export class LoginPage { loginInput: Locator; passwordInput: Locator; loginButton: Locator; constructor(private page: Page) { this.loginInput = this.page.getByTestId('login-input'); this.passwordInput = this.page.getByTestId('password-input'); this.loginButton = this.page.getByTestId('login-button'); } }
Zmiana ta dotyczy w tym momencie tylko plików stron 🙂
Kod w repozytorium zaktualizowaliśmy do najnowszych wymagań.
Poprzedni kod (gdzie konstruktor mamy pusty) nadal będzie działał, ale w VS Code otrzymasz podkreślone na czerwowo this.page
oraz informacje o błędzie:
Property 'page' is used before its initialization.ts(2729) login.page.ts(4, 15): 'page' is declared here. (property) LoginPage.page: Page
Jeśli jesteś zainteresowany czym jest ECMAScript, to skorzystaj z poniższych materiałów: