How to mock RouterContextProvider?

I’m using useRoutePath() in my component. When I run tests I get following error:


Is there a standard way to mock RouterContextProvider? There are LocationProvider and ParamsProvider that can be used in the tests, but I couldn’t find anything similar for useRoutePath().

Hello
@iam, I know its been a while but i just encountered this problem and was able to get around that same problem. here is how i did it, hope it helps you, or anyone else.

I needed a helper to pass in parameters only when the route need them, so i wrote this:

# useRouteHelper.ts

import { useMemo } from 'react'

import { routes, useRoutePaths, QueryParams } from '@redwoodjs/router'

const useRouteHelper = () => {
  const routePaths = useRoutePaths()

  const getRoute = useMemo(() => {
    return (to: string, params: QueryParams = {}) => {
      if (!routePaths[to]) {
        return ''
      }

      // If the route has a parameter, pass it in
      if (routePaths[to].includes('{')) {
        return routes[to](params)
      }
      // Otherwise, just return the route
      return routes[to]()
    }
  }, [routePaths])

  return { getRoute }
}

export default useRouteHelper

the test looks like this, notice how I mocked the router, kept most of the actual implementation, but replaced the useRoutePaths hook, and routes, in your case you can mock the hooks that you need.

# useRouteHelper.test.ts

import { routes } from '@redwoodjs/router'
import { renderHook } from '@redwoodjs/testing/web'

import useRouteHelper from './useRouteHelper'

jest.mock('@redwoodjs/router', () => ({
  ...jest.requireActual('@redwoodjs/router'),
  useRoutePaths: jest.fn(() => ({
    signup: '/signup',
    dashboard: '/{orgSlug}/dashboard',
    editUser: '/{orgSlug}/users/{id:Int}/edit',
    users: '/{orgSlug}/users',
  })),
  routes: {
    signup: jest.fn(() => '/signup'),
    dashboard: jest.fn(({ orgSlug }) => `/${orgSlug}/dashboard`),
    editUser: jest.fn(({ orgSlug, id }) => `/${orgSlug}/users/${id}/edit`),
    users: jest.fn(({ orgSlug }) => `/${orgSlug}/users`),
  },
}))

describe('useRouteHelper', () => {
  it('returns empty string if route does not exist', () => {
    const { result } = renderHook(() => useRouteHelper())
    const { getRoute } = result.current

    expect(getRoute('nonExistentRoute')).toBe('')
  })

  it('returns route with params if route includes parameter', () => {
    const { result } = renderHook(() => useRouteHelper())
    const { getRoute } = result.current

    getRoute('editUser', { orgSlug: 'test-org', id: 1 })
    expect(routes.editUser).toHaveBeenCalledWith({ orgSlug: 'test-org', id: 1 })
  })
  it('returns route without params if route does include unneeded parameters', () => {
    const { result } = renderHook(() => useRouteHelper())
    const { getRoute } = result.current

    getRoute('signup', { orgSlug: 'test-org', id: 1 })
    expect(routes.signup).toHaveBeenCalledWith()
  })

  it('returns route without params if route does not include parameter', () => {
    const { result } = renderHook(() => useRouteHelper())
    const { getRoute } = result.current

    getRoute('signup')
    expect(routes.signup).toHaveBeenCalled()
  })
})

Also, I would be very interested in know how you solved it!

Thank you for the reply. Basically I did the same way:


I was hoping there is something out of the box that can be reused and doesn’t require mocking the router module in every test file.