Komponenter, der tester i React: hvad og hvordan man tester med Jest og enzym.

Denne artikel om test af reaktionskomponenter er skrevet af Alona Pysarenko - Frontend Engineer hos Django Stars.
Læs den originale artikel på Django Stars-bloggen.

Test af React-komponenter kan være udfordrende for både begyndere og erfarne udviklere, der allerede har arbejdet med test. Det kan være interessant at sammenligne dine egne tilgange med dem, vi bruger i vores projekt. For at dække codebase skal du vide, hvilke komponenter der skal testes, og hvilken kode nøjagtigt i komponenten der skal dækkes.

I løbet af denne artikel vil jeg dække følgende emner:

  • Definer den rigtige rækkefølge af komponenternes test baseret på projektstruktur
  • Find, hvad man skal udelade i testdækning (hvad man ikke skal teste)
  • Identificer nødvendigheden af ​​snapshot-test
  • Definer, hvad der skal testes i komponenten, og i hvilken rækkefølge
  • Angiv detaljerede tilpassede kodeeksempler

Artiklen kræver, at du har viden om opsætning af Jest og enzym. Oplysninger om installation og konfiguration kan let findes på deres officielle websteder.

Antag følgende tilfælde: Du skal dække projektkodebasen med test. Hvad skal du starte med, og hvad skal du få ved afslutningen af ​​testen? 100% testdækning? Det er det benchmark, som du skal stræbe efter, men i de fleste situationer får du det ikke.

Hvorfor? Fordi du ikke bør teste al kode. Vi finder ud af, hvorfor og hvad der skal udelades fra testene. Endnu mere sikrer 100% testdækning ikke altid, at komponenten er fuldt testet. Der er heller ingen garanti for, at det giver dig besked, hvis noget er blevet ændret. Stræb ikke efter procentdelene, undgå at skrive falske prøver, og prøv bare ikke at miste de vigtigste komponentdetaljer.

Definition af den rigtige rækkefølge af komponenternes test baseret på projektstruktur

Lad os diskutere dette spørgsmål i den næste del af projektstrukturen:

Jeg tog delt mappe, fordi det er det vigtigste. Det består af de komponenter, der bruges på flere forskellige sider af projektet. De kan genanvendes, og normalt er de små og ikke komplekse. Hvis en eller en anden komponent mislykkes, vil det forårsage, at andre steder mislykkes. Derfor skal vi være sikre på, om de er skrevet korrekt. Strukturen i dette bibliotek er opdelt i flere mapper, der hver indeholder komponenter.

Sådan defineres den rigtige rækkefølge af komponenttesting i den delte bibliotek:

  • Følg altid reglen om at gå fra enkel til kompleks. Analyser hvert bibliotek og definer, hvilke komponenter der er uafhængige - nemlig at deres gengivelse ikke afhænger af de andre komponenter. De er selvudførte og kan bruges separat som en enkelt enhed. Fra strukturen ovenfor er det input-biblioteket i formularmappen. Det indeholder inputkomponenter til redux-formularer, såsom TextInput, SelectInput, CheckboxInput, DateInput osv.
  • Dernæst skal vi definere hjælpekomponenter, der ofte bruges i inputkomponenterne, men skal testes bortset fra dem. Dette er værktøjets bibliotek. Komponenter i denne mappe er ikke komplicerede, men meget vigtige. De kan ofte genanvendes og hjælpe med gentagne handlinger.
  • Det næste trin er at definere, hvilke komponenter der også kan bruges uafhængigt. Hvis det er tilfældet, skal du tage dem til test. Fra vores struktur er det widgets, de små komponenter med enkel funktionalitet. De vil være det tredje punkt i køen til testdækning.
  • Analyser endvidere resten af ​​bibliotekerne og definer mere komplekse komponenter, der kan bruges uafhængigt eller i forbindelse med andre komponenter. Det er biblioteket med modaler i vores tilfælde. Disse komponenter vil blive forklaret detaljeret nedenfor.
  • De mest komplekse komponenter overlades til slutningen. De er hoc-biblioteket og felterne fra formularmappen. Hvordan definerer du, hvilken der skal testes først? Jeg tager det bibliotek, hvorfra komponenter allerede er blevet brugt i testede komponenter. Således var komponenten fra hoc-biblioteket til stede i widgets-komponenten. Derfor ved jeg allerede, hvor og til hvilket formål denne katalog og dens komponent bruges.
  • Den sidste er feltmappen. Den indeholder komponenter forbundet med redux-formularer.

Den endelige komponenter ordre (baseret på vores eksempel) vil se sådan ud:

