Hướng dẫn Vitest: ‘Hack’ tốc độ Unit Test cho dự án Vite, React và Vue

Development tutorial - IT technology blog
Development tutorial - IT technology blog

Bối cảnh: Khi Jest trở thành ‘cục tạ’ lúc 2 giờ sáng

Hãy tưởng tượng bạn đang phải xử lý một lỗi nghiêm trọng trên production vào lúc nửa đêm. Áp lực tăng cao, bạn vừa sửa xong một dòng code then chốt và nhấn lệnh chạy test để kiểm tra. Thay vì kết quả hiện ra ngay, bạn phải ngồi nhìn màn hình đờ đẫn mất 45-60 giây chỉ để Jest khởi động, load Babel và transform file. Trong tình huống dầu sôi lửa bỏng, mỗi giây chờ đợi đó thực sự là cực hình.

Nghịch lý lớn nhất khi dùng Jest với Vite chính là sự xung đột về công nghệ. Vite chạy cực nhanh nhờ tận dụng ES Modules (ESM), trong khi Jest vẫn bám trụ với CommonJS theo mặc định. Để kết nối chúng, bạn buộc phải thiết lập một ‘mê cung’ cấu hình từ babel-jest đến ts-jest. Hệ quả là môi trường chạy test và môi trường dev thực tế của bạn chẳng liên quan gì đến nhau.

Vitest xuất hiện như một vị cứu tinh để xóa bỏ hoàn toàn rào cản này. Nó dùng chung bộ transform với Vite. Vì thế, chỉ cần code chạy được trên trình duyệt, Vitest sẽ xử lý ngon lành mà không cần thêm plugin hay alias lằng nhằng. Tốc độ khởi động của nó thường chỉ tính bằng mili giây, giúp bạn duy trì mạch tập trung mà không bị ngắt quãng.

Cài đặt: Đưa Vitest vào dự án trong 3 nốt nhạc

Nếu dự án React hoặc Vue của bạn đang dùng Vite, việc tích hợp Vitest dễ thở hơn nhiều so với ‘vật lộn’ với Jest. Đừng chần chừ, hãy mở terminal và tống khứ sự chậm chạp bằng lệnh sau:

npm install -D vitest @vitest/ui @vitest/coverage-v8 jsdom

Dưới đây là lý do chúng ta cần những gói này:

  • vitest: Công cụ chính để chạy test.
  • @vitest/ui: Dashboard trực quan trên trình duyệt, cứu cánh khi bạn cần soi lỗi mà không muốn căng mắt nhìn terminal.
  • jsdom: Giả lập môi trường trình duyệt, cực kỳ quan trọng khi test các component React/Vue.
  • @vitest/coverage-v8: Báo cáo chi tiết xem bạn đã test được bao nhiêu % logic code.

Sau khi cài xong, bạn hãy cập nhật package.json để kích hoạt các lệnh tắt:

{
  "scripts": {
    "test": "vitest",
    "test:ui": "vitest --ui",
    "test:coverage": "vitest run --coverage"
  }
}

Cấu hình thực chiến: Tối ưu để chạy ‘mượt’ hơn

Điểm ăn tiền của Vitest là khả năng dùng chung file vite.config.ts. Tuy nhiên, để quản lý chuyên nghiệp hơn, mình khuyên bạn nên tạo file vitest.config.ts riêng biệt. Cách này giúp tách bạch logic build production và logic chạy test:

import { defineConfig, mergeConfig } from 'vitest/config';
import viteConfig from './vite.config';

export default mergeConfig(viteConfig, defineConfig({
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: ['./src/setupTests.ts'],
    css: true,
  },
}));

Trong cấu hình trên, globals: true cho phép bạn gọi thẳng các hàm describe hay it mà không cần import ở mọi file. Điều này giữ cho code test sạch sẽ và quen thuộc nếu bạn chuyển từ Jest sang. Với environment: 'jsdom', bạn sẽ có sẵn các đối tượng windowdocument để thao tác với DOM.

Riêng với anh em làm React, hãy tạo thêm src/setupTests.ts để bổ sung các công cụ kiểm tra DOM mạnh mẽ hơn:

import '@testing-library/jest-dom';

Và đừng quên cài thư viện hỗ trợ: npm install -D @testing-library/react @testing-library/jest-dom.

Mẹo nhỏ: Khi làm việc với dữ liệu API phức tạp, mình thường dùng toolcraft.app để format lại JSON. Việc này giúp file test dễ đọc hơn hẳn, tránh được những lỗi ngớ ngẩn do thiếu dấu phẩy khi copy-paste lúc mệt mỏi.

Viết Test và hưởng thành quả: Tốc độ là tất cả

Hãy thử nghiệm thực tế với một hàm format tiền tệ đơn giản:

// src/utils/format.ts
export const formatCurrency = (amount: number) => {
  return new Intl.NumberFormat('vi-VN', { style: 'currency', currency: 'VND' }).format(amount);
};

Tạo file test tương ứng src/utils/format.test.ts:

import { formatCurrency } from './format';

describe('Utility: formatCurrency', () => {
  it('nên format đúng định dạng ₫ cho tiền Việt', () => {
    const result = formatCurrency(100000);
    expect(result.replace(/\s/g, ' ')).toContain('₫');
  });

  it('nên hiển thị 0 ₫ khi giá trị bằng 0', () => {
    expect(formatCurrency(0).replace(/\s/g, ' ')).toContain('0 ₫');
  });
});

Ngay khi chạy npm test, bạn sẽ thấy Vitest phản hồi gần như tức thì. Chế độ Watch mode của nó cực kỳ thông minh khi chỉ chạy lại đúng file bạn vừa sửa dựa trên dependency graph. Thay vì đợi 30 giây như trước, giờ đây bạn chỉ mất chưa tới 1 giây để biết code mình có chạy đúng hay không.

Nếu muốn trải nghiệm ‘xịn’ hơn, hãy thử npm run test:ui. Bạn sẽ có một giao diện web để quản lý hàng trăm bộ test, xem code coverage trực tiếp và debug từng case chỉ bằng một cú click. Đây là tính năng gây nghiện nhất giúp việc viết test không còn là cực hình.

Để đảm bảo code luôn chuẩn chỉnh trước khi merge, hãy đưa Vitest vào CI/CD (như GitHub Actions) với lệnh:

npx vitest run

Lệnh này sẽ chạy toàn bộ test một lần rồi thoát, cực kỳ phù hợp cho các quy trình kiểm tra tự động. Tóm lại, nếu bạn đã dùng Vite thì không có lý do gì để bám lấy Jest. Vitest không chỉ giúp dự án chạy nhanh hơn, nó giúp bạn giữ được sự tỉnh táo và hiệu suất làm việc cao nhất, ngay cả trong những ca trực đêm căng thẳng.

Share: