Mock useSearchParams react testing library

Viewed 1166

I have this custom hook

import { useLocation, useNavigate, useSearchParams } from "react-router-dom";

const useZRoutes = () => {
  const navigate = useNavigate();
  const { search, hash } = useLocation();
  const [searchParams, setSearchParams] = useSearchParams();

  return {
    getQueryParam: <T>(key: string): T | null => {
      if (searchParams.has(key)) {
        const value = searchParams.get(key);
        return value as unknown as T;
      }

      return null;
    },
    deleteQueryParam: (key: string): void => {
      if (searchParams.has(key)) {
        searchParams.delete(key);
        setSearchParams(searchParams);
      }
    },
    extendsNavigate: (pathname: string) => navigate({ pathname, search, hash }),
  };
};

export { useZRoutes };

Now, I need to test the getQueryParam function but I can't update the URL with query param.

I tried to mock useSearchParams with Object.defineProperty and with jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), // use actual for all non-hook parts useSearchParams: () => ("pid=123"), }));

and my test isn't passed. what should I do?

3 Answers

Instead of attempting to mock useSearchParams, I would recommend wrapping a component that is using your custom hook with a MemoryRouter and passing in your search params as initialEntries.

import { MemoryRouter } from 'react-router-dom'
import { render } from '@testing-library/react'

describe('My component using the useZRoutes hook', () => {    
  it('should do something', () => {
    render(
      <MemoryRouter initialEntries="?pid=123">
        <TestComponentUsingHook />
      </MemoryRouter>
    )
    // expect something
  })
})

Passing initialEntries only string we will have this error in Typescript

Type 'string' is not assignable to type 'InitialEntry[] | undefined'.ts(2322)
components.d.ts(9, 5): 
The expected type comes from property 'initialEntries' 
which is declared here on type 'IntrinsicAttributes & MemoryRouterProps'

instead of string, you can pass

["/path?pid=123"]

Mock useSearchParams

const searchParams = { "pid": "123"};
jest.mock('react-router-dom', () => ({
  ...(jest.requireActual('react-router-dom') as object),
  useSearchParams: () => [searchParams]
}));
Related