Jeśli korzystacie z Playwrighta lub interesujecie się jego rozwojem, zapewne wiecie, że Playwright oferuje wiele ciekawych integracji, które pozwalają rozszerzyć jego domyślną funkcjonalność – zarówno w testach API, jak i UI.
Jakiś czas temu napisałem dwa posty na temat wykorzystania wbudowanego mechanizmu visual regression [(link)] oraz integracji z narzędziem open-source Visual Regression Tracker [(link)].
Playwright posiada również integrację z innymi narzędziami, takimi jak Lighthouse.
Czym jest Lighthouse?

Lighthouse to narzędzie open-source rozwijane przez Google, które umożliwia generowanie raportów zawierających m.in. informacje o wydajności (performance) aplikacji webowej z perspektywy użytkownika. Lighthouse jest także wbudowany w przeglądarkę Chrome i dostępny w Chrome DevTools, co pozwala na wygenerowanie raportu dla dowolnej strony internetowej. Możemy tam również wybrać, czy analiza ma dotyczyć wersji mobilnej czy desktopowej.
Raport Lighthouse zawiera kluczowe informacje dotyczące wydajności (Performance), SEO oraz dostępności (Accessibility) danej strony.
Jakie aspekty analizuje Lighthouse?
⚡ Wydajność (Performance):
Mierzy, jak szybko strona internetowa ładuje się i reaguje na interakcje użytkownika. Kluczowe metryki to:

