Skip to content

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Handling Mouse Events in Your React Component Tests

May 28, 2020 • 6 Minute Read

Introduction

Testing a React component will most often involve some type of user interaction happening before you validate the expected outcome. This could include a user typing into a form field, pressing the escape key to close a modal, or clicking on an element. This guide will show you how to use these types of events in your tests.

React Testing Library

An essential tool for writing tests for React components is the React Testing Library. The React Testing Library (RTL) was created to help you write maintainable tests that focus on how your software is being used, instead of implementation details. Go here to learn more about RTL. The examples in this guide will use RTL.

Testing Click Events with FireEvent

When your React component involves a user clicking on an element, you'll want to use the fireEvent method from RTL. To illustrate this behavior, here is a simple component with a button that, when clicked, toggles the view of an image:

      import React from 'react';
export default function App() {
  const [isVisible, setIsVisible] = React.useState(false);
  const handleClick = () => {
    setIsVisible(!isVisible);
  };

  return (
    <div className='App'>
      <div>
        <button onClick={handleClick}>Toggle Image</button>
      </div>

      <br />

      <div style={{ display: isVisible ? 'block' : 'none' }}>
        <p>Look at this pretty cat</p>
        <img src='https://cataas.com/cat' alt='random cat' />
      </div>
    </div>
  );
}
    

When this component first renders, the cat image will not be displayed. You can show and hide the image by clicking a Toggle Image button. To test the toggle functionality you would use the fireEvent.click() method:

  1. Import the fireEvent method from RTL
  2. Import jest-dom from RTL to use assertions like toBeVisible()
  3. Use the fireEvent.click(element) method to click an element
      import React from 'react';
// 1
import { render, screen, fireEvent } from '@testing-library/react';

// 2
import '@testing-library/jest-dom';
import App from './App';

describe('<App />', () => {
  it('Should toggle the cat image div', () => {
    render(<App />);
    // Before clicking the toggle button, the image is NOT visible
    expect(screen.queryByText(/look at this pretty cat/i)).not.toBeVisible();

    // 3
    fireEvent.click(screen.queryByText(/toggle image/i));
    expect(screen.queryByText(/look at this pretty cat/i)).toBeVisible();
  });
});
    

Testing User Input with User-event

When you need to test a component that involves user input, you should use the user-event methods available in the @testing-library/user-event package. user-event is used to simulate real events that would happen in the browser like typing, clicking, or interacting with a select menu. Here's an example component that has the user type in an email address to see if it's valid:

      import React from 'react';
export default function Email() {
  const [emailAddress, setEmail] = React.useState();
  const [hasValidEmail, setHasValidEmail] = React.useState(false);
  const handleChange = (event) => {
    setEmail(event.target.value);
  };

  const handleClick = () => {
    const regex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
    setHasValidEmail(regex.test(emailAddress));
  };

  return (
    <div className='App'>
      <div>
        <label htmlFor='email'>Email</label>
        <input
          type='text'
          id='email'
          name='email'
          onChange={handleChange}
          value={emailAddress}
        />
        <button onClick={handleClick}>Check if email is valid</button>
      </div>
      {hasValidEmail && emailAddress ? (
        <p>Email Address is valid</p>
      ) : (
        <p>Email Address is NOT valid</p>
      )}
    </div>
  );
}
    

To test this component you'll use the type method userEvent.type(), where you'll pass in the input element as the first argument and the value as the second argument:

  1. Use userEvent.type() to enter an invalid email address
  2. Use the clear method to clear out the value of an input element
  3. Type in a valid email address
      import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Email from './Email';
import '@testing-library/jest-dom';

describe('<Email />', () => {
  it('Should validate the email address typed by the user', () => {
    render(<Email />);

    // 1
    userEvent.type(screen.queryByLabelText(/email/i), 'ham');
    fireEvent.click(
      screen.queryByRole('button', { name: /Check if email is valid/i }),
    );
    expect(screen.queryByText(/email address is not valid/i)).toBeVisible();

    // 2
    userEvent.clear(screen.queryByLabelText(/email/i));

    // 3
    userEvent.type(screen.queryByLabelText(/email/i), '[email protected]');
    fireEvent.click(
      screen.queryByRole('button', { name: /check if email is valid/i }),
    );
    expect(screen.queryByText(/email address is not valid/i)).toBeNull();
    expect(screen.queryByText(/email address is valid/i)).toBeVisible();
  });
});
    

Conclusion

I hope this helps you understand testing user interaction with your components. RTL provides a lot of useful tools that make this type of testing easy to accomplish. Please review these fireEvent and userEvent docs to learn more.

Thank you for reading!