Środowisko testowe

Jak zaznaczyliśmy w części Co to jest testowanie, testy w JavaScript to zasadniczo kod, który potwierdzamy, że działa prawidłowo, czyli nie powoduje wywołania Error. Jednym ze sposobów na uproszczenie tej definicji jest to, że nie uwzględnia ona miejsca uruchamiania kodu, czyli środowiska testowego.

Środowisko testowe definiuje się ogólnie jako 2 komponenty: środowisko wykonawcze służące do przeprowadzania testu (np. środowisko wykonawcze węzła lub przeglądarka) oraz dostępne dla Ciebie interfejsy API.

Środowisko wykonawcze

Środowisko wykonawcze, np. Node, lub podobne narzędzia, takie jak Deno czy Bun, są przeznaczone do obsługi kodu JavaScriptu po stronie serwera lub ogólnego przeznaczenia. Ich środowiska nie zawierają interfejsów API, których można się spodziewać w przeglądarce, np. tworzenia i pracy z elementami DOM i HTML, ani koncepcji komponentu wizualnego lub celu renderowania (czyli nie tylko elementów, ale renderowania ich za pomocą CSS w widocznym obszarze).

Jeśli spróbujesz np. wyrenderować elementy React na potrzeby testowania, te środowiska wykonawcze ogólnego przeznaczenia przestaną działać, ponieważ nie są dostępne żadne obiekty document ani window.

Z drugiej strony, jeśli przeprowadzasz testy w przeglądarce, wbudowane interfejsy API, których możesz się spodziewać w tych środowiskach wykonawczych, mogą nie być dostępne bez polyfill lub dodatkowej pracy. Częstym przypadkiem jest odczyt i zapisywanie plików. Nie można po prostu import { fs } from 'node:'fs'; w przeglądarce odczytać pliku w ten sposób w ramach testu.

Porównanie tego problemu z interfejsem API „internetowym” i „backendowym” wykracza poza zakres samego testowania, ponieważ posiadanie bazy kodu obejmującej zarówno serwer, jak i klienta może być kłopotliwe, ale wiąże się to z koncepcją pisania testowego kodu, który omówimy ponownie w tym kursie.

Testuj logikę algorytmiczną lub biznesową

Niektóre fragmenty kodu nie wymagają importowania węzłów ani przeglądarki do działania, a więc do testowania. O tym wspomnimy w dalszej części kursu, ale uporządkowanie bazy kodu w taki sposób, aby czysta „logia biznesowa” była oddzielona od renderowania czy kodu powiązanego z węzłami, może ułatwić testowanie.

Możesz np. użyć funkcji węzła, która odczytuje i zapisuje plik z dysku, modyfikując go w trakcie tego procesu. Dzięki refaktoryzacji funkcji w celu akceptowania funkcji, które wykonują odczyt i zapis z dysku, można ją testować wszędzie.

W tym przypadku możesz przetestować ten kod w dowolnym środowisku – w środowisku wykonawczym po stronie serwera lub w przeglądarce. W teście możesz udostępnić pliki pomocnicze, które przechowują plik wirtualny w pamięci lub zwracają dane zastępcze. Tego rodzaju pomocnik warto wprowadzić w teście, ponieważ nie trzeba na przykład sprawdzać, czy fs.writeFileSync działa. Skoncentruj się na kodzie i jego cechach, które sprawiają, że jest on wyjątkowy lub ryzykowny.

Emuluj interfejsy API przeglądarek

Wiele platform testowych, takich jak Vitest, udostępnia opcję emulacji środowiska interfejsu API przeglądarki bez uruchamiania przeglądarki. Vitest wewnętrznie używa biblioteki o nazwie JSDOM. Może to być dobre rozwiązanie w przypadku prostych testów komponentów, które wymagają dużego nakładu pracy związanej z przeglądarką.

Wspólną cechą każdej biblioteki emulacji jest to, że chociaż mogą emulować przeglądarkę (np. DOM, elementy i pliki cookie), nie zawierają komponentu wizualnego. Oznacza to, że zapewnią one możliwość pracy z elementami HTML i innymi elementami podstawowymi, ale nie będzie można renderować wyników na obrazie ani ekranie ani sprawdzić pozycji elementu w pikselach na stronie.

