Bonus: Dostosowanie wzorca POM do standardów TypeScript

TIP: Ta lekcja jest częścią rozwijanego Programu Testy Automatyczne z Playwright 🎭

Prezentacja

Bonus: Dostosowanie wzorca POM do standardów TypeScript

Bonus: Dostosowanie wzorca POM do standardów TypeScript

Bonus: Dostosowanie wzorca POM do standardów TypeScript

Bonus: Dostosowanie wzorca POM do standardów TypeScript

Bonus: Dostosowanie wzorca POM do standardów TypeScript

Bonus: Dostosowanie wzorca POM do standardów TypeScript

Bonus: Dostosowanie wzorca POM do standardów TypeScript

Bonus: Dostosowanie wzorca POM do standardów TypeScript

Bonus: Dostosowanie wzorca POM do standardów TypeScript

Bonus: Dostosowanie wzorca POM do standardów TypeScript

Zmiany

UWAGA: W tej lekcji będziemy operować na pewnych uproszczeniach, aby w przystępny sposób opisać wymagane zmiany i ich powody 🙂

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).

TIP: Z czasem wersja ES2022 zostanie zastąpiona nowszą – dlatego Twoja wersja będzie zależała od tego, kiedy oglądasz to nagranie 🙂

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) {}
TIP: Dla przypomnienia, zapis konstruktora:

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:

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *