TypeScript Wszystkie rzeczy w twoich testach cyprysowych #frontend@twiliosendgrid
Opublikowany: 2020-11-14W Twilio SendGrid piszemy większość naszych frontendowych aplikacji internetowych, w szczególności nowe strony i funkcje, za pomocą TypeScript i React już dziś, aby lepiej sprawdzać typy, ułatwiać konserwację i dokumentować naszą bazę kodu. Kiedy po raz pierwszy zaczęliśmy pisać testy Cypressa ponad dwa lata temu, większość naszych obiektów stron, pomocników i plików specyfikacji była wciąż zaimplementowana w JavaScript i byliśmy głównie na Cypress w wersji 3.xx Nowsze testy były już napisane w TypeScript, ale my nadal miał dużą liczbę plików do przekonwertowania i migracji do TypeScript.
Chcieliśmy w pełni czerpać korzyści z wpisywania naszych komponentów, testów jednostkowych i testów Cypress E2E . Tym, co ułatwiło ten proces, była migracja do nowszej wersji Cypress, aby skorzystać z gotowej obsługi TypeScript od Cypress 4.4.0.
Jeśli chcesz zrobić krok w tył i dowiedzieć się bardziej ogólnie, jak myśleć o pisaniu testów E2E, zajrzyj do tego wpisu na blogu. Jeśli chcesz również zobaczyć tysiąc stóp przegląd najczęstszych rzeczy, których używaliśmy lub robiliśmy wcześniej, pisząc testy Cypress w różnych środowiskach, możesz zapoznać się z tym wpisem na blogu, zanim zaczniesz dodawać TypeScript do swoich testów Cypress. W tym poście zakładamy, że znasz się na testach Cypress i korzystałeś już wcześniej z ich interfejsu API.
Jeśli jesteś gotowy, aby zobaczyć, jak coś wpisaliśmy, przyjrzyjmy się najpierw niektórym wstępnym zmianom, takim jak dodanie obsługi TypeScript do Cypressa, jeśli pochodzisz ze starszej wersji.
Migracja z Cypress 3.x do >= 4.4.0
Dla tych, którzy już skonfigurowali swoją infrastrukturę Cypress do pracy z TypeScript w Cypress w wersjach 3.xx do 4.4.3, najprawdopodobniej doświadczyłeś prób i błędów podczas konfigurowania właściwej konfiguracji preprocesora Webpack w swoich plugins/index.js
. W przypadku zespołu Twilio SendGrid wystąpiły pewne problemy z niektórymi plikami, które musiały być plikami JavaScript w plugins
i folderach support
, a trudne do debugowania błędy Cypressa pojawiały się. Kiedy już coś działa, powinno wyglądać mniej więcej tak.
Po aktualizacji z wcześniejszej wersji 3.xx byliśmy w stanie usunąć naszą konfigurację preprocesora Webpack, zastąpić nasz plik plugins/index.js
plikiem index.ts
, pomajstrować trochę przy tsconfig.json
naszego folderu Cypress i na koniec, używając plików TS w naszym folderze Cypress (takich jak some_page.spec.ts
, index.d.ts
lub page_object.ts
) - koniec z konfiguracją preprocesora Webpack i po prostu zadziałało! Byliśmy zadowoleni z tego, o ile czystsze i przyjemniejsze było nie zarządzanie własną konfiguracją preprocesora Webpack i lepsze pokrycie TypeScriptem naszych plików, jak pokazano poniżej.
Uwzględniając obsługę TypeScript, przyjrzeliśmy się następnie przykładowej aplikacji zespołu Cypress w świecie rzeczywistym, repozytorium aplikacji cypress-real-world-app, aby dowiedzieć się więcej o tym, jak lepiej pisać rzeczy. Odkryliśmy, jak wpisać cy.task(“pluginName”, { … })
i Cypress.env(“someEnvVar”)
w celu lepszego łączenia i wpisywania obsługi intellisense podczas aktualizacji plików. Przekopaliśmy się również przez towarzyszącą im dokumentację TypeScript. To nauczyło nas, jak pisać takie rzeczy, jak nasze niestandardowe polecenie cy.login()
i jak skonfigurować plik konfiguracyjny tsconfig.json
. Przykładowa aplikacja ma również plik tsconfig.json
, do którego można się odwoływać, co może zapewnić doskonałą podstawową konfigurację TypeScript, którą można dostosować do własnych preferencji. Zalecamy, abyś był na bieżąco z najnowszymi wersjami Cypress, zanurzył się w oficjalnych zasobach Cypress i eksperymentował z plikami definicji typów.
Wpisywanie niestandardowych poleceń
Stworzyliśmy kilka globalnych poleceń niestandardowych, takich jak cy.login()
, aby obsługiwać logowanie za pośrednictwem interfejsu API, dzięki czemu można je ponownie wykorzystać we wszystkich naszych plikach specyfikacji. Oto przykład, w jaki sposób możesz wpisać własne niestandardowe polecenie logowania z danymi uwierzytelniającymi użytkownika i zwracając token uwierzytelniania.
Wpisywanie zmiennych środowiskowych
Aby poradzić sobie z wieloma środowiskami testowymi, takimi jak dev i staging, skorzystaliśmy ze skonfigurowania zmiennych środowiskowych, takich jak: „testEnv” do przechowywania środowiska, na którym obecnie testujemy, na przykład „staging”, „apiHost” do przechowywania hosta interfejsu API zaplecza i inne zmienne. Możesz wpisać swoje wywołania Cypress.env()
, aby lepiej wypisać funkcje i inne obiekty, które opierają się na użyciu tych wartości zmiennych środowiskowych, takich jak ta.
Pisanie wtyczek
Stworzyliśmy wiele funkcji wtyczek cy.task()
do obsługi wywołań API, odpytywania usług i sprawdzania pasujących wiadomości e-mail w testowych skrzynkach odbiorczych. Wcześniej podczas łączenia w łańcuch dowolnych z tych wywołań funkcji, takich jak cy.task().then((data) => {})
, powiązany podmiot danych był wpisywany jako any
lub unknown
, co nie było dobre w przypadku naszych plików TypeScript. Dzięki przykładom Cypress odkryliśmy, jak lepiej wpisywać wtyczki na podstawie nazwy wtyczki i argumentów przekazywanych w wywołaniach funkcji. Umożliwiło to naszym plikom TypeScript wykrycie, jaki byłby łańcuchowy typ danych.
Jeden subtelny problem, którego doświadczyliśmy, polegał na tym, że nazwa wtyczki i argumenty muszą dokładnie pasować do tego, jak je .then()
. Zauważyliśmy, że ważne jest, aby najechać kursorem na połączony typ cy.task()
w edytorze, aby podwoić sprawdź, czy typy pasują poprawnie. Czasami, jeśli używasz powiązanego tematu z innej funkcji Cypress, takiej jak cy.getCookie(“auth_token”).its(“value”).then((token) => { })
cy.wrap(data).then((data) => {})
, musisz również wpisać te powiązane argumenty danych przed przekazaniem ich jako argument funkcji cy.task(..., { token, data })
lub nadal będziesz widzieć cy.task(...).then((data) => { })
część danych wpisana jako any
lub unknown
. Lepiej jest być bardziej precyzyjnym w wielu powiązanych typach funkcji Cypress, takich jak .its(“value”).then((token: string) => {})
lub cy.wrap(data).then((data: DataType) => {})
przed przekazaniem ich jako części obiektu argumentów cy.task()
, aby upewnić się, że typy znów działają.
Stworzyliśmy osobne pliki Typescript wtyczek, które eksportowały funkcje, które będą używane z powrotem w naszych plugins/index.ts
. W miarę wzrostu liczby wtyczek zalecamy organizowanie tych implementacji funkcji wtyczek według stron lub funkcji, aby utrzymać mały plik plugins/index.ts
. Powinieneś ułatwić sobie odczytanie na pierwszy rzut oka, w którym definiujesz wszystkie cy.task(...)
w pliku plugins/index.ts
. Możesz wreszcie wpisać te funkcje zadań w swoim index.d.ts
w następujący sposób:
Składając to wszystko razem w pliku deklaracji typu
Wszystkie nasze typy dla naszych poleceń niestandardowych, zmiennych środowiskowych i wtyczek umieściliśmy w pliku index.d.ts
w folderze support
. Zalecamy umieszczenie wszystkich typów Cypress w głównym pliku definicji TypeScript, aby utrzymać porządek. Aby ominąć brakujące typy w zewnętrznych zależnościach używanych w kodzie testowym Cypress, możesz również zdefiniować pliki modułów, takie jak „some-lib.d.ts”, które będą zawierać declare module 'some-lib'
, aby obejść ostrzeżenia TypeScript biblioteki. Możesz nawet użyć funkcji importowania typów TypeScript, aby wprowadzić typy/interfejsy zdefiniowane w innych plikach wtyczek/narzędzi, aby uniknąć duplikowania definicji typów w wielu plikach. Możesz dodać te typy w przestrzeni nazw Cypress i zorganizować je w następujący sposób:
Wpisywanie obiektów osprzętu testowego, obiektów stron i plików specyfikacji
Kiedy chcemy załadować różnych użytkowników i metadane dla środowiska testowego, wcześniej zilustrowaliśmy, jak możemy połączyć zmienne środowiskowe, takie jak „testEnv” z wartościami „testowanie” lub „staging”, aby wyodrębnić „testowanie” lub „ staging” z całego obiektu osprzętu testowego. Możesz wpisać te obiekty środowiska testowego z rodzajami, aby uzyskać spójną strukturę, którą wszystkie specyfikacje będą udostępniać. Dla każdego środowiska testowego możesz mieć te same poświadczenia użytkownika i pola meta przy użyciu typu ogólnego dla testu, aby dodać tyle właściwości, ile potrzeba. Zobacz przykład poniżej.
Wpisywanie obiektów strony i wpisywanie odpowiednich plików specyfikacji zależy od poleceń Cypress, wtyczek i innych używanych narzędzi. W większości przypadków wpisywanie obiektów strony lub plików specyfikacji nie wymaga wielu zmian w stosunku do ich odpowiedników JavaScript (zakładając, że już wpisałeś wtyczki i wywołania zmiennych środowiskowych). Czasami zdefiniowana przez Ciebie funkcja pomocnicza obiektu strony może wymagać wpisania pewnych argumentów lub odpowiedź wracająca z cy.request()
może wymagać wpisania za pomocą as
przykład response.body as SomeType
. Ogólnie rzecz biorąc, twój edytor, taki jak VSCode, może automatycznie wykrywać połączone typy cy.task()
lub cy.customCommand()
bez konieczności dodawania większej liczby typów w plikach specyfikacji, aby zrekompensować wszelkie ostrzeżenia TypeScript.
Oto przykład części obiektu strony z niektórymi funkcjami pomocniczymi i plikiem specyfikacji, który używa obiektu strony, niestandardowego polecenia logowania i zadań wtyczek.
Wniosek
Dodanie TypeScriptu do naszych testów Cypress pomogło nam uniknąć błędów i poprawiło nasze doświadczenie programistyczne podczas pisania testów Cypress. Korzystając z wywołań funkcji cy.task()
, Cypress.env()
i cy.customCommand()
, możemy uzyskać lepsze sprawdzanie typu argumentów i danych wyjściowych funkcji, a także skorzystać z uzupełniania kodu w naszym środowisku IDE, takim jak VSCode.
Kluczem do sukcesu jest utworzenie własnego pliku deklaracji typu, takiego jak plik index.d.ts
, w którym można nadpisać lub rozszerzyć interfejsy „Cypress” i „Chainable” w oparciu o niestandardowe polecenia, zmienne środowiskowe i funkcje wtyczek zadań. za pomocą. W obiekcie strony i specyfikacjach plików TypeScript można następnie użyć tych funkcji Cypress i najechać kursorem na lub postępować zgodnie z definicją oczekiwanych typów danych wejściowych i wyjściowych.
Co więcej, spróbuj użyć TypeScript z Cypress, ponieważ ma on gotową obsługę TypeScript w nowszych wersjach. Sprawdź, czy pomaga to w bardziej przejrzystym dokumentowaniu funkcji i unikaniu nieprawidłowego użycia interfejsu API. Twoje testy TypeScript prawdopodobnie nadal będą wyglądać podobnie do testów JavaScript Cypress, więc możesz stopniowo konwertować niektóre testy na raz, aby porównać i zestawić podejścia.
Jeśli interesują Cię więcej postów związanych z tym, czego nauczyliśmy się z naszych testów na Cypress, oto kilka artykułów, które powinieneś sprawdzić:
- Co wziąć pod uwagę podczas pisania testów E2E
- 1000 stóp Przegląd pisania testów na cyprys
- Radzenie sobie z przepływami wiadomości e-mail w testach cyprysowych
- Pomysły na konfigurację, organizację i konsolidację testów cyprysowych
- Integracja testów Cypress z Docker, Buildkite i CICD