Efter denne rækkefølge øger du kompleksiteten af ​​de testede komponenter trin for trin. Når det kommer til at arbejde med de mere komplekse komponenter, ved du allerede, hvordan de mindste opfører sig.

Tag ikke til test, f.eks. Feltet 'matrix', hvis du ikke er sikker på, hvordan du tester feltet 'tekst'. Tag ikke komponenter dekoreret med redux-form, hvis du ikke har testet feltet 'form'.

Vær konsekvent i dine valg, ikke tag den første komponent, der kommer ind i dit sind, og skift logik. Naturligvis kan strukturen i dit projekt variere. Det kan have andre katalognavne eller kan have yderligere komponenter, handlinger og reduktionsmaskiner, men logikken med at definere rækkefølgen for test af komponenterne er den samme.

Lad os definere, hvad der skal udelades i testdækning:

  • Tredjepartsbiblioteker. Test ikke funktionalitet, der er hentet fra et andet bibliotek. Du er ikke ansvarlig for denne kode. Spring over det eller imiter implementering, hvis du har brug for det for at teste din kode.
  • Konstanter. Navnet taler for sig selv. De kan ikke ændres. Det er sæt statisk kode, der ikke er beregnet til at variere.
  • Inline-stilarter (hvis du bruger dem i din komponent). For at teste inline-stilarter skal du duplikere objekt med stilarter i din test. Hvis objektformater ændres, skal du også ændre dem i testen. Du skal ikke kopiere en komponents kode i test. Du vil aldrig huske at ændre det i test. Derudover vil din kollega aldrig indse, at der er sket dobbeltarbejde. I de fleste tilfælde ændrer inline-stilarter ikke komponentens opførsel, så de bør ikke testes. Der kan være en undtagelse, hvis dine stilarter ændres dynamisk.
  • Ting, der ikke er relateret til den testede komponent. Spring over dækning med testkomponenter, der blev importeret i den testede komponent. Vær forsigtig, hvis den er indpakket i en anden. Test ikke indpakningen, bare analyser og test dem separat.

Så hvordan skriver du faktisk prøver? Jeg kombinerer to testmetoder:

  • Snapshot-test
  • Komponentlogikafprøvning

Jeg vil diskutere dem begge nu.

Sådan testes med snapshots

Snapshot Testing er et nyttigt testværktøj, hvis du vil være sikker på, at brugergrænsefladen ikke er ændret. Når du står overfor dette testværktøj for første gang, har du muligvis spørgsmål om organisering og styring af snapshots. Princippet er meget enkelt, men desværre er det ikke blevet beskrevet fuldt ud overalt.

Trin 1. Skriv testen for komponenten, og brug metoden .toMatchSnapshot () i forventningsblokken, der opretter selve Snapshot:

it ('gengiv korrekt tekstkomponent', () => {
    const TextInputComponent = renderer.create (). toJSON ();
    forventer (TextInputComponent) .toMatchSnapshot ();
});

Trin 2. Når du kører testen for første gang på det ene niveau sammen med testen, oprettes der et bibliotek med navnet __snapshots__ med den autogenererede fil inde i udvidelsen.snap.

Snapshot ser sådan ud:

// Jest Snapshot v1, https://goo.gl/fbAQLP
eksporterer [`Render TextInput korrekt komponent 1`] =`

`;

Trin 3. Skub snapshotet ind i depotet, og opbevar det sammen med testen.

Hvis komponenten er ændret, skal du bare opdatere snapshot med —updateSnapshot-flag eller bruge den korte formular u-flag.

Så snapshot er oprettet - hvordan fungerer det?

Lad os overveje to sager:

1. Komponenten er ændret

  • Kør test
  • Nyt snapshot oprettes, det sammenligner med det auto-genererede snapshot, der er gemt i biblioteket __snapshots__
  • Tests mislykkedes, fordi snapshot er anderledes

2. Komponenten er ikke ændret

  • Kør test
  • Nyt snapshot oprettes, det sammenligner med det auto-genererede snapshot, der er gemt i biblioteket __snapshots__
  • Test bestået, fordi snapshot er identisk

Alt er fint, når vi tester en lille komponent uden logik (bare UI-gengivelse). Men som praksis viser, er der ingen sådanne komponenter på virkelige projekter. Hvis de findes, er de få.

Er der nok snapshots til test af fuld komponent?

Hovedinstruktioner til test af komponenter

1. En komponent skal kun have et snapshot.

Hvis et snapshot mislykkes, vil andre sandsynligvis også mislykkes. Opret ikke og gem en masse unødvendige snapshots, der tilstopper pladsen og forvirrer udviklere, der læser dine test efter dig.

