Jest测试中无法Mock Webpack定义的全局变量该如何解决?
解决Jest中Mock Webpack DefinePlugin全局变量的问题
问题根源
Webpack的DefinePlugin是编译时替换变量,你的commonUtil.js在加载时就已经根据初始的__ENV__值生成了log函数。测试时直接修改__ENV__不会生效,因为log的逻辑已经在模块加载阶段固定了,后续的变量改动无法影响它。
解决方案
要覆盖不同环境的测试场景,需要确保每次测试都能重新加载commonUtil模块,并且在加载前设置好对应的全局变量。
方案1:重置模块缓存 + 预设置全局变量
利用jest.resetModules()在每个测试用例前清空模块缓存,然后在加载commonUtil前设置全局的__ENV__,这样每次测试都会基于新的变量生成log函数。
修改测试文件如下:
// commonUtil.jest.js const envs = { PROD: 'prod', DEV: 'dev' }; // 匹配你的实际envs定义 describe('commonUtils', () => { const testMsg = 'test'; beforeEach(() => { jest.resetModules(); // 重置模块缓存,避免复用之前加载的commonUtil jest.spyOn(console, 'log').mockImplementation(() => {}); // 统一Mock console.log }); afterEach(() => { console.log.mockRestore(); // 测试后恢复console.log原始实现 }); it('在生产环境不输出日志', () => { global.__ENV__ = envs.PROD; // 加载模块前设置全局变量 const { log } = require('./commonUtil'); log(testMsg); expect(console.log).not.toHaveBeenCalled(); }); it('在开发环境输出日志', () => { global.__ENV__ = envs.DEV; const { log } = require('./commonUtil'); log(testMsg); expect(console.log).toHaveBeenCalledWith(testMsg); }); });
方案2:Jest配置全局注入变量(适合固定场景)
如果只需要针对所有测试设置统一的环境变量,可以在jest.config.js中配置globals:
// jest.config.js module.exports = { globals: { __ENV__: JSON.stringify('dev') // 注意和DefinePlugin格式一致,用JSON.stringify生成带引号的字符串 } };
这种方式无法在单个测试用例中切换环境,适合单一环境的测试场景。
关键注意点
DefinePlugin会把__ENV__替换为字符串字面量,比如配置__ENV__: 'prod',实际代码中会变成'prod',所以模拟时要赋值对应的字符串,而非变量引用。- 必须在加载
commonUtil模块前设置全局变量,否则模块加载时已生成固定的log函数,后续修改无效。
内容的提问来源于stack exchange,提问作者Arpit Malik
相关产品推荐
相关产品推荐

