Jest+JSDOM切换beforeAll为beforeEach后第二个测试失败
问题原因分析
核心问题出在Jest的模块缓存机制和测试代码中重复引入业务脚本的方式上:
- 当你使用
beforeEach时,每次测试都会执行代码块,但Jest会对require/import的模块做缓存——第一次引入业务脚本(比如app.js)时,脚本里的事件绑定代码会执行,给当时的按钮绑定点击事件;但第二次require时,因为模块已经被缓存,脚本代码不会重新执行,而此时你已经通过innerHTML重置了DOM,新生成的按钮根本没有绑定事件,导致测试点击按钮后没有任何反应,自然失败。 - 单独运行第二个测试时,模块缓存是空的,
require会重新执行业务脚本,新按钮能正常绑定事件,所以测试通过。 - 改用
beforeAll时,DOM只初始化一次,事件也只绑定一次,两个测试共用同一批DOM元素,所以不会出现问题。
解决方法
- 每次测试时强制清除模块缓存:在
beforeEach里引入业务脚本前,先删除Jest的模块缓存,确保脚本每次都重新执行:beforeEach(() => { document.body.innerHTML = ` <button id="textBtn">Change Text</button> <button id="colorBtn">Change Color</button> <p id="text">Hello</p> `; // 清除对应模块的缓存 delete require.cache[require.resolve('./app.js')]; require('./app.js'); }); - 重构业务代码,支持重复初始化:把事件绑定逻辑封装成一个函数,比如
init(),在业务脚本里暴露这个函数,然后在测试的beforeEach里调用init(),而不是重复引入整个模块:// 业务脚本 app.js export function init() { document.getElementById('textBtn').addEventListener('click', () => { document.getElementById('text').textContent = 'Changed'; }); document.getElementById('colorBtn').addEventListener('click', () => { document.body.style.backgroundColor = 'red'; }); } // 如果是CommonJS: // module.exports = { init }; // 测试代码 beforeEach(() => { document.body.innerHTML = ` <button id="textBtn">Change Text</button> <button id="colorBtn">Change Color</button> <p id="text">Hello</p> `; const { init } = require('./app.js'); init(); });
内容的提问来源于stack exchange,提问作者HotSauceCoconuts
相关产品推荐
相关产品推荐

