How do you mock useLocation() pathname using shallow test enzyme Reactjs?

27,564

Solution 1

I know this isn’t a direct answer to your question, but if what you want is to test the browser location or history, you can use mount and add an extra Route at the end where you can “capture” the history and location objects.

test(`Foobar`, () => {
  let testHistory
  let testLocation

  const wrapper = mount(
    <MemoryRouter initialEntries={[`/`]}>
      <MyRoutes />
      <Route
        path={`*`}
        render={routeProps => {
          testHistory = routeProps.history
          testLocation = routeProps.location
          return null
        }}/>
    </MemoryRouter>
  )

  // Manipulate wrapper

  expect(testHistory)...
  expect(testLocation)...
)}

Solution 2

I found that I can mock the React Router hooks like useLocation using the following pattern:

import React from "react"
import ExampleComponent from "./ExampleComponent"
import { shallow } from "enzyme"

jest.mock("react-router-dom", () => ({
  ...jest.requireActual("react-router-dom"),
  useLocation: () => ({
    pathname: "localhost:3000/example/path"
  })
}));

describe("<ExampleComponent />", () => {
  it("should render ExampleComponent", () => {
    shallow(<ExampleComponent/>);
  });
});

If you have a call to useLocation in your ExampleComponent the above pattern should allow you to shallow render the component in an Enzyme / Jest test without error. Hope that helps!

Solution 3

I've been struggling with this recently too...

I found this works quite nicely:

import React from "react"
import ExampleComponent from "./ExampleComponent"
import { shallow } from "enzyme"

const mockUseLocationValue = {
    pathname: "/testroute",
    search: '',
    hash: '',
    state: null
}
jest.mock('react-router', () => ({
    ...jest.requireActual("react-router") as {},
    useLocation: jest.fn().mockImplementation(() => {
        return mockUseLocationValue;
    })
}));

describe("<ExampleComponent />", () => {
  it("should render ExampleComponent", () => {
    mockUseLocationValue.pathname = "test specific path";
    shallow(<ExampleComponent/>);
    ...
    expect(...
  });
});

this way, I was able to both mock useLocation and provide a value for pathname in specific tests as necessary.

HTH

Share:
27,564
purmo037
Author by

purmo037

Updated on November 18, 2021

Comments

  • purmo037
    purmo037 over 2 years

    I have header component like below:

    import { useLocation } from "react-router-dom";
    
    const Header = () => {
       let route = useLocation().pathname; 
       return route === "/user" ? <ComponentA /> : <ComponentB />;
    }
    

    How will you mock this useLocation() to get the path as user?

    I cant simply call the Header component as below in my test file as I am getting an error:

    TypeError: Cannot read property 'location' of undefined at useLocation

    describe("<Header/>", () => {
        it("call the header component", () => {
            const wrapper = shallow(<Header />);
            expect(wrapper.find(ComponentA)).toHaveLength(1);
        });
    });
    

    I have tried looking similar to the link How to test components using new react router hooks? but it didnt work.

    I have tried like below:

    const wrapper = shallow(
          <Provider store={store}>
            <MemoryRouter initialEntries={['/abc']}>
              <Switch>
                <AppRouter />
              </Switch>
            </MemoryRouter>
          </Provider>,
        );
        jestExpect(wrapper.find(AppRouter)
          .dive()
          .find(Route)
          .filter({path: '/abc'})
          .renderProp('render', { history: mockedHistory})
          .find(ContainerABC)
        ).toHaveLength(1);
    

    from the link Testing react-router with Shallow rendering but it didnt work.

    Please let me know.

    Thanks in advance.