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

React测试中spyOn多mock失效:desc测试始终不生效如何解决?

问题:CandidatesTableHeader组件desc类名测试不生效

我需要根据urlSearchParams中的order值,给<CandidatesTableHeader/>组件添加对应类名,但测试时desc场景始终不生效,返回值一直是asc。

测试代码

describe("<CandidatesTableHeader/>", function () {
    beforeEach(() => {
        jest
            .spyOn(useSearchParams, "useSearchParams")
            .mockReturnValueOnce([{
                get: (name: string): string => 'asc',
            }] as any)
            .mockReturnValueOnce([{
                get: (name: string): string => 'desc',
            }] as any);
    });

    it("Candidates table header should have asc class if it exists in urlParams", async () => {
        customRender(<CandidatesTableHeader columns={mockedColumns}/>);

        const tableHeader = await screen.findByTestId(TestIds.CandidatesTableHeaderSortable);
        const orderBlock = await screen.findByTestId(TestIds.CandidatesTableHeaderOrder);

        fireEvent.click(tableHeader);
        expect(orderBlock).toHaveClass('asc');

    });

    it("Candidates table header should have desc class if it exists in urlParams", async () => {
        customRender(<CandidatesTableHeader columns={mockedColumns}/>)

        const tableHeader = await screen.findByTestId(TestIds.CandidatesTableHeaderSortable);
        const orderBlock = await screen.findByTestId(TestIds.CandidatesTableHeaderOrder);

        fireEvent.click(tableHeader);
        expect(orderBlock).toHaveClass('desc');
    });
});

控制台报错信息

● <CandidatesTableHeader/> › Candidates table header should have desc class if it exists in urlParams

    expect(element).toHaveClass("desc")

    Expected the element to have class:
      desc
    Received:
      sortIcon asc

      79 |
      80 |         fireEvent.click(tableHeader);
    > 81 |         expect(orderBlock).toHaveClass('desc');
         |                            ^
      82 |     });
      83 | });

问题分析与修复

核心问题

  1. Mock配置错误:每个测试用例独立执行,beforeEach中两次调用mockReturnValueOnce,但每个测试仅调用一次useSearchParams,导致两个测试都拿到第一个mock返回值(asc),desc的mock从未触发。
  2. 测试逻辑矛盾:如果组件表头点击会切换排序方向,初始为desc的状态下,点击后会切换成asc,此时断言desc类名必然失败。

修复方案一:测试初始状态类名

将mock配置移到每个测试内部,确保每个测试拿到对应order值,同时去掉不必要的点击操作,直接校验初始状态:

describe("<CandidatesTableHeader/>", function () {
  // 每个测试后清理mock,避免跨测试污染
  afterEach(() => {
    jest.clearAllMocks();
  });

  it("初始asc排序时,表头应带有asc类名", async () => {
    jest.spyOn(useSearchParams, "useSearchParams").mockReturnValue([{
      get: (name: string): string => 'asc',
    }] as any);

    customRender(<CandidatesTableHeader columns={mockedColumns}/>);
    const orderBlock = await screen.findByTestId(TestIds.CandidatesTableHeaderOrder);
    
    expect(orderBlock).toHaveClass('asc');
  });

  it("初始desc排序时,表头应带有desc类名", async () => {
    jest.spyOn(useSearchParams, "useSearchParams").mockReturnValue([{
      get: (name: string): string => 'desc',
    }] as any);

    customRender(<CandidatesTableHeader columns={mockedColumns}/>);
    const orderBlock = await screen.findByTestId(TestIds.CandidatesTableHeaderOrder);
    
    expect(orderBlock).toHaveClass('desc');
  });
});

修复方案二:测试点击切换排序效果

如果测试目的是验证点击表头后的排序切换逻辑,调整断言的预期值:

describe("<CandidatesTableHeader/>", function () {
  afterEach(() => {
    jest.clearAllMocks();
  });

  it("初始asc排序,点击表头后切换为desc类名", async () => {
    jest.spyOn(useSearchParams, "useSearchParams").mockReturnValue([{
      get: (name: string): string => 'asc',
    }] as any);

    customRender(<CandidatesTableHeader columns={mockedColumns}/>);
    const tableHeader = await screen.findByTestId(TestIds.CandidatesTableHeaderSortable);
    const orderBlock = await screen.findByTestId(TestIds.CandidatesTableHeaderOrder);

    fireEvent.click(tableHeader);
    expect(orderBlock).toHaveClass('desc');
  });

  it("初始desc排序,点击表头后切换为asc类名", async () => {
    jest.spyOn(useSearchParams, "useSearchParams").mockReturnValue([{
      get: (name: string): string => 'desc',
    }] as any);

    customRender(<CandidatesTableHeader columns={mockedColumns}/>);
    const tableHeader = await screen.findByTestId(TestIds.CandidatesTableHeaderSortable);
    const orderBlock = await screen.findByTestId(TestIds.CandidatesTableHeaderOrder);

    fireEvent.click(tableHeader);
    expect(orderBlock).toHaveClass('asc');
  });
});

额外注意

确保mock的useSearchParams返回结构与真实API一致,如果组件用到URLSearchParams的其他方法,需要在mock中补充实现。

内容的提问来源于stack exchange,提问作者jonasdoe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 09:15:43