'Mocking react-router-dom hooks using jest is not working

I'm using Enzyme's shallow method to test a component which uses the useParams hook to get an ID from the URL params.

I'm trying to mock the useParams hook so that it does't call the actual method, but it doesn't work. I'm still getting TypeError: Cannot read property 'match' of undefined, so it calls the actual useParams, and not my mock.

My component:

import React from 'react';
import { useParams } from 'react-router-dom';

export default () => {

  const { id } = useParams();

  return <div>{id}</div>;

};

Test:

import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import React from 'react';
import Header from './header';
import { shallow } from 'enzyme';

Enzyme.configure({ adapter: new Adapter() });

describe('<Header />', () => {

  jest.mock('react-router-dom', () => ({
    useParams: jest.fn().mockReturnValue({ id: '123' }),
  }));

  it('renders', () => {
    const wrapper = shallow(<Header />);
    expect(wrapper).toBeTruthy();
  });

});

Thank you!



Solution 1:[1]

This works for me to mock useParams and change values for each unit test within the same file:

import React from "react";
import { render } from "@testing-library/react";
import Router from "react-router-dom";
import Component from "./Component";

jest.mock("react-router-dom", () => ({
 ...jest.requireActual("react-router-dom"),
 useParams: jest.fn(),
}));

const createWrapper = () => {
 return render(<Cases />);
};

describe("Component Page", () => {
 describe("Rendering", () => {
   it("should render cases container", () => {
     jest.spyOn(Router, 'useParams').mockReturnValue({ id: '1234' })
     const wrapper = createWrapper();
     expect(wrapper).toMatchSnapshot();
   });

   it("should render details container", () => {
     jest.spyOn(Router, 'useParams').mockReturnValue({ id: '5678' })
     const wrapper = createWrapper();
     expect(wrapper).toMatchSnapshot();
   });
 });
});

Just declare useParams as jest.fn() outside describe() and then change its values in each unit test with jest.spyOn

Solution 2:[2]

I am not sure why, also couldn't find it in the docs of react-router library, but changing react-router-dom to react-router in both tests and implementation worked for me.

So it becomes something like this:

import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import React from 'react';
import Header from './header';
import { shallow } from 'enzyme';

Enzyme.configure({ adapter: new Adapter() });

describe('<Header />', () => {

  jest.mock('react-router', () => ({
    useParams: jest.fn().mockReturnValue({ id: '123' }),
  }));

  it('renders', () => {
    const wrapper = shallow(<Header />);
    expect(wrapper).toBeTruthy();
  });

});

Solution 3:[3]

I've had a similar problem, I solved it like this:

import { Route, Router } from "react-router-dom";
import { createMemoryHistory } from "history";

const renderWithRouter = (component) => {
  const history = createMemoryHistory({
    initialEntries: ["/part1/idValue1/part2/idValue2/part3"],
  });
  const Wrapper = ({ children }) => (
    <Router history={history}>
      <Route path="/part1/:id1/part2/:id2/part3">{children}</Route>
    </Router>
  );
  return {
    ...render(component, { wrapper: Wrapper }),
    history,
  };
};

describe("test", () => {
  it("test desc", async () => {
    const { getByText } = renderWithRouter(<MyComponent/>);
    expect(getByText("idValue1")).toBeTruthy();
  });
});

Solution 4:[4]

I tried this mock but it doesn't work to me. Error: Cannot read property 'match' of undefined. It seems the component is not inside a router so it cannot mock the match with params. It works to me:

import { MemoryRouter, Route } from 'react-router-dom';

const RenderWithRouter = ({ children }) => (
  <MemoryRouter initialEntries={['uri/Ineed']}>
    <Route path="route/Ineed/:paramId">{children}</Route>
  </MemoryRouter>
);
const tf = new TestFramework();
describe('<MyComponent />', () => {
  tf.init({ title: 'Some test' }, props =>
    shallow(
      <RenderWithRouter>
        <MyComponent {...props} />
      </RenderWithRouter>
    )
  );

  it('Some description', () => {
    const wrapper = tf.render().html();
    expect(wrapper).toContain('something');
  });
});

Solution 5:[5]

For me mocking react-router-dom fix the issue:

jest.mock('react-router-dom', () => ({
    useParams: jest.fn().mockReturnValue({ nifUuid: 'nif123' }),
    useHistory: jest.fn()
}));

Solution 6:[6]

I had the same issue. I mocked useParams like this:

jest.mock('react-router-dom', () => {
  return {
    useParams: () => ({
      id: '123'
    })
  }
})

Solution 7:[7]

You might be missing to add other keys of react-router-dom as is.

jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'),
  useParams: jest.fn().mockReturnValue({ id: '123' })
}));

Solution 8:[8]

I had the same issue. Calling the "cleanup" function from the "@testing-library/react" helps me:

import { cleanup } from '@testing-library/react';

afterEach(() => {
    cleanup();
});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Ivan
Solution 3 Dharman
Solution 4
Solution 5 Ankita Srivastava
Solution 6 mojave
Solution 7 backslashN
Solution 8 JulienD