如何在Jest中测试React组件内链式调用的useEffect钩子
解决方案
你的测试思路没有问题,无法触发第二个useEffect的核心原因是你mock的XMLHttpRequest没有正确执行onload回调,导致setList状态更新逻辑没有运行,自然不会触发依赖list的第二个useEffect。
你可以按照以下步骤调整你的mock逻辑:
1. 完善XHR mock结构
需要确保你mock的XHR实例允许挂载onload回调,且预置好模拟的响应数据,示例如下(以Jest测试框架为例):
// 测试用例前置逻辑中完成XHR mock const mockXHRInstance = { open: jest.fn(), send: jest.fn(), status: 200, response: JSON.stringify({ list: [{ name: "选项A" }, { name: "选项B" }] // 你需要模拟的返回列表数据 }) }; window.XMLHttpRequest = jest.fn(() => mockXHRInstance);
2. 主动触发onload回调
当你模拟input输入事件、触发第一个useEffect执行后,手动调用你挂载在mock XHR实例上的onload回调,模拟请求成功返回的场景:
// 第一步:模拟用户输入,触发第一个useEffect const inputEl = screen.getByRole("textbox"); fireEvent.change(inputEl, { target: { value: "触发请求的输入值" } }); // 第二步:主动执行XHR的onload回调,触发内部setList逻辑 mockXHRInstance.onload({ target: mockXHRInstance } as ProgressEvent);
3. 等待状态更新落地后断言
因为React的状态更新和useEffect执行是异步批量处理的,建议用waitFor包裹后续的断言逻辑,确保第二个useEffect已经执行完成、select DOM已经更新:
await waitFor(() => { const optionEls = screen.getAllByRole("option"); // 验证选项数量:1个默认占位选项 + 2个模拟返回的选项 expect(optionEls).toHaveLength(3); expect(screen.getByText("选项A")).toBeInTheDocument(); });
额外排查点
如果调整后依然无法触发,可检查两个常见问题:
- 你mock的XHR实例是否是每次
new XMLHttpRequest时返回的同一个对象,确保onload回调是挂载到你能控制的实例上 - 确认你模拟的响应
status符合代码中>=200 && <400的判断条件,避免进入异常分支没有执行setList
内容的提问来源于stack exchange,提问作者charcole
相关产品推荐
相关产品推荐

