You need to enable JavaScript to run this app. Create React App 下 jest.fn() 模拟异步函数的行为异常问题
优惠活动
大模型
产品
解决方案
定价
更多

Create React App 下 jest.fn() 模拟异步函数的行为异常问题

CRA 中外层定义的jest.fn异步Mock失效的原因

根本原因

这不是jest.fn本身的行为变化,本质是CRA 内置的Jest预设(来自react-scripts)默认开启了resetMocks: true配置——这个选项在普通手写的原生Jest项目里默认是关闭的,也是造成行为差异的核心。

resetMocks: true的触发逻辑是:在每一个测试用例正式执行前,自动重置所有已经通过jest.fn()创建的mock实例的内部实现。无论你创建mock时传入了什么原始函数、给mock配置过什么返回值或自定义实现,只要是已经实例化完成的mock,都会被替换成默认的空实现(调用后直接返回undefined,同时清空所有调用统计记录)。

执行流程和现象的匹配

你看到的“外层mock失效、内部mock正常”的现象,本质是执行时机和重置逻辑的匹配结果,和所谓的“异步执行上下文”没有关系,完整执行顺序是这样的:

  1. Jest加载测试文件时,会第一时间跑完整个describe块的顶层代码:
    • 定义getFunc异步函数
    • 执行jest.fn(getFunc)创建getFuncOuterMock,此时这个mock的初始实现是正确的getFunc,调用后会返回带500ms延迟的预期promise
  2. 所有describe顶层代码执行完毕后,Jest才会开始逐个调度测试用例,而每个测试用例真正跑业务逻辑之前,resetMocks的自动重置钩子会先触发:
    • 把已经创建好的getFuncOuterMock的实现,替换成默认的空函数
  3. 随后开始执行第一个测试用例:
    • 在测试用例内部执行jest.fn(getFunc)创建getFuncInnerMock,这个mock是在重置钩子执行完成之后才创建的,没有被自动清空实现,自然能正常返回预期结果
  4. 第一个测试用例跑完,准备执行第二个测试用例前,resetMocks钩子会再次触发,再次把所有现存的mock实现(包括已经被重置过一次的getFuncOuterMock)清空。这时候你在第二个测试里调用getFuncOuterMock,本质是在调用一个已经被改成空的函数,自然拿到的返回值是undefined,和你遇到的报错完全一致。

和原生Jest项目的行为差异

从零搭建的普通Jest项目默认不会开启resetMocks: true,不会在每个测试用例前自动清空已创建mock的实现,所以你外层定义的异步mock会一直保留创建时传入的原始实现,自然能按照预期正常运行。

常见解决方式

  • 如果需要保留外层mock的固定实现,可以在package.json的jest配置项里,手动把resetMocks设置为false
  • 更推荐的写法是保持当前在test块内部定义mock的逻辑,这也是Jest官方倡导的测试隔离写法,能从根源上避免不同测试用例之间的状态污染
  • 如果不想修改全局配置,也可以加一个beforeEach钩子,在每次测试前给外层mock重新绑定原始实现,比如写beforeEach(() => getFuncOuterMock.mockImplementation(getFunc))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 06:27:08