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

如何用React Testing Library测试表单提交时的临时过渡加载文本?

问题原因
  1. 你当前的doformStuff是同步执行逻辑,React会对同一个同步任务栈内的多次状态更新做批量合并处理,所以你先后调用的_setTitle('Submitting...')和_setTitle('Submitted perfectly.')会被合并,最终只会渲染最终状态,中间的提交中状态根本不会渲染到DOM上。
  2. 即便没有批量更新机制,同步代码的执行速度远快于测试断言的触发时机,等你执行断言语句时,finally块内的状态更新已经执行完成,自然拿不到中间状态。
解决方案

方案1:改造业务代码为异步(推荐)

大部分真实场景的表单提交都是异步接口请求,你可以把提交逻辑改成异步,用await Promise.resolve()让出主线程,让React先把提交中的状态渲染完成,再执行后续的表单处理逻辑:

const handleSubmit = async (e, _setTitle) => {
    e.preventDefault()
    _setTitle('Submitting...')
    // 让出主线程,触发React渲染提交中状态
    await Promise.resolve()
    try {
      doformStuff(emailRef.current.value)
    } catch (err) {
      throw new Error(err)
    } finally {
      _setTitle('Submitted perfectly.')
    }
  }

如果你的doformStuff本身就是异步接口请求,直接加await等待它执行完成即可,不需要额外加上面的await Promise.resolve()。

方案2:调整测试用例,卡住异步执行时机

测试时把doformStuffmock成一个暂时不resolve的Promise,让提交逻辑停在try块内,不会走到finally的状态更新,此时就能断言到中间的提交中状态:

it('shows "submitting" when submitting', async () => {
    //  mock doformStuff,让其保持pending状态,不立即执行完成
    jest.spyOn(yourModule, 'doformStuff').mockImplementation(() => new Promise(() => {}))
    // arrange
    render(<MobileEmailCapture/>)
    // act
    const emailInput = screen.getByPlaceholderText('yourem@il.com')
    // userEvent的方法都是异步的,需要加await等待输入完成
    await userEvent.type(emailInput, fakeEmail)
    fireEvent.submit(screen.getByTestId('form'))
    // assert 此时提交逻辑还未执行完成,可捕获到提交中状态
    expect(screen.getByTestId('title')).toHaveTextContent('Submitting...')
  })

注意把代码里的yourModule替换成你实际导入doformStuff的模块名即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 16:45:04