The problem

If you happen to have Next.js useRouter hook in one of you're component to test, you have likely come across this error:

TypeError: Cannot destructure property `query` of 'undefined' or 'null'.
const { query, asPath } = useRouter();

During test the useRouter hooks returns null or undefined. There are different approach possible.

With a Higher Order Component (HOC)

The useRouter hook is basically a shortcut for accessing values from the RouterContext. Therefore in order to test a component with useRouter we need to wrap the component in a HOC with RouterContext.Provider component.

import React from 'react';
import { RouterContext } from 'next/dist/next-server/lib/router-context';

export const withTestRouter = (component, router) => {
  const {
    route = "",
    pathname = "",
    query = {},
    asPath = "",
    push = async () => true,
    replace = async () => true,
    reload = () => null,
    back = () => null,
    prefetch = async () => undefined,
    beforePopState = () => null,
    isFallback = false,
    events = {
      on: () => null,
      off: () => null,
      emit: () => null
    }
  } = router;

  return (
    <RouterContext.Provider value={{
      route,
      pathname,
      query,
      asPath,
      push,
      replace,
      reload,
      back,
      prefetch,
      beforePopState,
      isFallback,
      events
    }}>
      {component}
    </RouterContext.Provider>
  )
}

With jest.spyOn and mockImplementationOnce

With this approach we mock the implementation of useRouter with our own.

// SomeComponent.test.js
...

const useRouter = jest.spyOn(require('next/router'), 'useRouter');

useRouter.mockImplementationOnce(() => ({
  query: {page: 1, per_page: 10},
  asPath: '/posts'
}));
...