升级至Jest 26后Mock失效问题求助
刚把react-scripts升级到4.0(内置Jest 26及配套测试包)就碰到mock失效、返回undefined的问题?我之前也踩过一模一样的坑,主要是Jest 26对模块mock的处理更严格,再加上react-scripts默认配置的变化搞的鬼。咱们分两种情况逐个解决:
1. 默认导出Mock失效的解决办法
你的代码里已经加了__esModule: true,这部分是对的,但问题大概率出在resetMocks配置或者mock的时机上:
核心原因
react-scripts 4.0的默认Jest配置中,resetMocks被设为true了——这个配置会在每个测试用例执行前重置所有mock函数的状态,包括你在beforeAll里设置的mockReturnValue。所以第一个测试开始时,mock函数的返回值已经被清空,自然返回undefined。
解决方法(二选一)
方法一:把beforeAll改成beforeEach
这样每个测试用例执行前都会重新设置mock的返回值,避免被resetMocks清空:
import useFetch from "use-http"; jest.mock("use-http", () => ({ __esModule: true, default: jest.fn() })); describe("the user context", () => { beforeEach(() => { // 替换beforeAll为beforeEach useFetch.mockReturnValue({ get: async () => Promise.resolve({ foo: 666 }), response: { ok: true } }); }); // 你的测试用例代码... });
方法二:关闭resetMocks配置
如果你习惯用beforeAll,可以在项目根目录修改package.json里的jest字段,覆盖默认配置:
// package.json { "jest": { "resetMocks": false } }
2. 非默认导出Mock失效的解决办法
这个问题有两个常见原因,咱们逐一排查:
原因一:缺少__esModule: true标记
如果你的_hooks是ES模块(用export const useBaseUrls = ...导出),Jest 26要求mock时必须加上__esModule: true,否则无法正确识别ES模块的导出结构,导致导入的useBaseUrls是undefined。
修改后的mock代码:
jest.mock("_hooks", () => ({ __esModule: true, // 必须加上这个标记 useBaseUrls: jest.fn().mockReturnValue({ app: "bar" }) }));
原因二:同样受resetMocks配置影响
和第一个问题一样,如果resetMocks是true,你在mock工厂函数里设置的mockReturnValue会被重置。解决方法同上,要么改成beforeEach重新设置,要么关闭resetMocks。比如:
import { useBaseUrls } from "_hooks"; jest.mock("_hooks", () => ({ __esModule: true, useBaseUrls: jest.fn() })); describe("你的测试描述", () => { beforeEach(() => { useBaseUrls.mockReturnValue({ app: "bar" }); }); // 测试用例代码... });
补充:如果是TypeScript项目,记得给导入的mock函数加上类型断言,比如
(useFetch as jest.Mock).mockReturnValue(...),避免类型报错,但这不是导致返回undefined的直接原因。
内容的提问来源于stack exchange,提问作者eej

