Skip to content

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

Description

@jessethomson

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions