13 maj 2025
16 min

Testy E2E Angularowej aplikacji z wykorzystaniem Playwright

Testy end-to-end to już nie „fajny dodatek” w projektach Angulara – dziś to podstawa, jeśli chcemy budować stabilne i niezawodne aplikacje. Wraz z rozrastaniem się kodu i coraz częstszymi release’ami same testy jednostkowe nie wystarczają, żeby wychwycić wszystkie problemy. Potrzebujemy spojrzeć na aplikację z perspektywy użytkownika końcowego.

Na szczęście mamy narzędzia, które to oferują – jak choćby Playwright. Dzięki niemu proces testowania E2E staje się szybszy, bardziej naturalny i lepiej dopasowany do realiów współczesnego frontendu. Dla osób pracujących z Angularem to naprawdę sensowny wybór, który pozwala wdrażać nowe funkcje z większą pewnością.

Wprowadzenie

Playwright to nowoczesny framework do testów end-to-end, rozwijany przez Microsoft, który pozwala pisać szybkie, stabilne i wielu przeglądarkowe testy aplikacji webowych. Od razu po instalacji wspiera różne przeglądarki, umożliwia testowanie na różnych urządzeniach, a do tego oferuje kilka naprawdę ciekawych funkcji, takich jak automatyczne oczekiwanie na elementy, kontrola sieci czy równoległe uruchamianie testów. Wszystko po to, żeby szybciej wychwytywać błędy i zapewnić użytkownikom płynne działanie aplikacji.

Dlaczego warto wybrać Playwright?

Playwright łączy szybkość, niezawodność i elastyczność w sposób, który po prostu działa w realiach współczesnego testowania aplikacji webowych. Niezależnie od tego, czy piszesz szybkie smoke testy, czy kompleksowe scenariusze end-to-end, dostajesz spójne API i narzędzia, które dobrze wpisują się w codzienną pracę dewelopera. Co sprawia, że Playwright się wyróżnia?

  • wieloprzeglądarkowość: możesz uruchamiać testy na Chromium, WebKit i Firefoxie – bez żadnych dodatkowych konfiguracji,
  • wieloplatformowość: działa na Windowsie, macOS i Linuxie, lokalnie lub w CI, w trybie headless albo z widocznym UI,
  • wsparcie dla różnych języków: TypeScript, JavaScript, Python, .NET czy Java,
  • testowanie mobilne: emulacja rzeczywistych urządzeń za pomocą Chrome na Androida i Mobile Safari,
  • niezawodność: automatyczne oczekiwanie na elementy, asercje „web-first” – mniej flaky testów, zero ręcznych timeoutów,
  • izolowane środowiska testowe: lekki „browser context” pozwala testować w pełnej izolacji bez obciążania wydajności,
  • zaawansowane scenariusze: obsługuje wiele zakładek, użytkowników, a nawet Shadow DOM w ramach jednego testu,
  • wbudowane narzędzia: generator kodu, interaktywny inspector i trace viewer pomagają w debugowaniu i analizie,
  • wydajność: szybki start testów, możliwość ich równoległego uruchamiania,
  • trwałe sesje logowania: możesz korzystać z jednej sesji logowania w wielu testach bez rezygnacji z ich niezależności.

Playwright to nie tylko potężne narzędzie – to framework zaprojektowany z myślą o deweloperach. Wykorzystuje możliwości współczesnych przeglądarek i opakowuje je w workflow, który naprawdę dobrze się „czuje” podczas codziennej pracy.

Różnice względem Cypressa

Zarówno Playwright, jak i Cypress to solidne narzędzia do testów end-to-end – i dziś oferują wiele bardzo podobnych funkcji. Różnią się jednak podejściem do tego, jak testy działają pod maską, co może wpływać na to, jak dobrze wpisują się w Twój workflow.

Cypress uruchamia testy bezpośrednio w kontekście przeglądarki, co sprawia, że wszystko działa szybko – widzisz natychmiast, co się dzieje i łatwo możesz debugować problemy. Ale przez to, że testy działają „wewnątrz” przeglądarki, są też pewne ograniczenia – jak brak wsparcia dla wielu zakładek czy trudności z testowaniem scenariuszy wychodzących poza sandbox przeglądarki.

Playwright natomiast działa poza przeglądarką, jako niezależny kontroler, co daje znacznie większe możliwości – można obsługiwać wiele kart czy przejścia między różnymi domenami. Z drugiej strony, bardziej złożone przypadki, jak trwałe sesje logowania czy zarządzanie użytkownikami, mogą wymagać trochę dodatkowej konfiguracji.

Ostatecznie oba narzędzia są dojrzałe i potrafią naprawdę dużo. Wybór zależy od tego, czego potrzebuje Twój projekt, jaki styl pracy preferuje zespół i jak dużej elastyczności szukacie na dłuższą metę.

Przygotowanie środowiska

Przykładowa aplikacja

Aby skupić się na kluczowych aspektach testowania E2E, stworzyłem minimalistyczną aplikację w Angularze. Posiada tylko dwie ścieżki: stronę startową z przyciskiem do nawigacji oraz stronę „Todos”, która wyświetla listę zadań.

Ta prosta konfiguracja wystarczy do zaprezentowania typowych scenariuszy testów E2E, jednocześnie nie wprowadzając zbędnego chaosu w przykładzie.

Strona startowa:

Strona listy zadań:

Instalacja Playwright

Aby zintegrować Playwright z projektem, wystarczy uruchomić poniższe polecenie:

npm init playwright@latest

To polecenie automatycznie zajmie się konfiguracją i poprosi o wybranie kilku ustawień:

  • wybór języka: TypeScript (domyślnie) lub JavaScript,
  • katalog testów: domyślnie tests, lub e2e jeśli katalog tests już istnieje,
  • integracja z CI: opcja automatycznego wygenerowania workflow dla GitHub Actions,
  • instalacja przeglądarek: określenie, czy Playwright ma zainstalować pliki binarne przeglądarek (domyślnie: true).

Integracja z Nx

Jeśli w swoim projekcie używasz Nx, możesz dodać Playwright do istniejącej aplikacji, uruchamiając poniższe polecenie:

nx g @nx/playwright:configuration --project=your-app-name

To polecenie zarejestruje niezbędny plugin i odpowiednio skonfiguruje projekt, zapewniając pełną kompatybilność.

Alternatywa: Rozszerzenie dla Visual Studio Code

Playwright można również zainstalować i zarządzać za pomocą dedykowanego rozszerzenia dla Visual Studio Code, które oferuje dodatkowe narzędzia do tworzenia, uruchamiania i debugowania testów. Ta metoda zostanie krótko omówiona w późniejszej części artykułu, aby zaprezentować jej funkcjonalności i sposób użycia.

Początkowy setup dla projektów Angular

Playwright oferuje elastyczny system konfiguracji, który umożliwia łatwe dostosowanie sposobu, w jaki testy będą uruchamiane. Większość ustawień znajduje się w pliku playwright.config.ts (lub .js), który znajduje się w katalogu głównym projektu.

Oto kilka kluczowych opcji w pliku konfiguracyjnym:

  • testDir: określa katalog, relatywnie do pliku konfiguracyjnego, w którym Playwright będzie szukać plików testowych,
  • workers: kontroluje maksymalną liczbę równocześnie uruchomionych procesów, które Playwright wykorzysta do równoległego uruchamiania testów. Możesz podać wartość bezwzględną (np. 4) lub procent dostępnych rdzeni CPU (np. ’75%’),
  • projects: umożliwia zdefiniowanie różnych środowisk (przeglądarki, urządzenia itp.), w których testy będą uruchamiane. Może to obejmować konfiguracje dla różnych przeglądarek, takich jak Chromium, Firefox i WebKit, wraz ze specjalistycznymi ustawieniami, jak emulacja urządzeń czy inicjalizacja kontekstów.
    Projekty służą również do przekazywania zależności, jak fixtures czy pliki stanu (np. dla utrzymania sesji zalogowanego użytkownika między wieloma testami),
  • webServer: konfiguruje lokalny serwer, który ma zostać uruchomiony przed rozpoczęciem testów. Przykład:
