You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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回调函数
  • 后续逻辑连锁触发报错:
    1. 执行delete window.config[otherTestId]时,实际是将done函数转字符串作为key删除属性,完全没命中你要删的配置项
    2. 两个用例共享同一个window.config对象,前一个用例对配置的修改会污染后一个用例的执行环境
    3. Jest注入的done回调被意外当做普通值参与逻辑,执行第二个用例时被重复触发,最终抛出“done被多次调用”的错误。
修复方案
  1. 修正it.each的回调参数写法,对对象入参做解构,避免Jest误注入done回调
  2. 每个用例执行前重置window.config的初始状态,消除用例间的状态污染
  3. 断言元素不存在时,使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 08:33:12