Der er naturligvis undtagelser, når du skal teste en komponents adfærd i to tilstande: for eksempel i komponentens tilstand, før pop-up-åbningen åbnes og efter åbning.

Selv en sådan variant kan dog altid erstattes af denne: den første test gemmer komponentens standardtilstand uden popup i snapshot, og den anden test simulerer begivenheden og kontrollerer tilstedeværelsen af ​​en bestemt klasse. På denne måde kan du nemt omgå oprettelsen af ​​flere snapshots.

2. Test af rekvisitter

Som regel deler jeg testen af ​​rekvisitterne i to test:

  • Kontroller først gengivelsen af ​​standardværdier for prop. Når komponenten gengives, forventer jeg, at en værdi er lig standardProps, hvis denne prop har defaultProps.
  • For det andet skal du kontrollere den tilpassede værdi af rekvisitten. Jeg sætter min egen værdi og forventer, at den vil blive modtaget efter gengivelsen af ​​komponenten.

3. Test af datatyper

For at teste, hvilken type data der kommer i rekvisitterne, eller hvilken type data der opnås efter visse handlinger, kan vi bruge det specielle bibliotek jest-Extended (Yderligere Jest-matchere), som har et udvidet sæt matcher, der er fraværende i jest. Med dette bibliotek er det meget lettere og underholdende at teste datatyper.

At teste proptyper er på den anden side et modstridende spørgsmål. Nogle udviklere kan argumentere imod test af protypetyper, fordi det er en tredjepartspakke og ikke bør testes. Jeg insisterer stadig på at teste komponenters proptyper, fordi jeg ikke tester selve pakkefunktionaliteten. I stedet skal jeg bare sikre mig, at proptyperne er korrekte. Datatype er en meget vigtig programmeringsdel og bør ikke springes over.

4. Begivenhedsafprøvning

Når du har oprettet et snapshot og dækket rekvisitter med test, kan du være sikker på, at komponenten gengives korrekt. Men dette er ikke nok til fuld dækning, hvis du har begivenheder i komponenten.

Du kan kontrollere begivenheden på flere måder. De mest anvendte er:

  • mock event => simulere det => forventer, at hændelsen blev kaldt
  • mock begivenhed => simulere begivenhed med params => forvent forventet begivenhed blev kaldt med bestået params
  • passerer nødvendige rekvisitter => render component => simulere begivenhed => forventer en bestemt opførsel på kaldet begivenhed

5. Testbetingelser

Meget ofte kan du have betingelser for output fra en bestemt klasse, gengive et bestemt afsnit af koden, overføre de krævede rekvisitter osv. Glem ikke dette, for med standardværdier er det kun en gren, der består testen, mens den anden forbliver uprøvet.

I komplekse komponenter med beregninger og masser af betingelser kan du gå glip af nogle grene. For at sikre, at alle dele af koden er dækket af test, skal du bruge et testdækningsværktøj og kontrollere visuelt, hvilke grene der er dækket, og hvilke ikke.

6. Testtilstand

For at kontrollere tilstand er det i de fleste tilfælde nødvendigt at skrive to test:

  • Den første kontrollerer den aktuelle tilstand.
  • Den anden kontrollerer staten efter at have ringet til en begivenhed. Render component => opkaldsfunktion direkte i testen => kontroller, hvordan tilstand er ændret. For at kalde komponentens funktion skal du få en forekomst af komponenten og først derefter kalde dens metoder (eksempel vises i den næste test).

Når du har gennemgået denne liste over instruktioner, dækkes din komponent fra 90 til 100%. Jeg forlader 10% i særlige tilfælde, der ikke blev beskrevet i artiklen, men kan forekomme i koden.

Eksempler på testning

Lad os gå til eksempler og dække komponenter med test, som vi har beskrevet ovenfor trin for trin.

1. Test af en komponent fra formularer / input.

Tag en komponent fra mappen formular / input. Lad det være DateInput.js, komponenten til datepicker-feltet.

Kodeliste for testet komponent: DateInput.js
Ligner:

DateInput-komponenten bruger bibliotekets reaktionsdatapicker med to hjælpeprogrammer:

  • valueToDate (konverterer værdi til dato)
  • dateToValue (konverterer dato til værdi)

Pakken er beregnet til at manipulere med dato, og PropTypes er til kontrol af React props.

I henhold til komponentkoden kan vi se listen over standard-rekvisitter, der hjælper komponenten med at blive gengivet:

