Setting Up Unit Testing in React Vite with Vitest: A Practical Guide

Candra Kriswinarto
3 min readJan 11, 2025

--

Photo by Nguyen Dang Hoang Nhu on Unsplash

In this tutorial, we’ll walk through setting up and implementing unit tests for a simple React Todo application using Vitest and React Testing Library. We’ll create tests for both the main App component and a TodoList component while explaining each step in detail.

Project Setup

First, let’s create a new React project using Vite:

npm create vite@latest learn-vitest

The Application Code

Our application consists of two main components: App.tsx and a TodoList component. The App component serves as our main container, while TodoList handles the todo management functionality.

The TodoList component implements basic features like:

  • Adding new todos
  • Toggling todo completion status
  • Maintaining a list of todos in state

Setting Up Vitest

To get started with testing, we need to install Vitest and configure it properly:

npm i -D vitest happy-dom @testing-library/react @testing-library/jest-dom

Understanding the Vite Configuration

In our vite.config.ts, we've added specific test configuration:

test: {
environment: 'happy-dom',
setupFiles: ['./src/tests/setup.ts'],
include: ['src/**/*.{test,spec}.{ts,tsx}']
}

This configuration does several important things:

  • environment: 'happy-dom': Sets up a DOM-like environment for testing
  • setupFiles: Points to our test setup file
  • include: Specifies which files should be treated as test files (those ending in .test.ts/tsx or .spec.ts/tsx)

Test Setup File

The setup.ts file is crucial for our testing environment:

import { afterEach } from 'vitest';
import { cleanup } from '@testing-library/react';
import "@testing-library/jest-dom/vitest"

afterEach(() => {
cleanup();
});

This setup file:

  • Imports necessary testing utilities
  • Ensures cleanup after each test (preventing test pollution)
  • Adds jest-dom matchers for better assertions
  • Runs cleanup automatically after each test to maintain a clean testing environment

Writing Our Tests

Testing the App Component

Our App component test (App.test.tsx) verifies the basic structure:

describe("App Component", () => {
it("should render the app title in h1", () => {
render(<App />);
const heading = screen.getByTestId("title");

expect(heading).toBeInTheDocument();
expect(heading).toHaveTextContent(/React Testing Demo$/);
expect(heading.tagName).toBe("H1");
});
});

This test:

  1. Renders the App component
  2. Checks if the title exists using a data-testid
  3. Verifies the content and HTML tag of the title

Testing the TodoList Component

The TodoList tests (todo-list.test.tsx) are more comprehensive:

describe("Todo list Component", () => {
beforeEach(() => {
render(<TodoList />);
});

it("should render the todo list with initial empty state", () => {
const todoList = screen.getByTestId("todo-list");
expect(todoList).toBeInTheDocument();
expect(todoList.children).toHaveLength(0);
});
it("should add a new todo when input is filled and add button is clicked", async () => {
const input = screen.getByTestId("todo-input");
const addButton = screen.getByTestId("add-todo-button");
fireEvent.change(input, { target: { value: "New Todo Item" } });
fireEvent.click(addButton);
await waitFor(() => {
const todoList = screen.getByTestId("todo-list");
expect(todoList.children).toHaveLength(1);
expect(screen.getByText("New Todo Item")).toBeInTheDocument();
expect(input).toHaveValue("");
});
});
});

These tests verify:

  1. Initial empty state of the todo list
  2. Adding new todos through user interaction
  3. Proper state updates after adding todos

Key testing concepts demonstrated:

  • Using beforeEach for test setup
  • Testing user interactions with fireEvent
  • Handling asynchronous updates with waitFor
  • Using data-testid attributes for reliable element selection

Running the Tests

To run your tests, add a test script to your package.json:

{
"scripts": {
"test": "vitest"
}
}

Then run:

npm test

Video Tutorial

If you prefer a video walkthrough of this setup, check out the detailed tutorial here: https://youtu.be/SMsZDg-t_mA

--

--

Candra Kriswinarto
Candra Kriswinarto

Written by Candra Kriswinarto

👋 Front-End Developer & YouTuber. I write about web dev, share coding tips, and create tutorials to help others learn. https://youtube.com/@CandDev

No responses yet