You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Testing Library:订单项API调用失败测试问题修复

React Order组件API调用失败场景测试修复方案

问题描述

在测试Order组件的「View items」按钮API调用失败场景时,出现TypeError: Cannot read properties of undefined (reading 'items')错误,组件仍尝试处理未正确获取的订单项数组,无法渲染预期的错误提示。

问题原因

  1. Mock设置时机错误:原测试在beforeEach中已触发API调用,之后才设置mockRejectedValue,导致第一次API调用使用了默认mock实现(返回undefined),组件尝试访问order.items时报错。
  2. 组件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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 22:20:41