Artikkelit

Liikkeelle React-komponenttien testaamisessa

Teknologia

Olen pitänyt ajatusta käyttöliittymien testauksesta haastavana. Selain on niin monimutkainen ympäristö – miten siellä testaaminen toimii käytönnössä? Kannattaako testien laatimiseen käyttää aikaa? Mitä ylipäätään kannattaa testata?

Mikä on testaamisen arvoista?

Refaktoroidessani Omasivarin lomakkeita huomasin nopeasti pallottelevani editorin ja selaimen välillä. Vaihdoin yhden tekstikentän toteutusta, jonka jälkeen kokeilin, päivittyikö sen arvo edelleen oikein, sainko virheilmoituksen syöttäessäni sähköpostiosoitteen väärin ja vähän kaikkea muuta, mitä keksin kokeilla. Sama toistui seuraavan kentän kanssa. Ja seuraavan. Ja seuraavan, kunnes lopulta aloin kokeilemaan, lähetetäänkö kaikki tiedot todella palvelimelle, kun painan lomakkeen lähetyspainiketta. Entä jos pakollinen etunimikenttä on tyhjä ja tilinumeron tilalla on tuliemoji? 🔥

Seuraavaa lomaketta työstäessäni uskalsin jo muuttaa kaikkien kenttien toteutukset kerralla ja näpertää selaimen kanssa vasta sitten. Kävin silti kaikki mahdolliset validaatiovirheet läpi manuaalisesti. Kolmannen lomakkeen kohdalla aloin jo kyllästyä samojen asioiden toistamiseen. Päätin luoda Omasivarin ensimmäisen testin.

Ennen tätä lomakekoettelemusta en ollut osannut tunnistaa kehittämistäni sovelluksista sellaisia osia, jotka olisivat hyötyneet automatisoiduista testeistä. Tästä viisastuneena ymmärsin, että testaaminen kannattaa aloittaa sellaisista komponenteista, joita huomaa testaavansa toistuvasti käsin. Usein tätä tehdään juuri lomakkeiden kanssa, joiden kentissä olevat arvot määrittävät muun muassa sen, tuleeko lisätietokenttiä näyttää tai saako lomaketta edes lähettää. Testi tekee kaiken käsityön muutamassa sekunnissa ja takaa lomakkeen toimivan halutulla tavalla seuraavankin kerran, kun sitä pitää muuttaa.

Mitä testataan?

Edellä kuvaamani testauksen lähtökohtana on tarve toistaa käyttäjän tekemiä toimintoja. Kirjoitettavien testien tulisi siis varmistaa, että näiden toimintojen seurauksena tapahtuu juuri sitä, mitä halutaan tapahtuvan. Käyttäjä syöttää lomakkeen tiedot oikein ja lomake lähetetään. Tyhjäksi jätetty pakollinen kenttä johtaa puolestaan virheilmoituksen näkymiseen.

Käytetään esimerkkinä tapausta, jossa käyttäjä yrittää kirjautua sovellukseen ilman salasanaa. Lomake huomaa puuttuvan tiedon ja huomauttaa tästä käyttäjälle.

Kirjautumislomake, jonka salasanakenttä on tyhjä lähetetään. Seurauksena on puuttuvasta salasanasta huomauttava virheviesti.
Kirjautumisen ei tule olla mahdollista ilman salasanaa.

Testissä voidaan varmistaa, että lomakkeen renderöivän React-komponentin sisäinen tila muuttuu kuvaamaan virhetilannetta. Tätä kutsutaan implementaation testaamiseksi: ei tutkita käyttäjälle näkyvää toiminnan seurausta vaan tapaa, jolla lopputulosta tavoitellaan. Testi onnistuu, jos jokin muuttuja saa arvokseen Error objektin, mutta on vaarallista olettaa sen johtavan automaattisesti ruudulla näkyvään virheilmoitukseen.

On luotettavampaa testata komponentin käyttäytymistä käyttäjän näkökulmasta. Tutkitaan oikeasti renderöityä HTML-dokumenttia ja etsitään sieltä elementtiä, joka kertoo virheestä käyttäjälle. Testi onnistuu, jos elementti löytyy.

Painikke, jonka painamisesta seuraa sisäisen tilan muutos (implementaatio) tai selaimen virheilmoitus (käyttäytyminen).
Testin varmistukset voi kohdistaa implementaatioon tai käyttäytymiseen.

Mikään ei kuitenkaan ole mustavalkoista. Joskus voi huomata testaavansa implementaatiota vahingossa. Toisinaan se voi olla perusteltuakin. Vaikeinta on löytää itsensä jostain näiden rajamailta.

Millä React-komponentteja testataan?

