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

26,760

Solution 1

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

Solution 2

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)

Share:
26,760
vanegeek
Author by

vanegeek

Updated on November 23, 2021

Comments

  • vanegeek
    vanegeek over 2 years

    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')
    );
    
  • SuperUberDuper
    SuperUberDuper about 5 years
    can you use path or url to set location or do you just use window.location = 'localhost:3000/foo'
  • SuperUberDuper
    SuperUberDuper about 5 years
    Do you have a typescript friendly version of that code for contextWrap.ts
  • paibamboo
    paibamboo about 5 years
    I think you just have to supply match prop. Converting from real url to match prop is the work of routing library so we don't need to test it.
  • aviya.developer
    aviya.developer almost 5 years
    @paibamboo Is there any method to create a match object instead of hard-coding it? LikecreateBrowserHistory()
  • paibamboo
    paibamboo almost 5 years
    Not that I'm aware of, this doc - github.com/ReactTraining/react-router/blob/master/packages/… - just tells us how to use it, not how to create it.
  • RubbelDieKatz
    RubbelDieKatz over 4 years
    For ES7, use a spread operator on router(route), i. e. ...router(route).
  • tdy
    tdy over 2 years
    Please consider adding a brief explanation of how and why this solves the problem. This will help readers to better understand your solution.