Mezi nejznámější nástroje pro testování React (a obecně javascriptových) aplikací patří Jest, Mocha, Chai… A u nás v Ackee používáme pro unit a integrační testy právě Jest. Co se týče testování složitějších funkcionalit, není práce s Jestem vždy jednoduchá. Integrování více částí aplikace do testů je spojené se složitým nastavováním testovacího prostředí, mockováním a ošetřením asynchronních funkcí. Proto jsem se rozhodl vyzkoušet testovací nástroj Cypress, o kterém se dozvěděl kolega Lukáš na Reactive meetupu v Pardubicích, a v tomto článku se chci podělit o své zkušenosti.

Představujeme Cypress

Cypress je nástroj pro testování webových aplikací v reálném prostředí prohlížeče, který zjednodušuje psaní i “setup” e2e/integračních testů. Tedy těch, které testují kompletní části aplikace, ne pouze samostatné funkce/komponenty. Mimo jiné nabízí  stubování (mockování) funkcí a  network requestů, assertování pouhým nalezením HTML elementu, built-in ošetření asynchronní povahy webových aplikací nebo zakomponování testů do Continues Integration.

Nástroj je možné použít také pro unit testy, není to ale primární záměr a běh testů bude pomalejší, než např. v Jestu. Pro unit testy React aplikací existuje plugin.

Okno s průběhem testu
Okno s průběhem testu

Jedna z věcí, co je na Cypressu opravdu promakaná je UI testovacího prostředí a debugování testů. V UI testovacího prostředí vidíte vše, co se v průběhu testu v aplikaci děje a můžete se přepnout do jakéhokoliv okamžiku proběhlého testu. K tomu všemu máte k dispozici spoustu debugovacích informací, takže najít chybu v testu je snadné. Není potřeba něco luštit mezi řádky v konzoli a být nešťastný z toho, že test nefunguje.

Cypress je samozřejmě možné spustit i v konzoli , kde běží v Electron prohlížeči. Jak to všechno funguje je moc pěkně napsané v jejich dokumentaci.

Ukázka

Jak Cypress funguje, a jak se  v něm píšou testy, demonstruji na jednoduchém příkladu webového formuláře pro přidávání receptů, přičemž využiju veřejné Ackee cookbook API.

Testovaný formulář

Formulář bude pro zjednodušení obsahovat 3 pole – název receptu , doba přípravypopis. Po kliknutí na tlačítko „Přidat“ se odešle POST request na API. Pokud je recept úspěšně přidán, pod formulářem se zobrazí hláška o úspěchu, v opačeném případě o neúspěchu.

Formulář pro přidání receptu
Formulář pro přidání receptu

Instalace

Pokud ve svém projektu používáte NPM nebo YARN, je instalace opravdu jednoduchá:

  1. Balíček nainstalujeme jako dev dependency: npm i -D cypress.
  2. Do souboru package.json přidáme do sekce scripts  příkaz pro spuštění: "cypress:open": "cypress open".

Nástroj se pak spustí právě přidaným npm scriptem npm run cypress:open , otevře se okno aplikace se seznamem ukázkových testů. V projektu se vygenerovala složka cypress s několika podsložkami, jejichž struktura a účel je popsána v dokumentaci , kde také najdete další způsoby instalace a podrobný návod . Testy se nachází ve složce integrations.

Okno se seznamem ukázkových testů
Okno se seznamem ukázkových testů

Píšeme test

Testovací scénář našeho formuláře vypadá takto:

  1. Přijdeme na stránku s formulářem.
  2. Vyplníme pole hodnotami – název , doba trvánípopis.
  3. Klikneme na tlačítko Přidat.
  4. Zkontrolujeme, jestli se provedl dotaz na API a vrátíme simulovanou odpověď (pomocí stubu).
  5. Zkontrolujeme zobrazení hlášky o úspěchu.

 

Před samotným kódem testu je potřeba do souboru cypress.json přidat URL adresu, na které web běží, čímž zajistíme relativní adresaci v rámic Cypressu. V našem případě tedy localhost:

Vše je připraveno a můžeme jít napsat náš test, který bude vypadat skoro stejně jako testovací scénář díky jednoduchosti nástroje.

Nejdříve si před každým testem spustíme cy.server() a potom cy.route() . Tyto dva příkazy kontrolují chování network requestů a umožnují jejich „stubování“. Pomocí cy.route({...}) řekneme, ať se na POST  request na definovanou URL reaguje odpovědí {}  s výchozím status kódem 200. Naši route jsme přidali alias postAddRecipe , abychom později po odeslání formuláře mohli pomocí cy.wait('@postAddRecipe')  počkat na provedení a dokončení dotazu. Tohle je hodně užitečná funkcionalita, která umožňuje dělat testy nezávislé na externím API a definovat si všechny scénáře odpovědi včetně těch neúspěšných (404, 500,..).

Zbytek testovacího kódu už je jednoduchý. Nejdříve navštívíme požadovanou stránku, potom vyplníme hodnoty do formuláře, ten odešleme, počkáme na odpověď a zkontrolujeme zobrazení hlášky o úspěchu.

Tady jen upozorním na to, že ač se kód testu zdá synchronní, tak není . Cypress si interně přidává příkazy do fronty a může je v případě neúspěchu spouštět klidně několikrát za sebou s definovaným timeoutem. Proto si výsledek příkazu nemůžeme přiřadit do proměnné const button = cy.get('button')  a později jej použít, ale musíme použít právě alias cy.get('button').as('myButton') . Více o aliasech a jak to vlastně pod pokličkou funguje najdete v sekci Core Concepts z dokumentace.

Spuštění

A jak vlastně test probíhá?

Průběh testu
Průběh testu

Otevře se okno prohlížeče ve kterém se přehraje celý test. V levém sloupci vidíme všechny operace, které se provedly a kliknutím na ně se můžeme vráti do daného okamžiku k prozkoumání. Debugování testů je pak opravdu snadné. Do konzole prohlížeče se dokonce přidávájí další podrobné informace, což je užitečné hlavně u API requestů.

Výpis v konzoli prohlížeče
Výpis v konzoli prohlížeče

Problém s Fetch API

Cypress zatím bohužel nepodporuje Fetch API , které v mnohých moderních webových aplikacích nahrazuje XHR , jak píšou na stránce known issues. Pokud jej ve svých projektech používáte, nebude vám fungovat stubování network requestů. Pro tuto chybějící funkcionalitu existuje dočasné řešení, které spočívá v nahrazení Fetch API polyfilem. Blíže se tímto problémem komunita zabývá na GitHubu projektu.

Závěrem

Cypress oproti existujícím řešením přináší jednoduchý a rychlý způsob, jak automaticky testovat komplexnější flow webových aplikací, a tím nám ušetří práci se stále stejným manuálním testováním. Díky elegantnímu řešení asynchronních požadavků se v něm dá psát kód, jako by byl synchronní. Dovoluje nám testovat různé odpovědi z externích API, a tím silně prověřit funkcionalitu od začátku do konce.

Na unit testování (nejenom komponent, ale třeba i selektorů) se Cypress tolik nehodí a je lepší použít Jest nebo podobné nástroje, u kterých bude mimo jiné rychlejší běh testů.

O dalších tipech pro Cypress se můžete dočíst na našem frontend cookbooku.

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *