setupFilesAfterEnv中的Jest对象与测试文件中的Jest对象引用不一致问题
这个坑我之前踩过!当时盯着控制台的undefined和false愣了好久,后来才搞懂是Jest的上下文隔离机制在搞鬼,给你唠唠问题根源和解决办法:
问题根源
Jest为了保证每个测试用例的环境独立性,会在setupFilesAfterEnv的初始化上下文和单个测试文件的执行上下文中生成完全不同的jest对象实例。你在setup文件里修改的是初始化阶段的临时实例,而测试文件里用到的是Jest单独注入的全新实例,二者引用完全不重合,所以你挂载的toto属性自然在测试里读不到。
就像你代码里的情况:setup里把当前jest存到global.jestCopy,测试里对比发现jestCopy !== jest,本质就是两个完全不同的对象。
解决办法
方法一:直接挂载到全局对象(简单粗暴)
既然两个jest实例不共享,那我们直接把自定义属性挂到globalThis(Node环境下也可以用global)上,这样测试文件就能直接访问了:
// test/config.ts(setup文件) // 方式1:直接挂全局 (globalThis as any).toto = 'toto'; // 方式2:如果你想挂在jest名下,也可以这样 (globalThis as any).jest.toto = 'toto';
然后在测试文件里:
// *.spec.ts console.log(globalThis.toto); // 输出 'toto' // 或者用你想要的方式 console.log(jest.toto); // 输出 'toto'
要是用TypeScript的话,别忘了扩展全局类型避免报错,新建一个types/jest.d.ts文件:
declare global { var toto: string; namespace jest { interface Jest { toto: string; } } } export {};
然后在tsconfig.json里把这个类型文件加入include列表:
{ "include": ["src/**/*", "types/**/*"] }
方法二:从@jest/globals获取一致的Jest实例
测试文件里的jest其实是从@jest/globals模块导入的,你在setup文件里也直接导入这个模块的jest实例,修改它的属性,这样测试文件里就能读到了:
// test/config.ts import { jest as globalJest } from '@jest/globals'; (globalJest as any).toto = 'toto';
测试文件里直接用就行:
// *.spec.ts console.log(jest.toto); // 输出 'toto'
同样要加上面提到的TypeScript类型扩展,不然TS会报属性不存在的错误。
方法三:利用Jest的全局配置共享
如果你想更贴合Jest的规范,可以把自定义属性挂到Jest的全局配置上:
// test/config.ts jest.config.global.toto = 'toto';
测试文件里通过配置对象访问:
// *.spec.ts console.log(jest.config.global.toto); // 输出 'toto'
总结
核心就是绕开Jest的上下文隔离,要么通过全局对象共享属性,要么直接操作测试文件会用到的那个jest实例。记得给TypeScript补全类型,不然写代码的时候会红报错,影响开发体验~




