Intro
Sprawdzimy wszystkie popularne podejścia, które znacznie ułatwiają utrzymywanie oraz skalowanie selektorów dla testów e2e.
Trochę o selektorach dla testów e2e
Podczas pisania testów e2e musisz zawsze wykorzystać jakiś selektor. Im bardziej precyzyjny i unikalny, tym lepiej dla Ciebie i Twoich testów. Dlaczego? Załóżmy, że mamy selektor, który wygląda w ten sposób:
Ładowanie
Teraz w testach e2e, załóżmy, że korzystamy z Cypress, nasz kod mógłby wyglądać tak:
Ładowanie
Najlepiej pisać selektory w taki sposób, aby zawsze były unikalne i niezależne od struktury HTML (zmiana w niej nie powinna wywalić testów). Tylko takie podejście da Ci stabilność w testach. Oczywiście od tej reguły mogą być wyjątki, ale jeżeli jest taka możliwość, to powinniśmy starać się przestrzegać tej zasady.
Ładowanie
Szczerze? To chyba jeszcze gorszy pomysł. Dlaczego?
- Jak zmieni się nazwa komponentu - musisz zmienić nazwę klasy
- Selektor jest unikalny na skalę komponentu, lecz nie jest na skalę aplikacji :)
A może zmienić klasę na #id? Tutaj będą te same problemy. No to cholbyka, co w takim razie mamy zrobić? Problem nie jest w tym, jaki atrybut ustawiamy, ale w tym jaką wartość mu przypisujemy. Powinniśmy wiedzieć, jaki jest zbiór możliwych selektorów, skąd je brać i czy są unikalne na skalę aplikacji/biblioteki, bądź funkcjonalności.
Jak osiągnąć skończoną liczbę selektorów?
Możesz stworzyć zwykły obiekt JavaScript lub JSON i wykorzystywać jego wartości w testach e2e, jak i w kodzie aplikacji.
Ładowanie
Teraz już wiemy, jaką mamy liczbę selektorów, które powinny być wykorzystane w testach e2e - wiemy, że są skończone. Również utrzymanie ich będzie o wiele prostsze (zmiana w jednym miejscu).
Dalej widzę tu dwa problemy:
- Ten obiekt może być koszmarnie duży - co będzie rzutowało na rozmiar aplikacji,
- Każdy może użyć dowolnego atrybutu: klasa, id lub inny,
Jak pozbyć się dużego obiektu i odchudzić aplikację?
Najpierw zdefiniujmy string literals z TypeScript, które określą jakich selektorów możemy użyć.
Ładowanie
Teraz zarówno w kodzie testów e2e, jak i kodzie aplikacji będzie korzystać z następującej funkcji:
Ładowanie
Funkcja, która jedyne, co robi, to bierze parametr i go zwraca? LOL... No ok, to teraz patrz na to. Zamist dużego obiektu masz funkcję oraz type literals, które określają zawsze skończoną liczbę selektorów. Następującą funkcję należy teraz zaimportować i wywołać w aplikacji oraz w testach. Wygąda to tak:
Ładowanie
Zwróć uwagę na podpowiedzi, które otrzymujesz od TypeScript
Tworzymy fasadę na Cypress.get
No dobra, ale w dalszym ciągu każdy może użyć sobie dowolnego atrybutu. Jeden deweloper będzie wykorzystywać klasy, inny id, a jeszcze inny skorzysta z selektorów dostępności (accessibility), które dadzą możliwość używania strony osobom niepełnosprawnym.
Ładowanie
Powinniśmy używać tylko i wyłącznie konkretnych atrybutów (skończonej liczby) - na potrzeby przykładu będzie to data-attribute o nazwie data-i. Może być ich tyle ile chcemy, ale ilość musi być skończona i zdefiniowana w jednym miejscu.
Ładowanie
Zwróć uwagę na to, że przekazujemy instancję Cypress i de facto ją zwracamy, ale z przechwyconym typem.
A tak wygląda użycie w kodzie testów oraz aplikacji.
Ładowanie
Wybór selektorów dla testów e2e
No dobra, ale co z good practices? Część deweloperów uważa, że selektory dla testów e2e powinny być tam, gdzie możliwe oparte o atrybuty dostępności - accessibility. To zależy...
Jeżeli ktoś chce przetestować jednocześnie accessibility oraz ścieżki biznesowe aplikacji w testach e2e, musi się liczyć z tym, że takie testy mogą znacznie częściej psuć się i wymagać zmiany. Wykorzystanie data-attributes pozwala na oznaczenie elementu HTML unikalną wartością, która referuje do tego, czym ten element jest w kontekście biznesowym, a ten atrybut będzie tylko i wyłącznie używany przez testy e2e.
Dzięki temu zmiana styli, logiki, dodanie innych atrybutów, czy zmiana samej struktury HTML (zmiana kolejności, dodanie elementu wyżej lub niżej oraz zagnieżdżenie) - nie popsuje naszych testów.
Sama dokumentacja Cypress mówi o tym, że wykorzystanie data-cy to najlepsza możliwa praktyka. Nasze selektory będa odseparowane całkowicie od zmian w stylach, czy logice. Nie znięchęcam do używania selektorów accessibility, ale należy się liczyć z tym, że takie testy e2e będą znacznie cięższe do utrzymania, a zmiany w strukturze HTML będą psuły testy, a nie powinny.
Moim zdaniem to idealny przykład wyboru rozwiązania po preferencjach dewelopera, a nie zyskach/stratach. Ja wybieram opcję z data-attributes dlatego, że (i nie mówię Ci, że to best practice):
- Testy e2e są czasochłonne i kosztowne. Każdy false negative marnuje nam czas. Dlatego wolę ograniczyć ilość failujących testów w momencie zmiany struktury HTML'a.
- Wolę testować accessibility w izolacji - na poziomie testów jednostkowych komponentu, bądź nawet napisać testy e2e tylko dla komponentu, sprawdzające accessibility.
- Testy z data-attributes są bardzo łatwe w utrzymaniu i definiowaniu skończonej liczby selektorów e2e.
Link do dokumentacji Cypress z przykładem, o którym wspominałem: Cypress best practices.
Skalowanie selektorów i definicji typów
Jedna funkcja do obsługi wszystkich selektorów to trochę mało. Aby lepiej skalować podpowiedzi, które TypeScript będzie nam oferował, możemy stworzyć kilka funkcji (per feature):
Ładowanie
Podsumowanie i słów kilka o testach e2e
Testy e2e są piekielnie czasochłonne. Muszą być napisane w taki sposób, aby były odporne na zmianę implementacji - style, logika, struktura dokumentu HTML. Stosowanie selektorów w oparciu o data-attributes zapewnia odporność na wszystkie trzy wymienione.
Zmieniłeś nazwę klasy? Zmieniłeś strukturę HTML'a? Dodałeś nowe elementy? Testy będą dalej działać prawidłowo i nie będą wymagać żadnej zmiany, o tyle jeżeli funkcjonalność rzeczywiście działa i selektor z data-attribute nie uległ zmianie.
Proszę, potraktuj ten wpis jako ciekawostkę. Naprawdę nie lubię nazywać rzeczy jako good/bad practice, bo sądzę, że jeżeli ktoś umie uargumentować jakieś rozwiązanie, to jest to wystarczające do stosowania go. Oczywiście, jeżeli te argumenty do Ciebie trafiają. Sprawdź sam i wypracuj własną opinie!
Komentarze
Przejrzyj komentarze artykułu i dodaj swoją opinię.