Powrót do strony głównej

Stabilizacja testów Playwright w CI

Artykuł opisuje metodologię stabilizacji testów Playwright w CI za pomocą Dependency Projects, web-first asserty i właściwy wybór lokatorów. Podane są przykłady konfiguracji i kodu dla projektów enterprise.

Playwright: eliminujemy flaki w CI z Dependency Projects
Advertisement 728x90

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:

Google AdInline article slot
  • 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:

Google AdInline article slot
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:

Google AdInline article slot
  • 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

Advertisement 728x90

Czytaj dalej