React Testing Library: When to use userEvent.click and when to use fireEvent

Viewed 35404

I'm presently learning React-Testing-Library.

I'd like to test mouse interaction with an element. Presently it's a bit unclear to me the difference between userEvent.click(element) and fireEvent.click(element). Are both recommended for use, and in the example below are they being correctly implemented?

const mockFunction = jest.fn(() => console.info('button clicked'));
const { getByTestId } = render(<MyAwesomeButton onClick={mockFunction} />);
const myAwesomeButton = getByTestId('my-awesome-button');

// Solution A
fireEvent(myAwesomeButton)
expect(mockFunction.toHaveBeenCalledTimes(1);

// Solution B
userEvent.click(myAwesomeButton);
expect(mockFunction).toHaveBeenCalledTimes(1);

Thanks in advance for any clarity.

3 Answers

Behind the scenes, userEvent uses the fireEvent. You can consider fireEvent being the low-level api, while userEvent sets a flow of actions.

Here is the code for userEvent.click

You can see that depending of which element you are trying to click, userEvent will do a set of different actions (e.g. if it's a label or a checkbox).

According to Docs, you should use user-event to test interaction with your components.

fireEvent dispatches exactly the events you tell it to and just those - even if those exact events never had been dispatched in a real interaction in a browser.

User-event on the other hand dispatches the events like they would happen if a user interacted with the document. That might lead to the same events you previously dispatched per fireEvent directly, but it also might catch bugs that make it impossible for a user to trigger said events.

another good to mention difference between fireEvent and userEvent is that by default fireEvent is wrapped inside act function and this is useful when the user does some action and this action will cause component updates and re-render. on the controversy, if we used userEvent probably will notice "not wrapped in act(...)" warning error that appears in the console.

act(() => {
  userEvent.type(input, 'inputValue')
})

and here we don't need the act function, cause it's already wrapped over fireEvent

fireEvent.change(input, {target: {value: 'inputValue'}})

and this great article demonstrates this concept Common mistakes with React Testing Library

Related