Learn ReactJS - Testing & Quality
Episode 16 of 24

Learn ReactJS - Testing & Quality

This episode teaches unit testing with Jest and React Testing Library, snapshot testing, integration testing for component behavior, and E2E testing with Cypress or Playwright. Code quality is guaranteed, not merely hoped for.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Untested code turns into dreaded code. Episode 16 makes testing a natural part of your React workflow, not an obligation to keep postponing.

We build the testing pyramid from the bottom up: unit testing with Jest and React Testing Library, snapshot testing, integration testing for behavior across components, and E2E testing with Cypress or Playwright for real user flows in the browser.

Unit Testing with Jest and React Testing Library

Setting Up Vitest in a Vite Project

For a Vite project, Vitest is the natural match because it uses the same Vite config. Install it and add the scripts:

Install Vitest and Testing Library
npm install -D vitest @testing-library/react @testing-library/jest-dom jsdom
Test scripts in package.json
{
  "scripts": {
    "test": "vitest",
    "test:run": "vitest run"
  }
}

npm install -D vitest ... installs the test framework along with Testing Library. npm run test runs vitest in watch mode; vitest run runs once in CI.

Writing Your First Unit Test

React Testing Library tests behavior from the user's perspective — render the component, interact, and assert the results:

JSComponent unit test
import { render, screen, fireEvent } from "@testing-library/react"
import { describe, it, expect } from "vitest"
import Counter from "./Counter.jsx"
 
describe("Counter", () => {
  it("menambah angka saat tombol diklik", () => {
    render(<Counter />)
    const tombol = screen.getByRole("button")
    fireEvent.click(tombol)
    expect(screen.getByText("1")).toBeTruthy()
  })
})

screen.getByRole("button") finds the element by its accessibility role, not by text or class — mimicking how users and screen readers find elements. fireEvent.click simulates a click, then expect checks the result.

Snapshot Testing

Using Snapshots Wisely

Snapshot testing stores a serialized output of the component and compares it on the next test run. Writing one is as easy as a single line:

JSSimple snapshot
it("konsisten dengan snapshot", () => {
  const { container } = render(<Profil nama="Arman" />)
  expect(container).toMatchSnapshot()
})

expect(container).toMatchSnapshot() creates a snapshot file on first run, then compares against it on every run. Snapshots are great for detecting unintentional markup changes — for example, a CSS class that shifted.

When to Be Careful

Snapshots easily produce false positives: insignificant small changes fail the test, and developers get used to updating snapshots without looking. Use snapshots for stable components, and combine them with behavior assertions — not replace them.

Integration Testing and Component Behavior

Testing Interactions Between Components

An integration test combines several components and tests their flow together. Example: a login form that calls a handler and shows a message:

JSForm integration test
import { render, screen, fireEvent, waitFor } from "@testing-library/react"
 
it("menampilkan error saat login gagal", async () => {
  render(<FormLogin />)
 
  fireEvent.change(screen.getByLabelText(/email/i), {
    target: { value: "salah@contoh.com" },
  })
  fireEvent.click(screen.getByRole("button", { name: /masuk/i }))
 
  await waitFor(() => {
    expect(screen.getByText(/kredensial salah/i)).toBeTruthy()
  })
})

fireEvent.change fills the input, the click triggers the submit, then waitFor waits for the async result. This integration test ensures the form, validation, and handler work as a unit.

Choose Queries Close to the User

Query priority in Testing Library: getByRole and getByLabelText are better than getByTestId. Role-based queries force components to have good accessibility, and the tests aren't brittle to class or markup changes.

E2E Testing with Cypress or Playwright

Playwright: End-to-End in a Real Browser

Unit and integration tests don't guarantee the whole flow works. E2E runs the real app in a browser. Playwright is the modern choice:

Install Playwright
npm init playwright@latest
JSPlaywright E2E test
import { test, expect } from "@playwright/test"
 
test("login lalu melihat dashboard", async ({ page }) => {
  await page.goto("http://localhost:5173/login")
  await page.fill("#email", "admin@contoh.com")
  await page.fill("#password", "rahasia123")
  await page.click("button:has-text('Masuk')")
  await expect(page).toHaveURL(/dashboard/)
})

page.goto opens the real app, page.fill fills the form, and expect(page).toHaveURL ensures navigation succeeded. E2E tests what unit tests can't reach: routing, real rendering, and cross-page interactions.

When E2E, When Unit

Keep the pyramid right: many fast unit tests, some integration tests, and a few slow but most convincing E2E tests. Run E2E in CI, not on every save.

Tip

Start E2E with the most critical flows: login, checkout, and registration. These flows break most often and are most expensive if they fail in production.

Conclusion

Episode 16 built a culture of quality: unit tests with Vitest and React Testing Library, snapshot testing for markup regression detection, integration testing for behavior across components, and E2E with Playwright for real flows in the browser.

Key takeaways:

  • Vitest and React Testing Library are the standard pairing for Vite projects.
  • Prioritize role-based queries: getByRole, getByLabelText.
  • Snapshots catch unintended markup changes, but aren't a substitute for assertions.
  • Integration tests ensure components work together.
  • E2E with Playwright tests the real app in the browser.
  • Keep the pyramid: many unit tests, few E2E tests.

In the next episode, episode 17, we'll cover accessibility & UX — ARIA roles, keyboard navigation, and focus management, semantic HTML and accessible forms, mobile-first responsive design, and the basics of internationalization. Your app will be open to everyone.

Learn ReactJS - Testing & Quality | Learn ReactJS