使用 useLocation 开玩笑测试自定义钩子

问题描述 投票:0回答:1

我目前遇到一个情况,我想为我的自定义钩子编写单元测试,说

useMyHook
,其中称为
useLocation

一个简单的钩子案例就是……像这样:

import { useState, useEffect } from 'react'
import { useLocation } from 'react-router-dom'

const useMyHook = () => {
  const { pathname } = useLocation()
  const { myState, setMyState } = useState()
  useEffect(() => {
    switch(pathname) {
    case '/':
      setMyState('a')
      break
    case '/b':
      setMyState('b')
      break
    default:
      setMyState('c')
      break
    }
  }, [pathname])
  
  return myState
}

我的测试是这样的:

import { renderHook } from '@testing-library/react-hooks'
import useMyHook from '../useMyHook'

describe('useEventId', () => {
  it('path matches roleSelection', () => {
    jest.mock('react-router-dom', () => ({
      ...jest.requireActual('react-router-dom'), // since you still want to use the actual MemoryRouter
      useLocation: () => ({
        pathname: '/',
      }),
    }))
    const state = renderHook(() => useMyHook())
    expect(state).toBe('a')
  })
})

但是,我不断收到此错误:

useLocation() 只能在组件上下文中使用。

任何人都可以指出测试这种自定义挂钩的正确方法是什么?

javascript reactjs typescript react-hooks jestjs
1个回答
0
投票

您需要将测试环境包装在路由器上下文中(与真实路由器示例中的操作相同)

因此,您需要将钩子包装在提供必要上下文的功能组件中。

const wrapper = ({ children }) => <MemoryRouter>{children}</MemoryRouter>

这是代码的完整示例。

import React from 'react';
import { renderHook } from '@testing-library/react-hooks';
import { MemoryRouter } from 'react-router-dom';
import useMyHook from '../useMyHook';


const wrapper = ({ children }) => <MemoryRouter>{children}</MemoryRouter>;

describe('useMyHook', () => {
  it('returns "a" when pathname is "/"', () => {
    jest.mock('react-router-dom', () => ({
      ...jest.requireActual('react-router-dom'),
      useLocation: () => ({
        pathname: '/',
      }),
    }));

    // Use the custom wrapper to provide the router context
    const { result } = renderHook(() => useMyHook(), { wrapper });

    expect(result.current).toBe('a');
  });

  it('returns "b" when pathname is "/b"', () => {
    jest.mock('react-router-dom', () => ({
      ...jest.requireActual('react-router-dom'),
      useLocation: () => ({
        pathname: '/b',
      }),
    }));

    const { result } = renderHook(() => useMyHook(), { wrapper });

    expect(result.current).toBe('b');
  });

  it('returns "c" for other paths', () => {
    jest.mock('react-router-dom', () => ({
      ...jest.requireActual('react-router-dom'),
      useLocation: () => ({
        pathname: '/unknown',
      }),
    }));

    const { result } = renderHook(() => useMyHook(), { wrapper });

    expect(result.current).toBe('c');
  });
});
© www.soinside.com 2019 - 2024. All rights reserved.