typescript and javascript logo
author avatar

Grzegorz Dubiel

25-06-2025

(Nie tylko) Testowanie React'owych komponentów UI przy użyciu Vitest i Storybook

W moim poprzednim artykule skupiłem się na tworzeniu reużywalnych komponentów UI w React. Ten wpis jest kontynuacją tematu — tym razem z naciskiem na testowanie.

Mam przyjemność pracować przy rozwijaniu aplikacji webowych zarówno po stronie serwera, jak i klienta. Często powtarzam, że frontend bywa znacznie bardziej nieprzewidywalny niż backend, a kod bardzo łatwo może wymknąć się spod kontroli. Aby ograniczyć liczbę problemów, warto odpowiednio testować nasz kod odpowiedzialny za UI. W tym artykule pokażę, jak robić to dobrze.

Testy jednostkowe

Mówiąc o testowaniu, dobrze jest zacząć od testów jednostkowych jako krótkiej rozgrzewki. Idea jest prosta — test jednostkowy powinien być wykonywany na najmniejszym możliwym fragmencie logiki, takim jak pojedyńcza funkcja.

Użyjemy vitest jako test runnera testy oraz @testing-library/react, aby mieć dostęp do API Reacta w testach.

Zanim zaczniemy, stwórzmy dwa małe moduły z utilisami, które będziemy używać w naszych testach.

typescript

Teraz możemy przejść dalej i do tworzenia testów.

Pamiętasz komponent Button z poprzedniego artykułu, gdzie rozpoczęła się nasza podróż?

JSX

W komponencie Button używamy wzorca asChild. Warto przetestować to zachowanie, ponieważ określa, jak użytkownik używa naszego przycisku. Weźmy pod uwagę sytuację, gdy chcemy, aby pole do przesyłania plików wyglądało jak nasz Button.

Podstawowy test jednostkowy dla tego przypadku może wygladać tak:

JSX

Testy integracyjne

Proste komponenty, takie jak nasz Button, zwykle nie mają wielu przypadków użycia, które warto testować poprzez testami jednostkowymi. Oczywiste jest, że większość interakcji użytkownika zachodzi na wielu współpracujących ze sobą komponentach, i właśnie tutaj przydają się testy integracyjne. Takie podejście, zamiast skupiać się na najmniejszych częściach aplikacji, koncentruje się na integracji wielu komponentów.

Przegląd testowanego komponetu

Weźmy jako przykład komponent listy. Każdy element listy ma dwa przyciski: jeden do dodawania, drugi do usuwania. Jeśli na liście nie ma żadnych elementów, wyświetlana jest informacja o pustym stanie.

JSX

Komponent ListItem korzysta z reużywalnych komponentów, takich jak Button i AlertDialog. W naszym przykładzie omówimy tylko akcję usuwania, aby skupić się na testowaniu interakcji użytkownika komponentami.

Zachowanie jest dobrze znane: użytkownik klika przycisk usuwania, pojawia się okno dialogowe z dodatkowym komunikatem i dwoma opcjami w formie przycisków.

JSX

Logika usuwania i zarządzania stanem jest obsługiwana przez komponent ListExample.

JSX

Gdy użytkownik kliknie przycisk usuwania przy danym elemencie, pojawia się okno dialogowe z ostrzeżeniem. Użytkownik może anulować akcję usunięcia lub ją potwierdzić. Jeśli potwierdzi, element zostanie usunięty z listy. Jeśli lista stanie się pusta, zostanie wyrenderowany komponent EmptyState.

Pisanie testów

Mając zdefiniowane komponenty, możemy napisać testy. Przetestujemy kilka scenariuszy użytkownika:

  • potwierdzenie usunięcia elementu
  • anulowanie akcji usunięcia elementu
  • wyświetlenie informacji o pustym stanie po usunięciu ostatniego elementu

JSX

Jak widzimy, każdy komponent pełni swoją rolę i przyczynia się do całościowego doświadczenia w ListExample. Testowanie w jaki sposób te komponenty współpracują ze sobą jest cenne, ponieważ pozwala nam testować rzeczywiste scenariusze działań użytkownika.