webServer: {
    command: 'npm run start:dev',
    url: 'http://localhost:4200',
  }

Te opcje są bardzo elastyczne i możesz je dowolnie łączyć, co pozwala na dostosowanie testów do takich scenariuszy jak testowanie między przeglądarkami, uruchamianie testów równolegle czy obsługa różnych środowisk CI.

Dla uproszczenia, w tym artykule będziemy trzymać się domyślnej konfiguracji Playwrighta.

Struktura testów w Playwright

Dobrze zorganizowane testy poprawiają niezawodność, czytelność i łatwość utrzymania. W tej sekcji omówione zostaną najlepsze praktyki dotyczące organizacji testów przy użyciu Playwright, które pozwolą na utrzymanie wydajności i skalowalności.

Organizacja plików i katalogów

W naszej przykładowej aplikacji testy end-to-end zostały zorganizowane w sposób, który zapewnia modułowość, łatwość utrzymania i zgodność ze strukturą stron aplikacji. Katalogi testów dzielimy na:

  • shared/: zawiera wspólne elementy i komponenty używane w wielu testach (np. przyciski, dialogi, inputy),
  • <page>/: enkapsuluje całą logikę testów dla konkretnej strony lub funkcji. Zawiera obiekty stron (Page Object Model), fixture, reużywalne elementy oraz specyfikacje testów.

Każdy katalog zazwyczaj zawiera:

  • elements/: definiuje izolowane, wielokrotnego użytku elementy UI,
  • pages/: implementuje obiekty stron przy użyciu wzorca Page Object Model. Każda klasa zapewnia interfejs do interakcji z odpowiadającą jej stroną.
  • fixtures/: zawiera logikę inicjalizacji strony, taką jak ustawienie stanu początkowego i nawigacja. Przygotowuje stronę do testów,
  • <page>.spec.ts: plik testów zawierający rzeczywiste przypadki testowe dla danej strony.

Taka struktura pomaga utrzymać porządek w testach i ułatwia ich skalowanie, co sprawia, że łatwiej jest je utrzymywać, gdy nasza aplikacja się rozrasta.

Pierwszy test E2E

Jedną z potężnych cech Playwrighta jest jego zdolność do automatycznego zarządzania synchronizacją. Playwright automatycznie czeka, aż elementy na stronie będą dostępne. Ta wbudowana synchronizacja pozwala skupić się na pisaniu testów bez obaw o problemy związane z ładowaniem aplikacji. Na przykład, gdy wchodzisz w interakcję z elementem, Playwright automatycznie sprawdza, czy element jest widoczny i gotowy do wykonania żądanej akcji.

Kolejną kluczową cechą jest obsługa race conditions przez Playwrighta. Asercje w Playwright są zaprojektowane w taki sposób, by opisywać oczekiwane warunki, które powinny zostać finalnie spełnione. Dzięki temu framework może czekać na ich spełnienie bez przedwczesnego błędu, zapewniając, że testy będą zarówno niezawodne, jak i odporne na zmieniające się czasy ładowania.

Dodatkowo, Playwright wykonuje testy w pełnej izolacji. Oznacza to, że nawet gdy kilka testów działa w jednej instancji przeglądarki, każdy test działa tak, jakby był w zupełnie nowym profilu przeglądarki. Taka izolacja zapewnia brak wspólnych stanów między testami, co prowadzi do bardziej spójnych i przewidywalnych wyników w różnych przebiegach testów.

