Jeżeli piszesz testy automatyczne w Playwright, to bardzo szybko dojdziesz do momentu, w którym samo uruchamianie ich lokalnie przestaje wystarczać.
Na początku wygląda to niewinnie.
Odpalasz testy na swoim komputerze, wszystko przechodzi, jest zielono, więc wydaje się, że temat jest ogarnięty. Problem pojawia się dopiero później, gdy ktoś inny zrobi zmianę w aplikacji, wrzuci pull requesta albo zdeployuje nową wersję i nagle okazuje się, że coś przestało działać.
Dlatego testy automatyczne powinny być uruchamiane nie tylko lokalnie, ale też w procesie CI/CD.
W tym wpisie pokażę Ci, jak uruchamiać testy Playwright w GitHub Actions.
Po co uruchamiać testy Playwright w GitHub Actions?
Najprościej mówiąc: żeby nie sprawdzać wszystkiego ręcznie po każdej zmianie.
GitHub Actions pozwala automatycznie uruchomić testy po pushu do repozytorium albo po utworzeniu pull requesta. Dzięki temu możemy szybciej wykryć, że jakaś zmiana zepsuła logowanie, koszyk, formularz kontaktowy, płatność albo inny ważny proces w aplikacji.
W praktyce wygląda to tak:
- Programista robi zmianę w kodzie.
- Zmiana trafia na GitHuba.
- GitHub Actions uruchamia workflow.
- Instalowane są zależności.
- Uruchamiają się testy Playwright.
- Po zakończeniu widzimy, czy testy przeszły, czy coś się wysypało.
I to jest dokładnie ten moment, w którym automatyzacja zaczyna mieć większy sens.
Bo testy nie są już tylko czymś, co tester uruchamia u siebie raz na jakiś czas. Stają się częścią procesu dostarczania aplikacji.
Przykładowy projekt Playwright
Zakładam, że masz już projekt z Playwrightem.
Jeżeli nie, możesz utworzyć go poleceniem:
npm init playwright@latestPo instalacji w projekcie powinieneś mieć między innymi:
tests/
playwright.config.ts
package.jsonTesty możesz lokalnie uruchomić poleceniem:
npx playwright testJeżeli wszystko działa lokalnie, możemy przejść do konfiguracji GitHub Actions.
Gdzie dodać konfigurację GitHub Actions?
W repozytorium utwórz katalog:
.github/workflowsA w nim plik, na przykład:
playwright.ymlFinalna ścieżka powinna wyglądać tak:
.github/workflows/playwright.ymlTo właśnie w tym pliku opiszemy, kiedy i jak mają uruchamiać się nasze testy.
Prosty workflow dla Playwright
Na początek możemy przygotować bardzo prostą konfigurację:
name: Playwright Tests
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
test:
name: Run Playwright tests
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- name: Upload Playwright report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 7I to jest już działająca podstawa.
Po dodaniu tego pliku do repozytorium GitHub Actions uruchomi testy po pushu do brancha main oraz po utworzeniu pull requesta do main.
Co robią poszczególne kroki?
Przejdźmy przez ten plik spokojnie, bo na początku YAML może wyglądać trochę dziwnie.
name: Playwright TestsTo jest nazwa workflow. Będzie widoczna w zakładce Actions na GitHubie.
on:
push:
branches:
- main
pull_request:
branches:
- mainTutaj określamy, kiedy workflow ma się uruchamiać.
W tym przypadku testy uruchomią się po pushu do main oraz przy pull requestach kierowanych do main.
runs-on: ubuntu-latestTen fragment oznacza, że job zostanie uruchomiony na maszynie z Ubuntu. W większości przypadków do testów Playwright będzie to wystarczające.
uses: actions/checkout@v4Ten krok pobiera kod repozytorium do środowiska GitHub Actions.
uses: actions/setup-node@v4Tutaj instalujemy Node.js. W przykładzie używam wersji 22.
run: npm ciTo polecenie instaluje zależności projektu na podstawie pliku package-lock.json.
W CI lepiej używać npm ci zamiast npm install, ponieważ jest bardziej przewidywalne i lepiej pasuje do środowisk automatycznych.
run: npx playwright install --with-depsTen krok instaluje przeglądarki i zależności systemowe potrzebne do działania Playwrighta.
To ważne, bo na świeżej maszynie w GitHub Actions nie możemy zakładać, że wszystko będzie już gotowe.
run: npx playwright testTutaj uruchamiane są testy.
if: always()Ten fragment przy uploadzie raportu oznacza, że raport ma zostać zapisany nawet wtedy, gdy testy zakończą się błędem.
I to jest bardzo ważne.
Bo jeżeli testy się wysypią, to właśnie wtedy najbardziej potrzebujemy raportu, screenshotów albo trace’ów.
Raport HTML z testów
Playwright domyślnie potrafi wygenerować raport HTML. Po wykonaniu testów raport może zostać zapisany jako artefakt w GitHub Actions.
W naszym workflow odpowiada za to ten fragment:
- name: Upload Playwright report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 7Po zakończeniu workflow możesz wejść w konkretny run w GitHub Actions i pobrać raport z sekcji artefaktów.
To bardzo pomaga przy analizie błędów.
Zamiast zgadywać, co się stało, możesz sprawdzić, który test nie przeszedł, na którym kroku wystąpił problem i co faktycznie zobaczyła przeglądarka.
Trace Viewer, czyli ratunek przy trudniejszych błędach
Jedną z rzeczy, które bardzo lubię w Playwright, jest Trace Viewer.
Jeżeli test nie przejdzie, trace pozwala prześledzić wykonanie testu krok po kroku. Możemy zobaczyć akcje, asercje, screenshoty, logi, requesty i odpowiedzi.
W praktyce jest to dużo wygodniejsze niż czytanie samego komunikatu błędu w konsoli.
W pliku playwright.config.ts warto mieć ustawione trace, na przykład tak:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
retries: process.env.CI ? 2 : 0,
reporter: 'html',
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});W tym przykładzie:
- trace zostanie zapisany przy pierwszym ponowieniu testu,
- screenshot zostanie zapisany tylko przy błędzie,
- video zostanie zachowane tylko wtedy, gdy test nie przejdzie,
- w CI ustawiamy 2 ponowienia testów.
Oczywiście nie zawsze trzeba używać retry. Jeżeli testy są dobrze napisane, powinny być stabilne. Ale w prawdziwych projektach retry czasami pomaga odsiać chwilowe problemy środowiska od faktycznych błędów w aplikacji.
Co jeśli aplikacja musi zostać uruchomiona przed testami?
Bardzo często testy end-to-end wymagają działającej aplikacji.
Lokalnie możesz mieć aplikację pod adresem:
http://localhost:3000Ale w GitHub Actions trzeba ją najpierw uruchomić.
Można to zrobić na kilka sposobów. Jednym z wygodniejszych jest konfiguracja webServer w Playwright.
Przykład:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
webServer: {
command: 'npm run dev',
url: 'http://127.0.0.1:3000',
reuseExistingServer: !process.env.CI,
timeout: 120 * 1000,
},
use: {
baseURL: 'http://127.0.0.1:3000',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});Dzięki temu Playwright przed testami uruchomi aplikację, poczeka aż będzie dostępna pod wskazanym adresem, a dopiero później odpali testy.
W testach możesz wtedy używać ścieżek względnych:
import { test, expect } from '@playwright/test';
test('homepage should load', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveTitle(/Example/);
});To jest dużo wygodniejsze niż wpisywanie pełnego adresu w każdym teście.
Uruchamianie testów tylko dla pull requestów
Nie zawsze musisz uruchamiać testy po każdym pushu do każdej gałęzi.
Często dobrym rozwiązaniem jest uruchamianie testów na pull requestach do main.
Przykład:
on:
pull_request:
branches:
- mainDzięki temu testy sprawdzają zmianę zanim trafi ona do głównej gałęzi.
To ma duży sens w projektach zespołowych, bo pull request nie powinien być mergowany, jeżeli testy automatyczne nie przechodzą.
Uruchamianie testów na kilku przeglądarkach
Playwright pozwala testować aplikację na różnych przeglądarkach, na przykład Chromium, Firefox i WebKit.
W pliku playwright.config.ts możesz mieć taką konfigurację:
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],Czy zawsze warto uruchamiać testy na trzech przeglądarkach?
To zależy.
Jeżeli projekt jest mały, czasami wystarczy Chromium. Jeżeli aplikacja jest używana przez wielu klientów i musi działać poprawnie na różnych przeglądarkach, warto rozważyć szerszą konfigurację.
Ja zwykle zaczynam od najważniejszych scenariuszy na Chromium, a dopiero później dokładam kolejne przeglądarki tam, gdzie faktycznie ma to sens.
Najczęstsze problemy w GitHub Actions
Przy pierwszej konfiguracji Playwrighta w GitHub Actions najczęściej pojawiają się podobne problemy.
1. Brak zainstalowanych przeglądarek
Jeżeli zobaczysz błąd związany z brakiem przeglądarki, sprawdź, czy w workflow masz krok:
- name: Install Playwright browsers
run: npx playwright install --with-depsBez tego Playwright może nie mieć środowiska potrzebnego do uruchomienia testów.
2. Aplikacja nie wystartowała przed testami
Jeżeli testy próbują wejść na localhost, ale aplikacja nie działa, testy oczywiście się wysypią.
Wtedy warto użyć webServer w konfiguracji Playwright albo dodać osobny krok w workflow, który uruchomi aplikację przed testami.
3. Test działa lokalnie, ale nie działa w CI
To klasyk.
Najczęstsze przyczyny to:
- zależność od danych lokalnych,
- zbyt sztywne timeouty,
- słabe selektory,
- brak oczekiwania na element,
- różnice w środowisku,
- testy zależne od kolejności uruchamiania.
W takich przypadkach bardzo pomaga trace, screenshot i raport HTML.
4. Za długie wykonywanie testów
Jeżeli testów robi się dużo, workflow może trwać zbyt długo.
Na początku to nie problem, ale z czasem warto pomyśleć o:
- podziale testów,
- uruchamianiu tylko najważniejszych testów na każdym pull requeście,
- osobnym workflow dla pełnej regresji,
- sharding testów,
- uruchamianiu pełnego zestawu testów na przykład raz dziennie albo przed większym releasem.
Czy testy Playwright powinny blokować merge?
Moim zdaniem: tak, ale z głową.
Jeżeli masz kilka stabilnych testów sprawdzających najważniejsze procesy w aplikacji, to jak najbardziej powinny one blokować merge.
Przykładowo:
- logowanie,
- rejestracja,
- koszyk,
- płatność,
- wysłanie formularza,
- podstawowy proces zakupowy,
- najważniejsza ścieżka użytkownika.
Nie zaczynałbym od blokowania merge’a setką testów, które są niestabilne i co chwilę losowo się wysypują.
Najpierw lepiej mieć mały, ale stabilny zestaw testów. Dopiero później można go rozbudowywać.
Dobra praktyka: osobny workflow dla smoke testów
W wielu projektach dobrze sprawdza się podział testów.
Na przykład:
- smoke testy uruchamiane na każdym pull requeście,
- pełna regresja uruchamiana ręcznie albo według harmonogramu,
- testy cross-browser uruchamiane przed releasem.
Dzięki temu nie blokujemy pracy zespołu zbyt długim pipeline’em, ale nadal mamy automatyczną kontrolę jakości.
Przykładowo smoke testy mogą sprawdzać tylko najważniejsze funkcje aplikacji:
npx playwright test --grep @smokeA w testach możemy oznaczać scenariusze w nazwie:
test('@smoke user can open homepage', async ({ page }) => {
await page.goto('/');
await expect(page).toBeVisible();
});To prosty sposób na rozdzielenie szybkich testów od większej regresji.
Podsumowanie
Uruchamianie testów Playwright w GitHub Actions to jeden z tych kroków, które naprawdę podnoszą wartość automatyzacji.
Dopóki testy są uruchamiane tylko lokalnie, łatwo o nich zapomnieć. Dopiero kiedy trafiają do pipeline’u, zaczynają realnie wspierać zespół.
Dobrze skonfigurowany workflow pozwala:
- uruchamiać testy po pushu lub pull requeście,
- szybciej wykrywać błędy,
- zapisywać raporty HTML,
- analizować trace’y i screenshoty,
- blokować merge, jeśli najważniejsze scenariusze nie przechodzą.
Na start nie trzeba robić idealnej konfiguracji.
Wystarczy prosty workflow, kilka stabilnych testów i raport zapisywany jako artefakt. Później można stopniowo dokładać kolejne elementy: retry, trace, smoke testy, sharding, testy na wielu przeglądarkach czy pełną regresję.
Najważniejsze jest jedno: testy automatyczne powinny działać tam, gdzie faktycznie podejmujemy decyzję o jakości kodu.
A w wielu projektach tym miejscem jest właśnie GitHub Actions.
