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

React Testing Library如何断言异步函数执行的中间状态?

问题原因

测试失败是因为你mock的fetch是立即完成的(Promise直接resolve),React会对同步的状态更新做批量合并处理。点击按钮后,setIsLeaving(true)和紧接着的setIsLeaving(false)会被合并成一次状态更新,组件根本没机会渲染出显示'bye'的状态,所以测试里用getByText找不到对应的文本。

解决办法

你需要让mock的fetch稍微延迟完成,给React留出渲染'bye'状态的时间,具体有两种可行方式:

方式一:给mock的Promise加延迟

修改global.fetch的mock,把resolve逻辑放进setTimeout里,哪怕延迟0毫秒也能打破状态合并:

global.fetch = jest.fn(() =>
  new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        json: () =>
          Promise.resolve({
            data: {
              id: 1,
              attributes: {
                titles: { en: 'Fullmetal Alchemist' },
                synopsis: 'After losine.'
              }
            }
          })
      });
    }, 0);
  })
);

方式二:用findByText替代getByText

findByText本身结合了getByText和waitFor,可以自动等待目标元素出现。不过这种方式需要配合上面的延迟mock使用,修改测试断言部分:

await user.click(screen.getByRole('button', { name: /click me/i }));
// 用findByText等待'bye'状态渲染完成
expect(await screen.findByText(/bye/i)).toBeInTheDocument();
await waitFor(() => {
  expect(screen.getByText(/hi/i)).toBeInTheDocument();
});
完整修改后的测试代码示例
import {render,screen,waitFor} from '@testing-library/react';
import userEvent from '@testing-library/user-event'; 
import { Test } from './Test';
import '@testing-library/jest-dom';
    
describe('Test component test', () => {
  global.fetch = jest.fn(() =>
    new Promise((resolve) => {
      setTimeout(() => {
        resolve({
          json: () =>
            Promise.resolve({
              data: {
                id: 1,
                attributes: {
                  titles: { en: 'Fullmetal Alchemist' },
                  synopsis: 'After losine.'
                }
              }
            })
        });
      }, 0);
    })
  );

  it('should show "bye" text before showing "hi" text when data fetching is done', async () => {
    const user = userEvent.setup();
    render(<Test />);
    expect(screen.getByText(/hi/i)).toBeInTheDocument();
    
    await user.click(screen.getByRole('button', { name: /click me/i }));
    
    expect(await screen.findByText(/bye/i)).toBeInTheDocument();
    
    await waitFor(() => {
      expect(screen.getByText(/hi/i)).toBeInTheDocument();
    });
  });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 22:52:58