Monorepo根目录下如何Mock子项目Node模块(Jest+TypeScript)
解决Monorepo下Jest跨子项目Mock依赖的问题
核心原因
你推测的完全正确:根目录测试代码导入的axios是根node_modules里的实例,而service1内部引用的是自身node_modules里的axios,二者是独立的模块实例,所以根目录的spyOn无法作用到子项目的axios调用上。
可行解决方案
方案1:统一依赖到根目录(优先推荐)
如果子项目对axios、@aws-sdk等依赖的版本要求一致,直接把这些依赖安装在根目录的package.json中,删除子项目package.json里对应的依赖项(可保留peerDependencies声明)。这样所有子项目和根测试会共享同一个依赖实例,Mock自然生效。
操作步骤:
- 在根目录执行安装命令:
npm install axios @aws-sdk/xxx --save
- 删除service1和service2的
package.json中axios、@aws-sdk相关的dependencies/devDependencies - 重新安装依赖(根据你的包管理器执行
npm install或pnpm install)
之后原测试代码无需修改,spyOn就能正常Mock子项目里的axios调用。
方案2:用Jest的moduleNameMapper强制重定向依赖
如果子项目必须保留自身的依赖版本,可通过Jest的moduleNameMapper配置,把所有子项目对目标依赖的导入重定向到根目录的实例,或者直接Mock模块。
修改根目录的.jest.config.ts:
export default { // 其他已有配置 moduleNameMapper: { // 把所有axios导入指向根目录的axios '^axios$': '<rootDir>/node_modules/axios', // 同理处理@aws-sdk模块,示例: '^@aws-sdk/client-s3$': '<rootDir>/node_modules/@aws-sdk/client-s3' }, // 添加根目录到模块搜索路径,确保解析正确 modulePaths: ['<rootDir>'] }
配置完成后,测试代码里的spyOn就能作用到子项目的axios实例上。
方案3:直接Mock整个依赖模块(最可靠的Mock方式)
不管依赖实例是否重复,直接用jest.mock拦截整个模块,让所有导入该模块的地方都使用同一个Mock对象。
修改你的测试文件:
// 先Mock整个axios模块 jest.mock('axios', () => ({ request: jest.fn().mockResolvedValue('Success') })) import axios from 'axios' import { someFuncThatCallsAxios } from './service1/src/someFile' describe('E2E tests', () => { it('验证axios调用', async () => { // 可随时修改Mock实现 (axios.request as jest.Mock).mockResolvedValue('自定义返回值') await someFuncThatCallsAxios() // 断言调用行为 expect(axios.request).toHaveBeenCalled() }) })
这种方式不依赖依赖实例的一致性,Jest会拦截所有对axios的导入,强制使用你定义的Mock对象,彻底解决实例不一致问题。
额外注意事项
- 使用TypeScript时,确保根目录
tsconfig.json的moduleResolution设置为node或nodenext,避免模块解析异常。 - 若子项目有自定义的tsconfig路径映射,需要在根目录的tsconfig中同步配置,或在Jest的
moduleNameMapper中补充对应规则。
内容的提问来源于stack exchange,提问作者Yushu
相关产品推荐
相关产品推荐