https://blog.chromium.org/2020/05/introducing-web-vitals-essential-metrics.html
- FCP (First Contentful Paint) – czas do wyświetlenia pierwszego elementu treści
- LCP (Largest Contentful Paint) – czas do wyświetlenia największego elementu treści
- TBT (Total Blocking Time) – całkowity czas blokowania
- CLS (Cumulative Layout Shift) – przesunięcia układu strony
- TTI (Time to Interactive) – czas do pełnej interaktywności strony
♿ Dostępność (Accessibility):
Sprawdza, czy strona jest użyteczna dla osób z niepełnosprawnościami, w zgodzie z wytycznymi WCAG (Web Content Accessibility Guidelines). Przykłady:
- problemy z kontrastem kolorów
- brak tekstów alternatywnych (alt) dla obrazów
- nieprawidłowe użycie elementów HTML (np. nagłówki, linki)
Warto pamiętać, że wbudowane testy są bardzo podstawowe. Jeśli chcesz lepiej pokryć obszar dostępności, możesz użyć np. biblioteki Axe lub pa11y, która integruje się również z Playwright.
🔍 SEO (Search Engine Optimization):
Sprawdza, czy strona jest zoptymalizowana pod kątem wyszukiwarek. Przykłady kontroli:
- poprawne meta tagi (tytuł, opis)
- przyjazność dla urządzeń mobilnych
- użycie danych strukturalnych (schema.org)
🛠️ Najlepsze praktyki (Best Practices):
Ocena ogólnej jakości kodu i bezpieczeństwa. Przykładowe sprawdzenia:
- korzystanie z HTTPS
- użycie nowoczesnych funkcji JavaScript
- brak przestarzałych API
📱 PWA (Progressive Web App):
Weryfikuje, czy strona spełnia standardy PWA, czyli czy może być instalowana i działać niezawodnie offline. Obejmuje to:
- obecność service workera
- manifest aplikacji webowej
- wsparcie dla trybu offline
Kiedy takie testy mają sens?
Aplikacje SPA (Single Page Applications): W przypadku aplikacji typu SPA, gdzie zawartość strony ładowana jest dynamicznie (często za pomocą AJAX lub frameworków takich jak React, Angular, Vue.js), testowanie wydajności po stronie klienta jest niezbędne. Ważne jest, aby sprawdzić, jak szybko aplikacja reaguje na działania użytkownika i jak szybko ładuje różne komponenty.
Optymalizacja ładowania zasobów: Jeśli strona ma duży zestaw zasobów (np. obrazy, pliki CSS, JavaScript), testowanie wydajności pozwala zidentyfikować, czy czas ładowania strony jest akceptowalny, a także czy wszystkie zasoby są ładowane w sposób efektywny (np. lazy loading, asynchroniczne ładowanie skryptów).
Interaktywność strony: Strony, które opierają się na interakcji użytkownika, np. formularze, dynamiczne listy, filtry, mapy, gry online, powinny być testowane pod kątem szybkości i responsywności. Celem jest upewnienie się, że reakcje na akcje użytkownika są płynne, a czas oczekiwania na odpowiedź (np. na kliknięcie przycisku) jest jak najkrótszy.
Mobilne wersje stron: Wydajność po stronie klienta jest kluczowa w przypadku urządzeń mobilnych, które mają mniejszą moc obliczeniową, ograniczoną pamięć i wolniejsze połączenie internetowe. Testowanie aplikacji w kontekście mobilnym pozwala upewnić się, że działa ona płynnie na różnych urządzeniach.
Optymalizacja czasu renderowania i zasobów JavaScript: Jeśli aplikacja wykorzystuje duże skrypty JavaScript lub rozbudowane operacje DOM (np. animacje, zmiany w UI), testowanie pozwala zidentyfikować, które procesy powodują spadek wydajności, a także sprawdzić czas renderowania strony.
Zoptymalizowanie wydajności w różnych przeglądarkach: Testy pozwalają również sprawdzić, jak aplikacja działa w różnych przeglądarkach i wersjach, ponieważ różne przeglądarki mogą różnie obsługiwać renderowanie stron i przetwarzanie JavaScriptu.
Testowanie w różnych warunkach sieciowych: Często testy wydajności są przeprowadzane również z symulacjami różnych prędkości połączenia internetowego, aby sprawdzić, jak aplikacja zachowuje się przy słabym połączeniu lub w przypadku niestabilności sieci.
Gdy nasze podstrony pełnią funkcję sprzedażową, np. są landing page’ami prowadzącymi do koszyka zakupowego, warto zadbać o ich optymalizację. Dotyczy to również podstron, na których koncentruje się uwaga użytkowników i które są często odwiedzane.
W jaki sposób zintegrować Lighthouse z Playwrightem?
Jednym z pomysłów na integrację Playwrighta z Lighthouse jest użycie biblioteki playwright-lighthouse. Ale czy ta biblioteka faktycznie działa bez problemów?
Jakiś czas temu, w ramach PoC (Proof of Concept) integracji Lighthouse i Playwrighta dla jednego z klientów, natrafiłem na pewne wyzwania związane z użyciem tej biblioteki.
Już wcześniej wiedziałem, że Lighthouse można zintegrować z Playwrightem i że istnieje biblioteka wspierająca tę integrację. Jednak, gdy podjąłem próbę konfiguracji, zaczęły pojawiać się różne problemy – m.in.:
- trudności z przekazywaniem ciasteczek do tej biblioteki,
- brak aktualizacji – ostatnia wersja była rozwijana ponad rok temu,
- inne problemy zgłaszane przez użytkowników, które można znaleźć np. tutaj:
W związku z tym zacząłem zastanawiać się nad integracją Playwrighta z najnowszą wersją Lighthouse. W dzisiejszym wpisie pokażę Wam, jak można to zrobić oraz na co warto zwrócić uwagę.
Zaczynamy
Nasz test będzie polegał na przejściu na stronę główną mojego bloga, a następnie wykonaniu testu Lighthouse. Adres URL strony zostanie przekazany za pomocą pliku YAML. Oprócz adresu URL przekażę również parametry, tzw. thresholds, które określają maksymalne oczekiwane wartości dla poszczególnych obszarów ocenianych przez Lighthouse, takich jak performance, SEO, best practices oraz accessibility.
Konfiguracja Playwright i Lighthouse
Przede wszystkim zaczynam od utworzenia nowego projektu w Playwright. W tym celu uruchamiam komendę:
playwright init
Następnie przechodzę do pobrania najnowszej wersji Lighthouse poprzez instalację paczki:
npm install lighthouse
Warto pamiętać, że wersja nodejs, którą powinniśmy używać to przynajmniej wersja v18.
Dodanie wczytywanie ustawień z pliku yaml
Teraz przechodzimy do tworzenia kodu. Rozpoczynam pracę od stworzenia prostego kodu, który obsłuży wczytywanie ustawień z pliku yaml. Do tego potrzebujemy skorzystać z biblioteki js-yaml.
Nasz plik z ustawieniami Yamla prezentuję się w ten sposób.

