question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

userEvent.click does not wait for useEffect changes to be flushed

See original GitHub issue

Scenario

I have a component that executes a callback inside of useEffect any time there is a state change. In my tests, if I use userEvent.click to trigger that state change, the callback is executed after my test has already finished and the test fails. If I use fireEvent.click instead, the test passes.

Maybe this is expected and fireEvent.click is synchronous and userEvent.click is asynchronous and people are just expected to convert all their tests to be async when using userEvent (I hope that’s not the case, but maybe I’m missing something).

Full disclosure, I don’t actually know what the problem is and my understanding of the problem and the title of this issue could be wayyy off.

Example

App.js

const App = ({ onChange = noop }) => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    onChange(count);
  }, [count, onChange]);

  return <button onClick={() => setCount(c => c + 1)}>Increment</button>;
};

App.test.js

test("passes if I use fireEvent.click", () => {
  const onChangeMock = jest.fn();
  const { getByRole } = render(<App onChange={onChangeMock} />);

  expect(onChangeMock).toHaveBeenCalledTimes(1);

  fireEvent.click(getByRole("button"));
  expect(onChangeMock).toHaveBeenCalledTimes(2);
});

test("fails if I use userEvent.click", () => {
  const onChangeMock = jest.fn();
  const { getByRole } = render(<App onChange={onChangeMock} />);

  expect(onChangeMock).toHaveBeenCalledTimes(1);

  userEvent.click(getByRole("button"));
  expect(onChangeMock).toHaveBeenCalledTimes(2);
});

test("passes if I use userEvent.click with waitFor", async () => {
  const onChangeMock = jest.fn();
  const { getByRole } = render(<App onChange={onChangeMock} />);

  expect(onChangeMock).toHaveBeenCalledTimes(1);

  userEvent.click(getByRole("button"));
  await waitFor(() => expect(onChangeMock).toHaveBeenCalledTimes(2));
});

Expected

  • Replacing fireEvent.click for userEvent.click should not break tests of components with useEffect

Actual

  • Replacing fireEvent.click for userEvent.click does break tests of components with useEffect

Reproduction

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

4reactions
kentcdoddscommented, Jun 1, 2020

This is now fixed!

3reactions
gcvficommented, May 31, 2020

Another work around, after doing userEvent.click(some_element_object); and before checking the UI effect for above click action, add zero second delay using await new Promise(r=>setTimeout(()=>r(), 0));

I dont know, doing this work around has any other side effects. If not, can we make it part of userEvent.click()

Read more comments on GitHub >

github_iconTop Results From Across the Web

React Testing Library with userEvent.click wrong act() warning
I don't understand how the issue stems from useEffect when it executes on initial load and doesn't run ever again, including when the...
Read more >
You Probably Don't Need act() in Your React Tests
As you can see, we didn't use act() and the new title is flushed after the click. I mentioned synchronous act() for a...
Read more >
How To Test Your React App With React Testing Library
In this post we will learn how to test react components with react-testing-library using test driven development (TDD) approach.
Read more >
React Testing Library Tutorial - Robin Wieruch
Learn how to use React Testing Library in this tutorial. You will learn how to test your React components step by step with...
Read more >
React useLayoutEffect vs. useEffect with examples
With the click comes a state update, which in turn triggers a DOM mutation. The text content of the h1 element has to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found