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
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.clickto trigger that state change, the callback is executed after my test has already finished and the test fails. If I usefireEvent.clickinstead, the test passes.Maybe this is expected and
fireEvent.clickis synchronous anduserEvent.clickis asynchronous and people are just expected to convert all their tests to be async when usinguserEvent(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
App.test.js
Expected
fireEvent.clickforuserEvent.clickshould not break tests of components with useEffectActual
fireEvent.clickforuserEvent.clickdoes break tests of components with useEffectReproduction