'How to use MemoryRouter in order to test useParams call

I have a hypothetic React component named Component.ts with a code structure similar to that:


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

export const Guide: FC<{}> = () => {

  const { serviceId } = useParams();

  return (
    <p>{serviceId}</p>
  )

}

In order to test the behaviour of this component I was trying to do something similar to the following in my Component.test.ts file:


import React from 'react';
import { render } from '@testing-library/react';
import { Component } from './Component';
import { Route, MemoryRouter } from 'react-router-dom';


test('my Component test', async () => {

  const someServiceId = 'some-service-id';

  const { findByText } = render(
    <MemoryRouter initialEntries={[`guides/${someServiceId}`]}>
      <Route path='guides/:serviceId'> 
        <Guide />
      </Route>
    </MemoryRouter> 
  );
      
  expect(await findByText(someServiceId)).toBeInTheDocument();

});

My tests were working when I was using version 5.2.2 of react-router-dom but it is failing since I updated to 6.0.0-beta.0. Jest is showing up the following message when running the tests:

Relative pathnames are not supported in createMemoryHistory({ initialEntries }) (invalid entry: "guides/some-service-id")


Solution 1:[1]

After much searching, I found the answer in the test suite.

The trick in 6.0.0-beta.0 is to wrap your <Route />'s in <Routes />. Also note the components are imported from react-router instead of react-router-dom:

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

test('my Component test', async () => {
  const someServiceId = 'some-service-id';

  const { findByText } = render(
    <MemoryRouter initialEntries={[`guides/${someServiceId}`]}>
      <Routes>
        <Route path='guides/:serviceId'> 
          <Guide />
        </Route>
      </Routes>
    </MemoryRouter> 
  );
      
  await waitFor(() => expect(findByText(someServiceId)).toBeInTheDocument());
});

Solution 2:[2]

this worked for me

import WarehouseDetailsComponent from '../../containers/WarehouseDetailsPage'
import { render} from '@testing-library/react'
import { Route, MemoryRouter, Routes } from 'react-router-dom'

describe('WarehouseDetails', () => {
  test('should display warehouse and user details', async () => {
    render(
      <MemoryRouter initialEntries={['explore/1234']}>
        <Routes>
          <Route path="/explore/:id" element={<WarehouseDetailsComponent />} />
        </Routes>
      </MemoryRouter>
    )

  // assertions
})

Solution 3:[3]

MemoryRouter didn't worked for me

I was receiving this as warn:

  1. Relative pathnames are not supported in createMemoryHistory({ initialEntries }) (invalid entry: "my-route/15")
  2. No routes matched location "my-route/15"

So I figured it as a good option and worked for me.

import { render, screen, waitFor } from '@testing-library/react';
import { BrowserRouter as Router, Navigate, Route, Routes } from 'react-router-dom';
import { Provider } from 'react-redux';
import { store } from '../../Redux/store';

import MyComponent from './index';

describe('My component test', () => {
  it('should access right route', async () => {
    render(
      <Provider store={store}>
        <Router>
          <Routes>
            <Route path="/" element={<Navigate to="/my-route/15" replace />} />
            <Route path="/my-route/:id" element={<MyComponent />} />
          </Routes>
        </Router>
      </Provider>,
    );

    await waitFor(() => {
      expect(screen.getByText('Something should be rendered')).toBeInTheDocument();
    });
  });
});

Solution 4:[4]

MemoryRouter worked for me. See the example below.

import { cleanup, render, screen } from "@testing-library/react"
import { QueryClient, QueryClientProvider } from "react-query";
import Card from "../../../components/Card"
import { MemoryRouter } from "react-router-dom";
import { Route } from "react-router-dom";
import { create } from "react-test-renderer";

describe("test card component", () => {

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

  const mockItem = {
    name: "Test",
    summary: "This is test summary",
  }

  const MockComponent = () => {
    const queryClient = new QueryClient();
    const id = '12';

    return (
      <QueryClientProvider client={queryClient}>
        <MemoryRouter initialEntries={[`post/${id}`]}>
          <Route path='post/:id'>
            <Card data={mockItem} />
          </Route>
        </MemoryRouter>
      </QueryClientProvider>
    )
  }
  const setup = () => {
    return render(<MockComponent />);
  }

  it("should render the component", () => {
    setup()
    const cardElement = screen.getByTestId('card')
    expect(cardElement).toBeInTheDocument();
    expect(cardElement).toHaveTextContent(mockItem.name)
    expect(cardElement).toHaveTextContent(mockItem.summary)
  })

  it("should match the snapshot", () => {
    const tree = create(<MockComponent />).toJSON();

    expect(tree).toMatchSnapshot();
  })
})

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 likesalmon
Solution 2
Solution 3 Felipe Ernesto Schmidt
Solution 4 shreejana