React组件中Jest无法校验二次回调数据的问题求助
我明白你的问题了——你的测试目前只能捕捉到第一次回调的"Loading",却拿不到请求完成后的响应数据,这是因为测试没有等待异步的fetch操作完成就结束了。下面来一步步解决这个问题:
问题根源
你原来的测试里,await button.simulate('click')其实起不到等待异步操作的作用:simulate是同步触发点击事件的,但fetch和后续的.then回调属于异步微任务,测试会在这些微任务执行前就结束,自然抓不到第二次回调的响应数据。而且直接在回调里写expect(data).toBe("some json response")会在第一次调用(传入"Loading")时就触发断言失败。
解决方案
1. 模拟fetch,避免真实网络请求
测试里依赖真实API请求既不稳定又慢,我们用Jest模拟fetch返回预设数据:
// 在测试文件顶部添加 global.fetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve([{ id: 1, name: "Mock Product" }]) // 替换成你期望的响应结构 }) );
2. 工具函数:等待所有异步微任务完成
我们需要一个小函数来让测试等待fetch的.then回调执行完毕:
const flushPromises = () => new Promise(resolve => setImmediate(resolve));
3. 修改测试逻辑,跟踪回调调用
改用jest.fn()创建一个mock回调函数,这样能方便地跟踪它的调用次数和参数,避免在第一次回调时就触发断言失败:
完整的修改后测试代码:
import React from 'react'; import { shallow, configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import Left from '../Boxes/Left.js'; configure({adapter: new Adapter()}); // 模拟fetch请求 global.fetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve([{ id: 1, name: "Mock Product" }]) }) ); // 等待所有异步微任务完成的工具函数 const flushPromises = () => new Promise(resolve => setImmediate(resolve)); it('When button is clicked, it first shows Loading then the response', async () => { // 创建mock回调,用于跟踪调用情况 const mockUpd = jest.fn(); const wrapper = shallow(<Left cb={mockUpd}/>); const button = wrapper.find('#button_id'); // 触发按钮点击 button.simulate('click'); // 断言第一次调用:传入"Loading" expect(mockUpd).toHaveBeenCalledWith("Loading"); // 等待fetch的异步操作及回调执行完成 await flushPromises(); // 断言第二次调用:传入响应数据的JSON字符串 expect(mockUpd).toHaveBeenCalledWith(JSON.stringify({ id: 1, name: "Mock Product" })); // 可选:断言回调总共被调用2次 expect(mockUpd).toHaveBeenCalledTimes(2); }); // 测试后清除mock,避免影响其他测试 afterEach(() => { jest.clearAllMocks(); });
这样调整后,测试就能正确捕捉到两次回调的参数,验证从"Loading"到响应内容的完整流程了。
内容的提问来源于stack exchange,提问作者Bharat
相关产品推荐
相关产品推荐

