Testing React Components: Verify What Users Can Do
Testing React Components: Verify What Users Can Do
An attendance button renders without errors, but clicking it no longer changes the displayed status. A test that only checks that a component exists would miss the broken user task.
A component test renders an interface, performs supported interactions and checks the observed result. Prefer queries based on accessible roles, labels and text so tests describe the user’s task rather than private implementation details.
Understand
Choose a meaningful initial and changed-state assertion.
Build
Read a real React Testing Library test.
Check
Distinguish component checks from integration coverage.
A test follows a requirement through an interaction
Arrange
Render the attendance screen.
Act
Click the labeled attendance control.
Assert
Check that the expected status appears.
Test behavior at the interface boundary
A user should be able to find the attendance button and see Maya’s status change. React Testing Library can render the component in a supported test environment, and user-event can simulate interaction sequences closer to user behavior than directly calling a component’s private handler.
An assertion compares observed behavior with a requirement. Checking only that setState was called couples the test to implementation and may miss a wrong rendered result. Include meaningful boundary, failure and asynchronous cases where those are part of the promised behavior.
Use a clear component as the test subject
The subject has an accessible button name and a visible status. The requirement is that one click changes Maya from absent to present. This actual component can be used by the test shown later, rather than replacing React with a hand-written state simulation.
React · JavaScript with JSX
import { useState } from 'react';
export default function App() {
const [present, setPresent] = useState(false);
return <main><h1>Attendance test subject</h1><p role="status">Maya: {present ? 'present' : 'absent'}</p>
<button onClick={() => setPresent(value => !value)}>Toggle Maya attendance</button></main>;
}Expected screen and behavior
One click displays Maya: present. A second click returns to Maya: absent.Arrange, act and check the observed result
React · Use a clear component as the test subject
import { useState } from 'react';
export default function App() {
const [present, setPresent] = useState(false);
return <main><h1>Attendance test subject</h1><p role="status">Maya: {present ? 'present' : 'absent'}</p>
<button onClick={() => setPresent(value => !value)}>Toggle Maya attendance</button></main>;
}Render the subject, then use getByRole to find the button by its name. Await user.click because the interaction helper can perform a sequence of events. Finally check the status text or use findByText for an asynchronously appearing value.
The example below is a real test for a configured Vitest project with a browser-like jsdom environment. Save the subject as App.jsx and the test as App.test.jsx. The test assumes React Testing Library and user-event are installed and the runner transforms JSX; it is not executable as a plain browser script.
Prepare a browser-like component test
Use the React Vite project created in setting up React. From that project folder, install the test runner, its browser-like document environment, and the two interaction libraries. The tools below run on your computer; they are not libraries your school page must download for visitors.
Terminal commands:
npm install --save-dev vitest jsdom @testing-library/react @testing-library/user-eventSave this JavaScript configuration as vitest.config.js beside package.json. The React plugin already comes with the Vite React template and transforms JSX; jsdom supplies document and browser elements for a component test.
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
test: { environment: "jsdom" }
});Save the next component as src/App.jsx and the test as src/App.test.jsx, then run npx vitest run. A passing test confirms its stated attendance interaction. jsdom does not reproduce a real browser’s layout, so responsive appearance still needs a browser check.
Read the real test and its environment requirements
JavaScript test for Vitest with jsdom:
import { test, expect } from "vitest";
import { render, screen, cleanup } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import App from "./App.jsx";
test("toggles Maya attendance", async () => {
const user = userEvent.setup();
render(<App />);
try {
expect(screen.getByRole("status").textContent).toContain("Maya: absent");
await user.click(screen.getByRole("button", { name: "Toggle Maya attendance" }));
expect(screen.getByRole("status").textContent).toContain("Maya: present");
} finally { cleanup(); }
});Use the runner’s supported jsdom configuration and a command such as npx vitest run. This course does not assume every existing project has that runner already. A browser end-to-end check additionally exercises routing, loading, layout and the real deployed environment; one component test does not cover all of those concerns.
Try the school task
React · starting example
import { useState } from 'react';
export default function App() {
const [present, setPresent] = useState(false);
return <main><h1>Attendance test subject</h1><p role="status">Maya: {present ? 'present' : 'absent'}</p>
<button onClick={() => setPresent(value => !value)}>Toggle Maya attendance</button></main>;
}Extend the requirement to verify a second click restores absent. Keep the subject’s behavior simple and predict both states before writing the assertions.
Worked answer
The complete subject below supports both directions. Add another awaited user.click and assert Maya: absent in the same test. The browser check for this worked answer performs both clicks, so the restored state is independently observed.
React · JavaScript with JSX
import { useState } from 'react';
export default function App() {
const [present, setPresent] = useState(false);
return <main><h1>Two-way attendance</h1><p role="status">Maya: {present ? 'present' : 'absent'}</p>
<button onClick={() => setPresent(value => !value)}>Toggle attendance</button></main>;
}Expected screen and behavior
Toggle attendance produces Maya: present, then Maya: absent on the next click.Mistakes and boundaries
Do not use fixed sleeps to guess when asynchronous UI will be ready. Await an appropriate observable condition through supported async queries.
Mock external services deliberately and label what is mocked. A mocked success response does not verify server authorization or production request handling.
A screenshot or snapshot can catch appearance changes but does not replace task-based assertions. Check keyboard behavior and accessible names as part of meaningful interface requirements.
Check your reasoning
React · Use a clear component as the test subject
import { useState } from 'react';
export default function App() {
const [present, setPresent] = useState(false);
return <main><h1>Attendance test subject</h1><p role="status">Maya: {present ? 'present' : 'absent'}</p>
<button onClick={() => setPresent(value => !value)}>Toggle Maya attendance</button></main>;
}Choose the answer that follows the data and the interaction, then read the explanation for each alternative.
Carry the idea forward
Render, interact and check requirements through the visible interface. Connect this with accessible controls and investigating failed behavior.
Read the primary reference: React Testing Library: testing principles and setup.
Reaching the recap and completing the quizzes are separate milestones.