A co jeśli chcemy zobaczyć interakcje na ekranie bez uruchamiania całej aplikacji lub jeśli tworzymy design system całkowicie niezależny od jakiejkolwiek aplikacji? Tutaj z pomocą przychodzi Storybook.

Storybook

Podczas tworzenia front-endu testy, których wyniki wyświetlane są tylko w terminalu, często nie wystarczają. Interfejsy użytkownika to to, co użytkownicy widzą i z czym wchodzą w interakcję. Komponenty często nie tylko zachowują się inaczej, ale też wyglądają inaczej, gdy otrzymują różne propsy lub znajdują się w obrębie różnych layout'ów. Dobrze jest mieć je odizolowane i móc łatwo zmieniać ich input.

Storybook to narzędzie, które pozwala deweloperom tworzyć komponenty UI w izolacji. Jego funkcje ułatwiają proces tworzenia, od projektowania i debugowania po testy manualne i automatyczne.

Skupmy się na kilku funkcjach Storybooka, które mogą usprawnić proces testowania i tworzenia interfejsów użytkownika.

Stories & Docs

Stories to doskonała rzecz do dokumentowania komponentów i testowania ich manualnie w izolacji. Pozwalają nam sprawdzić doświadczenie użytkownika poprzez interakcję z komponentami tak, jak robią to użytkownicy. Stories służą również do definiowania, w jakich warunkach komponent jest renderowany, co ułatwia stworzenie galerii tego samego komponentu w różnych scenariuszach.

Napiszmy Docsy dla naszego komponentu Button:

JSX

Jedną z rzeczy, którą powinniśmy zrobić, to udokumentowanie naszego komponentu. W erze asystentów programowania opartych na edytorach AI, takich jak GitHub Copilot, Cursor i inne, dodanie dokumentacji jest obligatoryjne. Można wygenerować dokumentację i szybko ją przejrzeć. Będzie to szczególnie pomocne dla zespołu, na wypadek gdy komponent jest skomplikowany.

API Docs'ów Storybooka jest intuicyjne i łatwe do zrozumienia.

Rezultat powyższego kodu wygląda całkiem nieźle:

Wizualna reprezentacja docs

Możemy wizualnie przejrzeć nasz komponent, wchodzić z nim w interakcję oraz dynamicznie zmieniać jego właściwości (propsy) za pomocą kontrolek. Wszelkie zmiany komponentu są natychmiast widoczne w preview.

Ok, mamy już Docs — teraz zdefiniujmy Stories dla naszego komponentu:

JSX

Stories to obiekty, które opisują wygląd i zachowanie naszego komponentu. Zdefiniowanie Story jest jak wywołanie komponentu z określonymi właściwościami (propsami). Jest to bardzo przydatne, szczególnie w przypadku naszego komponentu Button, do sprawdzenia, wyglądu i działania przy użyciu wzorca asChild.

Każde wyeksportowane Story będzie dostępne w zakładce Docs w sekcji „Stories” pod główną sekcją komponentu:

Sekcja stories

Aby wchodzić w interakcję z każdym z osobna, musimy przejść do dedykowanego widoku dostępnego w nawigacji.

Wybierzmy "Upload" story naszego komponentu Button:

Upload story dla komponentu button

Praca ze Stories pomaga developerom wychwycić wiele błędów na wczesnym etapie. Podobnie jak z TypeScript — pomaga on wykryć problemy jeszcze zanim uruchomimy kod aplikacji.

Let's play! Pobawmy się w automatczyne testy w Storybooku

Nie ma wątpliwości, że Stories to potężne narzędzie, ale aby uzupełnić proces testowania, potrzebujemy automatyzacji. Storybook daje nam możliwość pisania testów automatycznych. Jest to możliwe dzięki funkcji play, którą możemy zdefiniować w naszych Stories.

Przejdźmy do naszego komponentu ListExample i napiszmy dla niego testy.

JSX

Jak widać, niektóre patterny i składnia testów są podobne do tych, które już znamy. Testy są również zawarte częścia Stories.