test('Test 1', async ({ page }) => {
  // page jest izolowany
});

test('Test 2', async ({ page }) => {
  // ten page jest izolowany od page w Test 1
});

Podstawowy test

W naszym pierwszym teście end-to-end chcemy upewnić się, że komunikat powitalny na stronie startowej wyświetla poprawny tekst: “Welcome to Angular E2E with Playwright„.

Aby ułatwić identyfikację docelowego elementu, dodamy do niego atrybut data-testid. Oto kod dla tego elementu:

<header class="header">
    <h1 data-testid="start-page-welcome-message" class="title">Welcome to Angular E2E with Playwright</h1>
    <p class="subtitle">A demonstration project for end-to-end testing</p>
  </header>

Teraz możemy użyć funkcji getByTestId() Playwrighta – która jest częścią wbudowanego fixture Page – aby zlokalizować nasz element i móc wchodzić z nim w interakcję. Tak wygląda nasz test:

import { expect, test } from './fixtures';

test.describe('Start Page', () => {
  test('has welcome message', async ({ page }) => {
    await page.goto('/start');

    await expect(page.getByTestId('start-page-welcome-message'))
    .toContainText('Welcome to Angular E2E with Playwright');
  });
});

Chociaż ten test działa dobrze, można go uprościć, tak aby kod był łatwiejszy w utrzymaniu. Na przykład moglibyśmy pozbyć się ręcznego wywołania await page.goto(’/start’); (aktualnie musielibyśmy je powtarzać w każdym teście), bezpośrednie poleganie na selektorze data-testid sprawia natomiast, że kod jest mniej przejrzysty.

Aby zredukować ilość logiki i poprawić przejrzystość, możemy przekształcić test, wykorzystując Page Object Model. POM pozwala nam ukryć szczegóły implementacyjne, takie jak nawigacja i selektory elementów, dzięki czemu test będzie bardziej skoncentrowany na zachowaniu, które rzeczywiście testujemy.

Przeróbmy nasz test, aby wykorzystywał Page Object Model.

Wykorzystanie Page Object Model

Jak wspomniano wcześniej, wzorzec Page Object Model pomaga w organizacji i optymalizacji utrzymania testów. Poprzez scentralizowanie selektorów elementów i interakcji, POM zmniejsza powtarzalność i pomaga utrzymać czysty kod testów. Ułatwia również refaktoryzację, ponieważ zmiany w interfejsie użytkownika są izolowane do obiektu strony.

Przejdźmy teraz do migracji naszego testu strony startowej.

Krok 1: Stworzenie klasy Page

Zaczynamy od stworzenia dedykowanej klasy dla strony startowej. Ta klasa będzie obsługiwać interakcje z stroną, w tym selektory elementów i nawigację. Umieścimy ją w nowym pliku o nazwie start.page.ts w katalogu pages.

import type { Locator, Page } from '@playwright/test';

export class StartPage {
  readonly welcomeMessage: Locator = this.page.getByTestId('start-page-welcome-message');

  constructor(private readonly page: Page) {}

  async goto() {
    await this.page.goto('/start');
  }
}

W tej klasie definiujemy locator dla komunikatu powitalnego oraz metodę goto(), która umożliwia nawigację do strony startowej. Dzięki temu cała logika związana ze stroną jest zamknięta w jednym miejscu.

Krok 2: Refaktoryzacja testu

Teraz, zamiast ręcznie tworzyć zapytania, wykorzystamy klasę startPage, która zapewnia bezpośredni dostęp do elementów i metod strony.

import { expect, test } from '@playwright/test';
import { StartPage } from './pages';

test.describe('Start Page', () => {
  test('has welcome message', async ({ page }) => {
    // Stworzenie instancji klasy StartPage i nawigacja
    const startPage = new StartPage(page);
    await startPage.goto();

    await expect(startPage.welcomeMessage)
    .toContainText('Welcome to Angular E2E with Playwright');
  });
});

