Source:  Twitter logo

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

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();
22 users liked answer #0dislike answer #022
paibamboo profile pic
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)

4 users liked answer #1dislike answer #14
Steve Banton profile pic
Steve Banton
const wrapper = mount(
  <MemoryRouter initialEntries={['/1234']}>
    <Route exact path="/:id/" component={Details} />
  </MemoryRouter>
);
0 users liked answer #2dislike answer #20
Niranjan profile pic
Niranjan

Copyright © 2022 QueryThreads

All content on Query Threads is licensed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA 3.0).