Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I have a component that has props which extend RouteComponentProps that looks like this:

export interface RouteComponentProps<P> {
  match: match<P>;
  location: H.Location;
  history: H.History;
  staticContext?: any;

Now, when I use my component in the app, I pass these props to it:

<MyComponent
    match={this.props.match}
    location={this.props.location}
    history={this.props.history}

The props are available already because it's running inside react router.

Now, how do I test this component without match, location, history available?

Do I need to mock them or is it supposed to somehow automatically load them with some helper function?

To answer your last question, the recommended approach is to use <MemoryRouter>< *your component here* ></MemoryRouter> in your tests. Typescript does not pick up that this component will pass the required props to your component, as such I assume it not to be a type safe approach.

This is for React Router v4 and doesn't apply to previous versions.

For a typesafe method to test components that are wrapped with the HOC withRouter you can build the location, history and match from the react-router and history packages.

This example uses enzyme and snapshot testing but could just as easily be any other test.

This avoided me needing to use <MemoryRouter> as a wrapper that typescript did not like anyhow.

// Other imports here
import { createMemoryHistory, createLocation } from 'history';
import { match } from 'react-router';
const history = createMemoryHistory();
const path = `/route/:id`;
const match: match<{ id: string }> = {
    isExact: false,
    path,
    url: path.replace(':id', '1'),
    params: { id: "1" }
const location = createLocation(match.url);
test('shallow render', () => {
    const wrapper = shallow(
        <MyComponent history={history}
                     location={location}
                     match={match} />
    expect(wrapper).toMatchSnapshot();

CAUTION Do not use this to test implementation detail, it can be tempting but it will cause you a lot of pain should you want to refactor.

Making a helper for this would probably be the best way to make this re-usable.

import { createLocation, createMemoryHistory } from 'history';
import { match as routerMatch } from 'react-router';
type MatchParameter<Params> = { [K in keyof Params]?: string };
export const routerTestProps = <Params extends MatchParameter<Params> = {}>
    (path: string, params: Params, extendMatch: Partial<routerMatch<any>> = {}) => {
        const match: routerMatch<Params> = Object.assign({}, {
            isExact: false,
            path,
            url: generateUrl(path, params),
            params
        }, extendMatch);
        const history = createMemoryHistory();
        const location = createLocation(match.url);
        return { history, location, match };
const generateUrl = <Params extends MatchParameter<Params>>
    (path: string, params: Params): string => {
        let tempPath = path;
        for (const param in params) {
            if (params.hasOwnProperty(param)) {
                const value = params[param];
                tempPath = tempPath.replace(
                    `:${param}`, value as NonNullable<typeof value>
        return tempPath;

Now we can just use the routerTestProps function in our tests

const { history, location, match } = routerTestProps('/route/:id', { id: '1' });

A gentleman by the name of Timmy Huang provided a solution that involves a simple mock...

https://spectrum.chat/react/help/how-do-you-test-components-that-use-routecomponentprops~495fe95b-6925-4e7f-bfe8-65a737c5d24e?m=MTU4Mjk1MjQ4ODQ0MA==

const routeComponentPropsMock = {
  history: {} as any,
  location: {} as any,
  match: {} as any,

I tried this using Jest and it worked. My component had this signature...

export const MyComponent: React.FC<RouteComponentProps> = ({location}:RouteComponentProps) => {

My basic test to confirm the component loads then looked like this...

function renderMyComponent() {
  return render(
    <MyComponent {...routeComponentPropsMock}/>

I have been looking for a good solution to this. I was hoping I could do it in the mapStateToProps function or something simular, but have not been able to do this yet.

The best I could do was mock this out and pass in the match, location and history. I used the following:

import { RouteComponentProps } from 'react-router'
import { match } from 'react-router-dom';
import {UnregisterCallback, Href} from 'history'
export function getMockRouterProps<P>(data: P) {
    var location: {
            hash: "",
            key: "",
            pathname: "",
            search: "",
            state: {}
    var props: RouteComponentProps<P> = {
    match: {
            isExact: true,
            params: data,
            path: "",
            url: ""
        location: location,
        history: {
            length:2,
            action:"POP",
            location: location,
            push: () => {},
            replace: () => {},
            go: (num) => {},
            goBack: () => {},
            goForward: () => {},
            block: (t) => {
                var temp: UnregisterCallback = null;
                return temp;
            createHref: (t) => {
                var temp: Href = "";
                return temp;
            listen: (t) => {
                var temp: UnregisterCallback = null;
                return temp;
        staticContext: {
    return props;

Then in my test I did:

    var routerProps = getMockRouterProps<ReduxTestComponentProps>(null);
    const wrapper = mount<ReduxTestComponent, ReduxTestComponentState>(
            <ReduxTestComponent
                history={routerProps.history}
                location={routerProps.location}
                match={routerProps.match}
                isLoadingTodo={false}
                todos={todos}
                addAsyncTodoActionDispatch={() => mockTodoAddDispatch()}
                deleteTodoActionDispatch={() => mockTodoDeleteDispatch()}

I used a solution similar to another answer; construct the props using a helper.) My helper uses path-to-regexp's compile:

import { createLocation } from "history";
import { compile } from "path-to-regexp";
import { match } from "react-router";
 * Makes RouteComponentProps.
 * @param path The parameterized react-router path: `/p/:id`.
 * @param params the parameters to substitute in the path: `{id: "123"}`.
export function makeRouteComponentProps<T extends Record<string, string>>(
  path: string,
  params: T
  const toUrl = compile(path, { encode: encodeURIComponent });
  const url = toUrl(params);
  const match: match<T> = {
    isExact: false,
    path,
    params,
  const location = createLocation(match.url);
  return { match, location };

Use it like this in a test:

    const history = createMemoryHistory();
    const { location, match } = makeRouteComponentProps(
      "p/:rootTargetId/:slug",
        rootTargetId: proposition.id,
        slug: toSlug(proposition.text),
    // Act
    const { container } = renderWithProviders(
      <JustificationsPage
        rootTargetType={"PROPOSITION"}
        history={history}
        location={location}
        match={match}
      { history }

Where renderWithProviders is like suggested in the redux docs:

import React, { PropsWithChildren } from "react";
import { render } from "@testing-library/react";
import type { RenderOptions } from "@testing-library/react";
import type { PreloadedState } from "@reduxjs/toolkit";
import { Provider } from "react-redux";
import { Router } from "react-router-dom";
import { createMemoryHistory, History } from "history";
import { persistStore, PersistorOptions } from "redux-persist";
import type { AppStore, RootState } from "./setupStore";
import { setupStore } from "./setupStore";
interface ExtendedRenderOptions extends Omit<RenderOptions, "queries"> {
  preloadedState?: PreloadedState<RootState>;
  store?: AppStore;
  persist?: boolean;
  history?: History<any>;
export function renderWithProviders(
  ui: React.ReactElement,
    preloadedState = {},
    store = setupStore(preloadedState),
    persist = true,
    history = createMemoryHistory(),
    ...renderOptions
  }: ExtendedRenderOptions = {}
  const persistor = persistStore(store, {
    manualPersist: true,
  } as PersistorOptions);
  if (persist) {
    persistor.persist();
  function Wrapper({
    children,
  }: PropsWithChildren<Record<string, unknown>>): JSX.Element {
    return (
      <Provider store={store}>
        <Router history={history}>{children}</Router>
      </Provider>
  return {
    store,
    persistor,
    history,
    ...render(ui, { wrapper: Wrapper, ...renderOptions }),

Regarding createLocation missing from history@5, this comment suggests that parsePath could be used as a replacement, but I didn't look into it since I'm still on v4.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.