Równoległość, sharding i Playwright gotowy na CI
Testy Playwright mogą działać równolegle na wielu workerach, a nawet na wielu maszynach. Dowiedz się, jak skonfigurować workery, podzielić pakiety testów dla CI, zbierać artefakty trace i wideo oraz.
Ten wpis jest częścią serii Podstawy Playwright. Jeśli pominąłeś poprzedni post, przeczytaj najpierw Część 7 — Testy wizualne i dostępności w Playwright.
Wprowadzenie — szybkość to funkcja
Pakiet testów, który trwa 45 minut, to pakiet testów, który nie jest uruchamiany. Deweloperzy przestają czekać na CI. Mergują bez zielonych sprawdzeń. Niestabilne testy są ignorowane, ponieważ nikt nie ma czasu na dochodzenie.
Szybkość to nie luksus — to warunek wstępny adopcji.
Playwright jest zaprojektowany z myślą o szybkości. Domyślnie uruchamia testy równolegle w wielu kontekstach przeglądarki. Dzięki shardingowi możesz rozdzielić testy na wiele maszyn CI i skrócić całkowity czas wykonania o 10x lub więcej. Dzięki zbieraniu trace możesz debugować awarie bez ich reprodukowania lokalnie.
Ten post pokaże ci, jak skonfigurować równoległe wykonywanie, jak shardować pakiety testów na workerach CI, jak zbierać i przesyłać artefakty testów (traces, wideo, zrzuty ekranu) oraz jak zbudować pipeline Playwright klasy produkcyjnej w GitHub Actions.
Równoległe wykonywanie: workery i konteksty
Domyślnie Playwright uruchamia testy równolegle, używając workerów. Każdy worker to osobny proces Node.js, który uruchamia podzbiór twoich testów. W ramach każdego workera testy działają sekwencyjnie, ale wiele workerów działa jednocześnie.
Domyślna równoległość
Jeśli masz 10 testów i 5 workerów, Playwright:
- Przypisze ~2 testy do każdego workera
- Uruchomi 5 workerów jednocześnie
- Każdy worker uruchomi przypisane mu testy sekwencyjnie
Wynik: Całkowity czas wykonania to mniej więcej czas najwolniejszych 2 testów, a nie suma wszystkich 10.
Konfigurowanie workerów
Kontroluj liczbę workerów w playwright.config.ts:
import { defineConfig } from '@playwright/test';
export default defineConfig({
workers: 5, // Użyj 5 równoległych workerów
});
Lub ustaw workery na podstawie dostępnych rdzeni CPU:
export default defineConfig({
workers: process.env.CI ? 2 : undefined,
// Na CI: 2 workery (maszyny CI są często ograniczone zasobami)
// Lokalnie: undefined oznacza, że Playwright wykrywa automatycznie na podstawie rdzeni CPU
});
:::tip[Zacznij konserwatywnie na CI] Runnery CI często mają ograniczone CPU i pamięć. Zacznij od 2–4 workerów i zwiększaj na podstawie obserwowanej stabilności. Zbyt wiele workerów może powodować konkurencję o zasoby i zwiększać niestabilność. :::
Tryb w pełni równoległy
Domyślnie testy w tym samym pliku działają sekwencyjnie w ramach workera. Jeśli chcesz, aby testy w tym samym pliku działały równolegle, włącz fullyParallel:
export default defineConfig({
fullyParallel: true,
});
Lub per plik:
// tests/checkout.spec.ts
import { test } from '@playwright/test';
test.describe.configure({ mode: 'parallel' });
test('checkout kartą kredytową', async ({ page }) => { /* ... */ });
test('checkout przez PayPal', async ({ page }) => { /* ... */ });
:::warning[Współdzielony stan i w pełni równoległy]
Jeśli testy w pliku modyfikują współdzielony stan (rekordy bazy danych, ustawienia konta), włączenie fullyParallel może powodować race conditions. Użyj oddzielnych kont testowych lub wyłącz tryb równoległy dla tych testów.
:::
Tryb szeregowy dla testów zależnych od kolejności
Jeśli testy muszą działać w określonej kolejności (np. “utwórz użytkownika” → “edytuj użytkownika” → “usuń użytkownika”), użyj .serial():
test.describe.serial('cykl życia użytkownika', () => {
test('utwórz użytkownika', async ({ page }) => { /* ... */ });
test('edytuj użytkownika', async ({ page }) => { /* ... */ });
test('usuń użytkownika', async ({ page }) => { /* ... */ });
});
Te testy będą działać sekwencyjnie w ramach ich bloku describe, ale inne testy nadal mogą działać równolegle.
Sharding: dystrybucja testów na wiele maszyn
Sharding dzieli twój pakiet testów na N części i uruchamia każdą część na osobnej maszynie. Jeśli masz 100 testów i 4 maszyny CI, każda maszyna uruchamia 25 testów. Całkowity czas wykonania spada do ~25% czasu szeregowego.
Jak działa sharding
Flaga --shard w Playwright przyjmuje stosunek: --shard=X/N oznacza “jestem maszyną X z N wszystkich maszyn.”
Przykład z 4 shardami:
npx playwright test --shard=1/4
npx playwright test --shard=2/4
npx playwright test --shard=3/4
npx playwright test --shard=4/4
Każde polecenie uruchamia inne 25% pakietu testów. Uruchom wszystkie cztery równolegle (na różnych maszynach lub w różnych zadaniach CI), a zmniejszysz całkowity czas wykonania czterokrotnie.
Sharding w GitHub Actions
Oto workflow GitHub Actions klasy produkcyjnej z shardingiem:
name: Playwright Tests
on:
push:
branches: [main, develop]
pull_request:
jobs:
test:
timeout-minutes: 30
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Run Playwright tests
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-results-${{ matrix.shardIndex }}
path: test-results/
retention-days: 7
- name: Upload Playwright report
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.shardIndex }}
path: playwright-report/
retention-days: 7
Ten workflow:
- Tworzy 4 równoległe zadania (jedno na shard)
- Instaluje zależności i przeglądarki Playwright
- Uruchamia 1/4 pakietu testów w każdym zadaniu
- Przesyła wyniki testów i raporty HTML jako artefakty
Jeśli masz 200 testów, które trwają 40 minut szeregowo, sharding na 4 maszyny zmniejsza czas CI do ~10 minut.
Adaptacyjny sharding
Jeśli twój pakiet testów jest mały (< 50 testów), sharding może nie pomóc — narzut uruchamiania 4 zadań CI może przekroczyć korzyść z równoległości. Użyj dynamicznego shardingu na podstawie rozmiaru pakietu:
strategy:
matrix:
shardIndex: ${{ github.event_name == 'pull_request' && fromJSON('[1, 2]') || fromJSON('[1, 2, 3, 4]') }}
shardTotal: ${{ github.event_name == 'pull_request' && 2 || 4 }}
To uruchamia 2 shardy na PR (szybszy feedback) i 4 shardy na głównej gałęzi (głębsze pokrycie).
Artefakty: Traces, wideo i zrzuty ekranu
Gdy testy padają w CI, potrzebujesz danych diagnostycznych. Playwright automatycznie przechwytuje traces, wideo i zrzuty ekranu.
Traces
Trace to pełne nagranie wykonania testu: każda akcja, każde żądanie sieciowe, każdy snapshot DOM. Możesz otworzyć to w przeglądarce trace Playwright i przechodzić przez test, jakbyś debugował go na żywo.
Skonfiguruj zbieranie trace w playwright.config.ts:
export default defineConfig({
use: {
trace: 'on-first-retry',
// Opcje: 'off', 'on', 'retain-on-failure', 'on-first-retry'
},
});
Zalecane ustawienia:
- Lokalnie:
'off'(traces są duże i wolne) - CI:
'on-first-retry'(przechwytuj traces tylko dla niestabilnych lub padających testów)
Wideo
Wideo pokazują dokładnie, co przeglądarka zrobiła podczas testu. Są łatwiejsze do przejrzenia niż traces, ale mniej szczegółowe.
export default defineConfig({
use: {
video: 'retain-on-failure',
// Opcje: 'off', 'on', 'retain-on-failure', 'on-first-retry'
},
});
Zrzuty ekranu
Playwright automatycznie przechwytuje zrzuty ekranu przy awarii. Możesz też robić zrzuty ekranu ręcznie:
test('strona główna się ładuje', async ({ page }) => {
await page.goto('/');
await page.screenshot({ path: 'homepage.png' });
});
Przesyłanie artefaktów w CI
Artefakty są bezużyteczne, jeśli pozostaną na maszynie CI. Prześlij je, aby deweloperzy mogli je pobrać i przejrzeć:
- name: Upload artifacts on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-artifacts-${{ matrix.shardIndex }}
path: |
test-results/
playwright-report/
retention-days: 7
Gdy test pada, przejdź do uruchomienia GitHub Actions, pobierz artefakt i otwórz trace:
npx playwright show-trace trace.zip
Przeglądarka trace otwiera się w twojej przeglądarce z pełną osią czasu wykonania testu.
Ponowne próby: obsługa niestabilnych testów
Rzeczywiste aplikacje są niestabilne. Żądania sieciowe wygasają. API przejściowo zwracają błędy 500. Animacje zakłócają kliknięcia. Ponawianie nieudanych testów zmniejsza fałszywe negatywy.
Skonfiguruj ponowne próby w playwright.config.ts:
export default defineConfig({
retries: process.env.CI ? 2 : 0,
// Na CI: ponów nieudane testy do 2 razy
// Lokalnie: nie ponawiaj (szybko pada, więc naprawiasz problem)
});
Gdy test pada, Playwright:
- Uruchamia test ponownie (pierwsza próba)
- Jeśli nadal pada, uruchamia go ponownie (druga próba)
- Jeśli nadal pada, oznacza test jako nieudany
Jeśli jakakolwiek próba się powiedzie, test jest oznaczony jako niestabilny (passed with retries). Niestabilne testy przechodzą build CI, ale są oznaczone w raporcie, abyś mógł zbadać.
:::warning[Ponowne próby maskują problemy] Ponowne próby zmniejszają niestabilność, ale ukrywają przyczyny źródłowe. Śledź liczbę niestabilnych testów w swoich metrykach CI. Jeśli test jest niestabilny w ponad 10% przypadków, napraw test lub aplikację, nie ponawiaj w nieskończoność. :::
Reporter Playwright dla CI
Wbudowany reporter HTML Playwright jest świetny do lokalnego rozwoju, ale zbyt ciężki dla logów CI. Użyj reportera list dla CI:
export default defineConfig({
reporter: process.env.CI
? [['list'], ['html', { open: 'never' }]]
: [['html', { open: 'on-failure' }]],
});
Ta konfiguracja:
- Na CI: Wyświetla listę wyników testów linia po linii do stdout, generuje raport HTML, ale go nie otwiera
- Lokalnie: Otwiera raport HTML automatycznie przy awarii
Możesz też zintegrować z reporterami stron trzecich:
- GitHub Actions:
@playwright/test/reporterwyświetla adnotacje na PR - JUnit XML:
['junit', { outputFile: 'test-results/junit.xml' }]do integracji z narzędziami do zarządzania testami - Allure:
allure-playwrightdla bogatego raportowania historycznego
Zmienne środowiskowe i sekrety
Testy często potrzebują kluczy API, danych uwierzytelniających bazy danych lub tokenów OAuth. Nigdy nie commituj sekretów do kontroli kodu źródłowego.
Używanie GitHub Secrets
Przechowuj sekrety w ustawieniach repozytorium GitHub:
- Przejdź do Settings → Secrets and variables → Actions
- Dodaj sekrety (np.
TEST_USER_EMAIL,TEST_USER_PASSWORD,API_KEY) - Odwołuj się do nich w workflow:
- name: Run Playwright tests
env:
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
API_KEY: ${{ secrets.API_KEY }}
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
W swoich testach czytaj z process.env:
test('użytkownik może się zalogować', async ({ page }) => {
await page.goto('/login');
await page.fill('input[name="email"]', process.env.TEST_USER_EMAIL!);
await page.fill('input[name="password"]', process.env.TEST_USER_PASSWORD!);
await page.click('button[type="submit"]');
});
:::tip[Szybko pada przy brakujących sekretach] Dodaj krok walidacji na początku swojego pakietu testów:
// global-setup.ts
if (!process.env.TEST_USER_EMAIL || !process.env.TEST_USER_PASSWORD) {
throw new Error('Brakuje wymaganych zmiennych środowiskowych: TEST_USER_EMAIL, TEST_USER_PASSWORD');
}
To powoduje natychmiastową awarię buildu z jasnym komunikatem, zamiast 50 niezrozumiałych awarii testów. :::
Kompletny workflow GitHub Actions
Oto pipeline Playwright CI klasy produkcyjnej:
name: Playwright Tests
on:
push:
branches: [main, develop]
pull_request:
workflow_dispatch:
jobs:
test:
timeout-minutes: 30
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Run Playwright tests
env:
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-results-${{ matrix.shardIndex }}
path: test-results/
retention-days: 7
- name: Upload Playwright HTML report
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.shardIndex }}
path: playwright-report/
retention-days: 7
merge-reports:
if: always()
needs: test
runs-on: ubuntu-latest
steps:
- name: Download all reports
uses: actions/download-artifact@v4
with:
path: all-reports
- name: Merge reports
run: npx playwright merge-reports ./all-reports
- name: Upload merged report
uses: actions/upload-artifact@v4
with:
name: playwright-report-merged
path: playwright-report/
retention-days: 30
Ten workflow:
- Uruchamia testy w 4 równoległych shardach
- Przesyła indywidualne raporty shardów
- Łączy wszystkie raporty shardów w jeden raport HTML
- Przesyła scalony raport
Deweloperzy mogą pobrać scalony raport i zobaczyć wszystkie wyniki testów w jednym miejscu.
Typowe pułapki CI
Pułapka 1: Nie instalowanie zależności przeglądarki
Przeglądarki Playwright potrzebują zależności systemowych (czcionki, biblioteki). Jeśli widzisz błędy takie jak “Could not find browser binary,” zainstaluj je:
npx playwright install --with-deps chromium
Pułapka 2: Uruchamianie wszystkich przeglądarek w CI
Nie uruchamiaj Chromium, Firefox i WebKit w każdym uruchomieniu CI. To potraja czas wykonania przy minimalnej wartości. Uruchamiaj Chromium domyślnie:
export default defineConfig({
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
],
});
Uruchamiaj testy międzyprzeglądarkowe według harmonogramu (nocnie) lub ręcznie przed wydaniami.
Pułapka 3: Ignorowanie niestabilnych testów
Jeśli skonfigurujesz retries: 3 i zignorujesz ostrzeżenia o niestabilnych testach, zbudowałeś system CI, który ukrywa problemy. Ustaw budżet niestabilnych testów (np. “nie więcej niż 2% wskaźnik niestabilności”) i badaj, gdy go przekroczysz.
Podsumowanie
Playwright jest zaprojektowany z myślą o szybkości i skali. Równoległe wykonywanie, sharding i zbieranie trace przekształcają wolny, niewiarygodny pakiet testów w szybki, debugowalny pipeline CI.
Kluczowe wnioski:
- Użyj workerów, aby uruchamiać testy równolegle lokalnie
- Użyj shardingu, aby rozdzielić testy na wiele maszyn CI
- Zbieraj traces i wideo tylko przy awarii, aby zminimalizować koszt przechowywania
- Skonfiguruj ponowne próby na CI, aby obsłużyć przejściową niestabilność
- Przesyłaj artefakty, aby deweloperzy mogli debugować awarie bez reprodukowania lokalnie
- Użyj GitHub Secrets dla danych uwierzytelniających, nigdy nie commituj ich do kontroli kodu źródłowego
:::tip[Mierz i iteruj] Śledź swoje metryki CI: całkowity czas wykonania, wskaźnik niestabilnych testów, wskaźnik przejść, rozmiar artefaktów. Ustaw cele (np. “wszystkie testy działają w mniej niż 10 minut”) i optymalizuj swoją konfigurację, aby je osiągnąć. :::
Zadanie na ten tydzień: Dodaj sharding do swojego pipeline’u Playwright CI. Zmierz czas wykonania przed i po. Jeśli twój pakiet jest mały (< 50 testów), pomiń sharding, ale skonfiguruj zbieranie trace przy awarii. Pobierz trace z nieudanego testu i poznaj przeglądarkę trace — zobaczysz, dlaczego to najlepsze narzędzie do debugowania testów E2E.
Następny w tej serii: Część 9 — Debugowanie padających testów Playwright jak pro