Ten wybór sprawdza się również w przypadku testowania komponentów, gdy komponent reprezentuje element reakcji, komponent internetowy itp. Tego typu komponenty zazwyczaj tworzą DOM i wchodzą z nimi w interakcję w stosunkowo niewielki sposób. Emulowana przeglądarka może zapewniać wystarczającą funkcjonalność, aby potwierdzić, że komponent działa zgodnie z oczekiwaniami. W kolejnej części znajdziesz przykład testowania komponentów React za pomocą Vitest i JSDOM.

Emulowanie przeglądarki to powszechnie używana metoda – skrypt JSDOM został wprowadzony w 2014 roku. Zawsze jednak różni się od używania prawdziwej przeglądarki. Różnice te mogą być oczywiste: na przykład JSDOM nie zawiera mechanizmu układów, więc nie da się sprawdzić rozmiaru elementu ani przetestować złożonego gestu, takiego jak przesunięcie palcem. Różnice mogą też być subtelne i nieznane, dlatego najlepiej jest zadbać o zwięzłość testów opartych na JSDOM. Dzięki temu ryzyko odbiega od rzeczywistego działania.

Steruj prawdziwą przeglądarką

Jeśli chcesz przetestować kod w sposób, jaki zobaczą użytkownicy, najlepszym rozwiązaniem jest użycie prawdziwej przeglądarki. W praktyce testowanie środowisk wykonawczych obsługujących przeglądarkę uruchamiają i kontrolują instancje prawdziwej przeglądarki, nawet jeśli uruchamiają się w środowisku Node.js.

Kontrola przeglądarki w ramach testu sprawia, że otwiera się ona tak samo jak u użytkownika. Dzięki temu można kontrolować ją za pomocą ładowania adresów URL, niestandardowego kodu HTML i JS lub innych elementów potrzebnych do przeprowadzenia testu. Następnie możesz napisać kod, który będzie działać jako użytkownik, np. sterując myszą lub wpisując dane w polach do wprowadzania danych.

Nowoczesne narzędzia, takie jak WebdriverIO czy Web TestRunner, pozwalają sterować wszystkimi popularnymi przeglądarkami, a nawet uruchamiać wiele instancji jednocześnie. Te przeglądarki mogą działać w sąsiedztwie mechanizmu uruchamiania testów (np. na Twoim komputerze lub w ramach działania CI) albo zostać zlecone zewnętrznym usługom, które będą je uruchamiać za Ciebie.

Bardziej znane biblioteki testowe (w tym Vitest i Jest) często mają tryb przeglądarki, ale ponieważ ich źródło pochodzi z Node.js, tryby przeglądarki są często „przyłączone” i brakuje w nich przydatnych funkcji. Vitest nie może na przykład imitować importów modułów w przeglądarce, co jest zaawansowanym narzędziem podstawowym, którego używamy w przykładzie na następnej stronie.

W praktyce

Testy stają się coraz bardziej złożone, dlatego coraz ważniejsze staje się używanie prawdziwej przeglądarki.

  • W przypadku testów, w których nie wykorzystuje się żadnych funkcji DOM lub ich nie ma, nawet funkcje dostępne w Node.js i podobnych środowiskach wykonawczych, takich jak fetch czy EventTarget, nie ma znaczenia.
  • W przypadku testów z małymi komponentami odpowiednim rozwiązaniem może być JSDOM.
  • Większe testy, na przykład kompleksowe testy, które mogą symulować logowanie użytkownika i wykonywanie podstawowych działań, warto przeprowadzić w całości w prawdziwej przeglądarce.

W tej sekcji skupiamy się na teorii i przedstawiamy różne punkty widzenia dotyczące testów. W praktyce w Twojej bazie kodu stosowane są często różne podejścia do różnych typów testów w zależności od Twoich potrzeb i zapewnienia narzędzi do testowania.

Sprawdź swoją wiedzę

Które funkcje przeglądarki *nie* obsługuje warstwa emulacji jsdom?

Mechanizm układu.
Ponieważ JSDOM nie jest narzędziem wizualnym, nie można go używać do sprawdzania pozycji elementu na stronie, rozpoznanych atrybutów CSS ani żadnych innych części układu witryny.
WebSocket
Biblioteka JSDOM zawiera kod polyfill WebSocket, więc korzystający z niego kod będzie działać.
requestAnimationFrame
Dzięki flagie „pretendToBeVisual” jsdom wywołuje wywołanie zwrotne „animation” z szybkością 60 kl./s, mimo że w rzeczywistości nic nie jest narysowane.