Powyżej zdefiniowane Stories to wielokrotnego użytku kroki, które odzwierciedlają proces testowania. Te pierwsze trzy Stories nie są celowo eksportowane, ponieważ nie chcemy, aby pojawiały się w nawigacji — służą one wyłącznie jako wielokrotnego użytku, kompozycyjne elementy do poniższych testów integracyjnych:

JSX

Tutaj definiujemy nasze testy interakcji, które zapewniają, że komponent działa zgodnie z oczekiwaniami. Użyta składnia i wzorce są dobrze znane, więc każdy programista może szybko zacząć pisać testy w Stories Storybooka. Dodatkowo labels przekazywane do funkcji step sprawiają, że kod jest zrozumiały i samoopisujący się. Łatwo możemy wywnioskować, które kroki będą testowane, a także zobaczyć, jak komponenty zachowują się na żywo.

Na dole podglądu znajduje się zakładka "Interactions", która pozwala nam przechodzić ręcznie przez każdy zdefiniowany test lub odtworzyć wzystkie od początku.

Interfejs interakcji

Możemy wchodzić w interakcję z tą listą, przechodząc do konkretnego kroku. Stan komponentu będzie również wizualnie odzwierciedlony w podglądzie.

Klikanie w konkretną interakcję

Testowanie accessibility

Dostępność jest bardzo ważna podczas tworzenia interfejsów użytkownika, dlatego testowanie jej jest równie istotne. Storybook udostępnia narzędzie, które automatycznie skanuje nasze komponenty i wyświetla wyniki tych testów poniżej podglądu komponentu:

Testy accessibility - pozytywne rezultaty

Testy accessibility - wykryte problemy

Jak widać, dla naszego przycisku Button użytego jako kontrolka do przesyłania plików, niektóre testy zakończyły się pomyślnie, ale wykryto także pewne błędy.

Taka funkcjonalnośc może być świetnym punktem wyjścia do bardziej szczegółowych testów accessibility.

Sharing

Dzięki Storybookowi możemy udostępniać nasz design system. Dzielenie się postępami prac jest bardzo ważne dla osób decyzyjnych oraz biznesu. W rozmowach o wymaganiach biznesowych kluczowe są jasne przykłady i widoczne rezultaty — pozwala to uniknąć nieporozumień, co przyspiesza i usprawnia iteracje.

Storybook oferuje solidne możliwości udostępniania, takie jak budowanie i publikowanie jako statyczna aplikacja webowa lub integracja z Figmą.

Podsumowanie

Jak widać, testowanie i budowanie z użyciem odpowiednich narzędzi może zaoszczędzić nam wiele czasu. Co więcej, wyobraźmy sobie tworzenie desing systemu z pomocą agentów AI a następnie testowanie ich w Storybooku - prawda że to potężne combo? Przy właściwie skonfigurowanym środowisku testowym możemy skupić się na rozwiązywaniu rzeczywistych problemów biznesowych bez spędzania przesadnie długiego czasu na naprawianiu bledów. Jednak pamiętajmy, że Storybook nie zawsze jest najlepszym wyborem. Czasami korzystanie z niego w mniejszych projektach może być wytoczeniem armaty na muchę — podobnie jak w przypadku testów jednostkowych czy integracyjnych. Gdy aplikacja jest mała lub jest to statyczna strona, często szybsze i równie bezpieczne jest testowanie ręczne lub same testy end-to-end.

Planując ten artykuł, miałem szczęście znaleźć świetny odcinek podcastu Syntax z jednym z członków zespołu Storybook. Jeśli chcesz poznać Storybook z perspektywy jego zespołu, zdecydowanie warto posłuchać.

PS: Syntax jest moim ulubionym podcastem ze świata web developmentu.

Dzięki za prześledzene tematu ze mną! Stay tuned!

PS: Jeżeli chcesz pobawić się kodem z tego artykułu, odwiedź to repozytorium na GitHub'ie.

typescript and javascript logogreg@aboutjs.dev

©Grzegorz Dubiel | 2026