Say I have the following component which I grabbed from https://www.codeday.top/2017/11/08/56644.html. Here I am using match.params to access the id. How would I write a unit test for this component tests the presence of the h2 element using Jest+Enzyme+Typescript+React.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Route, BrowserRouter as Router, Link, match } from 'react-router-dom';
// define React components for multiple pages
class Home extends React.Component<any, any> {
render() {
return (
<div>
<div>HOME</div>
<div><Link to='/details/id123'>Goto Details</Link></div>
</div>);
}
}
interface DetailParams {
id: string;
}
interface DetailsProps {
required: string;
match?: match<DetailParams>;
}
class Details extends React.Component<DetailsProps, any> {
render() {
const match = this.props.match;
if (match) {
return (
<div>
<h2>Details for {match.params.id}</h2>
<Link to='/'>Goto Home</Link>
</div>
);
} else {
return (
<div>
<div>Error Will Robinson</div>
<Link to='/'>Goto Home</Link>
</div>
)
}
}
}
ReactDOM.render(
<Router>
<div>
<Route exact path="/" component={Home} />
<Route exact path="/details/:id" component={(props) => <Details required="some string" {...props} />} />
</div>
</Router>
, document.getElementById('root')
);
You can use the createMemoryHistory function and Router component to test it. Create a memory history with initial entries to simulate the current location, this way we don't rely on the real browser environment. After firing the click event, assert the pathname is changed correctly or not.
Jest can be used without Enzyme to render components and test with snapshots, Enzyme simply adds additional functionality. Enzyme can be used without Jest, however Enzyme must be paired with another test runner if Jest is not used.
Route params are parameters whose values are set dynamically in a page's URL. This allows a route to render the same component while passing that component the dynamic portion of the URL, so that it can change its data based on the parameter.
Use containsMatchingElement
const wrapper = shallow(
<Details
required={true}
match={{params: {id: 1}, isExact: true, path: "", url: ""}}
/>
);
expect(wrapper.containsMatchingElement(<h2>Details for 1</h2>)).toBeTruthy();
Router exists in context, so you can wrap your tests in context and supply match params to it to test how your component picks them up.
import { BrowserRouter } from 'react-router-dom';
import { shape } from 'prop-types';
import { mount } from 'enzyme';
// Instantiate router context
const router = route => ({
history: new BrowserRouter().history,
route,
});
const createContext = route => ({
context: { ...router(route) },
childContextTypes: { router: shape({}) },
});
export function mountWrap(node, route) {
return mount(node, createContext(route));
}
Example describe:
import React from 'react';
import { TableC } from '../../src/tablec';
import { mountWrap, shallowWrap } from '../testhelp/contextWrap';
import { expectedProps } from './mockdata'
describe('Table', () => {
let props;
let component;
let route = {
location: {},
match: {[MATCH OBJ HERE]}
}
const wrappedMount = () => mountWrap(<TableC {...props} />, route);
beforeEach(() => {
props = {
query: {
data: tableData,
refetch: jest.fn(),
},
};
if (component) component.unmount();
});
test('should call a DeepTable with correct props', () => {
let route = {
location: {},
match: {[UPDATE MATCH OBJ HERE BEFORE TEST]}
}
const wrapper = wrappedMount();
expect(wrapper.find('DeepTable').props()).toEqual(expectedProps);
});
});
This also allows you to optionally add other things to context, and allows the top level object in the wrapper to be your component (as opposed to wrapping with BrowserRouter or StaticRouter)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With