📜 ⬆️ ⬇️

Unit testing of react components withRouter (jest, enzyme)

When developing unit tests for the react component wrapped with withRouter (Component), I encountered an error message that such a component can exist only in the context of a router. The solution to this problem is very simple and should not in theory cause any questions. Although for some reason links to the documentation https://reacttraining.com/react-router/web/guides/testing Google stubbornly refused to issue. It doesn’t surprise me at all. the documentation is written as a pure SPA application without any SSR there and from the point of view of the search engine it looks like this:

Display image
image

To whom enough documentation can on it finish reading. And for myself I will make a few notes under the cut.

The component being tested (paginator) takes as parameters the number of lines - total, per page and the current page number. It is necessary to create a component with links of the form:


import React from 'react'; import _ from 'lodash'; import { withRouter } from 'react-router-dom'; import Link from '../asyncLink'; // eslint-disable-line function prepareLink(match, page) { const { url } = match; const basePath = url.replace(/\/(page\/[0-9]+)?$/, ''); if (page === 1) { return basePath || '/'; } return `${basePath}/page/${page}`; } const Pagination = ({ count, pageLength, page, match }) => ( // eslint-disable-line react/prop-types, max-len count && pageLength && count > pageLength ? <nav> <ul className="pagination"> { _.range(1, 1 + Math.ceil(count / pageLength)).map(index => ( <li className={`page-item${index === page ? ' active' : ''}`} key={index}> <Link className="page-link" to={prepareLink(match, index)}> {index} </Link> </li>)) } </ul> </nav> : null ); export default withRouter(Pagination); 

This component uses the match property, which becomes available only for components that are wrapped with a withRouter(Pagination) call. When testing, you need to create a context using a special MemoryRouter router for testing. And also place the component in the appropriate Route route to form matches:
')
 /* eslint-disable no-undef, function-paren-newline */ import React from 'react'; import { MemoryRouter, Route } from 'react-router-dom'; import { configure, mount } from 'enzyme'; import renderer from 'react-test-renderer'; import Adapter from 'enzyme-adapter-react-16'; import Pagination from '../../../src/react/components/pagination'; configure({ adapter: new Adapter() }); test('Paginator snapshot', () => { const props = { count: 101, pageLength: 10, page: 10, }; const component = renderer.create( <MemoryRouter initialEntries={['/', '/page/10', '/next']} initialIndex={1}> <Route path="/page/:page"> <Pagination {...props} /> </Route> </MemoryRouter>, ); const tree = component.toJSON(); expect(tree).toMatchSnapshot(); }); test('Paginator for root route 1st page', () => { const props = { count: 101, pageLength: 10, page: 1, }; const component = mount( <MemoryRouter initialEntries={['/before', '/', '/next']} initialIndex={1}> <Route path="/"> <Pagination {...props} /> </Route> </MemoryRouter>, ); expect(component.find('li.active').find('a').prop('href')).toEqual('/'); expect(component.find('li').first().find('a').prop('href')).toEqual('/'); }); test('Paginator for root route 2nd page', () => { const props = { count: 101, pageLength: 10, page: 2, }; const component = mount( <MemoryRouter initialEntries={['/', '/page/2', '/next']} initialIndex={1}> <Route path="/page/:page"> <Pagination {...props} /> </Route> </MemoryRouter>, ); expect(component.find('li.active').find('a').prop('href')).toEqual('/page/2'); expect(component.find('li').first().find('a').prop('href')).toEqual('/'); }); test('Paginator for some route 1st page', () => { const props = { count: 101, pageLength: 10, page: 1, }; const component = mount( <MemoryRouter initialEntries={['/', '/some', '/next']} initialIndex={1} context={{}}> <Route path="/some"> <Pagination {...props} /> </Route> </MemoryRouter>, ); expect(component.find('li.active').find('a').prop('href')).toEqual('/some'); expect(component.find('li').first().find('a').prop('href')).toEqual('/some'); }); test('Paginator for /some route 2nd page', () => { const props = { count: 101, pageLength: 10, page: 2, }; const component = mount( <MemoryRouter initialEntries={['/', '/some/page/2', '/next']} initialIndex={1}> <Route path="/some/page/:page"> <Pagination {...props} /> </Route> </MemoryRouter>, ); expect(component.find('li.active').find('a').prop('href')).toEqual('/some/page/2'); expect(component.find('li').first().find('a').prop('href')).toEqual('/some'); }); 

MemoryRouter contains an “imaginary” component history, which can then be moved back and forth. The initial index is specified by the initialIndex property.

Tests use the popular library from airbnb - enzyme and run with the jest command.
The jest framework at the first launch generates a snapshot of the component with which it then checks the resulting document:

  const tree = component.toJSON(); expect(tree).toMatchSnapshot(); 

Enzyme library commands for searching DOM elements and analyzing them are not as concise as jquery. Nevertheless, everything is very convenient.

apapacy@gmail.com
March 5, 2018.

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


All Articles