Jest升级至v28后多测试用例触发done多次调用错误求助
解决Jest v28多测试用例使用done回调时报错的问题
问题背景
将Jest从v24升级到v28,配置了jsdom测试环境,设置了setupFiles指向setup.js:
"jest": { "testEnvironment": "jsdom", "setupFiles": ["<rootDir>/setup.js"] }
当同一测试文件中多个使用done回调的测试用例一起运行时,出现错误:
Expected done to be called once, but it was called multiple times.
单独运行单个测试用例时无异常。
可能原因及解决方案
1. 全局副作用未清理(setup.js或测试全局操作)
Jest v28对测试环境的隔离机制比v24更严格,但如果setup.js中存在全局事件监听、定时器或未清理的异步操作,会跨测试用例残留,导致done被意外多次调用。
- 检查
setup.js,比如是否添加了window.addEventListener这类全局监听,必须在afterEach中移除对应的监听:// setup.js let handleResize; beforeEach(() => { handleResize = () => { /* 业务逻辑 */ }; window.addEventListener('resize', handleResize); }); afterEach(() => { window.removeEventListener('resize', handleResize); jest.clearAllTimers(); jest.resetAllMocks(); }); - 确保所有全局异步操作(如定时器、Promise)在每个测试用例结束后被清理。
2. 测试用例内部异步逻辑重复触发done
如果测试用例中绑定了事件监听但未在测试结束后解绑,当后续测试用例触发相同事件时,会再次调用之前测试的done回调:
// 错误示例:未解绑事件 it('test resize', (done) => { window.addEventListener('resize', () => { expect(true).toBe(true); done(); }); window.dispatchEvent(new Event('resize')); }); // 修复:测试后解绑事件 it('test resize', (done) => { const handler = () => { expect(true).toBe(true); done(); }; window.addEventListener('resize', handler); window.dispatchEvent(new Event('resize')); afterEach(() => { window.removeEventListener('resize', handler); }); });
3. 改用async/await替代done回调
Jest v28更推荐使用async/await处理异步逻辑,避免done回调带来的多次调用风险,代码更简洁易维护:
// 替代done的写法 it('test async logic', async () => { const result = await someAsyncFunction(); expect(result).toBe('expected'); });
4. 检查测试环境版本兼容性
确认jest-environment-jsdom的版本与Jest v28匹配,避免版本不兼容导致的环境异常:
npm list jest-environment-jsdom
确保版本为28.x.x,若不一致则重新安装对应版本:
npm install jest-environment-jsdom@28 --save-dev
内容的提问来源于stack exchange,提问作者Niyaz
相关产品推荐
相关产品推荐

