Stabilizacja testów Playwright w CI: Projekty zależności i aserty web-first
Wprowadzenie zależności w Playwright zapobiega uruchamianiu testów w nieprzygotowanym środowisku. Oszczędza to zasoby CI i zmniejsza liczbę fałszywych alarmów.
Najpierw wykonywana jest autoryzacja przez API z zapisaniem stanu magazynowania. Następnie sprawdzana jest dostępność API za pomocą health check. Dopiero po tym uruchamiane są główne testy UI.
Zalety w porównaniu do globalSetup:
- Pełne trace z żądaniami sieciowymi, zrzutami ekranu i logami konsoli.
- Mechanizm fail-fast: awaria setupu zatrzymuje zależne projekty.
- Izolacja: można testować poszczególne etapy za pomocą
npx playwright test --project=auth-setup.
Konfiguracja w playwright.config.ts:
export default defineConfig({
projects: [
{
name: 'auth-setup',
testMatch: /.*\.auth\.setup\.ts/,
},
{
name: 'healthcheck',
testMatch: /.*\.health\.setup\.ts/,
dependencies: ['auth-setup'],
},
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
dependencies: ['healthcheck'],
},
],
});
Autoryzacja przez API minimalizuje czas: żądanie POST trwa 50–100 ms w porównaniu do 2–5 sekund przy logowaniu przez UI.
Przykład testu auth-setup:
test('setup', async ({ request }) => {
await request.post('/api/login', { data: { user, pass } });
await request.storageState({ path: '.auth/user.json' });
});
Wykres zależności eliminuje warunki wyścigu podczas równoległego uruchamiania.
Poprawny wybór lokalizatorów
Lokalizatory decydują o odporności testów na zmiany interfejsu. Podziel je według przeznaczenia: do akcji — getByTestId, do weryfikacji — getByRole lub getByLabel.
Zasady wyboru:
- Akcje (klik, wpisywanie):
page.getByTestId('add-to-cart-button').click()— niezależnie od tekstu czy stylu. - Weryfikacje tekstu/stanu:
expect(page.getByRole('heading')).toHaveText('Konto użytkownika'). - Pola wejściowe:
page.getByLabel('Email').fill('[email protected]'). - Liczniki:
expect(locator).toHaveText('3').
Selektory CSS dopuszczalne tylko jako fallback. Przeszkolenie zespołu na poprawne lokalizatory się opłaca wielokrotnie przy skalowaniu.
Aserty web-first vs. flaky
Sprawdzanie snapshota typu await loc.isVisible() naraża się na warunki wyścigu. Aserty web-first z polingiem zapewniają stabilność.
Porównanie asertów:
| Sprawdzenie | Snapshot (nie czeka) | Web-first (polling) |
|----------|-------------------|---------------------|
| Widoczność | await loc.isVisible() | expect(loc).toBeVisible() |
| Tekst | await loc.textContent() | expect(loc).toHaveText('Tekst') |
| Liczba | await loc.count() | expect(loc).toHaveCount(3) |
| Atrybut | await loc.getAttribute('href') | expect(loc).toHaveAttribute('href', '/path') |
| Pole wyboru | await loc.isChecked() | expect(loc).toBeChecked() |
| Stan | await loc.isEnabled() | expect(loc).toBeEnabled() |
Polling powtarza sprawdzenie co 100 ms do momentu przekroczenia limitu, ignorując chwilowe drgania interfejsu.
Hydracja i force: true
Błąd hydracji występuje w aplikacjach SSR/SSG: kod serwerowy został wyrenderowany, ale skrypty JS nie zostały jeszcze przypięte.
Czekaj na sygnalizatory gotowości:
await page.waitForSelector('.hydrated', { state: 'attached' })await expect(page.locator('#global-loader')).toBeHidden()
force: true wyłącza sprawdzanie aktywności (widoczność, stabilność, włączoność, odbiór zdarzeń), zamieniając test na skrypt DOM. Używaj z komentarzem i tylko gdy konieczne (np. dla inputu plików).
Co ważne
- Projekty zależności tworzą graf zależności, zapobiegając uruchomieniu testów w niegotowym środowisku.
- Aserty web-first z polingiem eliminują 80% flaków spowodowanych warunkami wyścigu.
- Podział lokalizatorów według roli zwiększa odporność na refaktoryzację interfejsu.
- Autoryzacja przez API przyspiesza setup 20–50 razy w porównaniu do logowania przez UI.
- Trace zamiast zrzutów ekranu daje kompletną wizję awarii w CI.
— Editorial Team
Brak komentarzy.