Jest już lepiej, ale nasz test wciąż ma trochę nadmiarowości – za każdym razem ręcznie tworzymy instancję klasy i nawigujemy na stronę. Możemy uprościć ten proces, wprowadzając niestandardowy fixture, który zajmie się tą konfiguracją za nas.

Krok 3: Własny fixture

Playwright jest stworzony w oparciu o fixtures, czyli pomocnicze elementy, które przygotowują dokładnie to czego potrzebuje dany test. Fixture’y są od siebie odizolowane, więc każdy test zaczyna się w świeżym, czystym środowisku. Widzieliśmy to już w poprzednim teście – użycie ({ page }) powoduje, że Playwight korzysta ze swojego wbudowanego fixture’a page, żeby dać nam dostęp do strony w przeglądarce.

Żeby nasza konfiguracja testów była czystsza i łatwiejsza do ponownego użycia, możemy rozszerzyć bazowy fixture o nasz obiekt startPage. Dzięki temu fixture sam zadba o przejście do strony startowej przed każdym testem, a my możemy skupić się na pisaniu właściwej logiki testu, bez powtarzania tych samych kroków w każdym z nich.

Tak wygląda definicja naszego własnego fixture’a w pliku start.fixture.ts (w katalogu fixtures):

import { test as base } from '@playwright/test';

import { StartPage } from '../pages';

export const test = base.extend<{ startPage: StartPage }>({
  startPage: async ({ page }, use) => {
    // Setup naszego fixture
    const startPage: StartPage = new StartPage(page);
    await startPage.goto();

    // Użycie fixture w teście
    await use(startPage);

    // Potencjalne akcje wywołane po zakończeniu testu
    // e.g. await startPage.close();
  },
});

export { expect } from '@playwright/test';

Dzięki temu każdy test automatycznie dostaje gotowy do użycia obiekt startPage, który nawiguje nas pod odpowiedni adres URL.

Teraz możemy uprościć nasz test w taki sposób:

import { expect, test } from './fixtures';

test.describe('Start Page', () => {
  test('has welcome message', async ({ startPage }) => {
    await expect(startPage.welcomeMessage)
    .toContainText('Welcome to Angular E2E with Playwright');
  });
});

Dzięki naszemu własnemu fixture’owi test skupia się już tylko na tym, co naprawdę istotne – czyli na oczekiwanym zachowaniu. Cała konfiguracja dzieje się w tle, co sprawia, że testy są prostsze do czytania, pisania i utrzymania.

Korzyści z używania Page Object Model

Refaktoryzacja z wykorzystaniem Page Object Model niesie za sobą sporo zalet, które sprawiają, że testy są wydajniejsze, łatwiejsze w utrzymaniu i gotowe na rozwój aplikacji. Oto kilka najważniejszych:

  • mniej powtórzeń w kodzie: nawigacja i selektory są w jednym miejscu, więc nie trzeba ich kopiować w każdym teście,
  • lepsza czytelność: testy skupiają się na zachowaniu, są czystsze i prostsze do ogarnięcia,
  • łatwiejsze utrzymanie: jeśli zmieni się selektor lub element UI, poprawiasz to tylko raz w Page Object Modelu, zamiast w każdym teście z osobna,
  • lepsza skalowalność: testy pozostają uporządkowane i elastyczne, nawet gdy aplikacja zaczyna rosnąć.

Reużywalne elementy testowe

Tak jak w przypadku stron, możemy zastosować Page Object Model do reużywalnych elementów aplikacji, takich jak przyciski, inputy czy inne komponenty. Takie podejście zapewnia, że nasze testy pozostaną czyste i łatwe do utrzymania.

W naszym przypadku stworzymy test element dla komponentu FilterInputComponent. Pozwoli nam to na interakcję z inputem: wprowadzenie wartości i jej resetowanie przez kliknięcie przycisku.

Krok 1: Dodanie atrybutów data-testid

Na początku musimy się upewnić, że komponent, input i przycisk resetu są łatwe do zidentyfikowania. Robimy to dodając atrybuty data-testid do każdego z tych elementów w komponencie FilterInputComponent.

Tak wygląda nasz komponent po zmianach:

@Component({
  selector: 'app-filter-input',
  templateUrl: './filter-input.component.html',
  styleUrl: './filter-input.component.scss',
  host: {
    'data-testid': 'filter-input-component',
  },
})
export class FilterInputComponent {
  // …
}

A tak wygląda szablon z dodanymi atrybutami data-testid:

<div class="filter-container">
  <input
    type="text"
    placeholder="Filter..."
    class="filter-input"
    data-testid="filter-input"
    [(ngModel)]="searchTerm"
    (ngModelChange)="emitSearchTerm()"
  />

  @if (filterText()) {
  <button class="filter-reset" data-testid="filter-input-reset" (click)="resetFilter()"></button>
  }
</div>

Krok 2: Stworzenie klasy elementu

Po dodaniu niezbędnych atrybutów, stworzymy klasę FilterInputElement, która pozwoli nam na interakcję z inputem i przyciskiem resetowania.

Dodamy tę klasę do nowego pliku o nazwie filter-input.element.ts w katalogu shared/elements. Oto jak wygląda ta klasa:

import type { Locator, Page } from '@playwright/test';

export class FilterInputElement {
  private readonly container: Locator = this.parent.getByTestId('filter-input-component');

  readonly input: Locator = this.container.getByTestId('filter-input');
  readonly resetButton: Locator = this.container.getByTestId('filter-input-reset');

  constructor(private readonly parent: Locator | Page) {}

  async fillInput(text: string): Promise<void> {
    await this.input.fill(text);
  }

  async clearInput(): Promise<void> {
    await this.resetButton.click();
  }
}

Klasa FilterInputElement udostępnia metody, które pozwalają wprowadzać tekst do pola wejściowego (metoda fillInput(text)) oraz czyścić to pole przez kliknięcie przycisku resetowania (metoda clearInput()). Dzięki temu interakcja z polem filtra w naszych testach staje się łatwiejsza i bardziej przejrzysta.

Krok 3: Integracja elementu z obiektem strony

Teraz musimy stworzyć Page Object Model dla strony listy zadań wraz z klasą FilterInputElement w jej kontekście. Dzięki temu będziemy mogli bezpośrednio uzyskać dostęp do funkcji filtra w obrębie strony listy zadań.

Oto jak wygląda klasa TodosPage:

export class TodosPage {
  // Dodajemy stworzony element do klasy strony
  readonly filterInput: FilterInputElement = new FilterInputElement(this.page);

  constructor(private readonly page: Page) {}

  async goto() {
    await this.page.goto('/todos');
  }
}

Dzięki tej konfiguracji mamy teraz dostęp do elementu filterInput w klasie TodosPage.

Krok 4: Stworzenie fixture

Fixture tworzony jest w ten sam sposób, co poprzednio:

export const test = base.extend<{ todosPage: TodosPage }>({
  todosPage: async ({ page }, use) => {
    // Setup naszego fixture
    const todosPage: TodosPage = new TodosPage(page);
    await todosPage.goto();

    // Użycie fixture w teście
    await use(todosPage);
  },
});

export { expect } from '@playwright/test';

Krok 5: Napisanie testu

Teraz możemy napisać prosty test, który zweryfikuje funkcjonalność pola filtra na stronie TodosPage. Użyjemy elementu filterInput z fixture todosPage i sprawdzimy, czy możemy poprawnie wpisać wartość do inputa.

Oto kod testu:

import { expect, test } from './fixtures';

test.describe('Todos Page', () => {
  test('input should have correct value', async ({ todosPage }) => {
    todosPage.filterInput.fillInput('Test value');

    await expect(todosPage.filterInput.input).toHaveValue('Test value');
  });
});

W tym teście używamy metody fillInput z klasy FilterInputElement, aby wpisać „Test value” do inputa, a następnie sprawdzamy, czy wartość w inpucie została poprawnie ustawiona.

Autentykacja

Playwright umożliwia uruchamianie testów w izolowanych kontekstach przeglądarki, jednocześnie wspierając ponowne użycie wcześniej uwierzytelnionych sesji. Żeby to osiągnąć wczytujemy zawartość pliku stanu autentykacji. Zazwyczaj taki mechanizm wiąże się ze stworzeniem dedykowanego projektu konfiguracyjnego, który działa jak wstępny test. Wykonuje on workflow autentykacji i zapisuje wynikowy stan sesji do określonego pliku. Ten projekt konfiguracyjny jest następnie wykorzystywany jako zależność w pliku konfiguracyjnym Playwrighta, zapewniając, że kolejne testy mogą rozpocząć się z uwierzytelnionym kontekstem.

Dokumentacja Playwrighta pokazuje implementację tego mechanizmu w różnych przypadkach użycia.

Uruchamianie i debugowanie testów

Testy można uruchomić za pomocą następującego polecenia:

npx playwright test 

Jeżeli używasz Nxa, testy możesz uruchomić za pomocą:

nx e2e <PROJECT-NAME> 

Domyślnie testy są wykonywane w przeglądarkach określonych w pliku konfiguracyjnym Playwright. Testy są uruchamiane w trybie headless, co oznacza, że wyniki testów są wyświetlane wyłącznie w terminalu.

Dla przyjemniejszych doświadczeń, możesz przełączyć się na tryb UI, który pozwala na debugowanie testów krok po kroku. W tym trybie dostępne są narzędzia, takie jak picker lokalizatorów ułatwiający wybór konkretnych elementów, oraz watch mode, który automatycznie ponownie uruchamia testy po wykryciu zmian w plikach. 

Tryb UI można włączyć, dodając flagę –ui do polecenia uruchomienia testów:

npx playwright test --ui

W tym trybie możemy zobaczyć wykonanie naszych testów w czasie rzeczywistym.

Na załączonym zrzucie ekranu możesz zobaczyć oś czasu wykonania testów dla strony Todos, która pokazuje sekwencję i czas trwania każdego kroku testowego. To pomaga w debugowaniu i analizie wydajności.

Playwright Inspector

Uruchomienie testów z flagą –debug otwiera Playwright Inspector. Dodatkowo uruchamia przeglądarkę w trybie headed i wyłącza timeout testów, ustawiając go na 0. Kiedy uruchamiasz wszystkie testy z flagą –debug, każdy z nich jest uruchamiany sekwencyjnie, otwierając nową instancję przeglądarki i nowe okno Inspektora dla każdego testu.

Playwright Inspector pozwala na uruchamianie, pauzowanie i krokowe przechodzenie przez wykonanie testu. Możesz zobaczyć bieżącą akcję podświetloną zarówno w kodzie, jak i w przeglądarce, co znacząco ułatwia śledzenie tego, co się dzieje. Jeśli chcesz przerwać wykonanie testu w określonym miejscu, możesz dodać page.pause(), co spowoduje zatrzymanie testu w tym punkcie.

Dodatkowo, możesz skorzystać z wbudowanego pickera lokalizatorów, który pozwala na najechanie na elementy w przeglądarce. Pokaże to konkretny lokalizator elementu, którego możesz użyć w kodzie testu. Kliknięcie na ten element dodaje ten lokalizator do inputa w Inspectorze, dzięki czemu możesz go skopiować i wkleić bezpośrednio do testów.

Równoległe wykonywanie testów