Jest to prosta konfiguracja, która pozwala na przekazywanie wartości do YAMLa z zewnątrz, np. w CI, dzięki czemu te wartości nie są zahardcodowane. Definiujemy kluczowe dla nas wartości parametrów, takich jak performance i accessibility.
Rozpoczynamy od określenia adresu URL naszej strony, a następnie konfigurujemy port instancji przeglądarki, który jest niezbędny do działania Lighthouse. Ponieważ chcemy korzystać z tej samej przeglądarki, musimy go tutaj ustawić.
Kolejnym krokiem jest konfiguracja Chromium tak, aby uruchamiało się w trybie headless – oznacza to, że podczas wykonywania testu nie będziemy widzieć „wyskakującego” okna, a test będzie działał w tle jako proces.
Potrzebujemy interfejsów, które pozwolą nam na zrzutowanie naszego pliku.
Interfejsy i typy: LighthouseScoreThresholds, ScoreKey, ChromeConfig, LighthouseConfig, ScoreResult

Na początku definiujemy interfejs LighthouseScoreThresholds, który określa oczekiwane wartości progowe (tzw. thresholdy) dla różnych metryk wydajnościowych w Lighthouse, takich jak performance, accessibility, bestPractices i SEO.
Następnie deklarujemy typ ScoreKey, który jest kluczem dla wartości w LighthouseScoreThresholds. Dzięki temu możemy później dynamicznie odnosić się do poszczególnych kategorii wyników.
Interfejs ChromeConfig na ten moment zawiera tylko jedno pole – debuggingPort, które wskazuje port używany przez Chrome w testach automatycznych. Jest to jednak struktura, którą można w przyszłości łatwo rozszerzyć o dodatkowe ustawienia.
Główny interfejs, LighthouseConfig, agreguje wszystkie niezbędne ustawienia do uruchomienia testu Lighthouse. Zawiera on:
- baseUrl – adres URL testowanej strony,
- chrome – konfigurację przeglądarki (obecnie reprezentowaną przez ChromeConfig),
- thresholds – wartości progowe wyników Lighthouse,
- formFactor – określający, czy test ma być wykonywany w trybie mobile czy desktop,
- logLevel – poziom szczegółowości logów (silent, error, info, verbose),
- onlyCategories – opcjonalną listę kategorii do testowania.
Ostatnia definicja to ScoreResult, który jest mapą (Record), gdzie kluczami są metryki Lighthouse (ScoreKey), a wartościami ich wyniki jako liczby (number).
Następnym krokiem jest stworzenie pliku lighthouse.config.ts, w którym definiujemy ścieżkę do pliku konfiguracyjnego w formacie YAML. Domyślnie ścieżka ta jest przekazywana jako argument do konstruktora, ale istnieje możliwość podania alternatywnej konfiguracji, np. z innymi ustawieniami.
Jeżeli ścieżka do pliku konfiguracyjnego nie została określona w parametrze, system domyślnie pobiera ją ze zmiennej środowiskowej LIGHTHOUSE_CONFIG_PATH. Jeśli żadna z tych wartości nie zostanie ustawiona, aplikacja zgłosi błąd, informując o konieczności podania ścieżki do konfiguracji.
Dodatkowo, w tej implementacji obsługiwane jest wczytywanie pliku YAML oraz konwersja wartości progów (thresholds) na liczby. Tworzony jest również katalog Lighthouse-reports, jeśli jeszcze nie istnieje.

