React Testing — Vitest and React Testing Library

Sanjeev SharmaSanjeev Sharma
2 min read

Advertisement

React Testing — Vitest and React Testing Library

Testing React components ensures reliability and prevents regressions.

Setup

npm install -D vitest @testing-library/react @testing-library/jest-dom

Basic Test

import { test, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import { Counter } from '@/components/counter'

test('renders counter', () => {
  render(<Counter />)
  expect(screen.getByText(/count/i)).toBeInTheDocument()
})

test('increments on button click', () => {
  render(<Counter />)
  const button = screen.getByRole('button', { name: /increment/i })
  button.click()
  expect(screen.getByText('1')).toBeInTheDocument()
})

User Interactions

import { userEvent } from '@testing-library/user-event'

test('form submission', async () => {
  const user = userEvent.setup()
  render(<LoginForm />)

  const input = screen.getByLabelText(/email/i)
  await user.type(input, 'test@example.com')

  const button = screen.getByRole('button')
  await user.click(button)

  expect(screen.getByText(/logged in/i)).toBeInTheDocument()
})

Mocking

import { vi } from 'vitest'

test('calls API on submit', async () => {
  const mockFetch = vi.fn().mockResolvedValue({
    json: () => Promise.resolve({ id: 1 })
  })

  global.fetch = mockFetch

  render(<Form />)
  // ... test form submission
  expect(mockFetch).toHaveBeenCalled()
})

Real-World: Component Test

test('todo list', async () => {
  const user = userEvent.setup()
  render(<TodoList />)

  // Add a todo
  const input = screen.getByPlaceholderText(/add todo/i)
  await user.type(input, 'Learn testing')

  const addButton = screen.getByRole('button', { name: /add/i })
  await user.click(addButton)

  // Verify todo appears
  expect(screen.getByText('Learn testing')).toBeInTheDocument()

  // Delete todo
  const deleteButton = screen.getByRole('button', { name: /delete/i })
  await user.click(deleteButton)

  expect(screen.queryByText('Learn testing')).not.toBeInTheDocument()
})

FAQ

Q: Should I test implementation details? A: No, test behavior instead. Use React Testing Library, not shallow render.

Q: How much coverage do I need? A: Aim for 80% coverage of critical paths, not 100%.

Q: Is E2E testing better than unit tests? A: Both are needed. Unit tests for components, E2E for workflows.


Good testing practices build confidence in your React code.

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro