Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you test router match params with jest and enzyme?

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')
);
like image 988
vanegeek Avatar asked Feb 20 '18 22:02

vanegeek


People also ask

How do I test a route in jest?

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.

Should I use enzyme with jest?

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.

What is params React Router?

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.


2 Answers

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();
like image 147
paibamboo Avatar answered Sep 18 '22 11:09

paibamboo


Wrap All Tests In Context

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)

like image 39
Steve Banton Avatar answered Sep 17 '22 11:09

Steve Banton