ensureReportsDirectory()
Jedną z potrzebnych metod jest ensureReportsDirectory(), która odpowiada za tworzenie katalogu przeznaczonego na raporty Lighthouse. Jeśli katalog nie istnieje, metoda go utworzy, aby przechowywać w nim wygenerowane wyniki testów.
2. loadConfig()
Metoda loadConfig() wczytuje konfigurację Lighthouse z pliku YAML, parsuje go na interfejs LighthouseConfig i zwraca obiekt zawierający wszystkie wcześniej zdefiniowane pola. Jest to kluczowy element, ponieważ na podstawie tego obiektu określane są wszystkie parametry testów.
3. audit()
Kolejnym krokiem jest dodanie kluczowej metody audit(), która odpowiada za przeprowadzanie audytu strony przy użyciu Lighthouse.
- Metoda jako parametr przyjmuje
url, który domyślnie pobiera z pliku YAML zawierającego ustawienia. Użytkownik może jednak podać inny adres URL, jeśli chce przetestować inną stronę. - Następnie importujemy i definiujemy Lighthouse, aby móc z niego korzystać.
- W kolejnym etapie konfigurujemy raport, ustawiając kluczowe parametry, takie jak:
- port – pobierany z pliku YAML,
- log level – określający poziom szczegółowości logów,
- formFactor – określający, czy testy mają być uruchamiane w trybie mobilnym czy desktopowym.
- Na końcu definiujemy format raportu. W naszym przypadku jest to HTML, ale nic nie stoi na przeszkodzie, aby rozszerzyć obsługę o inne formaty, np. JSON lub CSV. Te formaty są bardziej przystępne do dalszego przetwarzania i analizy wyników niż HTML.

Ostatnie metody w klasie – getThresholds() i getConfig()
Na końcu definiujemy dwie metody: getThresholds() oraz getConfig(), które będą wykorzystywane w testach.
getThresholds()– zwraca obiekt zawierający wartości progowe (thresholds) dla poszczególnych metryk Lighthouse. ZastosowanieReadonly<LighthouseScoreThresholds>zapewnia, że zwrócone wartości nie będą modyfikowane poza klasą.getConfig()– zwraca pełną konfigurację testów w postaci obiektuLighthouseConfig. Podobnie jak w przypadkugetThresholds(), zastosowanieReadonly<LighthouseConfig>gwarantuje, że konfiguracja pozostaje niezmienna po pobraniu.

Kod testów – przykładowy test

Testy rozpoczynają się od deklaracji lighthouseService w bloku beforeEach, co zapewnia jego inicjalizację przed każdym testem.
- Pobranie konfiguracji
Za pomocą getConfig() pobieramy ustawienia testowe, które zostały wcześniej sparsowane z pliku YAML. Dzięki temu unikamy problemów związanych z twardo zakodowanymi wartościami. - Uruchomienie przeglądarki Chromium
- W argumencie –remote-debugging-port przekazujemy numer portu używanego przez Lighthouse, co pozwala uniknąć potencjalnych błędów wynikających z jego hardkodowania.
- Określamy tryb uruchomienia testu (headless lub nieheadless).
Od wersji Chromium 109, do uruchomienia przeglądarki w trybie headless służy argument –headless=new.
W kodzie (linia 21) sprawdzamy wartość config.chrome.headless – jeśli wynosi true, używamy nowego parametru –headless=new, w przeciwnym razie przeglądarka uruchamia się w trybie graficznym.
- Tworzenie kontekstu i strony w Playwright
- Tworzymy nowy kontekst i stronę (page) w Playwright, które następnie przekazujemy do obiektu HomePage.
- navigate() – metoda nawigacji, która przechodzi do testowanej strony.
- Wykonanie audytu Lighthouse
- Metoda audit() uruchamia testy Lighthouse.
- Wyniki są przetwarzane przez funkcję extractScores(audit).
- Następnie porównujemy uzyskane wyniki z wartościami progowymi za pomocą assertScores(scores, LighthouseService.getThresholds()).
- Zamknięcie przeglądarki
- Na końcu testu przeglądarka jest zamykana metodą browser.close().
Klasa HomePage – obsługa nawigacji w testach

