w Praktyce
3 godz. 17 min · ReactJS · Full-stack i Programowanie
Przemysław NowakSoftware EngineerJeżeli masz już doświadczenie w tworzeniu aplikacji komunikujących się z backendem to z pewnością wiesz czym jest ból niespójnego API oraz wielu sposobów wykonywania requestu po dane. Apollo rozwiązuje ten problem udostępniając jedno proste API do obsługi komunikacji z serwerem GraphQL. Nie musisz się martwić o to jak otworzyć kanał WebSocket dla subskrypcji czy o to jak napisać poprawny Query Document - to wszystko i jeszcze więcej dostarcza dla nas Apollo Client.
Apollo 3 posiada niesamowity mechanizm cache, który pozwala zaoszczędzić czas na wykonywanie zapytań oraz setup bibliotek do przechowywania stanu serwera. Wszystkie request trafiają do warstwy pamięci podręcznej, którą zarządza dla nas Apollo - wybiera, dodaje oraz łączy odpowiednie podzbiory tak aby jak najmniej komunikować się z serwerem, a mimo to wiedzieć jaki jest jego stan. Dodatkową cechą mechanizmu Cache jest to, że może być łatwo użyty jako stan lokalny - bez potrzeby instalowania bibliotek takich jak Redux, jesteśmy w stanie stworzyć aplikację stateful w niesamowitym tempie!
Być może spotkałeś się już kiedyś z problemem Unit Testów, które działają - są na "zielono" ale mimo wszystko aplikacji jest zepsuta - to przykład źle napisanych jednostek. Komunikacja z serwerem i odbieranie danych to kluczowy element każdej aplikacji - dlatego ważne jest aby stworzyć poprawne unit testy, które będą nas chronić przed zepsutą aplikacją na produkcji. W kursie tym poznasz poprawny sposób na testowanie klienta Apollo, tak aby testy były stabilne i spełniały swoją rolę.
Z pewnością wyobrażasz sobie magiczne aplikację, które działają szybko bez potrzeby czekania na odpowiedzi z serwera oraz posiadające poprawne dane. Skoro tak, wiesz również, że stworzenie takich aplikacji wymaga wiele pracy, dodatkowych bibliotek oraz rozpisania każdego przypadku, tak aby wiedzieć kiedy dane są poprawne a kiedy trzeba zapytać serwer o nie jeszcze raz... A co jeżeli Ci powiem, że Apollo zrobi to za nas? Podejście Cache-First, o które oparta jest biblioteka klienta apollo dostarcza nam te wszystkie w/w cechy, a kurs ten pokaże Ci jak sprawnie posługiwać się tymi narzędziami.
Apollo to poważny gracz w wielu stackach technologicznych. Jeżeli firma decyduje się używać GraphQL - który jest coraz bardziej popularny - to przeważnie w parze idzie Apollo. Dlatego w wielu ofertach pracy możesz spotkać tą technologię jako wymaganą. Zresztą, nie bez przyczyny, Apollo pozwala na sprawne, spójne oraz szybkie budowanie aplikacji czy to z Reactem, czy to z Angularem, Vue, Svelte oraz z Androidem czy iOS - mając jeden wspólny interfejs pracy, firmy są wstanie tworzyć aplikację w różnych technologiach komunikujących się z warstwą Apollo w jeden określony sposób.
Kurs ten jest stworzony z myślą o FrontEnd developerach znających ReactJS oraz podstawy GraphQL, którzy chcą dodać do swojego arsenału technologicznego poważną broń jaką jest Apollo.
Cześć tej lekcji.
Chciałbym żebyśmy przeszli przez testowanie i chciałbym Ci pokazać jakie są
dobre pattern jeżeli chodzi o testowanie query w Apollo.
W następnej lekcji pokażę Ci jak testować mutacje, natomiast generalnie sam pattern
będzie ten sam, czyli podobnie jak z query jest zmniejszenie strat.
Jeżeli nauczysz się jak jest z query
to już będziesz wiedział jak działać z kolejnymi łukami.
Natomiast chciałbym Ci pokazać na początek
test case, który jest często tworzony żeby przetestować Apollo Clienta.
Natomiast jest to według mnie i chciałbym Ci pokazać dlaczego.
Więc to co teraz widzisz na ekranie to jest plik index.
Ja dodałem tu taki jeden test dla naszego
dla naszej listy produktów i ja tutaj zdefiniowałem test, który
działa, zwraca nam dane i sprawdzamy czy na przykład w naszym dokumencie pojawiły
się jakieś konkretne dane, które dostalibyśmy z query.
Generalnie zasadą taką jeżeli chodzi o testowanie jest to, żebyśmy
nie wywołali prawdziwych kolei do API z różnych przyczyn.
Przede wszystkim nigdy nie wiemy, jak długo będziemy czekać na taki call.
Druga sprawa takie API act są niepożądane.
Nie ma sensu, żeby nasz zjazd również pytał o to.
No i trzecia sprawa często są blokowane po prostu, więc taki test się nie udał
w jakimś takim środowisku, ponieważ był uznany za bota,
więc musimy tworzyć nowe wartości, ponieważ chcemy przetestować nasz kod.
Chcemy stworzyć jakąś nową wartość dla tego, co zwraca nam już Query.
Jeżeli wejdziemy jeszcze raz index.
Jest to tutaj.
Mamy właśnie tą naszą funkcję z query i ta funkcja jest pobierana z Apollo Client
i często zdarza się, że ludzie mocują cały Apollo Client i tworzą implementacje dla
Just Query, żeby zmontować to co ta funkcja może zwrócić.
I to jest poniekąd ok, ponieważ
tak naprawdę third party nie mocujemy swojego kodu, więc poniekąd jest ok.
Ale za chwilę Ci pokażę dlaczego
to nie zadziała i pokażę Ci sytuację, gdzie mamy testy na zielono.
Nasza aplikacja w rzeczywistości nie nie
działa, więc wejdźmy sobie tutaj do index PGS.
Chciałbym Ci na początek pokazać co tutaj mamy.
Generalnie jest to klient jak.
A więc testy opierają się o Testing
Library i tutaj jest zaimportowany render oraz wait for.
Za chwilę Ci tutaj wytłumaczę o co tutaj chodzi i jest tutaj smakowania klient.
Do tego mocka jeszcze wrócimy.
Również mamy tutaj zaimportowany nasz produkt page
i tutaj renderuje my właśnie w naszym teście ten produkt page.
Oczywiście musieliśmy jeszcze użyć tutaj Memory Router, ponieważ używamy funkcji
Link na naszej stronie, więc musieliśmy również użyć tego routera,
żeby zamocować taki router dla naszego testu.
No i generujemy nasz komponent izolacji i
chcemy sprawdzić tutaj Wait for używamy dlatego, że ten status się zmienia
zwracane przez query, więc na początku jest to and i potem jest to dodane.
Dlatego używamy wait for i w tym wait for wykonujemy asercji.
Czy taki tekst Hello world i kategorii 1 jest w dokumencie?
A taki tekst powinien być, ponieważ tutaj właśnie w tym demie
jako name naszego items zwracamy właśnie Hello World i jako kategorii
Name zwracamy kategorię 1, więc chcielibyśmy to sprawdzić.
Oczywiście asercji możemy wykonać tutaj więcej, żeby sprawdzić pracę.
Możemy też poszukać sprawdzić jak działa.
Natomiast nie chciałem tutaj zbyt dużego testu tworzyć tylko jakiś mały
test, żeby pokazać Ci jak prawidłowo testować klienta i te wszystkie query.
Więc to co tutaj widzisz to jest dokładnie taki malutki teścik,
który ma sprawdzić te dwa elementy i mamy tutaj mocka
i zmarnowaliśmy cały moduł Apollo Client i dlatego właśnie musiałem również tutaj na
przykład zmapować taga, dlatego, że kiedy blokujemy cały
Apollo klienta to tutaj otworzę ten indeks.
To w naszym indeksie ten tag również jest
używany, więc on musi mieć jakąś implementację.
To nie jest ważne co on tutaj robi, ponieważ nas komponent jakby po prostu
wykona tą funkcję czy ma argumenty czy nie.
Nie ma to znaczenia dlatego, że jak widzisz ten US Query również nie przyjmuje
u nas żadnych argumentów, więc to jest jakby nasza implementacja z query
i to jest dosyć słabe z tego względu, że my zawsze mówimy, że dostaniemy.
Jeżeli wykonamy jest query, zawsze
dostaniemy takie dane i nasz test będzie na zielono.
Teraz w tym przypadku możemy odpalić sobie
ten test i zobaczyć, że on rzeczywiście przechodzi, że wszystko jest ok.
OK, to jest fakt.
Patrzmy co jest nie tak.
Tak jak mówiłem jakąś zmianę zrobić.
Natomiast to, co jesteś w stanie zauważyć, to to, że ten test faktycznie przechodzi.
Więc.
Więc mamy ten test, on przechodzi.
Wszystko jest w porządku.
I teraz jeżeli
sobie zerkniemy, co tutaj dostajemy, to my będziemy mieć zawsze te dane.
Ale jeżeli teraz wejdziemy sobie w nasz
indeks, to jest nie może sobie pozwolę tutaj otworzyć.
I ja teraz na przykład wyrzucę ten page.
I my wiemy, że jeżeli ja wyrzucę tam z
Variable, to to nasze query nie będzie działać.
Ale nasz test przechodzi.
I to jest problem, ponieważ to query wiemy, że nie będzie działać.
Wiemy, że musimy mieć tutaj page podany
lub musimy mieć jakiś PR page, ponieważ inaczej dostaniemy inne dane.
I wiemy, że te nasze query w rzeczywistości nie zadziała.
A tutaj działa.
I to jest sytuacja, kiedy nasz kod
rzeczywiście jest zepsuty, a testy nam tego nie wyłapali.
I to jest przykład złego unit testu.
I właśnie takich testów mieć nie powinniśmy.
Więc Apollo przychodzi tutaj z innym pomysłem.
Jeszcze, żeby Ci pokazać na czym to
testowanie je, bo pewnie się z tym spotkasz.
Polega to polega na mocowaniu funkcji i
teraz, gdybyśmy chcieli jeszcze zmontować kolejne stany jak
loading error, żeby jeszcze sprawdzić, czy odpowiednie ekrany się
tutaj jeszcze wyświetlają, to zrobimy już prawidłowym testowaniu.
Natomiast w tej metodologii, tej złej metodologii, którą chcę Ci teraz tutaj
zaprezentować, robilibyśmy po prostu tutaj gest FN, czyli blokowali byśmy te
query i byśmy tutaj implementation, więc robili za każdym razem i zwracali inne
dane, czyli raz by to była data, a raz loading raz error.
I byśmy tutaj po prostu robili asercji dla każdego takiego stanu.
Czy taki stan się wyświetlił z nowymi mocami?
Natomiast to jest test słaby i przed chwilą Ci pokazałem dlaczego jest słaby.
Aplikacja jest zepsuta, test jest na zielono.
I teraz to przychodzi nam z pomocą.
Przychodzi nam z pomocą Apollo, więc jeżeli sobie zerkniemy na dokumentację
to mamy tutaj całą stronę jak testować komponenty jak i całe.
Testowanie komponentów obiektowych Apollo opiera się o providera.
Moc Provider dostarcza nam wszystko.
My nie musimy renderować Apollo providera, my po prostu sobie wygenerujemy mock
providera i w tym moc providera dostarczymy mocy.
I teraz tłumoki, które dostarczamy mają dwie części.
Jedna część to jest request.
A druga część to jest reset.
Czyli ja w moim teście jestem w stanie napisać, że dla mojego requestów z takimi
dokładnie zmiennymi chcę dostać taki rezultat.
I to jest ważne, ponieważ raz, że wrzucam tutaj query
i dwa, że wrzucam tutaj variable, to tylko dla takiego query variable
dostanę taki rezultat i tylko w taki sposób będę w stanie ten rezultat uzyskać.
Co mam na myśli?
Mam na myśli, że jeżeli ja tutaj mówię, że taki request dokładnie musi się wykonać i
takie zmienne, to mój komponent rzeczywisty
również będzie wykonywał taki request i takie zmienne.
Więc jeżeli ja w rzeczywistym komponencie
zmiany zmienię te zmienne, a w moim teście, czyli tutaj w tym moim oku
ta zmienna zostanie, no to wtedy nie dostanę już tego rezultatu
i wtedy test się po prostu nie wykona, będzie na czerwono.
Więc to jest to, co Ci chcę za chwilę zaprezentować, więc po prostu sobie
przypiszemy ten test na tą prawidłową wersję.
Więc przejdźmy do indeksu.
Jest.
I to co zwracamy w zasadzie możemy sobie
zabrać, bo to będzie jednak troszkę przydatne.
Więc może weźmy sobie tego biura. Jest.
Kopiujemy.
Wiecie coś skopiowałam?
Numer kopiemy to data z numerem i wyrzućmy tego moda.
Teraz nie będzie to działało.
Ja sobie tutaj jedynie otworzę komentarz
i wrzucę sobie tego mocka, żeby go nie zgubić.
Natomiast my będziemy chcieli takie dane zwracać.
I teraz jeżeli wrócimy tutaj już mamy błędy, że nie jesteśmy w
stanie znaleźć pewnych elementów, że wykonują się,
że nie mamy klienta w kontekście, czyli cały nasz tekst falował.
Więc wracając tutaj, co musimy zrobić?
Musimy stworzyć sobie emotki i musimy do
tych kroków tutaj do naszego testu dodać providera.
I to jest taki przykład jak to wygląda.
Więc tutaj również jest taki przykład.
Więc musimy sobie zaimportować providera
Capello Client Testing i to właśnie zrobimy.
Ja na razie wyłączę jeszcze te testy i importujemy sobie tutaj match providera
i teraz tego mock providera będziemy chcieli sobie tutaj również wyrenderować.
To jest tak naprawdę taki context.
Więc tak mock provider.
I tutaj będzie również Raider.
Zamykamy go i tutaj będziemy dodawać sobie mocy.
Tę moc będziemy chcieli sobie tutaj zdefiniować.
A więc wejdźmy.
Tutaj skupiłem sobie na przykład, jak te marki mogą wyglądać.
Czyli to jest taki przykładowy mock.
Wróćmy sobie tu i stworzymy sobie max.
I wrzućmy sobie tego mocka.
I teraz tak.
Request wykonujemy.
To jest nasz request.
W tym miejscu, czyli gier
i wariantów Steve'a Diablo, możemy sobie w zasadzie skopiować.
I my będziemy chcieli je tutaj dodać.
Więc to jest stres.
I tutaj pragnę powiedzieć, że zawsze sobie patrzę i patrzę, że to będzie 8 po prostu.
I teraz my takiego query nie mamy.
Natomiast mamy query get produkt.
I my będziemy chcieli tutaj zaimportować.
A więc zrobimy sobie import produkcję ram indeksu.
W zasadzie możemy tutaj to połączyć, bo już mamy product page.
OK, tak będzie lepiej.
I teraz tutaj będziemy chcieli dla takiego query dostać konkretnie jakieś rezultaty.
I my te rezultaty mamy tutaj już zapisane,
więc może sobie teraz kopiujemy tylko formatowanie.
Dobra data wr.
Wątku skupimy to.
I tutaj dodajemy sobie to w tym miejscu.
Tutaj też formatowanie, czyli ten kursor strasznie dobra.
I tutaj mamy już to też poprawione.
I mamy tutaj jasną informację jeżeli ktoś
wykona w mojej aplikacji taki request, to dodaje mi takie rezultaty.
Na tej zasadzie działają te.
Okej, więc ja tutaj w aplikacji takie
request wykonuję i tutaj dostanę dla takiego request to ok, fajnie.
Więc teraz wejdźmy sobie tutaj emocje, przekażmy je w tym miejscu, dobra?
I zobaczmy teraz, czy wszystko już jest w porządku.
NPM test.
Testujemy nasz indeks i mamy.
Zobaczymy co jest nie tak.
Ja spędziłem chwilkę żeby zobaczyć co jest nie tak i problemem był cash.
Więc teraz już jest ok i po prostu nie
zauważył, że ten provider jest importowany z tego miejsca i przez to
nie traktowała providera jako dostarczyciela kontekstu.
A więc teraz odpaliłem ten test jeszcze
raz wykonując npm test i mamy wszystko w porządku.
A więc test przechodzi i to działa najfajniej.
Teraz Mock Provider jest o tyle
fajniejszy, że jeżeli zerkniemy jeszcze raz do dokumentacji, to tutaj mamy
informacje jak testować odpowiednie staty, jak testować Laughing State State.
Tak, test State jest po prostu właśnie ten stan, który my przetestowaliśmy w tym
momencie, czyli my poczekaliśmy na to, aż dostaniemy już te dane, ponieważ składnia
na początku zwróci nam stan ładowania, dopiero przy drugim
przeładowaniu dostaniemy nasze dane i ten zakres przetestowaliśmy,
ale nie przetestowaliśmy jeszcze stanu ładowania,
przy czym nam stan ładowania będzie bardzo prosty do przetestowania, dlatego, że
będziemy chcieli sprawdzić po prostu czy ten loader nam się wyświetla.
Jak to możemy zrobić?
Zobaczmy w indeksie, że tutaj ten komponent loader.
Mamy tutaj własny komponent loader.
I teraz jeżeli zerkniemy na ten komponent
na folder components tutaj launcher to tutaj ten loader.
Ja dodałem tutaj Data to jest loader, więc
za pomocą tego data test będziemy mogli sobie znaleźć ten loader.
To jest również
identyfikator dla jak Testing Library jeżeli nie jesteś z tym zaznajomiony.
Natomiast działa to mniej więcej tak, że
tutaj kolejną funkcją pomocniczą test możemy wybrać sobie taki loader i tutaj
możemy zrobić sobie jedną serię, czyli zanim tutaj będzie to drugie przeładowanie
powinniśmy mieć loader na true, czyli ten test i tutaj weźmiemy sobie loader.
Musimy to zwrócić to PBI inny dokument
i zobaczmy czy test teraz będzie przechodził.
Poczekajmy chwilę OK i test przeszedł.
Natomiast tutaj teraz już
powinniśmy mieć node, ponieważ tutaj już nie powinien być w dokumencie.
Czyli tutaj jest ten drugi stan aplikacji po zmianie i wtedy jest tutaj not ok.
Zobaczmy co jest nie tak.
OK. Tak, zgadza się.
Najlepiej działa jeszcze w taki sposób,
że jeżeli on nie znajdzie niczego, to znaczy, że test się nie powiódł.
Więc tutaj tak naprawdę powinniśmy zrobić
query test i wtedy to query test będzie działał poprawnie.
I tak rzeczywiście jest.
Jak widzisz testy przeszły, a więc w porządku.
Działa to ok.
Tak jak mówię, gesty działają tak, że one od razu robią asercji jQuery.
Jeżeli nic nie zwróci, to nie, to nie zepsuje nam testu.
Ale, ale, ale, ale wtedy musimy robić to, co jest w dokumencie, czego nie ma.
Ja zawsze lubię robić całe serce.
Jest to takie dla mnie explicite.
Natomiast jak uważasz, można by było też zostawić tutaj też w zasadzie tylko tak,
bo te testy robią te serca i wtedy nie robić z niego eksperta.
Ale to już jest szczegół testów, a nie testowania Maków.
I teraz kolejny test jakie możemy zrobić to przetestować error.
Tak, i tutaj również mamy taką informację jak taki error state możemy przetestować.
A więc zobaczmy sobie tutaj jest dokładnie to samo.
Czyli dla tego requestów zwróć mi error i my dokładnie to samo zrobimy tutaj.
Wtedy byśmy chcieli wyświetlić nasz error
czyli nasz stan error w aplikacji i ten stan mamy.
Właśnie tutaj jest ten komponent result i
taki stan się tutaj wyświetla, więc możemy np.
oszukać czy mamy przycisk return, więc możemy tak to zrobić.
Lecimy sobie tutaj, stworzymy sobie nowego i tak więc kopiujemy sobie to wszystko
i tutaj stworzymy sobie render errors, tak?
Czyli to będzie nasz drugi test i naszym okiem tutaj już nie dostaniemy result,
tylko będziemy chcieli dostać w tym miejscu error.
To będzie new error.
Tutaj co chcemy dobrze chcemy zrobić i to już jest nasza sprawa.
Teoretycznie to jest tak tylko dla testów.
Gdybyśmy wyświetlały jakieś archiwum to wtedy miałoby tutaj sens.
Widać coś konkretnego.
My nie wyświetlamy, ponieważ my
wyświetlamy jakiś konkretny, konkretny element.
I teraz tak. Tutaj mamy również ten test.
Mógłby działać w ten sposób, ale już nam
logger przetestowaliśmy, więc nie ma to sensu.
I znowu na Outside będziemy szukać jakiegoś tekstu.
Ja bym poszukał tutaj po prostu texture Tutaj zawsze można też dodać tam
identyfikatory czy czy poszukać, czy tutaj jest baton itd.
Można by również tutaj przetestować ten error 103.
Po kliknięciu w ten baton wykonuje się funkcja refresh.
Natomiast myślę, że to będzie w porządku.
Tutaj sobie możemy to usunąć.
No i zobaczmy.
OK.
Testy przeszły trwają około czterech sekund.
Mamy errors state poprawny.
Gdybyśmy tutaj chcieli wyszukać to na początku,
to tutaj już będziemy mieć błąd, ponieważ nie znajdziemy na początku tego replay.
Dopiero po drugim drugim wykonaniu znajdziemy takie raczej.
Więc tak jak mówiłem tutaj będzie błąd.
Natomiast moglibyśmy tutaj zrobić asercji
znowu query text i wtedy moglibyśmy zrobić, że
przy pierwszym render nie może być na stronie, ale już przy drugim powinien się
znaleźć, ponieważ zwracamy tutaj error i wtedy będzie w porządku.
Czyli jak widzisz nasze testy są już
napisane i to co jesteś wstanie zauważyć przede wszystkim.
Jeżeli teraz wzięlibyśmy właśnie tutaj
tą zmienną to nasze testy się wywalą, bo dlaczego tak się dzieje?
To się dzieje dlatego, że mamy już wykonujemy query dla innych wartości,
czyli nie wykonujemy tego query, które mówimy, że wykonamy takie dokładnie query
z takimi wartościami, bo to wykonaliśmy z innymi i to jest właśnie ta różnica.
Więc dla tego provider jest dużo fajniejszy.
I jeszcze jeden plus mock providera.
Jeżeli byś zaadaptował dla klienta, to przy takich mocach Apollo jak pokazywałem
Ci na początku to wszystko będzie działało dalej.
Natomiast gdyby w API Apollo coś się zmieniło, Ty byś zaadaptował, to Twoje
testy również będą na czerwono, ponieważ jakieś API się zmieniło.
Tutaj używasz starego API, więc tutaj wszystko się
będzie świecić na czerwono, a przy tym jest cały Apollo client.
Co jest niepożądane
to wtedy wszystko jest ok, ponieważ tak naprawdę Twój tekst ma blokowany cały
moduł i testuje Twoją implementację, a nie implementacja Apollo.
No dobra, myślę, że to wszystko w tej lekcji.
Ja myślę, że pokazałem Ci jak testować w
dobry sposób i pewny komponenty używające Apollo Client.
W następnej lekcji jeszcze przejdziemy sobie przez mutację.
Natomiast myślę, że to była taka kluczowa
lekcja byś dowiedział się jak to robić poprawnie i jak działać z tymi.