Omaan testityökalupakkiini päätyivät seuraavat työkalut:

  • Jest – pyörittää koko testikoneistoa
  • jest-dom – tarjoaa varmistuksia HTML-dokumentin testaamiseen
  • React Testing Library – työkaluja DOM-elementtien etsimiseen ja manipuloimiseen intuitiivisella tavalla
  • user-event – simuloi käyttäjän tekemiä toimintoja todella helppokäyttöisesti

Kokeilin seuraavia työkaluja, mutta jätin ne tarkoituksella pois:

  • Enzyme – täyttää saman roolin kuin React Testing Library, mutta painottaa enemmän implementaation testaamista ja React-komponenttien sisäisen tilan tutkimista.

Jatkan seuraavassa kirjoituksessa käytännöllisemmillä esimerkeillä React-lomakkeiden testaamisesta. Käydään siellä läpi miten testi luodaan, mistä osista se koostuu, ja kuinka testejä ajetaan.

React hooks – React blogi part 2

Teknologia

Otetaanpas jälleen kevyt tekstin aloitus asiaan liittyvällä meemillä.

Yleistä React hookeista

  • Hookit ovat täysin taaksepäin yhteensopivia.
  • Hookkeja ei ole pakko käyttää. Niitä voi helposti testata muutamassa komponentissa ilman, että joutuu kirjoittamaan olemassa olevaa koodia uusiksi.
  • Luokat eivät ole poistumassa Reactista.
  • Hookit tuli käytettäväksi Reactin 16.8 versiossa.

Mitä Hookit ovat?

Ne ovat funktioita, joilla voi hallita Reactin tilaa ja ”napata” kiinni elinkaaren (lifecycle) ominaisuuksiin funktionaalisissa komponenteissa. Hookkeja ei voi käyttää luokka-komponenteissa – ne sallivat Reactin käytön ilman luokkia.

Osalle JavaScript-luokkien käyttö on saattanut aiheuttaa päänvaivaa, sillä ne eroavat muiden kielien luokista melkoisesti. Luokkia voi kuitenkin huoletta käyttää jatkossakin, sillä ne eivät ole Reactista poistumassa.

Hookeilla voidaan ”kaivaa” tilallista logiikan komponenteista, joita voidaan riippumattomasti testata ja uudelleen käyttää. Hookit sallivat tilallisen logiikan uudelleenkäytön muuttamatta komponentin hierarkiaa. 

Hookit ovat JavaScript funktioita, mutta niillä on kaksi sääntöä:

  • Hookkeja ei saa kutsua looppien sisällä tai nestatuissa funktioissa.
  • Hookkeja ei saa kutsua tavallisista JavaScript funktioista –niitä voi käyttää vain Reactin funktionaalisissa komponenteissa.

Omasta kokemuksesta voin sanoa, että funktionaaliset komponentit + hookit yksinkertaistavat React-devausta ja ovat nopeampia oppia verrattuna luokka-komponentteihin.

Mitä Hookit korvaavat?

  • Luokat
  • Render Prop kuvion

Hieman vaihtelevaa mielipidettä on siitä, mitä ne eivät korvaa. Muutamia on tullut vastaan tuolla internetin ihmeellisessä maailmassa, mutta teemaksi on alkanut muotoutua esimerkiksi seuraavat:

  • Redux
  • Higher Order Components (HOC)

Tässä täytyy nyt mainita, että luokka-komponenttien kanssa HOC tulee epäilemättä pysymään käytössä, mutta funktionaalisissa komponenteissa sen voi korvata custom hookeilla. Täältä käytännön esimerkkiä kuinka korvata HOC custom hookeilla: https://dev.to/gethackteam/from-higher-order-components-hoc-to-react-hooks-2bm9

Erityisesti Reduxin suhteen tuntuu olevan paljon mietintää siitä, voivatko Hookit sen korvata. Reduxin käytöllä on omat etunsa, etenkin koko sovelluksen tilaa hallittaessa. Hookkeja käytettäessä taas ei tarvitse latailla/asentaa mitään riippuvuuksia. Molemmissa on puolensa, joten voidaan todeta, että riippuu täysin tilanteesta, sovelluksen koosta ja tarpeesta, kumpaa kannattaa käyttää; oman sovelluksen osalta ratkaisua kannattaa harkita ja päätös tehdä tilannekohtaisesti.

Lähteet ja lisää luettavaa

https://joinex.fi/react-pahkinankuoressa/

https://reactjs.org/docs/hooks-intro.html

https://medium.com/javascript-scene/do-react-hooks-replace-redux-210bab340672

https://www.simplethread.com/cant-replace-redux-with-hooks/