我目前遇到一个情况,我想为我的自定义钩子编写单元测试,说
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() 只能在组件上下文中使用。
任何人都可以指出测试这种自定义挂钩的正确方法是什么?
您需要将测试环境包装在路由器上下文中(与真实路由器示例中的操作相同)
因此,您需要将钩子包装在提供必要上下文的功能组件中。
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');
});
});