Instruction file imported from wojciech-borek/billzilla (
.cursor/rules/vitest-unit-testing.mdc). Copyright stays with the author.
Zasady Testów Jednostkowych: Vitest & React Testing Library
1. Główne Zasady i Filozofia
1.1. Testuj Zachowanie, a Nie Implementację
Skupiaj się na tym, co komponent robi z perspektywy użytkownika, a nie na jego wewnętrznej strukturze. Testy powinny weryfikować funkcjonalność, a nie detale implementacyjne (np. nazwy stanów, metody wewnętrzne).
1.2. Stosuj Wzorzec "Arrange, Act, Assert" (AAA)
Każdy test powinien mieć klarowną i oddzieloną strukturę:
- Arrange: Przygotuj dane, mocki, zrenderuj komponent i ustaw stan początkowy.
- Act: Wykonaj interakcję lub akcję, którą testujesz (np. kliknięcie przycisku).
- Assert: Sprawdź, czy rezultat jest zgodny z oczekiwaniami.
1.3. Dbaj o Izolację Testów
Każdy test (it lub test) musi być w pełni niezależny. Wynik jednego testu nie może wpływać na wynik innego. Używaj beforeEach i afterEach do czyszczenia stanu, mocków i przywracania pierwotnych implementacji.
2. Wytyczne dla VITEST
2.1. Efektywne Użycie Obiektu vi
Używaj odpowiednich narzędzi do tworzenia dublerów testowych:
vi.fn(): Do tworzenia prostych mocków funkcji, gdy nie interesuje Cię oryginalna implementacja.vi.spyOn(): Preferowany wybór, gdy chcesz śledzić wywołania istniejącej funkcji (np. metody obiektu) bez zmiany jej zachowania.vi.stubGlobal(): Do mockowania globalnych obiektów (window,fetch,console).
2.2. Opanowanie Wzorców vi.mock()
- Umiejscowienie: Fabryki mocków (
vi.mock('path', () => ({...}))) umieszczaj na samej górze pliku testowego. Pamiętaj, że są "wynoszone" (hoisted) i wykonują się przed importami. - Dynamiczna Kontrola: Używaj
mockImplementation()lubmockReturnValue()wewnątrzbeforeEachlub bezpośrednio w teście, aby dynamicznie kontrolować zachowanie mocków dla różnych przypadków. - Mockuj Rozsądnie: Mockuj tylko to, co konieczne, przede wszystkim zależności zewnętrzne (np. zapytania sieciowe, biblioteki firm trzecich, moduły poza testowanym zakresem), aby testować logikę w izolacji.
2.3. Czystość Mocków i Stanu
- Czyszczenie Mocków: W pliku
setupTests.tslub w blokuafterEachw testach, używajvi.clearAllMocks()lubvi.restoreAllMocks(), aby zapewnić, że mocki nie przenoszą stanu między testami.vi.clearAllMocks(): Resetuje tylko właściwości.mock(np.calls).vi.restoreAllMocks(): Przywraca oryginalne implementacje funkcji (dlavi.spyOn).
2.4. Pliki Konfiguracyjne (setup)
- Centralna Konfiguracja: Globalne mocki (np.
window.matchMedia), niestandardowe matchery i konfigurację środowiska umieszczaj w dedykowanych plikach ładowanych przez opcjęsetupFileswvitest.config.ts. To utrzymuje testy w czystości i zapewnia spójne środowisko.
2.5. Użycie Snapshotów z Rozwagą
- Snapshoty Inline: Zamiast złożonych asercji obiektów, używaj
expect(value).toMatchInlineSnapshot(), aby wynik był widoczny bezpośrednio w kodzie. - Świadoma Akceptacja: Zmiany w snapshotach traktuj jak zmiany w kodzie – muszą być świadomie akceptowane i sprawdzane podczas code review. Unikaj ich dla komponentów, które często się zmieniają.
2.6. Monitorowanie Pokrycia Kodu (Coverage)
- Cel, nie Fetysz: Ustaw progi pokrycia w
vitest.config.ts, ale traktuj je jako wskaźnik, a nie cel sam w sobie. Skupiaj się na testowaniu krytycznych i złożonych ścieżek aplikacji, a nie na osiągnięciu 100%.
2.7. Efektywny Workflow (Watch & UI Mode)
vitest --watch: Uruchamiaj w trakcie developmentu, aby uzyskać natychmiastowy feedback. Używaj flagi-tdo filtrowania testów i skupienia się na konkretnym fragmencie kodu.vitest --ui: Używaj do wizualnej nawigacji po wynikach, analizy grafu zależności modułów i łatwiejszego debugowania w większych projektach.
2.8. Środowisko Testowe (jsdom vs. Browser Mode)
jsdom: Ustawenvironment: 'jsdom'w konfiguracji dla większości testów komponentów.- Browser Mode: Dla testów wymagających najwyższej pewności (np. skomplikowane interakcje z DOM, API przeglądarki), rozważ użycie trybu
--browser, który uruchamia testy w prawdziwym silniku przeglądarki.
2.9. Struktura i Czytelność Testów
- Grupowanie: Używaj bloków
describedo grupowania powiązanych testów. - Unikaj Zagnieżdżania: Płaska struktura (maksymalnie 1-2 poziomy
describe) jest zazwyczaj bardziej czytelna. - Opisowe Nazwy: Pisz nazwy testów w formie "should [do something] when [in some state/condition]".
2.10. Integracja z TypeScript
- Ścisłe Sprawdzanie Typów: Włącz ścisłe sprawdzanie typów w
tsconfig.jsonrównież dla plików testowych, aby wcześnie wykrywać błędy. - Asercje Typów: Używaj
expectTypeOf()do asercji na poziomie typów, aby upewnić się, że generyczne funkcje i typy działają zgodnie z oczekiwaniami.
3. Wytyczne dla REACT TESTING LIBRARY
3.1. Pisz Testy Zorientowane na Użytkownika
Zamiast szukać elementów po detalach implementacyjnych (np. data-testid), używaj zapytań (queries) w następującej kolejności priorytetów:
- Dostępne dla wszystkich:
getByRole,getByLabelText,getByPlaceholderText,getByText,getByDisplayValue. - Semantyczne:
getByAltText,getByTitle. - Ostateczność:
getByTestId.
3.2. Symuluj Realistyczne Interakcje z user-event
- Preferuj
user-event: Zawsze używaj biblioteki@testing-library/user-eventzamiastfireEvent.user-eventlepiej symuluje rzeczywiste zachowania przeglądarki i interakcje użytkownika (np. wywołuje odpowiednie zdarzenia dlahover,focusczytype).
3.3. Obsługa Kodu Asynchronicznego
async/await: Zawsze używajasync/awaitw funkcjach testowych, które zawierają operacje asynchroniczne.findBy*: Używaj zapytańfindBy*do obsługi elementów, które pojawiają się na ekranie asynchronicznie (np. po załadowaniu danych). Zapytania te automatycznie czekają na pojawienie się elementu.waitFor: UżywajwaitFordo oczekiwania na asercje, które nie są związane z pojawieniem się lub zniknięciem elementu (np. gdy oczekujesz na zmianę atrybutu lub wywołanie mocka).