Do konstruktora klasy HomePage przekazujemy dwa parametry:
page– obiekt strony z Playwrighta, który będzie używany do interakcji z przeglądarką,config– obiekt konfiguracyjnyLighthouseConfig, sparsowany z pliku YAML.
Metoda navigate()
Metoda navigate() odpowiada za przejście do strony domowej aplikacji testowanej w Lighthouse.
Działa w następujący sposób:
- Przechodzi do strony na podstawie adresu
baseUrl, pobranego z konfiguracji YAML. - Oczekuje na pojawienie się nagłówka (
h1), co zapewnia, że strona została w pełni załadowana przed rozpoczęciem testów.
Korzyści z użycia pliku konfiguracyjnego YAML
Jednym z kluczowych atutów korzystania z zewnętrznych plików konfiguracyjnych jest elastyczność:
- Ścieżka do pliku YAML jest przechowywana w
.env, co umożliwia łatwe przełączanie konfiguracji. - Dzięki temu możemy szybko uruchomić różne testy, wystarczy zmienić ścieżkę w zmiennej środowiskowej bez modyfikacji kodu.
Jak wygląda wygenerowany raport?
Uruchomiłem test Lighthouse dla strony głównej mojego bloga. Obecne wyniki są bardzo dobre, choć na wcześniejszych etapach – podczas tworzenia bloga i konfiguracji – sytuacja wyglądała gorzej. Musiałem przeskalować dodane grafiki, włączyć cache oraz wprowadzić kilka innych optymalizacji, które pozwoliły mi osiągnąć wysoką szybkość wczytywania elementów na stronie.
Optymalizacja to proces ciągły – strona może ewoluować, a treści się zmieniać, dlatego warto regularnie przeprowadzać testy i wprowadzać niezbędne poprawki. Zachęcam Was do systematycznego korzystania z Lighthouse w Waszych aplikacjach webowych. Analiza raportu pomaga wykryć potencjalne problemy i wdrożyć usprawnienia, które zwiększą wydajność, dostępność oraz jakość strony.
Należy również pamiętać, że istnieje niemal nieskończona liczba kombinacji ustawień testowych – od prędkości internetu, przez rozdzielczość ekranu, aż po typ urządzenia, na którym uruchamiamy stronę. Testowanie w różnych warunkach pozwala skutecznie identyfikować obszary wymagające dalszej optymalizacji.

Czy testy w Lighthouse są stabilne?
Na początku przygody z testami wydajności po stronie klienta można zauważyć, że ich wyniki są silnie uzależnione od jakości połączenia internetowego oraz środowiska, w którym są uruchamiane. Dlatego warto wykonywać testy w miejscu z stabilnym dostępem do Internetu oraz na maszynie o odpowiednich zasobach.
Warto również zwrócić uwagę na porę testowania – np. w godzinach szczytu (np. o 11:00), gdy więcej użytkowników korzysta z tego samego środowiska, wyniki mogą być mniej wiarygodne. Dlatego zalecam uruchamianie testów o stałej porze, najlepiej wtedy, gdy zasoby serwera nie są nadmiernie obciążone.
Po co korzystać regularnie z Lighthouse?
Regularne uruchamianie testów wydajności po stronie klienta pozwala na szybkie wykrywanie ewentualnych spadków płynności działania naszej aplikacji webowej.
Lighthouse umożliwia również emulację wolniejszych połączeń internetowych, co jest niezwykle przydatne – nie wszędzie użytkownicy mają dostęp do sieci 5G czy 4G, więc zasoby strony mogą ładować się znacznie wolniej.
Dzięki analizie raportów Lighthouse możemy sprawdzić, które elementy strony wymagają optymalizacji, czy wszystkie zasoby mają odpowiednie rozmiary oraz czy można je efektywniej cache’ować. Regularne testowanie pozwala na bieżąco poprawiać wydajność i komfort użytkowania naszej aplikacji.
Natywne możliwości
GitHub Actions & inne CI/CD
Jednym z pomysłów na wykorzystanie Lighthouse jest skonfigurowanie joba, który codziennie uruchamia testy wydajności i wysyła raport na Teams/Slacka. Dzięki temu cały zespół może na bieżąco monitorować, jak wygląda wydajność kluczowych stron.
W tym podejściu możemy określić oczekiwane wartości, np. że wynik wydajności nie powinien spaść poniżej 90%. Dodatkowo w prosty sposób można dodać kod, który porównuje wyniki z poprzednich uruchomień w danym środowisku i wykrywa potencjalne regresje.
Alternatywy?
Sitespeed.io
Jest to jedno z ciekawszych rozwiązań open-source, które pod spodem zawiera wiele różnych narzędzi do mierzenia różnych metryk.
Jakie posiada dodatkowe niedostępne w Lighthouse możliwości?
Poprzez posiadania większej ilości opcji możemy np. przetestować jak szybko video ładuje się na naszej stronie internetowej.
Integracja z Grafaną
Ktoś mógłby zadać pytanie czy sitespeed panuję integrację z playwrightem – takie pytanie padło jakiś czas temu na ichniejszym githubie – https://github.com/sitespeedio/sitespeed.io/issues/3452

