Testen der Komponenten der Reaktionsoberfläche

Was mache ich jetzt?


Ich teste derzeit eine Code-Implementierung. Solche Tests brechen jedes Mal nach dem Refactoring ab, insbesondere bei den Komponenten der Benutzeroberfläche. Infolgedessen verbringe ich viel Zeit damit, mich mit den .test.js Dateien zu .test.js , und .test.js gleichzeitig die magische Zahl von 80% für die Testabdeckung .


Was soll ich tun


Wenn ich irgendeine Art von Test schreibe, einschließlich Unit-Tests, sollte ich weniger an den Code denken, den ich teste, als vielmehr an die Funktionsweise dieses Codes. Dies bedeutet, Tests zu schreiben, die das Benutzerverhalten nachahmen. Selbst auf der untersten Ebene.


Beispiel


Stellen Sie sich eine Standard Yuy Akkordeon Komponente vor. Beim Drücken wird es geöffnet oder geschlossen. Der Inhalt wird als untergeordnetes Element an die Komponente übergeben.


Bild


Die Funktionalität unserer Testkomponente ist wie folgt:


  • Die ersten 3 Akkordeons werden eingesetzt, alle verbleibenden sind geschlossen.
  • Wenn Sie auf das Akkordeon klicken, wird das publishAccordionAnalytics Modul publishAccordionAnalytics , das die publishAccordionAnalytics verfolgt. Wir importieren dieses Modul aus dem @myProject/analyticsHelpers Paket
  • Wenn der Benutzer auf das ausgeblendete Akkordeon unten in der Anwendung klickt und sich der Akkordeoninhalt nach dem Öffnen nicht im Sichtfeld des Benutzers befindet, wird eine Animation ausgelöst und der Inhalt der Komponente wird in den sichtbaren Bereich des Bildschirms verschoben.

 ... import { publishAccordeonAnalytics } from '@myProject/analyticsHelpers'; class Accordion extends Component { positionReference: RefObjectType; constructor(props) { super(props); this.positionReference = React.createRef(); } scrollToRef = (ref) => { const wrapper = document.querySelector('.app'); return isInViewPort(ref, wrapper) ? null : setTimeout(() => { return ref.current && wrapper && wrapper.scrollTo(wrapper.scrollTop, wrapper.scrollTop + ref.current.offsetTop) }, 300); }; render() { const { headerName, children, index } = this.props; const { scrollToRef, positionReference } = this; const defaultOpenAccordions = index >= 3; return ( <Accordion defaultOpen={!defaultOpenAccordions} headerName={headerName} onChange={(open) => { publishAccordionAnalytics(open, headerName); if (defaultOpenAccordions) { scrollToRef(positionReference); } }} id={headerName} > {children} {defaultOpenAccordions && <div data-testId="referenced-div" ref={positionReference} />} </Accordion> ); } } 

So schreibe ich jetzt einen Test:


 jest.mock('@myProject/analyticsHelpers'); describe('', () => { test(' ', () => { const jsx = ( <Accordion headerName=" "> <div>Test</div> </Accordion> ); const tree = renderer .create(jsx) .toJSON(); expect(tree).toMatchSnapshot(); }); test(' ', () => { const wrapper = mount( <Accordion headerName=" " index={1}> <div>Test</div> </Accordion> ); wrapper.find('Header').simulate('click'); expect(publishAccordeonAnalytics).toHaveBeenCalledTimes(1); }); test(' scrollToRef ', () => { const wrapper = shallow( <Accordion headerName=" " index={7}> <div>Test</div> </Accordion>); const component = wrapper.instance(); component.scrollToRef = jest.fn(); wrapper.find('Header').simulate('click'); expect(publishAccordeonAnalytics).toHaveBeenCalledTimes(1); expect(component.scrollToRef).toHaveBeenCalled(); }) }); 

Ich teste die Struktur der Komponente mit Snapshots sowie Funktionsaufrufen per Mausklick.


Dieses Akkordeon erfüllt die erwartete Funktionalität vollständig und Tests bestätigen dies. Jetzt mache ich das Refactoring, ersetze die React.Component durch die functional component und scrollToRef Komponentenmethode in eine separate Funktion.


 function Accordion ({ marketName, children, index }) { const positionReference = React.createRef(); const defaultOpenAccordions = index >= config.defaultOpenAccordions; return ( <Accordion defaultOpen={!defaultOpenAccordions} headerName={headerName} onChange={(open) => { publishAccordeonAnalytics(open, marketName); if (defaultOpenAccordions) { scrollToRef(positionReference); } }} id={marketName} > {children} {defaultOpenAccordions && <div data-testId="referenced-div" ref={positionReference} />} </Accordion> ); } 

Meine Tests fielen aus ... der Test ' scrollToRef ' schlägt fehl, weil Die scrollToRef Funktion scrollToRef keine private Komponentenmethode mehr. Dasselbe würde mit dem ' ' -Test passieren, aber es handelt sich um einen Import aus dem Modul, also ist er jetzt bestanden.


Um einen guten Test zu schreiben, muss ich verstehen, wie der Benutzer meine Komponente verwendet. Benutzer:


  1. Hab ein Akkordeon gefunden, das die Informationen enthält, die er braucht
  2. Klicken Sie auf den Namen des Akkordeons, um es zu öffnen
  3. Ich las ifna
  4. Geschlossenes Akkordeon


Mir wurde klar, dass es ihm egal ist, wie meine Komponente heißt, worauf sie klickt und so weiter. Nach diesem Prinzip sollte ich so etwas schreiben:


 import '@testing-library/jest-dom/extend-expect'; import { render, fireEvent, screen } from '@testing-library/react'; jest.mock('@myProject/analyticsHelpers'); describe('', () => { test('  ', () => { const child = <div></div>; //  № 10   const { getByText } = render( <Accordion headerName="  10" index={9}> {child} </Accordion> ); //   fireEvent.click(getByText(/  10/i)); expect(publishAccordeonAnalytics).toHaveBeenCalled(); expect(screen.queryByText('')).toBeInTheDocument(); expect(screen.getByTestId('referenced-div')).toBeInTheDocument(); //   fireEvent.click(getByText(/  10/i)); expect(publishAccordeonAnalytics).toHaveBeenCalled(); }); }); 

Jetzt habe ich das Nutzerverhalten nachgebildet. Ich fand das 10. Akkordeon, klickte darauf, las den Inhalt, schloss es - das war's!


Dieser Test ist visuell viel sauberer, kann Refactoring aushalten und simuliert die Benutzerinteraktion. Und es war viel einfacher für mich, sie zu schreiben.


Mithilfe dieses Musters können wir die Verwendung von nativen Funktionen Enzyme instance() , state() , find('ComponentName') und anderen Funktionen, die die Implementierung des Codes testen, vermeiden.


Für den neuen Test habe ich verwendet


Source: https://habr.com/ru/post/de485438/


All Articles