Jest使用it.each搭配getByTestId时出现done多次调用报错原因
报错根本原因
这个报错是it.each参数写法错误,触发Jest的异步回调检测机制导致的:
- Jest对测试回调的判定规则:只要传给
it/test的回调函数声明了形参,Jest就会默认将该形参作为done异步回调注入,等待回调被调用后才结束当前用例,不会按同步逻辑执行。 - 你当前用
it.each传入对象格式的用例数据时,没有对入参做解构,直接写了(testId, otherTestId)两个形参:- 第一个形参
testId实际接收到的是整个用例对象{ testId: 'xxx', otherTestId: 'xxx' } - 第二个形参
otherTestId根本不是你预期的用例字段,而是Jest自动注入的done回调函数
- 第一个形参
- 后续逻辑连锁触发报错:
- 执行
delete window.config[otherTestId]时,实际是将done函数转字符串作为key删除属性,完全没命中你要删的配置项 - 两个用例共享同一个
window.config对象,前一个用例对配置的修改会污染后一个用例的执行环境 - Jest注入的
done回调被意外当做普通值参与逻辑,执行第二个用例时被重复触发,最终抛出“done被多次调用”的错误。
- 执行
修复方案
- 修正
it.each的回调参数写法,对对象入参做解构,避免Jest误注入done回调 - 每个用例执行前重置
window.config的初始状态,消除用例间的状态污染 - 断言元素不存在时,使用
queryBy*系列查询方法——getBy*找不到目标元素会直接抛错,无法配合not.toBeInTheDocument()做断言
修复后的测试代码:
// 每个用例执行前统一重置配置,消除状态污染 beforeEach(() => { window.config = { one: true, two: true } }) it('renders both by default', () => { const Comp = getComponent(); render(<Comp />); expect(screen.getByTestId('one')).toBeInTheDocument(); expect(screen.getByTestId('two')).toBeInTheDocument(); }) it.each([ { testId: 'one', otherTestId: 'two'}, { testId: 'two', otherTestId: 'one' }, ])('renders $testId, not $otherTestId', ({ testId, otherTestId }) => { // 对对象入参做解构 delete window.config[otherTestId]; const Comp = getComponent(); render(<Comp />); expect(screen.getByTestId(testId)).toBeInTheDocument(); // 不存在场景必须用queryBy查询 expect(screen.queryByTestId(otherTestId)).not.toBeInTheDocument(); })
内容的提问来源于stack exchange,提问作者AncientSwordRage
相关产品推荐
相关产品推荐

