Vitest và React Testing Library: Unit Test React Hiện Đại Thay Thế Jest 2025

Vitest và React Testing Library đang trở thành bộ đôi testing phổ biến nhất cho dự án React hiện đại. Nếu bạn vẫn còn dùng Jest, bài viết này sẽ cho bạn thấy lý do nên chuyển sang Vitest — tốc độ nhanh hơn, cấu hình gần như zero, tương thích hoàn toàn với React Testing Library.

Tại sao chuyển từ Jest sang Vitest?

Jest đã là tiêu chuẩn testing JavaScript nhiều năm, nhưng Vitest mang lại trải nghiệm tốt hơn nhờ:

  • Tốc độ cực nhanh: dựa trên Vite, chạy hot module replacement, chỉ re-test file bị thay đổi.
  • Cấu hình gần như zero: không cần jest.config.js phức tạp, chỉ cần vài dòng trong vite.config.ts.
  • Tương thích Jest API: describe, it, expect, vi.fn() đều hoạt động y hệt.
  • TypeScript native: config tự nhận kiểu dữ liệu, không cần ts-jest.

Vitest test runner interface showing fast test execution in terminal

Cài đặt Vitest cho dự án React

Thêm Vitest vào project React Vite chỉ mất vài phút:

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

Sau đó thêm section test vào vite.config.ts:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  test: {
    environment: 'jsdom',
    globals: true,
    setupFiles: './src/test/setup.ts',
  },
})

React Testing Library: Test theo cách người dùng thật sự dùng

React Testing Library (RTL) khuyến khích bạn test component từ góc nhìn người dùng — click, type, query theo label chứ không phải implementation detail. Đây là ví dụ test component LoginForm:

import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import LoginForm from './LoginForm'

test('submit form with valid credentials', async () => {
  render(<LoginForm />)
  
  await userEvent.type(screen.getByLabelText(/email/i), '[email protected]')
  await userEvent.type(screen.getByLabelText(/mật khẩu/i), 'secret123')
  await userEvent.click(screen.getByRole('button', { name: /đăng nhập/i }))
  
  expect(await screen.findByText(/chào mừng/i)).toBeInTheDocument()
})

React Testing Library DOM queries showing getByRole and getByLabelText selectors

So sánh tốc độ Jest vs Vitest

Trên dự án React có 200 test cases, Vitest chạy xong trong khoảng 3-5 giây trong chế độ watch, trong khi Jest cần 15-20 giây cho lần chạy đầu và 8-12 giây khi incremental. Hiệu năng khác biệt rõ rệt khi bạn phải chạy test liên tục trong quá trình phát triển.

Mock và Spy trong Vitest

Vitest cung cấp API vi tương tự Jest nhưng với một số cải tiến:

  • vi.fn() — mock function có thể kiểm tra toHaveBeenCalled()
  • vi.spyOn() — theo dõi method gốc mà không ghi đè
  • vi.mock() — mock toàn bộ module
vi.mock('./api', () => ({
  fetchUser: vi.fn().mockResolvedValue({ name: 'Hung', role: 'admin' }),
}))

Coverage report tích hợp sẵn

Vitest có built-in coverage nhờ @vitest/coverage-v8. Chỉ cần thêm flag --coverage khi chạy:

npx vitest run --coverage

Báo cáo sẽ hiển thị line, function, branch coverage trực quan trong terminal hoặc HTML report. Không cần cấu hình thêm babel-plugin-istanbul hay jest-coverage.

Khi nào nên giữ Jest?

Jest vẫn phù hợp nếu bạn dùng React Native (Metro bundler chưa hỗ trợ Vitest tốt), hoặc project legacy cần migrate từng bước. Tuy nhiên, với dự án React mới khởi tạo bằng Vite, Vitest là lựa chọn tối ưu.

Migrate từ Jest sang Vitest: Mẹo thực tế

Quá trình migrate thường nhẹ nhàng vì API tương thích, nhưng có một vài điểm cần lưu ý:

  • Setup files: Cài đặt lại các mock global trong test/setup.ts thay vì jest.setup.js.
  • Snapshot testing: Vitest dùng thư viện @vitest/snapshot, snapshot cũ cần cập nhật lại.
  • Timer mocks: Thay jest.useFakeTimers() bằng vi.useFakeTimers().
  • Module mocks: vi.mock() hoạt động ở top-level, không cần factory function như Jest.

Ví dụ migrate một test case:

// Jest
jest.mock('./utils', () => ({
  formatDate: jest.fn().mockReturnValue('2025-01-01'),
}));

// Vitest
vi.mock('./utils', () => ({
  formatDate: vi.fn().mockReturnValue('2025-01-01'),
}));

Vitest UI: Giao diện trực quan cho testing

Vitest đi kèm UI dashboard chạy bằng npx vitest --ui. Bạn có thể:

  • Xem test tree, filter theo tên, trạng thái pass/fail.
  • Inspect source code tại dòng bị fail.
  • Re-run single test bằng click chuột.
  • Xem coverage overlay trực tiếp trên code.

Điều này giúp debug test nhanh hơn nhiều so với terminal output thuần túy, đặc biệt khi test suite lớn.

CI/CD Integration

Vitest tích hợp trực tiếp vào GitHub Actions, GitLab CI hoặc Vercel. Chỉ cần cài đặt Node 18+, chạy npx vitest run trong workflow. Output JSON cho Jest compatibility nên bạn có thể giữ lại cấu hình CI cũ.

Tổng kết

Vitest kết hợp React Testing Library tạo ra workflow testing nhanh, hiện đại và ít friction nhất cho React hiện tại. Tìm hiểu thêm tại vitest.devtesting-library.com. Bạn có thể migrate từng file mà không cần đổi toàn bộ codebase nhờ tương thích API Jest.

Tôi là một lập trình viên IOS. Code chính là IOS nhưng thỉnnh thoảng vẫn đá sang Android hoặc web. Mặc dù không quá thông thạo nhưng tôi sẽ chia sẻ những kiến thức mà mình đã tìm hiểu, áp dụng qua.

Bài viết liên quan

Rust Async Trait và GAT: Viết code bất đồng bộ an toàn kiểu

Rust Async Trait và GAT: Viết code bất đồng bộ an toàn kiểu Vấn đề với async fn trong trait trước Rust 1.75 Lập trình bất đồng bộ (async) đã…

Xem thêm

eBPF trong Linux: Giám sát và networking hiệu năng không cần kernel module

eBPF trong Linux: Giám sát và networking hiệu năng không cần kernel module eBPF (extended Berkeley Packet Filter) đang thay đổi cách nhà phát triển và system engineer tương tác…

Xem thêm

Cursor IDE vs Claude Code: AI coding agent workflow phù hợp dev 2025

Cursor IDE vs Claude Code: AI coding agent workflow nào phù hợp dev 2025? AI coding agent không còn là khái niệm xa vời trong nghiên cứu — nó đang…

Xem thêm
0 0 đánh giá
Article Rating
Theo dõi
Thông báo của
guest
0 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất