userEvent.click does not wait for useEffect changes to be flushed
See original GitHub issueScenario
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
foruserEvent.click
should not break tests of components with useEffect
Actual
- Replacing
fireEvent.click
foruserEvent.click
does break tests of components with useEffect
Reproduction
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (4 by maintainers)
Top 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 >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
This is now fixed!
Another work around, after doing
userEvent.click(some_element_object);
and before checking the UI effect for above click action, add zero second delay usingawait 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()