Menguji Komponen UI Bereaksi

Apa yang saya lakukan sekarang


Saat ini saya sedang menguji implementasi kode. Tes semacam itu pecah setiap kali setelah refactoring, terutama di komponen antarmuka pengguna. Akibatnya, saya menghabiskan banyak waktu untuk menggali file .test.js , secara simultan mengikuti angka ajaib 80% untuk Cakupan Tes .


Apa yang harus saya lakukan


Saat menulis segala jenis tes, termasuk pengujian unit, saya harus kurang memikirkan kode yang saya uji, dan lebih banyak tentang apa yang dilakukan kode ini. Ini berarti menulis tes yang meniru perilaku pengguna. Bahkan di level terendah.


Contoh


Bayangkan komponen akordeon yuy standar. Saat ditekan, itu membuka atau menutup. Konten diteruskan ke komponen sebagai children - children .


gambar


Fungsionalitas komponen pengujian kami adalah sebagai berikut:


  • 3 akordion pertama dikerahkan, semua yang tersisa ditutup.
  • Ketika Anda mengklik pada akordeon, modul publishAccordionAnalytics , yang melacak analitik. Kami mengimpor modul ini dari paket @myProject/analyticsHelpers
  • Jika pengguna mengklik pada akordeon tersembunyi di bagian bawah aplikasi, dan setelah membuka konten akordion tidak di bidang tampilan pengguna, animasi dipicu dan konten komponen bergerak ke bagian layar yang terlihat.

 ... 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> ); } } 

Bagaimana saya akan menulis tes sekarang:


 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(); }) }); 

Saya menguji struktur komponen menggunakan snapshots, serta panggilan fungsi saat klik.


Akordeon ini sepenuhnya memenuhi fungsionalitas yang diharapkan dan pengujian mengonfirmasi hal ini. Tapi sekarang saya akan melakukan refactoring, mengganti React.Component dengan functional component , dan scrollToRef komponen scrollToRef dalam fungsi terpisah.


 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> ); } 

Tes saya jatuh ... fungsi tes ' scrollToRef ' gagal karena Fungsi scrollToRef tidak lagi menjadi metode pribadi komponen. Hal yang sama akan terjadi dengan tes ' ' , tetapi ini merupakan impor dari modul, jadi sekarang sudah lulus.


Untuk menulis tes yang bagus, saya perlu memahami bagaimana pengguna menggunakan komponen saya. Pengguna:


  1. Menemukan akordeon yang berisi informasi yang dia butuhkan
  2. Klik pada nama akordeon untuk membukanya
  3. Saya membaca ifna
  4. Akordeon tertutup


Saya menyadari bahwa dia tidak peduli apa yang disebut komponen saya, apa yang diklik, dan sebagainya. Mengikuti prinsip ini, saya harus menulis sesuatu seperti ini:


 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(); }); }); 

Sekarang saya telah mereproduksi perilaku pengguna. Saya menemukan akordeon ke-10, mengkliknya, membaca kontennya, menutupnya - itu dia!


Tes ini secara visual jauh lebih bersih, dapat menahan refactoring dan mensimulasikan interaksi pengguna. Dan jauh lebih mudah bagi saya untuk menulisnya.


Dengan menggunakan pola ini, kita dapat menghindari penggunaan instance() Enzyme asli instance() , state() , find('ComponentName') dan fungsi-fungsi lain yang menguji implementasi kode.


Untuk tes baru, saya menggunakan


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


All Articles