Skip to main content

Overview

Component testing ensures your React components render correctly and behave as expected. Using React Testing Library with Vitest, you can write tests that closely resemble how users interact with your application.

Basic Component Test Structure

Every test follows a clear structure:
  1. Arrange: Set up the test data and render the component
  2. Act: Perform actions (if needed)
  3. Assert: Verify the expected outcome

Testing Component Rendering

Let’s examine a real component from the codebase:
MyAwesomeApp.tsx
const firtsName = "angels";
const lastName = "mejia";
const juegos = ["forrnite", "gd", "metro"];

export function MyAwesomeApp() {
  return (
    <div data-testid="div-app">
      <h1 data-testid="firts-namee">{firtsName}</h1>
      <h3>{lastName}</h3>
      <p className="miClaseFavorita">{juegos.join(",")}</p>
    </div>
  );
}

Query Methods: Container vs Screen

React Testing Library offers two approaches for querying elements:
import { describe, expect, test } from "vitest";
import { render, screen } from "@testing-library/react";
import { MyAwesomeApp } from "./MyAwesomeApp";

describe("MyAwesomeApp", () => {
  test("should render firstName and lastName", () => {
    const { container } = render(<MyAwesomeApp />);
    
    const h1 = container.querySelector("h1");
    expect(h1?.innerHTML).toContain("a");

    const h3 = container.querySelector("h3");
    expect(h3?.innerHTML).toContain("mejia");
  });
});
The screen approach is recommended by React Testing Library as it’s more concise and encourages accessible queries. Use data-testid attributes when you can’t query by role, label, or text.

Testing Helper Functions

Unit tests for pure functions follow the Arrange-Act-Assert pattern clearly:
math.helper.ts
export const add = (a: number, b: number) => {
  return a + b;
}

export const sub = (a: number, b: number) => {
  return a - b;
}

export const multiply = (a: number, b: number) => {
  return a * b;
}

Testing Pure Functions

math.helper.test.ts
import { describe, expect, test } from "vitest";
import { add, multiply, sub } from "./math.helper";

describe("add", () => {
  test("should add two positive numbers", () => {
    // 1. Arrange
    const a = 1;
    const b = 5;

    // 2. Act
    const result = add(a, b);
    
    // 3. Assert
    expect(result).toBe(a + b);
  });
});

describe("substract", () => {
  test("should subtract two positive numbers", () => {
    const a = 2;
    const b = 3;
    const result = sub(a, b);
    expect(result).toBe(a - b);
  });

  test("should subtract with negative numbers", () => {
    const a = -2;
    const b = 3;
    const result = sub(a, b);
    expect(result).toBe(a - b);
  });
});

describe("multiply", () => {
  test("should multiply two positive numbers", () => {
    const a = 2;
    const b = 3;
    const result = multiply(a, b);
    expect(result).toBe(a * b);
  });

  test("should multiply with negative numbers", () => {
    const a = -6;
    const b = 4;
    const result = multiply(a, b);
    expect(result).toBe(a * b);
  });
});

Debugging Tests

Use screen.debug() to print the current DOM state:
test("should render component", () => {
  const { container } = render(<MyAwesomeApp />);
  screen.debug(); // Prints the entire DOM tree
});
screen.debug() is invaluable for understanding what React Testing Library “sees” in your component. Use it when tests fail unexpectedly.

Best Practices

  1. Use data-testid sparingly: Prefer querying by role, label, or text content
  2. Test user behavior: Focus on what users see and do, not implementation details
  3. Keep tests simple: Each test should verify one specific behavior
  4. Use descriptive test names: Test names should clearly state what is being tested
  5. Follow AAA pattern: Always structure tests with Arrange, Act, Assert

Common Queries

  • getByTestId(): Query by data-testid attribute
  • getByRole(): Query by ARIA role (button, heading, etc.)
  • getByText(): Query by text content
  • getByLabelText(): Query form elements by label
  • queryBy*(): Returns null if not found (for negative assertions)
  • findBy*(): Async queries that wait for elements

Next Steps

  • Learn about snapshot testing to catch UI regressions
  • Explore async testing with findBy queries
  • Add test coverage reporting to your workflow

Build docs developers (and LLMs) love