如何在Jest测试中验证props传入的useState的set函数是否被调用?
解决React组件测试中setOrder未被调用的问题
问题背景
React组件中包含异步处理函数:
const changeOrder = () => { /* WebSocket 请求逻辑 */ }; const handleArrow = async () => { const res = await changeOrder(side, headingOrder, config); if (res !== undefined) setOrder(res); };
其中setOrder是通过props传入的useState更新函数。测试时希望验证setOrder是否被调用,但最后断言expect(setOrder).toHaveBeenCalled()失败,错误信息显示调用次数为0,且已确认res !== undefined条件成立。
测试代码如下:
// WebSocket Mock-up let ws: WS; beforeEach(async () => { ws = new WS("ws://localhost:8764", { jsonProtocol: true }); new WebsocketClient("localhost", 8764); await ws.connected; }); afterEach(() => { WS.clean(); }); describe("The ChangeOrderArrow component", () => { it("should render left arrow and can send a request to change the heading order", async () => { const setOrder = jest.fn(); render( <ChangeOrderArrow setOrder={setOrder} />, ); fireEvent.click(screen.getByTestId("left-heading-button")); const req: { request: RequestMessage } = (await ws.nextMessage) as { request: RequestMessage }; const uuid = req.request.path.split("/")[2]; expect(req.request.options.value).toEqual(359); act(() => { ws.send(responseChangeOrderArrow(uuid)); }); expect(setOrder).toHaveBeenCalled(); }); });
解决思路
1. 等待React异步更新完成
handleArrow是异步函数,WebSocket响应触发组件状态更新也是异步的,直接断言时React可能还未完成状态更新。改用waitFor包裹断言,等待异步操作完成:
import { waitFor } from '@testing-library/react'; // ... 其他代码不变 act(() => { ws.send(responseChangeOrderArrow(uuid)); }); await waitFor(() => { expect(setOrder).toHaveBeenCalled(); });
2. 检查act的覆盖范围
如果ws.send内部是异步触发组件更新,单纯用act包裹send可能无法覆盖后续的状态更新流程。可以将send和断言都放在waitFor中,或者确保所有状态更新都在act的作用域内。
3. 先隔离测试核心逻辑
暂时Mock掉changeOrder函数,直接返回预期值,测试handleArrow本身的逻辑是否正确,排除WebSocket的干扰:
it("should call setOrder when changeOrder returns a value", async () => { const setOrder = jest.fn(); const mockChangeOrder = jest.fn().mockResolvedValue({ /* 预期返回值 */ }); // 假设组件接收changeOrder作为props,或者通过其他方式注入mock render( <ChangeOrderArrow setOrder={setOrder} changeOrder={mockChangeOrder} />, ); fireEvent.click(screen.getByTestId("left-heading-button")); await waitFor(() => { expect(setOrder).toHaveBeenCalled(); }); });
4. 验证WebSocket响应是否正确触发changeOrder的返回
确认ws.send(responseChangeOrderArrow(uuid))发送的响应确实能被组件的WebSocket客户端正确接收,并触发changeOrder返回预期值。可以在测试中添加日志或者断点,检查响应是否被正确处理。
内容的提问来源于stack exchange,提问作者rahan
相关产品推荐
相关产品推荐