Unlighthouse
Ciekawą alternatywą dla klasycznego Lighthouse jest Unlighthouse, które pozwala na uruchomienie testów dla każdej wykrytej podstrony, a następnie generuje zbiorczy raport dla wszystkich znalezionych adresów.
Dla stron niedostępnych dla niezalogowanych użytkowników istnieje również możliwość przekazania danych uwierzytelniających, co umożliwia przeprowadzenie testów także w obszarach wymagających logowania.
Puppeteer & Lighthouse
Innym rozwiązaniem jest skorzystanie z oficjalnie utrzymywanej wersji Lighthouse. Samo Google zaleca to podejście, co jest zrozumiałe, ponieważ Puppeteer, często używany w połączeniu z Lighthouse, również jest rozwijany przez Google.
Web page test
Innym ciekawym i dość popularnym narzędziem jest WebPageTest – umożliwia ono testowanie wydajności strony również z perspektywy użytkownika. W przeciwieństwie do Lighthouse, które wykonuje szybki test i dostarcza kluczowe informacje, WebPageTest oferuje bardziej zaawansowany audyt wydajności.
Jedną z funkcji, której Lighthouse nie posiada, jest możliwość testowania renderowania wideo na stronie. WebPageTest pozwala na dokładniejszą analizę tego procesu.
Dobrym podejściem może być korzystanie z obu narzędzi, np. w ramach sitespeed.io – Lighthouse można uruchamiać regularnie i często, natomiast WebPageTest przy większych zmianach w aplikacji. Ostateczny wybór zależy od charakterystyki projektu i konkretnych potrzeb.
Może Lighthouse – bez Playwrighta?
Oczywiście można korzystać z Lighthouse bez integracji z Playwrightem. Jednak jedną z kluczowych zalet tej integracji jest możliwość łatwego nawigowania do określonej strony internetowej w stanie uwierzytelnionym, co pozwala na przeprowadzenie testów w bardziej realistycznych warunkach.
Wykonanie takiego testu bezpośrednio w Lighthouse byłoby znacznie trudniejsze, ponieważ narzędzie to nie oferuje natywnego wsparcia dla przechodzenia przez proces logowania. Istnieją jednak sposoby na przekazanie autoryzacji lub skorzystanie z narzędzi takich jak Puppeteer czy właśnie Playwright, który znacząco ułatwia ten proces, umożliwiając bardziej elastyczne testowanie aplikacji webowych.
Podsumowanie
W dzisiejszym wpisie przedstawiłem, jak podejść do instalacji Playwrighta, jakie aspekty są kluczowe i na co warto zwrócić uwagę. W przyszłości planuję pokazać, jak w GitHub Actions stworzyć prosty pipeline, który pomoże w wykrywaniu potencjalnych regresji na frontendzie naszej aplikacji.





