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

React Testing Library测试useEffect内setState及定时器

离线提示组件测试实现方案

先提你代码里的一个显性bug:定时器清理逻辑误用了clearInterval,你创建延时任务用的是setTimeout,这里要改成clearTimeout(timer),不然清理逻辑本身就不生效,测试结果会不符合预期。

测试全程用Jest自带的Fake Timer能力即可,不需要额外依赖,测试文件开头先开启假定时器:

jest.useFakeTimers()

同时提前mock好useNetInfo的返回值,支持手动修改网络状态触发组件重渲染即可。


对应你三个疑问的测试实现

  • 测试网络恢复时的横幅隐藏逻辑
    不管是isConnected变回true,还是isInternetReachable变回true,隐藏逻辑都是同步触发的,不需要等待定时器。状态变更操作包在act()中保证React完成渲染后,直接断言横幅不存在即可:

    test('网络状态恢复时自动隐藏离线横幅', () => {
      // 初始化为断网状态,横幅默认显示
      mockUpdateNetInfo({ isConnected: false, isInternetReachable: false })
      const { queryByText } = render(
        <OfflineModeContainer>
          <Text>页面内容</Text>
        </OfflineModeContainer>
      )
      expect(queryByText('aucune connexion internet.')).toBeTruthy()
    
      // 触发isConnected恢复为true
      act(() => {
        mockUpdateNetInfo({ isConnected: true })
      })
      expect(queryByText('aucune connexion internet.')).toBeFalsy()
    
      // 测试isInternetReachable恢复的场景
      act(() => {
        mockUpdateNetInfo({ isConnected: false, isInternetReachable: false })
        jest.advanceTimersByTime(3000) // 等3秒触发横幅显示
      })
      expect(queryByText('aucune connexion internet.')).toBeTruthy()
      act(() => {
        mockUpdateNetInfo({ isInternetReachable: true })
      })
      expect(queryByText('aucune connexion internet.')).toBeFalsy()
    })
    
  • 测试setTimeout3秒延迟显示逻辑
    不需要真实等待3秒,用jest.advanceTimersByTime手动控制时间推进即可,精准验证时间阈值前后的显示状态:

    test('isInternetReachable为false满3秒才显示横幅', () => {
      // 初始状态网络正常
      mockUpdateNetInfo({ isConnected: true, isInternetReachable: true })
      const { queryByText } = render(
        <OfflineModeContainer>
          <Text>页面内容</Text>
        </OfflineModeContainer>
      )
      expect(queryByText('aucune connexion internet.')).toBeFalsy()
    
      // 触发网络不可达
      act(() => {
        mockUpdateNetInfo({ isInternetReachable: false })
      })
      // 时间推进2999毫秒,还没到阈值,横幅不显示
      act(() => {
        jest.advanceTimersByTime(2999)
      })
      expect(queryByText('aucune connexion internet.')).toBeFalsy()
      // 再推进1毫秒,满3秒,横幅显示
      act(() => {
        jest.advanceTimersByTime(1)
      })
      expect(queryByText('aucune connexion internet.')).toBeTruthy()
    })
    
  • 测试定时器清理逻辑
    核心验证点是:3秒阈值到达前如果网络恢复,定时器会被清除,不会后续触发横幅显示。可以通过spy监听clearTimeout的调用做断言:

    test('网络提前恢复时清除定时器,不会延迟显示横幅', () => {
      const clearTimeoutSpy = jest.spyOn(global, 'clearTimeout')
      mockUpdateNetInfo({ isConnected: true, isInternetReachable: true })
      const { queryByText } = render(
        <OfflineModeContainer>
          <Text>页面内容</Text>
        </OfflineModeContainer>
      )
    
      // 触发网络不可达
      act(() => {
        mockUpdateNetInfo({ isInternetReachable: false })
      })
      // 1秒后网络提前恢复
      act(() => {
        jest.advanceTimersByTime(1000)
        mockUpdateNetInfo({ isInternetReachable: true })
      })
      // 断言清理定时器的逻辑被调用
      expect(clearTimeoutSpy).toHaveBeenCalled()
      // 时间推进到3秒后,横幅也不会显示
      act(() => {
        jest.advanceTimersByTime(3000)
      })
      expect(queryByText('aucune connexion internet.')).toBeFalsy()
    
      clearTimeoutSpy.mockRestore()
    })
    

现有测试用例报错原因

你贴的失败用例有两个问题:

  1. queryByText是同步查询方法,不会返回Promise,前面加await拿到的是RTL返回的元素包装对象,不是null,自然过不了toBeFalsy断言
  2. 状态更新、时间推进的操作没有包在act()中,React没完成渲染就执行断言,结果不符合预期

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 04:24:15