█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Programming Languages/React (Standalone Deep Dive)/Testing React
45 minIntermediate

Testing React

After this lesson, you will be able to: Apply React Testing Library philosophy: test behavior, not implementation; mock API calls cleanly.

Tests that survive refactors test what the user sees, not internals.

Prerequisites:Forms

RTL basics

Query by role + label + text, like a screen reader.

python
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Counter } from "./Counter";
it("increments on click", async () => {
const user = userEvent.setup();
render(<Counter initial={0} />);
expect(screen.getByText(/count: 0/i)).toBeInTheDocument();
await user.click(screen.getByRole("button", { name: /increment/i }));
expect(screen.getByText(/count: 1/i)).toBeInTheDocument();
});

Mocking API calls with MSW

Mock Service Worker intercepts fetch at the network layer.

python
// test/handlers.ts
import { http, HttpResponse } from "msw";
export const handlers = [
http.get("/api/users", () => HttpResponse.json([{ id: "u1", name: "Alex" }])),
http.post("/api/users", async ({ request }) => {
const body = await request.json();
return HttpResponse.json({ id: "u2", ...body }, { status: 201 });
}),
];
// test/setup.ts
import { setupServer } from "msw/node";
import { handlers } from "./handlers";
export const server = setupServer(...handlers);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

Test behavior, not implementation

Bad: assert on state shape, hook return values, internal method names. Refactor = test breaks. Good: assert on what the user sees (text, roles, behavior after click). Refactor with same UI = test passes. Rule of thumb: if your test imports useState or jest.spyOn to peek inside, you're testing implementation.

Common mistakes only experienced React testers avoid

getByTestId everywhere. Couples tests to implementation. Prefer getByRole. Mocking everything, including the component under test. Render the real thing; mock the boundary. Async tests without await. Assertions race the DOM. Always `await findByX` or `await user.click`. Snapshots for everything. They become ignored noise.

Quick Check

Why prefer getByRole("button", { name: /save/i }) over getByTestId("save-btn")?

Pick the senior answer.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←Forms in React
Back to React (Standalone Deep Dive)
React Server Components→