React Testing Library:订单项API调用失败测试问题修复
React Order组件API调用失败场景测试修复方案
问题描述
在测试Order组件的「View items」按钮API调用失败场景时,出现TypeError: Cannot read properties of undefined (reading 'items')错误,组件仍尝试处理未正确获取的订单项数组,无法渲染预期的错误提示。
问题原因
- Mock设置时机错误:原测试在
beforeEach中已触发API调用,之后才设置mockRejectedValue,导致第一次API调用使用了默认mock实现(返回undefined),组件尝试访问order.items时报错。 - 组件catch逻辑缺失:
fetchOrderItems函数的catch块未设置isLoadingItems为false,会导致组件一直停留在加载状态,无法切换到错误提示渲染。
修复方案
1. 修复组件的错误处理逻辑
修改fetchOrderItems函数,在catch块中添加加载状态重置:
const fetchOrderItems = async() => { setIsLoadingItems(true); try { let order = await Server.getOrders(id); setItems(order.items); setIsLoadingItems(false); } catch (err) { setError(true); setIsLoadingItems(false); // 新增:重置加载状态 console.log(err); } }
2. 调整测试用例结构
将成功/失败场景拆分,确保每个测试用例的mock设置在触发API调用前完成:
import { render, fireEvent, screen } from "@testing-library/react"; import Order from "../../../components/Primary/Orders/Order"; import { Customer } from "../../../api/Server"; import { orders } from "../../util/dataMock"; const Server = Customer.orders; describe("Order", () => { describe("View items button", () => { const mockGetOrders = jest.spyOn(Server, "getOrders"); // 成功场景测试 describe("when API call succeeds", () => { beforeEach(() => { // 提前设置成功mock返回 mockGetOrders.mockResolvedValue({ items: [{ productId: 1, name: "Test Product", quantity: 1, totalCost: 100 }] }); const { getAllByRole } = render(<Order details={orders[2]} />); fireEvent.click(getAllByRole("button")[0]); }); test("triggers API call when clicked", () => { expect(mockGetOrders).toBeCalled(); }); test("renders loading skeleton during API call", () => { expect(screen.getByTestId("order-items-loading")).toBeInTheDocument(); }); }); // 失败场景单独测试 test("renders error message if API call fails", async () => { // 提前设置失败mock mockGetOrders.mockRejectedValue("Error: An unknown error occurred. Kindly try again."); const { getAllByRole } = render(<Order details={orders[2]} />); fireEvent.click(getAllByRole("button")[0]); // 等待异步错误提示渲染 const errorMsg = await screen.findByText( "An error occurred loading order items. Kindly refresh the page and try again." ); expect(errorMsg).toBeInTheDocument(); // 验证加载状态已重置 expect(screen.queryByTestId("order-items-loading")).not.toBeInTheDocument(); }); }); test("calls cancelOrder when button is clicked", () => { const clickMock = jest.fn(); const { getAllByRole } = render(<Order details={orders[2]} cancelOrder={clickMock} />); fireEvent.click(getAllByRole("button")[1]); expect(clickMock).toBeCalled(); }); });
关键修改说明
- 拆分测试场景:将成功/失败测试分离,避免mock行为互相干扰。
- 提前设置mock:确保API调用触发前,mock的拒绝/成功状态已配置完成。
- 完善组件错误状态:重置加载状态,保证错误提示能正常渲染。
内容的提问来源于stack exchange,提问作者Davy Kamanzi
相关产品推荐
相关产品推荐

