测试使用useEffect、useReducer的自定义hook时出现act警告如何解决
这个警告的产生原因是你使用的waitForNextUpdate没有自动将promise resolve后触发的dispatch状态更新包裹进React要求的act测试上下文,导致状态更新发生在React的测试追踪范围外,以下是三种可行的解决方法,按推荐优先级排序:
方案1:使用waitFor替代waitForNextUpdate(最推荐)
waitFor是测试库官方更推荐的异步等待工具,会自动将内部涉及的所有状态更新包裹在act中,同时会自动重试断言直到超时。你可以直接把原测试中的等待和断言逻辑合并,修改后测试代码如下:
// 先从测试库引入waitFor import { waitFor } from '@testing-library/react-hooks' describe('[Hook] useJobs', () => { const httpServiceInstance = new HttpService(); it.only('Should return jobs when response is successful', async () => { const response: IApiResponse<Job[]> = { status: 200, response: [mockJob()], }; jest .spyOn(httpServiceInstance, 'get') .mockImplementation(() => Promise.resolve(response)); const wrapper = ({ children }: { children?: React.ReactNode }) => ( <HttpContext.Provider value={httpServiceInstance}> {children} </HttpContext.Provider> ); const { result } = renderHook(() => useJobs(), { wrapper, }); // 替换原来的waitForNextUpdate + 单独断言 await waitFor(() => { expect(result.current).toEqual([mockJob()]); }) }); });
方案2:手动用act包裹异步等待逻辑
如果你暂时需要保留waitForNextUpdate的写法,可以手动用异步act包裹等待逻辑,强制将后续的状态更新纳入测试上下文:
import { act } from '@testing-library/react-hooks' // ...其他代码不变 const { result, waitForNextUpdate } = renderHook(() => useJobs(), { wrapper }); await act(async () => { await waitForNextUpdate(); }) expect(result.current).toEqual([mockJob()]);
方案3:React 18+项目迁移到官方内置的renderHook
如果你使用的是React 18及以上版本,@testing-library/react-hooks已经被官方废弃,你可以直接使用@testing-library/react内置的renderHook,新版本的测试工具会自动处理所有异步状态更新的act包裹,不需要额外手动修改逻辑即可消除警告。
额外优化提示:你的hook中httpService.get().then()的回调函数标记了async但内部没有任何await逻辑,可以把这个多余的async去掉,避免不必要的异步层级。
内容的提问来源于stack exchange,提问作者Lucas Ezequiel Ojeda
相关产品推荐
相关产品推荐

