Steve Kinney

Introduction to Testing

FireEvent vs UserEvent in Testing

fireEvent is useful for—umm—firing events, but generally speaking there is more to a user interaction than just one event. Consider the list of events that fireEvent supports. that fireEvent supports. Let’s look at an over-simplified list of what happens when a user types into an input field:

  • The user might click to focus on the field (click, focus).
  • They might press a key (keydown, keypress).
  • They’ll probably release that key (keyup).
  • That’ll trigger a change event on the input field.

That’s not even all of it. But, you get the point. The idea is that we want to simulate what an actual user will do as opposed to getting too in the weeds about the events that the browser is firing on our behalf.

In most cases, you’ll want to prefer using @testing-library/user-event over the built-in fireEvent.

Let’s take it for a spin with that counter.test.ts file that we were looking at earlier:

test('it should increment with the "Increment" button is pressed', () => {
  render(<Counter />);

  const currentCount = screen.getByTestId('current-count');
  const incrementButton = screen.getByRole('button', { name: 'Increment' });

  fireEvent.click(incrementButton);

  expect(currentCount).toHaveTextContent('1');
});

Using userEvent

Our first attempt might be something like this:

test('it should increment with the "Increment" button is pressed', () => {
  const user = userEvent.setup();
  render(<Counter />);

  const currentCount = screen.getByTestId('current-count');
  const incrementButton = screen.getByRole('button', { name: 'Increment' });

  user.click(incrementButton);

  expect(currentCount).toHaveTextContent('1');
});

This test will fail. But, why?

The problem is that user.click() returns a Promise, so we need to make our test function async. Luckily, that’s an easy problem to solve:

test('it should increment with the "Increment" button is pressed', async () => {
  const user = userEvent.setup();
  render(<Counter />);

  const currentCount = screen.getByTestId('current-count');
  const incrementButton = screen.getByRole('button', { name: 'Increment' });

  await user.click(incrementButton);

  expect(currentCount).toHaveTextContent('1');
});

Additional Hype for user-event

You might not be totally sold on user-event just yet, but it comes with a bunch of other goodies that would be otherwise hard to emulate by hand. For example, let’s say you wanted to emulate a user pressing and holding the left shift key:

const user = userEvent.setup();

await user.keyboard('[<ShiftLeft>]'); // Press Shift (without releasing it)
await user.click(element); // Perform a click with `shiftKey: true`

(Source: user-event documentation)

Last modified on .