TypeScript Wszystkie rzeczy w twoich testach cyprysowych #frontend@twiliosendgrid

Opublikowany: 2020-11-14

W 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