如何让Jest与Node.js vm模块兼容以Mock系统时间?
解决Jest Mock时间在Node.js VM模块中不生效的问题
问题核心在于:Jest的useFakeTimers仅替换当前模块作用域内的Date构造函数,但vm.runInThisContext执行的代码默认会使用Node.js原生的全局Date,而非测试代码中被Mock的版本,所以始终获取真实系统时间。
下面提供两种可行的解决方法:
方法1:向VM上下文注入Mock的Date
修改业务代码,在执行VM脚本时将当前上下文的Date传入,让VM内的代码复用Jest Mock后的Date:
// myFunction.js const vm = require('vm'); function getDateUsingVM() { // 构建包含当前Mock Date的上下文 const context = { Date }; vm.createContext(context); const script = ` const currentDate = new Date(); return currentDate.toISOString(); `; // 使用runInContext执行脚本,绑定我们的上下文 return vm.runInContext(script, context); } module.exports = getDateUsingVM;
测试代码无需修改,此时VM内的new Date()会自动使用Jest设置的Mock时间。
方法2:外部传入Date实例到VM脚本
如果允许调整业务逻辑,可以将外部创建的Date实例传入VM脚本,避免在VM内部实例化Date:
// myFunction.js const vm = require('vm'); function getDateUsingVM(currentDate) { const script = ` ((date) => date.toISOString()) `; const theFunction = vm.runInThisContext(script); return theFunction(currentDate); } module.exports = getDateUsingVM;
对应的测试代码调整为:
// myFunction.test.js const getDateUsingVM = require('./myFunction'); describe('getDateUsingVM', () => { beforeEach(() => { jest.useFakeTimers(); }); afterEach(() => { jest.useRealTimers() }); test('should return the same date as the mocked date', () => { const mockDate = new Date('2022-01-01T12:00:00Z'); jest.setSystemTime(mockDate); // 传入基于Mock时间创建的Date实例 const result = getDateUsingVM(new Date()); expect(result).toBe(mockDate.toISOString()); }); });
内容的提问来源于stack exchange,提问作者JJS
相关产品推荐
相关产品推荐

