Search code examples
javascriptreactjsjestjsreact-testing-libraryjest-dom

Jest's `it.each` causes a 'Expected done to be called once, but it was called multiple times' error when used with 'getByTestId'


I have a component with some parts that are conditionally rendered based on some config on the window object. This all works, I can confirm this manually.

I have this sort of test setup, but I have simplified it somewhat:

it('renders both by default', () => { // PASS
  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) => { // FAIL
  delete window.config[otherTestId]; // this works
  const Comp = getComponent();
  render(<Comp />);
  expect(screen.getByTestId(testId)).toBeInTheDocument();
  expect(screen.getByTestId(otherTestId)).not.toBeInTheDocument();
})

But I am getting this error:

Expected done to be called once, but it was called multiples times. Reason 'two'.

Which is not something I've ever seen before. None of my tests that are running here are async. The component isn't async. I'm not using done anywhere near this.

What's happening?


Solution

  • You need to destructure your test variables

    Jest is expecting testId to be an object containing all your test variables, and otherTestId to be the function done.

    I'm not sure why it thinks it's called multiple times, but making the first argument:

    { testId, otherTestId }
    

    Works around this, and matches the documentation correctly.


    Alternatively, follow this answer for replacing jest's for loop with the native one, which is a better approach in many ways.