Domyślnie Playwright optymalizuje wykonanie testów, uruchamiając je równolegle. W obrębie każdego pliku testowego testy są jednak wykonywane sekwencyjnie w tym samym workerze.

Jeśli chcesz uruchamiać testy w ramach jednego pliku równolegle, możesz włączyć tę opcję globalnie, ustawiając fullyParallel: true w konfiguracji Playwright. Alternatywnie, możesz włączyć ją na poziomie projektu w swojej konfiguracji. Dla bardziej precyzyjnej kontroli, możesz włączyć tryb równoległy dla konkretnych zestawów testowych, używając: test.describe.configure({ mode: 'parallel’ });.

Aby całkowicie wyłączyć równoległe wykonywanie testów, ustaw workers: 1 w pliku konfiguracyjnym lub przekaż –workers=1 za pomocą linii poleceń. Kiedy równoległość jest wyłączona, pliki testowe będą wykonywane sekwencyjnie w porządku alfabetycznym.

CI/CD

Testy e2e napisane w Playwright mogą być uruchamiane w każdym środowisku CI. Dokładne informacje można znaleźć na stronach Continuous Integration i Setting up CI w oficjalnej dokumentacji.

Bonus: Rozszerzenie dla VS Code 

Jeśli regularnie korzystasz z Playwright, rozszerzenie Playwright Test for VSCode to świetny sposób na usprawnienie workflow. Bardzo dobrze integruje Playwright z VS Code, oferując szereg przydatnych narzędzi bezpośrednio w IDE.

Żeby zainstalować Playwrighta przez rozszerzenie otwórz panel poleceń i wybierz “Install Playwright”. Rozszerzenie przeprowadzi Cię przez proces konfiguracji – będziesz mógł wybrać, które przeglądarki chcesz używać, a także dodać gotowy workflow GitHub Actions dla CI.

Po zainstalowaniu samego rozszerzenia zobaczysz panel Test Explorer, z którego możesz uruchamiać pojedyncze testy lub całe zestawy testowe, włączać watch mode lub przejść do trybu debugowania bezpośrednio w VS Code.

Masz również dostęp do narzędzi takich jak Pick Locator, które pomagają bezpośrednio z przeglądarki wybrać selektory, oraz możliwość nagrywania nowych testów. Chcesz zobaczyć, co robi przeglądarka? Włącz opcję “Show browser”, aby przejść do trybu headed.

Dla mnie korzystanie z rozszerzenia Playwright w VS Code stało się standardem. Jest intuicyjne, oszczędza czas i trzyma wszystko w jednym miejscu. Jeśli codziennie pracujesz z Playwright, zdecydowanie polecam wypróbowanie tego rozszerzenia – po prostu ułatwia to cały workflow.

Podsumowanie

Playwright sprawia, że testowanie end-to-end aplikacji Angular nie jest tylko potężnym narzędziem, ale jest również zaskakująco przyjazne dla dewelopera. W tym artykule przeszliśmy przez proces konfiguracji, napisaliśmy przykładowe testy i zapoznaliśmy się z kluczowymi funkcjami, które wyróżniają Playwright w kontekście nowoczesnych aplikacji webowych.

To, co omówiliśmy, to tylko początek. Playwright oferuje również wiele innych funkcji, takich jak porównania wizualne zrzutów ekranu, mockowanie zapytań sieciowych, testowanie na różnych viewportach i urządzeniach i wiele innych. Niezależnie od tego, czy testujesz responsywne widoki, czy złożone flow użytkownika, prawdopodobnie istnieje wbudowane narzędzie do tego celu.

Jeśli szukasz nowoczesnego, szybkiego i elastycznego podejścia do testowania E2E – szczególnie dla Angular – Playwright z pewnością zasługuje na uwagę.

Podziel się artykułem

Zapisz się na nasz newsletter

Dołącz do community Angular.love i bądź na bieżąco z trendami.