Reactjs 如何用酶测试自定义useFetch钩子
那里 我这里有一个useFetch,它将使用useReducer触发组件的状态更改两次Reactjs 如何用酶测试自定义useFetch钩子,reactjs,unit-testing,jestjs,enzyme,react-hooks,Reactjs,Unit Testing,Jestjs,Enzyme,React Hooks,那里 我这里有一个useFetch,它将使用useReducer触发组件的状态更改两次 type AsyncType = 'INIT' | 'PENDING' | 'RESOLVED' | 'REJECTED' | 'REDIRECTED' type AsyncAction = | { type: 'PENDING' } | { type: 'RESOLVED'; data: any } | { type: 'REJECTED'; error: Error } | { type
type AsyncType = 'INIT' | 'PENDING' | 'RESOLVED' | 'REJECTED' | 'REDIRECTED'
type AsyncAction =
| { type: 'PENDING' }
| { type: 'RESOLVED'; data: any }
| { type: 'REJECTED'; error: Error }
| { type: 'REDIRECTED' }
interface AsyncState {
data?: any
error?: Error
type: AsyncType
}
const dataFetchReducer = (
state: AsyncState,
action: AsyncAction
): AsyncState => {
switch (action.type) {
case 'PENDING':
return {
...state,
type: 'PENDING',
}
case 'RESOLVED':
return {
...state,
type: 'RESOLVED',
data: action.data,
}
// We can choose to ignore it, retry it or throw it to let the error boundary to catch it.
case 'REJECTED':
return {
...state,
type: 'REJECTED',
error: action.error,
}
case 'REDIRECTED':
return {
...state,
type: 'REDIRECTED',
}
default:
throw new Error()
}
}
// We can ignore the input if we don't want it to fetch new data when the component just mounted
export const useFetch = (
initialRequestConfig?: AxiosRequestConfig,
initialData?: any
): [AsyncState, Dispatch<AxiosRequestConfig>] => {
const [requestConfig, setRequestConfig] = useState(initialRequestConfig)
const [state, dispatch] = useReducer<typeof dataFetchReducer>(
dataFetchReducer,
{
type: 'INIT',
data: initialData,
}
)
useEffect(() => {
if (!requestConfig) return
let didCancel = false
const fetchData = async () => {
dispatch({ type: 'PENDING' })
try {
const result = await axios(requestConfig)
if (!didCancel) {
dispatch({ type: 'RESOLVED', data: result.data })
}
} catch (error) {
if (!didCancel) {
if (
error.response &&
error.response.data &&
error.response.data.redirect
) {
dispatch({ type: 'REDIRECTED' })
} else {
dispatch({ type: 'REJECTED', error })
}
}
}
}
fetchData()
return () => {
didCancel = true
}
}, [requestConfig])
return [state, setRequestConfig]
}
我试着像这样测试我的组件
export const PrivateRoute: FC<RouteProps> = ({
component: Component,
...rest
}) => {
const [state] = useFetch(api.getUser()) // the api with only return the axios config, like this: { method: "GET", url: '/user' }
if (!Component) return null
console.log(state)
return (
<Route
{...rest}
render={props =>
state.type === 'PENDING' ? (
<p>Loading</p>
) : state.type === 'RESOLVED' ? (
<Component {...props} />
) : state.type === 'REJECTED' ? (
<Error err={state.error} />
) : null
}
/>
)
}
import axios, { AxiosStatic } from 'axios'
interface AxiosMock extends AxiosStatic {
mockResolvedValue: Function
mockRejectedValue: Function
}
jest.mock('axios')
const mockedAxios = axios as AxiosMock
it('renders without crashing', async () => {
const MockComp = () => <p>Test</p>
mockedAxios.mockResolvedValue({ data: { user: 'caso' } })
let wrapper
await act(() => {
wrapper = mount(
<MemoryRouter initialEntries={['/random']}>
<PrivateRoute path="/" component={MockComp} />
</MemoryRouter>
)
wrapper.update() // wherever I put the update, the wrapper is always loading
})
console.log(wrapper.debug()) // this line will always be loading
expect(wrapper.find(Route).prop('path')).toBe('/')
})
it('renderingwithwithcrashing',async()=>{
常量MockComp=()=>测试
mockedAxios.mockResolvedValue({data:{user:'caso'}})
让包装器
等待行动(()=>{
包装=装载(
)
wrapper.update()//无论我把更新放在哪里,包装器总是在加载
})
console.log(wrapper.debug())//将始终加载此行
expect(wrapper.find(Route.prop('path')).toBe('/'))
})
总会有这样的警告
警告:测试中对PrivateRoute的更新未包装在act(…)中。
我不知道什么是测试它的正确方法。我花了两天的时间。有人知道什么是测试它的正确方法吗?我已经升级到react 16.9,我刚刚找到了最好的解决方案,我们可以使用jest模拟
useFetch
,我们只需返回模拟状态并测试渲染结果