Jest如何Mock Lerna多包仓库中子包内部使用的useData Hook
问题根因
你当前的Mock写法不生效的核心原因是:@project/shared-component包内部的SharedComponent调用useData时,使用的是包内部相对路径导入,而非包对外暴露的入口导出值。你Mock的是NPM包对外的入口导出,包内部的直接调用不受影响。
可行解决方案
方案1:修改子包内部导入规则(改造成本最低)
将@project/shared-component包内所有调用useData的地方,从相对路径导入改为从包入口导入:
// 改造前(SharedComponent内部导入) import useData from './hooks/useData' // 改造后 import { useData } from '@project/shared-component'
改造完成后,SharedComponent内部调用的就是包对外暴露的useData,你原来写的Mock代码即可正常生效。
注意:该方案需要确保你的打包工具(Rollup/TSUP/Vite等)支持处理包内部自引用,当前主流Monorepo场景下的打包工具默认都兼容该写法,不会产生循环依赖问题。
方案2:配置Jest模块映射直接Mock源码
如果不想修改@project/shared-component的业务代码,可以在@project/consumer的Jest配置中添加模块映射,让Jest直接解析子包的源码而非node_modules中的构建产物:
- 先修改
@project/consumer的jest.config.js配置:
module.exports = { moduleNameMapper: { // 路径根据你的实际项目目录调整,这里假设两个子包都在packages目录下 '^@project/shared-component(.*)$': '<rootDir>/../shared-component/src$1', } }
- 测试用例中直接Mock
useData对应的源码文件:
// 路径对应useData在shared-component包中的实际源码路径 jest.mock('@project/shared-component/hooks/useData', () => ({ useData: jest.fn(), // 根据实际导出格式调整,默认导出则写default: jest.fn() }))
方案3:增加依赖注入入口(无侵入无兼容问题)
在@project/shared-component的SharedComponent中增加可选的useData注入参数,默认使用内部实现:
// @project/shared-component 中SharedComponent的实现 import useData from './hooks/useData' const SharedComponent = (props) => { // 优先使用传入的useData,没有则用内部实现 const { useData: customUseData = useData } = props const data = customUseData() // 原有组件逻辑 }
测试用例中直接传入Mock后的useData即可:
import { SharedComponent } from '@project/shared-component' const mockUseData = jest.fn().mockReturnValue({ test: 'mock数据' }) test('测试ConsumerComponent', () => { render(<ConsumerComponent useData={mockUseData} />) // 测试逻辑 })
该方案不需要修改Jest配置,也不需要调整模块导入规则,不会产生任何打包或解析兼容问题。
内容的提问来源于stack exchange,提问作者Lukas Bach
相关产品推荐
相关产品推荐

