Dzisiejszy wpis będzie dotyczył testowania aplikacji w React. Będzie to totalny wstęp i artykuł kieruję głównie do osób, które nie miały w ogóle styczności z testowaniem w React.

Temat ten jest na tyle złożony, że na pewno pojawi się kilka artykułów dotyczących testowania, więc zapraszam do śledzenia bloga.

Motywacją do napisania tego artykułu był fakt, że często w aplikacjach testy po prostu nie występują. Testowanie schodzi na drugi plan ze względu na terminy, wymagania, zmiany w kodzie, brak zasobów itd. Z drugiej strony testy potrafią pomóc i ułatwić znalezienie błędów, które czasami mogłoby pozostać niezauważone przez dłuższy czas…

Pierwszy artykuł będzie wstępem do tego, aby w ogóle zacząć pisać podstawowe testy i z czasem dodawać nowe rodzaje testów do naszej aplikacji. Ma to być pewnego rodzaju inspiracja do tego, że może jednak warto zacząć to robić. Niektóre testy możemy napisać stosunkowo szybko i warto w to zainwestować. Jeżeli zainteresuje Was ten temat, to w internecie jest cała masa różnego rodzaju artykułów na ten temat, ale czasami najtrudniej jest po prostu zacząć. 🙂 Ze swojej strony będę chciał jednak przygotować cykl artykułów, które pozwolą na pisanie mniej lub bardziej zaawansowanych testów.

Powiem też bardzo otwarcie, że nie uważam się za osobę, która posiada ogromną wiedzę w tej dziedzinie, natomiast bazując na obecnych doświadczeniach oraz korzystając z wielu ciekawych źródeł, postaram się przekazać wiedzę jak najlepiej. Standardowo skorzystam z praktycznych przykładów, gdyż tak jak wielokrotnie wspominałem – uważam taką formę nauki za najbardziej skuteczną.

Instalacja, pierwszy test

Skorzystamy z create-react-app (https://github.com/facebook/create-react-app), aby szybko „postawić” nową aplikację React.

npx create-react-app demo_test

Ponieważ startowa aplikacja create-react-app posiada napisany test do komponentu App, to w zasadzie możemy już uruchomić testy poleceniem:

npm test

W wyniku uruchomienia tego polecenia, otrzymamy rezultat:

> npm test

PASS  src/App.test.js
  √ renders learn react link (55 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.425 s
Ran all test suites.

Jak widzimy, został uruchomiony test zlokalizowany w src/App.test.js, został wykonany jeden test, który zakończył się sukcesem, a całość trwała ponad 4 sekundy.

Nazwa pliku i struktura folderów

W tym momencie warto zwrócić uwagę na nazwę pliku App.test.js, dla komponentu App.js.
Jedną z rekomendowanych metod nazewnictwa jest NazwaKomponentu.test.js, która powinna być zlokalizowana w strukturze „obok” testowanego komponentu. Celowo „obok” umieściłem w cudzysłowie, bo podejść może być kilka i zależy to od struktury projektu i jego złożoności.
Więcej na ten temat możemy przeczytać tutaj: https://create-react-app.dev/docs/running-tests/#filename-conventions

Polecam też artykuł pana Robina Wieruch dotyczący struktury folderów https://www.robinwieruch.de/react-folder-structure
Polecam kliknąć CTRL + F (wyszukiwanie tekstu) i wpisanie słowa test

Jeżeli chodzi o i mnie, pracując przy jednym projekcie struktura testów wyglądała następująco…

W folderze posiadamy:

  • komponent Counter.js, a test do komponentu znajduje się w folderze __tests__/Counter.test.js
  • plik utils w folderze /utils/table.js, a test znajduje się w folderze __tests__/utils/table.test.js
  • jakiś inny plik znajdujący się w folderze logic/counter/abcdef/xyz.js, a test znajdujący się w folderze __tests__/logic/counter/abcdef/xyz.js

Oczywiście wskazane jako przykład komponenty jak i inne pliki mogą być położone w innych folderach, natomiast folder __tests__ znajdował się obok wskazanych plików.

Struktura pliku z testami

Przyjrzyjmy się teraz strukturze pliku App.test.js i metodzie test().

test('renders learn react link', () => {
  render(<App />);
  const linkElement = screen.getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});

Pierwszy argument to nazwa testu, drugi zaś, to anonimowa funkcja, uruchamiana podczas testów. Tutaj zwrócę uwagę, aby nazywać testy w taki sposób, aby szybko można było stwierdzić co dany test robi i czego oczekujemy od testu. Nazwa ta będzie wyświetlana również, w przypadku niepowodzenia testu.

Zmieńmy zatem test, aby zwracał błąd, modyfikując linię

const linkElement = screen.getByText(/learn react/i);

na dowolny inny ciąg znaków, który nie występuje w komponencie, np. learn Angular 😉

Ponowne uruchomienie npm test zwróci nam błąd, a nazwa testu zostanie wyświetlona:

> npm test
 FAIL  src/App.test.js
  × renders learn react link (60 ms)

  ● renders learn react link

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        4.702 s
Ran all test suites.

W komunikacie jest też więcej informacji, mianowicie wskazane jest miejsce, w którym test nie wykonał się poprawnie. Nie wklejałem tego do artykułu celowo (za dużo tekstu…), ale wykonując polecenia na własnym komputerze, na pewno zauważycie różnicę. Polecam prześledzić, co wyświetla npm test.

W przypadku metody test(), chcę też wspomnieć o metodzie describe(), która pomaga grupować testy. Na przykład, gdy chcemy przetestować jakąś część komponentu/funkcji i napisać do niej kilka testów, następnie chcemy przetestować inną cześć i tutaj też napisać kilka innych testów możemy pogrupować testy. Tak naprawdę sposób grupowania zależy już od nas…

describe('Check App component for text', () => {
    test('renders learn react link - learn React', () => {
        render(<App />);
        const linkElement = screen.getByText(/learn React/i);
        expect(linkElement).toBeInTheDocument();
    });

    test('renders learn react link - learn Angular', () => {
        render(<App />);
        const linkElement = screen.getByText(/learn Angular/i);
        expect(linkElement).toBeInTheDocument();
    });
});

Teraz npm test da nam wynik:

 FAIL  src/App.test.js
  Check App component for text
    √ renders learn react link - learn React (56 ms)
    × renders learn react link - learn Angular (15 ms)

  ● Check App component for text › renders learn react link - learn Angular

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        6.25 s
Ran all test suites related to changed files.

Podsumowanie

Z artykułu dowiedzieliśmy się jak uruchamiać testy, jak nazywać pliki, jaką strukturę folderów zastosować, dlatego kolejnym krokiem będzie już pisanie pierwszych testów.

Podsumujmy jednak najważniejsze kwestie:

  • npm test uruchamia testy,
  • pamiętajmy o poprawnym nazewnictwie plików np. KomponentNazwa.test.js,
  • pamiętajmy o poprawnej strukturze folderów,
  • nazywajmy testy w odpowiedni sposób, aby nazwa wskazywała co test sprawdza i czego oczekujemy od testu,
  • korzystajmy z grupowania testów.

Jako, że artykuł jest wstępem do testowania (a jak wiadomo wstęp nie może być za długi, bo staje się nudny 🙂 ), to by było tyle na dzisiaj… Zapraszam do następnych artykułów, gdzie na pewno będzie kolejna dawka wiedzy, już bardziej praktycznej. Dzięki!

Źródła:
Obraz: https://unsplash.com/photos/WC6MJ0kRzGw
create-react-app: https://github.com/facebook/create-react-app
nazewnictwo plików: https://create-react-app.dev/docs/running-tests/#filename-conventions
struktura folderów wg. R. Wieruch: https://www.robinwieruch.de/react-folder-structure