const defaultProps = {
    inputClassName: 'input-custom',
    måneder vist: 1,
    dateFormat: 'DD.MM.YYYY',
    showManeder Årsnedgang: falsk,
    minDate: moment ()
};

Alle rekvisitter er passende til oprettelse af snapshot undtagen et: minDate: moment (). moment () giver os den aktuelle dato, hver gang vi kører testen, og snapshotet mislykkes, fordi det gemmer forældet dato. Løsningen er at spotte denne værdi:

const defaultProps = {
    minDate: øjeblik (0)
}

Vi har brug for minDate-prop i hver gengivet komponent. For at undgå duplikation af props opretter jeg HOC, der modtager defaultProps og returnerer en smuk komponent:

import TestDateInput fra '../DateInput';
const DateInput = (rekvisitter) =>
    ;

Glem ikke øjeblikket tidszone, især hvis dine test vil blive kørt af udviklere fra et andet land i en anden tidszone. De vil modtage den hånede værdi, men med en tidszoneændring. Løsningen er at indstille en standard tidszone:

const moment = demand.requireActual ('moment-timezone'). tz.setDefault ('America / Los_Angeles')

Nu er datoinputkomponenten klar til test:

1.Opret snapshot først:

it ('gengiv korrekt datokomponent', () => {
    const DateInputComponent = renderer.create (). toJSON ();
    forventer (DateInputComponent) .toMatchSnapshot ();
});

2.Tests rekvisitter:

Se gennem rekvisitterne og find de vigtige. Den første prop, der testes, er showMonth årDropdowns. Hvis det er indstillet til sandt, vises rullemenuen for måned og år:

