Effective Testing in React: A Guide with Real Examples

Oussama ChahidiOussama Chahidi
3 min read

Introduction

When I first started building React applications, I used to test everything manually—filling out forms, clicking buttons, and hoping for the best. But as my apps grew more complex, that approach quickly became unsustainable. Writing automated tests changed everything. Not only did it catch bugs early, but it also gave me something even more valuable: confidence. Confidence that my forms behave as expected, that edge cases are handled, and that future changes won’t silently break critical functionality. In this article, I’ll walk you through how I test React components—specifically sign-up and sign-in forms—using React Testing Library and Jest, based on my real-world experience.

Setting Up the Testing Environment

Before diving into the tests, let’s make sure we have the right tools in place. For this project, I’m using Jest as the test runner and React Testing Library (RTL) for rendering components and interacting with the DOM in a way that resembles real user behavior. These tools together promote better testing practices by focusing on what the user sees and does, rather than implementation details.

If you’re starting from scratch, install the necessary packages:

npm install --save-dev jest @testing-library/react @testing-library/jest-dom @testing-library/user-event

Make sure to also add the following to your test setup file to get better matchers for DOM assertions:

create a jest.setup.js

import '@testing-library/jest-dom';

Now that our environment is ready, let’s look at a practical example: testing the SignUp page. We'll simulate user interactions—typing input, selecting options, checking checkboxes—and assert that the right values are passed to our sign-up function.

🧪 Writing the SignUp Page Test

Let’s break the test down into meaningful pieces: rendering, interacting, and asserting behavior.

1. Submitting with Valid Data

First, we simulate a real user filling out the form:

import { render, screen, waitFor } from "@testing-library/react"; 
import userEvent from "@testing-library/user-event"; 
import SignUpPage from "@/app/(auth)/sign-up/page"; 
import { signUpUser } from "@/loaders/auth";

jest.mock("@/loaders/auth", () => ({ signUpUser: jest.fn() }));

Then we simulate typing and clicking:

it("submits the form with valid data", async () => {
    (signUpUser as jest.Mock).mockResolvedValue({ success: true });
    const user = userEvent.setup();

    render(<SignUpPage />);

    await user.type(screen.getByLabelText(/first name/i), "John");
    await user.type(screen.getByLabelText(/last name/i), "Doe");
    await user.type(
      screen.getByLabelText(/email address/i),
      "john.doe@example.com"
    );
    await user.type(screen.getByLabelText(/password/i), "Test@1234");

    const termsCheckbox = screen.getByRole("checkbox");
    await user.click(termsCheckbox);

    await user.click(screen.getByRole("button", { name: /create account/i }));

    await waitFor(() => {
      expect(signUpUser).toHaveBeenCalledWith({
        firstName: "John",
        lastName: "Doe",
        email: "john.doe@example.com",
        password: "Test@1234",
      });
      expect(toast.success).toHaveBeenCalledWith(
        "Account created successfully !"
      );
    });
  });

This test ensures that all user inputs are captured correctly and the submission function is called with the expected payload.

2. Showing Validation Messages

Next, we check that our form correctly handles validation errors:

 it("shows validation messages on invalid form", async () => {
    render(<SignUpPage />);
    const submitButton = screen.getByRole("button", {
      name: /create account/i,
    });

    await userEvent.click(submitButton);

    await waitFor(() => {
      expect(screen.getByText(/first name is required/i)).toBeInTheDocument();
      expect(screen.getByText(/last name is required/i)).toBeInTheDocument();
      expect(screen.getByText(/email is required/i)).toBeInTheDocument();
      expect(screen.getByText(/password is required/i)).toBeInTheDocument();
      expect(screen.getByText(/terms of service/i)).toBeInTheDocument();
    });
  });

🚀 Why This Matters

These tests might look like a bit of extra work at first, but they pay off quickly. Every time I refactor or add a new feature, my test suite acts like a safety net. I no longer have to double-check everything manually—I just run the tests and let them tell me if something broke.

It’s honestly a game-changer.

Conclusion

Testing in React isn't just a best practice—it's a confidence booster. After writing comprehensive tests for my SignUp and SignIn pages, I noticed a major shift in how I approach development. I’m no longer second-guessing whether my form validations work, whether the correct data is sent to the server, or whether UI feedback shows up properly. I just run the tests—and they tell me everything I need to know.

0
Subscribe to my newsletter

Read articles from Oussama Chahidi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Oussama Chahidi
Oussama Chahidi

Hi, my name is oussama and i am a self-taught full stack javascript developer with interests in computers. I like the expend my knowledge and learn new things each day cause i always see the beauty in mystery.