Dlaczego postawiliśmy na automatyzację testów E2E poprzez Cypress'a?
Nasza przygoda z Cypress zaczęła się na etapie poszukiwań nowego framework do testów E2E (end to end), który miał zastąpić Behata. Były dwa powody tych poszukiwań. Pierwszym z nich, był brak rozwoju Behata i zakończenie jego wsparcia przez swoich twórców. Drugim powodem był szybki rozwój naszej aplikacji frontowej, pisanej w asynchronicznym Angular.js.
Przed wyborem, razem z zespołem Frontend, zdiagnozowaliśmy kryteria, które miało spełnić nowe rozwiązanie w celu optymalizacji naszej pracy. Tymi kryteriami były:
- posiadanie zakresu funkcjonalnego jak Behat,
- bycie asynchronicznym rozwiązaniem,
- pomijanie warstwy Selenium.
Podczas testów różnych frameworków wybraliśmy Cypress’a. Już w momencie jego pierwszych testów, a było to kilka lat temu, zapowiadał się obiecująco. Jednym z głównych powodów jego wyboru była możliwość nagrywania przypadków testowych, co było i jest cennym dodatkiem przy szukaniu problemów z testem lub aplikacją oraz fakt posiadania bardzo czytelnych raportów generowanych przez plugin mocha. Poza tym, przy każdej kolejnej aktualizacji, twórcy Cypress zaskakiwali nas szybkością wprowadzania poprawek oraz dodatkowych funkcjonalności.
I tak, w roku 2019 roku, rozpoczęliśmy intensywne prace nad przeniesieniem scenariuszy z Behat do Cypress. Wymagało to od testerów zmiany (nie bez bólu) języka programowania z PHP na JavaScript. Finalnie, po realizacji kilku szkoleń oraz dzięki pomocy Frontend Developerów byliśmy w stanie dopasować Cypress do poziomu, który był dla nas zadowalający. A ten poziom charakteryzował się:
- obsługą kilkunastu projektów,
- posiadania transakcji językowych,
- nadawaniem się do "wpięcia" w proces CI/CC.
Czy Cypress jest uniwersalnym narzędziem do testów?
Wraz ze wzrostem popularności Cypress, jego twórcy starają się zapewnić mu multifunkcyjność. I tak z raczkującego frameworku, w którym zaczęliśmy pracę, stał się potężnym narzędziem, które wyprzedziło nasze oczekiwania i zapewniło możliwość pokrycia testami wszystkich poziomów standardowej piramidy testów. Do tego dokumentacja techniczna jest jedną z najlepszych jakie widziałem. Wszystko jest poparte przykładami użycia i zdjęciami, a aktualizacje dokonywane są na bieżąco i równolegle z rozwojem aplikacji.
Cypress jest nie tylko narzędziem do testów E2E aplikacji webowych, ale również umożliwia testowanie jednostkowe komponentów Angular czy React. Poniżej kilka przykładów użycia:
- Testy jednostkowe aplikacji frontowych React / Angular w izolacji.
- Testy integracyjne - sprawdzanie requestów.
- Testy akceptacyjne E2E:
Każdy z poziomów (niekoniecznie piramidy) można przetestować za pomocą Cypress. Jednak w naszym przypadku główne zastosowanie to testy E2E.
Jak widać w ostatnim przykładzie, test został napisany przy pomocy komend Cypress i przed rozpoczęciem prac zastanawialiśmy się czy wybrać „Page object” czy ”Cypress commands”. Stosując się do zaleceń dokumentacji Cypress, jako że testy pisane z wykorzystaniem PO wydłużają ich czas trwania, zdecydowaliśmy się zastosować “Cypress commands”. Co nam to dało? W moim odczuciu poprawiona została czytelność testów dla osób, które nie muszą ich pisać. Komendy zdefiniowane są podobnie jak kroki “biznesowego” scenariusza testowego. Dzięki temu to, co test ma wykonać, jest zrozumiałe nie tylko dla testersko-developerskiej części naszego zespołu.
Kolejnym wyzwaniem, który musieliśmy rozwiązać było rozdzielenie Cypress na dużą ilość naszych projektów. Nie wszystkie projekty muszą mieć te same testy, nie wszystkie korzystają z tych samych elementów html. Udało się to wykonać dzięki możliwości załadowania odpowiedniego profilu podczas odpalenia testów.
Nazwę configu definiujemy w skrypcie napisanym w package.json. W skrypcie startu Cypress mamy możliwość wskazania pliku konfiguracyjnego oraz ścieżki do katalogu z testami. Skrypty te są naszymi skryptami startowymi Cypress’a w procesie CI/CD.
Dodatkowo, w samym pliku konfiguracyjnym istnieje możliwość wyłączenia konkretnych plików z testami w sekcji e2e -> excludeSpecPattern, gdzie wskazujemy ścieżkę do plików, które nie powinny być obsłużone.
Teraz trochę o możliwościach samego Cypress’a, które uratowały nas lub mocno pomogły w samym procesie tworzenia testów:
Dużą zaletą tego frameworku jest możliwość podania listy blokowanych hostów. Dzięki temu przestają być nam straszne, przykładowo: pop-upy dołączane przez klienta poprzez np. GTM. Wystarczy dodać host do listy w pliku konfiguracyjnym.
Inną, bardzo pomocną funkcją Cypress, jest możliwość mockowania requestów, czyli przechwytywania i podmieniania zawartości respons’a.
Tak przygotowaną zaślepkę, zapisaną wcześniej w fixturach, możemy wykorzystać w celu przyspieszenia testowania funkcjonalności, która wymaga odpowiedzi z aplikacji, by mogła się pojawić. Tak np. jest ze zgodami marketingowymi - wymagają zapewnienia zawartości koszyka oraz dostępnych metod transportu. „Zawartość” koszyka jest „zaślepiona” plikiem json. Tą możliwość daje nam komenda cy.intercept, dzięki której nie musimy tworzyć produktu, cennika, transportu, metody płatności, żeby móc zweryfikować zgody w koszyku. Zaoszczędzimy czas na wykonanie wszystkich tych operacji.
Teraz pokażę rozwój logowania użytkownika w celu przeprowadzania testów panelu administracyjnego. Aby przeprowadzić testy w panelu admina, musimy być zalogowani. Można to zrobić poprzez zalogowanie się, wpisując dane do logowania w sekcji beforeEach:
Jednak proces ten jest po pierwsze czasochłonny, po drugie musi się wykonać przed każdym testem.
Innym rozwiązaniem jest zastosowanie autoryzacji logowania poprzez token JWT.
Tutaj autoryzacja odbywa się w sekcji Before, a w sekcji BeforeEach podawany jest już token w formie ciastka i jesteśmy zalogowani przed każdym testem. Jak widać, zaoszczędziliśmy czas na kilkukrotne logowanie, jednakże nadal musimy otworzyć stronę, aby móc ustawić ciastko „auth_key”.
Tutaj z pomocą przychodzi Cypress ze swoimi możliwościami. Dodaliśmy i zrobiliśmy to w następujący sposób:
Użyliśmy funkcji getConfigValue, która pobiera nasz wcześniej zapisany token z pliku, następnie wpisujemy go w sekcję onBeforeLoad. Jest to bardzo dobre rozwiązanie, ponieważ przeglądarka przed wejściem na stronę ma już ustawione pliki cookies. Nie musimy uprzednio wchodzić na stronę, by (jak wcześniej podałem) skorzystać z komendy cy.setCookie. Oszczędzamy mnóstwo czasu, jednocześnie nie martwiąc się o logowanie i dodawanie zbędnego kodu w sekcjach before i BeforeEach.
Opisałem tylko kilka rozwiązań problemów, na które się napotkaliśmy oraz możliwości, jakie dał nam Cypress, aby je rozwiązać. Po latach doświadczenia z pracą nad automatyzacją testowania, jestem w stanie stwierdzić, iż wybór Cypress’a był strzałem w dziesiątkę. Jest narzędziem, które wyczerpuje w pełni nasze oczekiwania i zapotrzebowanie na automatyzację testów E2E oraz jest doskonałym uzupełnieniem testów integracyjnych opartych na codeception, testów jednostkowych oraz funkcjonalnych w naszym procesie CI/CD.
Autorem artykułu jest Łukasz Wieczorek