it ('Kontroller dropdowns for måned og år vist', () => {
    const props = {
            showManthårDropdowns: sandt
        },
        DateInputComponent = mount ().find('.datepicker ');
    forventer (DateInputComponent.hasClass ( 'reagere-datepicker-hide-måned)) toEqual (sand).;
});

Test nul-propværdien. Denne kontrol er påkrævet for at sikre, at komponenten gengives uden en defineret værdi:

it ('render datoindtastning korrekt med nulværdi', () => {
    const props = {
            værdi: null
        },
        DateInputComponent = mount ();
    forventer ((DateInputComponent) .prop ( 'value')) toEqual (nul).;
});

3.Test proptyper for værdi, dato forventes at være streng:

it ('Kontroller typen af ​​værdi', () => {
    const props = {
            værdi: '10 .03.2018 '
        },
        DateInputComponent = mount ();
    forventer (DateInputComponent.prop ( 'value')) toBeString ().;
});

4.Test-begivenheder:

Kontroller først onChange-begivenheden.

  • hån on on Skift tilbagekald
  • gengivelse af input-komponent
  • simulere ændringshændelse med ny målværdi
  • og kontroller til sidst, at onChange-begivenhed er blevet kaldt med ny værdi.
it ('Kontroller onChange tilbagekald', () => {
    const onChange = jest.fn (),
        rekvisitter = {
            værdi: '20 .01.2018 ',
            onChange
        },
        DateInputComponent = mount ().find('input ');
    DateInputComponent.simulate ('ændring', {target: {value: moment ('2018-01-22')}});
    forventer (onChange) .toHaveBeenCalledWith ('22 .01.2018' );
});

Dernæst skal du sikre dig, at popup-datoen til datopicker åbnes efter et klik på datoindtastningen. For at finde dato input => simulere click event => og forvente popup, når klasse .react-datepicker er til stede.

it ('check DatePicker popup åben', () => {
    const DateComponent = mount (),
        dateInput = DateComponent.find ("input [type = 'tekst']");
    dateInput.simulate ( 'klik');
    forventer (DateComponent.find () 'reagere-datepicker.') toHaveLength (1).;
});

Fuld testliste: DateInput.test.js

2. Hjælpeprogram:

Kodeliste til testet værktøj: valueToDate.js

Formålet med dette værktøj er at omdanne en værdi til en dato med et brugerdefineret format.

Lad os først og fremmest analysere det givne værktøj og definere de vigtigste tilfælde til test:

  1. I henhold til formålet med dette værktøj transformerer det værdi, så vi er nødt til at kontrollere denne værdi:
  • I tilfælde af at værdien ikke er defineret: vi skal være sikre på, at værktøjet ikke returnerer undtagelse (fejl).
  • I tilfælde af at værdien er defineret: vi er nødt til at kontrollere, at værktøjet returnerer tidspunktet for øjeblikket.

2. Den returnerede værdi skal tilhøre momentklassen. Derfor burde det være et øjeblik.

3. Det andet argument er dateFormat. Indstil det som konstant inden test. Det er derfor, det overføres i hver test- og returværdi i henhold til datoformatet. Bør vi teste datoformat separat? Jeg formoder, at nej. Dette argument er valgfrit - hvis vi ikke indstiller datoformat, brydes værktøjet ikke, og det returnerer bare dato i standardformat. Det er et øjeblik job, vi bør ikke teste tredjepartsbiblioteker. Som jeg nævnte før, bør vi ikke glemme øjeblikket tidszone; det er et meget vigtigt punkt, især for udviklere fra forskellige tidszoner.

Lad os kode:

  1. Skriv testen til det første tilfælde. Når vi ikke har en værdi, er den tom.
const format = 'DD.MM.YYYY';
it ('render værdiToDate-værktøj med tom værdi', () => {
    const value = valueToDate ('', format);
    forventer (værdi) .toEqual (null);
});

2. Kontroller, om værdien er defineret.

const date = '21 .11.2015 ',
      format = 'DD.MM.YYYY';
it ('render værdiToDate-værktøj med defineret værdi', () => {
    const-værdi = valueToDate (dato, format);
    forvente (værdi) .toEqual (øjeblik (dato, format));
});

3. Kontroller, om værdien hører til momentklassen.

const date = '21 .11.2015 ',
    format = 'DD.MM.YYYY';
it ('check-værdi er forekomst af øjeblik') () => {
    const-værdi = valueToDate (dato, format);
    forventer (værdi instans af øjeblik) .toBeTruthy ();
});

Fuld testliste: valueToDate.test.js

3. Test af widgets

Til widgets-test tog jeg en spinnekomponent.

Kodeliste for testet widget: Spinner.js

Ser sådan ud:

Spinneren kræves ikke i forklaringen, da næsten alle webressourcer har denne komponent.

Så hvis vi går til at skrive prøver:

  1. Første trin - opret snapshot:
it ('gengiv korrekt Spinner-komponent', () => {
   const SpinnerComponent = montering ();
   forventer (SpinnerComponent) .toMatchSnapshot ();
});

2. Test af rekvisitter:

Først ser vi på standard prop-titel og kontrollerer, om den gengives korrekt.

it ('check prop title as default', () => {
 const SpinnerComponent = montering ();
    forventer (SpinnerComponent.find ('p'). tekst ()). toEqual ('Vent venligst');
});

Derefter tjekker vi den tilpassede prop-titel. Vi er nødt til at kontrollere, at det returnerer den korrekt definerede prop. Se på koden, titlen er indpakket i rawMarkup util og udsendes ved hjælp af farligtSetInnerHTML-egenskab.

Kodeliste for rawMarkup util:

eksport standardfunktion rawMarkup (skabelon) {
    returner {__html: template};
}

Skal vi inkludere tests for rawMarkup i spinnekomponenten? Nej, det er et separat hjælpeprogram, og det skal testes bortset fra spineren. Vi er ligeglad med, hvordan det fungerer - vi skal bare vide, at titelprop giver det rigtige resultat.

Afklaring: Årsagen til brug af egenskaben farligtSetInnerHTML er følgende. Vores side er flersproget, som oversættelsesmarketingteamet er ansvarligt for. De kan oversætte det ganske enkelt med en kombination af ord eller endda dekorere med HTML-tags, som , , eller endda skive tekst med listerne

    ,
      . Vi ved ikke med sikkerhed, hvordan de oversætter og dekorerer teksten. Vi skal bare korrekt gengive alt dette.

      Jeg kombinerede to vigtigste testtilfælde i en test:

      • returner korrekt tilpasset prop-titel
      • gengiv propstittlen korrekt med HTML-tags
      it ('check prop title with html tags', () => {
          const props = {
                  titel: ' Vent venligst '
              },
              SpinnerComponent = montering ();
          forventer (SpinnerComponent.find ('p'). tekst ()). toEqual ('Vent venligst');
      });

      Tag den næste propsundertitel. Det er valgfrit, og det er derfor, det ikke har en standard-prop, så spring springet over med standard-rekvisitter og test brugerdefinerede rekvisitter:

      • Kontroller, at teksten i underTitle-prop er gengivet korrekt:
      const props = {
              undertitel: 'venstre 1 minut'
          },
          SpinnerComponent = montering ();
      it ('gengiv korrekt tekst', () => {
          forventer (SpinnerComponent.find ( 'p') ved (1) .text ().) toEqual (props.subTitle).;
      });

      Vi ved, at undertitel er valgfri. Derfor er vi nødt til at kontrollere, om det ikke er gengivet med standard-rekvisitter, i henhold til skæringsmarkeringen. Kontroller blot antallet af tags

      :

      it ('check subTitle er ikke gengivet', () => {
        const SpinnerComponent = montering ();
          forventer (SpinnerComponent.find ( 'p') længde.) .toEqual (1);
      });

      3.Testing rekvisittyper:

      • For titelprop forventes at være streng:
      it ('check prop type for title is string', () => {
          const props = {
                  titel: 'Vent'
              },
              SpinnerComponent = montering ();
          forventer (SpinnerComponent.find ( 'p') tekst ().) toBeString ().;
      });
      • For subTitle prop forventes også at være streng:
      const props = {
              undertitel: 'venstre 1 minut'
          },
          SpinnerComponent = montering ();
      it ('type for subTitle er streng', () => {
          forventer (SpinnerComponent.find ( 'p') ved (1) .text ().) toBeString ().;
      });

      Fuld testliste: Spinner.test.js

      4. Modals testing (ModalWrapper.js og ModalTrigger.js)

      Ligner:

      Sådan testes modaler

      Først og fremmest vil jeg forklare, hvordan modaler er organiseret på vores projekt. Vi har to komponenter: ModalWrapper.js og ModalTrigger.js.

      ModalWrapper er ansvarlig for popup-layout. Den indeholder den modale beholder, knappen 'luk', den modale titel og krop.

      ModalTrigger er ansvarlig for modal håndtering. Det inkluderer ModalWrapper-layout og indeholder begivenheder til modals layoutkontrol (åbne og lukke handlinger).

      Jeg gennemgår hver enkelt komponent separat:

      1.Kodeliste for testet komponent: ModalWrapper.js

      Lad os kode:

      Først modtager ModalWrapper komponenten og gengiver den inde. Først og fremmest skal du kontrollere, at ModalWrapper ikke mislykkes uden komponenten. Opret et snapshot med standard-rekvisitter:

      it ('uden komponent', () => {
          const ModalWrapperComponent = lavt ();
          forventer (ModalWrapperComponent) .toMatchSnapshot ();
      });

      Det næste trin er at simulere dens faktiske tilstand med gengivelse af komponenter, der er passeret gennem rekvisitter:

      it ('med komponent', () => {
         const props = {
                 komponent: () => {}
              },
              ModalWrapperComponent = lavt ();
          forventer (ModalWrapperComponent) .toMatchSnapshot ();
      });

      Test af rekvisitter

      Modtagelse af brugerdefineret klassenavn:

      it ('gengiv det korrekte klassens navn', () => {
          const props = {
                  modalClassName: 'brugerdefineret klasse-navn'
              },
              ModalWrapperComponent = lavt ().find('Modal ');
              forventer (ModalWrapperComponent.hasClass ( 'custom-klasse-navn')) toEqual (sand).;
      });

      Modtagelse af brugerdefineret titel prop:

      it ('render correct title', () => {
          const props = {
                 titel: 'Modal title'
             },
             ModalWrapperComponent = lavt ().find('ModalTitle ');
          forventer (ModalWrapperComponent.props (). børn) .toEqual ('Modal title');
      });

      Modtager korrekt show prop:

      it ('check prop value', () => {
              const props = {
                     Vis: sandt
                 },
                 ModalWrapperComponent = lavt ().find('Modal ');
              forventer (ModalWrapperComponent.props () show.) .toEqual (sand);
          });

      Testning af proptyper

      • Til show prop
      it ('check prop type', () => {
          const props = {
                 Vis: sandt
              },
              ModalWrapperComponent = lavt ().find('Modal ');
          forventer (ModalWrapperComponent.props () show.) .toBeBoolean ();
      });
      • Til onHide prop
      it ('gengiv korrekt onHide prop type', () => {
          const props = {
                  onHide: () => {}
              },
              ModalWrapperComponent = lavt ().find('Modal ');
          forventer (ModalWrapperComponent.props () onHide.) .toBeFunction ();
      });
      • For komponent prop
      it ('gengiv den korrekte komponent prop-type', () => {
         const props = {
                 komponent: () => {}
             },
             ModalWrapperComponent = montering ();
         forventer (ModalWrapperComponent.props () komponent.) .toBeFunction ();
      });

      Fuld testliste: ModalWrapper.test.js

      2.Kodeliste for testet komponent: ModalTrigger.js

      Modalindpakningen er dækket med en test. Den anden del er at dække den modale triggerkomponent.

      Komponentoversigt: Det er baseret på den skiftede tilstand, der angiver ModalWrappers synlighed. Hvis der skiftes: falsk, er popup'en skjult, ellers er den synlig. Funktionen åben () åbner popup på underordnede element. Klikhændelsen og funktionen tæt () skjuler popup på knappen, der er gengivet i ModalWrapper.

      Oprettelse af snapshot:

      it ('gengiv ModalTrigger-komponent korrekt', () => {
          const ModalTriggerComponent = lavt ( 
      );     forventer (ModalTriggerComponent) .toMatchSnapshot (); });

      Bør vi teste ModalTrigger med gengivelse af komponent prop? Nej - fordi komponenten gengives inden i ModalWrapper-komponenten. Det afhænger ikke af den testede komponent. Det var allerede dækket med test i ModalWrapper-testene.

      Test rekvisitter:

      Vi har et rekvisitebørn, og vi vil være sikre på, at vi kun har et barn.

      it ('Sørg for kun at have et barn (kontrolelement)', () => {
          forventer (ModalTriggerComponent.findWhere (node ​​=> node.key () === 'modal-control'). længde) .toEqual (1);
      });

      Testning af proptyper:

      Børnetropen skal være et objekt, så kontroller dette i den næste test:

      const ModalTriggerComponent = montering ( 
      );
      it ('Kontroller type props for børn', () => {
            forventer (ModalTriggerComponent.props () børn.) .toBeObject ();
      });

      En vigtig del af ModalTrigger-komponenten er at kontrollere tilstande.

      Vi har to stater:

      • Popup åbnes. For at vide, at modalen åbnes, er vi nødt til at kontrollere dens tilstand. Til dette skal du ringe til den åbne funktion fra komponentens forekomst og forvente, at skiftet i tilstand skal være sandt.
      it ('Kontroller, at modalen er åbnet', () => {
          const event = {
              preventDefault: () => {},
              stopPropagation: () => {}
          };
          ModalTriggerComponent.instance () åben (begivenhed).;
          forventer (ModalTriggerComponent.state () slås til.) .toBeTruthy ();
      });
      • Popup er lukket. Det testes omvendt, skiftet i tilstand skal være falsk.
      it ('Kontroller, at modalen er lukket', () => {
         ModalTriggerComponent.instance () tæt (.);
         forventer (ModalTriggerComponent.state () slås til.) .toBeFalsy ();
      });

      Fuld testliste: ModalTrigger.test.js

      Nu er modaler fuldt testet. Et råd til test af komponenterne, der er afhængige af hinanden: Kig først igennem komponenterne og skriv testplanen, definer, hvad du har brug for at teste i hver komponent, kontroller testsager for hver komponent, og vær sikker på, at du ikke gør det gentag den samme testtilfælde i begge komponenter. Analysér omhyggeligt mulige og optimale varianter til testdækning.

      5. HOC-test (højere ordre-komponent)

      De to sidste dele (HOC'er og test af formfelter) er sammenkoblet. Jeg vil gerne dele med dig, hvordan du tester feltlayout med dets HOC.

      Her er en forklaring på, hvad BaseFieldLayout er, hvorfor vi har brug for denne komponent, og hvor vi bruger den:

      • BaseFieldLayout.js er indpakningen for forminputkomponenter som TextInput, CheckboxInput, DateInput, SelectInput osv. Deres navne slutter med -Input, fordi vi bruger redux-form pakke, og disse komponenter er inputkomponenterne til redux-form logik.
      • Vi har brug for BaseFieldLayout til at oprette layoutet til formfeltkomponenter, dvs. rendering af etiket, værktøjstip, præfikser (valuta, kvadratmeter forkortelser osv.), Ikoner, fejl og så videre.
      • Vi bruger den i BaseFieldHOC.js til indpakning af inputComponenten i feltlayout og tilslutning af den med redux-form ved hjælp af komponenten.

      Kodeliste for testet komponent: BaseFieldHOC.js

      Det er en HOC, der modtager formindgangskomponenten og returnerer komponenten, forbundet med redux-form.

      Analyse af HOC:

      • Denne komponent modtager kun en prop, komponent. Først og fremmest skal jeg oprette denne komponent og pakke den ind i BaseFieldHOC.
      • Derefter skal jeg dekorere den indpakket HOC med redux-form for at få feltet forbundet med redux-form.
      • Giv dette felt inde i React Redux -komponent for at gøre butikken tilgængelig for den testede komponent. For at håne på butikken skal du bare gøre:
      const store = createStore (() => ({}));

      Før hver test skal jeg gøre følgende:

      lad BaseFieldHOCComponent;
      beforeEach (() => {
          const TextInput = () => {return 'text input'; },
              BaseFieldHOCWrapper = BaseFieldHOC (TextInput),
              TextField = reduxForm ({form: 'testForm'}) (BaseFieldHOCWrapper);
          BaseFieldHOCComponent = renderer.create (
              
                  
              
          ) .ToJSON ();
      });

      Derefter er komponenten klar til test:

      1. Opret snapshot:
      it ('gengiv korrekt komponent', () => {
          forventer (BaseFieldHOCComponent) .toMatchSnapshot ();
      });

      2. Sørg for, at inputkomponenten er indpakket i BaseFieldLayout efter gengivelse:

      it ('Tjek inputkomponent er pakket ind i BaseFieldLayout', () => {
          forventer (BaseFieldHOCComponent.props.className) .toEqual ( 'formular-gruppe');
      });

      Det er alt, HOC er dækket. Den mest komplicerede del i testning af komponenter, der er forbundet med redux-form, er at forberede marken (dekorere med redux-form og installationslager). Resten er let, bare følg instruktionerne og intet andet.

      Fuld testliste: BaseFieldHOC.test.js

      6. Test af formularer / felter

      Feltet HOC er dækket med test, så vi kan flytte til BaseFieldLayout-komponenten.

      Kodeliste for testet komponent: BaseFieldLayout.js

      Lad os kode BaseFieldLayout.js og skriv testene i henhold til instruktionerne ovenfor:

      1. Opret først et øjebliksbillede.

      Denne komponent gengives ikke uden defaultProps:

      • inputComponent
      • Rekvisitterne leveret af redux-form: input og meta-objekter. Input med egenskabsnavn og meta med egenskabsfejl og berørt:
      const defaultProps = {
         meta: {
              berørt: null,
              fejl: null
          },
          input: {
              navn: 'feltnavn'
          },
          inputComponent: () => {return 'test case'; }
      }

      Gør følgende for at bruge defaultProps i hvert testet indpakning:

      import TestBaseFieldLayout fra '../BaseFieldLayout';
      const BaseFieldLayout = (props) => ;

      Nu er vi klar til at oprette snapshot:

      it ('gengiv BaseFieldLayout-komponent korrekt', () => {
          const BaseFieldLayoutComponent = renderer.create (). toJSON ();
          forventer (BaseFieldLayoutComponent) .toMatchSnapshot ();
      });

      2. Test af rekvisitter:

      Denne komponent har mange rekvisitter. Jeg vil vise eksempler på flere, og resten testes analogt.

      • Sørg for, at ikonbeskyttelsen gengives korrekt
      it ('render correct icon prop', () => {
          const props = {
                  icon: 
              },
              BaseFieldLayoutComponent = montering ();
              forventer (BaseFieldLayoutComponent.find (spændvidde) hasClass ( 'ikon-udråbstegn').) toBeTruthy ().;
      });
      • Sørg for, at indholdet af værktøjstip vises ved siden af ​​etiketten
      const props = {
              labelTooltipContent: 'tooltip for label'
          },
          BaseFieldLayoutComponent = montering ();
      it ('check prop er gengivet', () => {
         forventer (BaseFieldLayoutComponent.find (spændvidde) hasClass ( 'værktøjstip-ikonet').) toBeTruthy ().;
      });
      • TestfeltLink-prop
      • Sørg for, at fieldLink som standard er null
      it ('check prop er null som standard', () => {
          const BaseFieldLayoutComponent = lavt ();
          forventer (BaseFieldLayoutComponent.props () fieldLink.) .toBe (null);
      });
      • Sørg for, at fieldLink gengives korrekt med tilpasset værdi

      3. Testfejl:

      it ('tjek om felt har fejl', () => {
          const props = {
                  meta: {
                      rørt: sandt,
                      fejl: 'Dette felt er påkrævet'
                  }
              },
              BaseFieldLayoutComponent = montering ();
          forventer (BaseFieldLayoutComponent.find () 'fejl.') toHaveLength (1).;
      });

      Fuld testliste: BaseFieldLayout.test.js

      Bundlinie

      Nu ved du, hvordan du udfører fuld dækningstest af komponenter baseret på projektstruktur. Fra min egen erfaring forsøgte jeg at forklare, hvad der er nødvendigt for at teste, i hvilken rækkefølge, og hvad du kan udelade i testdækningen. Desuden demonstrerede jeg eksempler på adskillige testkomponenter og opdagede sekvensen for codebase-dækning.

      Jeg håber, at du finder denne artikel nyttig og deler dine svar. Tak fordi du læste.

      Hvis du finder dette indlæg nyttigt, skal du trykke på -knappen nedenfor :)