Vitest vs Jest 2026: Test runner nào đã thắng rõ ràng
Vitest thắng Jest năm 2026: khởi động nhanh hơn 5,6×, watch mode nhanh hơn 28×, không cần cấu hình TypeScript. Khi nào nên chuyển và khi nào nên ở lại.
Bởi Ethan · Cập nhật 17 tháng 5, 2026
2.414 từ · 13 phút đọc
Vitest là lựa chọn đúng cho mọi dự án mới dùng Vite hoặc TypeScript-first trong năm 2026. Khoảng cách hiệu suất là có thật, khả năng tương thích API là thực chất, và hệ sinh thái đã đạt đến mức mà nếu bạn chọn Jest cho một dự án mới thì cần phải có lý do cụ thể. Nếu bạn đang dùng React Native, Angular, hoặc đang có một bộ test Jest ổn định mà CI không đau đầu gì, cứ ở lại. Còn lại, hãy đọc tiếp để hiểu bạn đang bỏ qua gì.
Bài này dành cho ai
Các developer đang chọn test runner cho dự án mới, hoặc đang cân nhắc migrate bộ test Jest hiện có. Nếu bạn đang dùng React Native hoặc Angular, hãy đọc phần “Khi nào Jest vẫn thắng” trước — sẽ tiết kiệm thời gian đọc.
Chúng tôi đã kiểm tra gì
Các con số trong bài này đến từ hai nguồn benchmark bên ngoài, trích dẫn chính xác:
- Nghiên cứu PkgPulse: 500 file test. Nguồn: pkgpulse.com.
- Case study migration thực tế: Một bài viết ghi lại chi tiết quá trình migrate 10k+ test từ Jest sang Vitest, có số liệu CI pipeline và chi phí GitHub Actions trước/sau. Lưu ý: URL gốc (
johal.in/war-story-migrating-10k-tests-jest-300-vitest-story/) hiện trả về 403 và không thể xác minh tại thời điểm viết bài. Các con số từ nguồn này được ghi chú bên dưới là mang tính minh họa.
Phiên bản dùng trong benchmark PkgPulse: Vitest 3, Jest 30 (tháng 6/2025). Node version không được ghi rõ. Vitest 4.1 (phát hành tháng 3/2026) là phiên bản hiện tại; chưa có benchmark bên thứ ba nào cho dòng 4.x tại thời điểm viết. Cải tiến hiệu suất trong 4.x được kỳ vọng là tăng dần.
Vitest vs Jest: TL;DR
| Vitest 3 | Jest 30 | |
|---|---|---|
| Cold start (500 tests) | 38 s | 214 s |
| Watch mode re-run | 0.3 s | 8.4 s |
| Peak memory | 400 MB | 930 MB |
| Hỗ trợ ESM | Native, không cần config | Experimental |
| TypeScript transform | esbuild (tích hợp sẵn) | ts-jest hoặc Babel |
| Overhead config | Dùng chung vite.config.ts | Config riêng + transforms |
| Browser testing | Trình duyệt thật qua Playwright | Chỉ có jsdom |
| Snapshot testing | Có | Có + Interactive Mode |
| React Native | Chưa hỗ trợ chính thức | Chính thức, do Meta duy trì |
| Tương thích API | Gần như đầy đủ; thay thế trực tiếp cho phần lớn dự án | — |
Hiệu suất
Sự chênh lệch cold start — 38 s so với 214 s trên bộ 500 test — nằm ở cách mỗi runner xử lý TypeScript và module resolution. Vitest transform TypeScript qua esbuild, nhanh hơn ts-jest hoặc Babel 10–100 lần. Nó cũng dùng dependency graph của Vite để biết test nào bị ảnh hưởng bởi một thay đổi, nên watch mode re-run mất 0.3 s thay vì 8.4 s.
Con số watch mode nhanh hơn 28 lần không phải trường hợp được chọn lọc có lợi. Đó là kết quả của Hot Module Replacement áp dụng vào test: thay đổi một component và chỉ những test import nó mới chạy lại, trong khoảng 20 ms. Watch mode của Jest dùng git diff heuristics và re-evaluate toàn bộ dependency graph mỗi lần có thay đổi.
Memory cũng kể câu chuyện tương tự: 400 MB so với 930 MB ở mức peak. Vitest tái sử dụng process Vite đã chạy sẵn; Jest tạo worker mới với process isolation đầy đủ theo mặc định.
Lưu ý: Những lợi ích này rõ nhất trên các bộ TypeScript lớn đang phát triển tích cực. Một benchmark của Speakeasy trên bộ test Vue/Vite production nhỏ hơn cho kết quả phụ thuộc vào cấu hình — một số trường hợp Jest vẫn nhanh hơn. Bộ test nhỏ (dưới 100 test) có thể chỉ cải thiện khoảng 2 lần. Phạm vi 5–28 lần phù hợp với team có hàng trăm hoặc hàng nghìn test và dùng watch mode nhiều.
Chi phí CI thực tế: Một case study migration đã công bố (10k+ test, 2 tuần, 3 kỹ sư) ghi nhận pipeline time giảm từ 14 phút xuống dưới 5 phút, tiết kiệm đáng kể chi phí GitHub Actions. URL nguồn hiện không truy cập được (trả về 403), nên các con số này không thể xác minh độc lập — xem như minh họa cho quy mô tiết kiệm có thể đạt được, không phải benchmark tái lập được.
Overhead cấu hình
Đây là nơi Vitest có lợi thế thường bị đánh giá thấp nhất với người dùng Vite.
Jest cần một file jest.config.js (hoặc jest.config.ts) riêng, quy tắc transform tường minh cho TypeScript và JSX, một moduleNameMapper riêng cho path aliases, và thường có cả một entry identity-obj-proxy cho CSS mocking.
Vitest kế thừa tất cả những thứ đó từ vite.config.ts có sẵn của bạn. Path aliases, CSS handling, TypeScript config — Vite đã biết gì thì Vitest biết đó. Không có gì cần khai báo lại.
// vitest.config.ts — cấu hình tối giản cho dự án Vite/React
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true,
environment: 'jsdom',
setupFiles: ['./src/setupTests.ts'],
coverage: { provider: 'v8' },
},
})
Đó là toàn bộ config cho hầu hết dự án Vite/React. Tương đương với Jest cần thêm hai đến bốn file nữa tùy vào setup TypeScript và CSS của bạn.
ESM và TypeScript
Hỗ trợ ESM trong Jest 30 vẫn còn experimental. Bạn có thể làm cho nó chạy được — nhưng cần flag --experimental-vm-modules của Node, cấu hình transform cụ thể, và đôi khi phải tìm cách workaround tùy dependency tree. Không phải zero-config.
Vitest coi ESM là mặc định. TypeScript chạy qua esbuild không cần cấu hình gì thêm. Nếu bạn bắt đầu dự án TypeScript hôm nay và không có lý do cụ thể để chọn Jest, thì không có bước setup ESM nào cả.
Tương thích API
Vitest tương thích API rộng rãi với Jest; tài liệu Vitest mô tả nó là thay thế trực tiếp cho phần lớn dự án. Các tên đổi là máy móc:
| Jest | Vitest |
|---|---|
jest.fn() | vi.fn() |
jest.spyOn() | vi.spyOn() |
jest.mock() | vi.mock() |
jest.useFakeTimers() | vi.useFakeTimers() |
jest.clearAllMocks() | vi.clearAllMocks() |
setupFilesAfterEnv | setupFiles |
Điểm khác biệt thực sự: factory function của vi.mock() chạy trong context được hoisted và không thể tham chiếu đến biến khai báo ở module scope. Trong Jest, cách này hoạt động bình thường:
// Jest — chạy được
const mockValue = 'hello'
jest.mock('./config', () => ({ value: mockValue })) // ✅
Trong Vitest, nó fail âm thầm hoặc throw. Factory bị hoisted lên trên khai báo biến.
// Vitest — không chạy được
const mockValue = 'hello'
vi.mock('./config', () => ({ value: mockValue })) // ❌ mockValue là undefined
Cách sửa là chuyển giá trị vào trong factory, hoặc đặt trong beforeEach. Phần lớn codebase gặp vấn đề này ở một số chỗ khi migrate. Sửa được — nhưng đây là cạm bẫy hay gặp nhất, và sẽ tốn thời gian nếu bạn không chuẩn bị trước.
Khi nào Vitest thắng
- Dự án dùng Vite (React + Vite, Vue, Svelte, SolidJS): cấu hình gần như bằng không và dùng chung pipeline có sẵn.
- Codebase nặng TypeScript: esbuild transform loại bỏ hoàn toàn ts-jest hoặc Babel.
- Phát triển tích cực với watch mode: re-run nhanh hơn 28 lần thay đổi feedback loop từ “đủ thời gian kiểm tra Slack” thành “gần như tức thì.”
- Bộ test lớn: khoảng cách hiệu suất tăng theo tỷ lệ với kích thước bộ test.
- Behavior trên trình duyệt thực: Vitest chạy test trong Chromium/Firefox/WebKit thật qua Playwright; jsdom của Jest chỉ là giả lập DOM.
- Chi phí CI: nếu bạn đang trả tiền cho GitHub Actions minutes và bộ test lớn, phép tính thường nghiêng về phía migrate.
Khi đã chọn xong Vitest, quyết định tiếp theo là lớp E2E. Bài so sánh Playwright vs Cypress của chúng tôi phân tích kỹ hai lựa chọn này trong 2026 — Playwright thắng về tốc độ và đa trình duyệt, Cypress thắng về DX khi test component.
Khi nào Jest vẫn thắng
- React Native: chưa có hỗ trợ Vitest chính thức. Có project cộng đồng
vitest-mobilenhưng chưa production-ready tính đến giữa 2026. Nếu dự án nhắm React Native, ở lại Jest. - Angular:
@angular-builders/jesttích hợp sâu với CLI. Vitest chạy được với Angular nhưng cần cấu hình thêm và mất một số tích hợp toolchain. - Codebase CommonJS cũ: Vitest hoạt động với CJS nhưng ưu tiên ESM. Nếu bạn chưa sẵn sàng migrate dependency tree sang ESM, quá trình chuyển đổi sẽ có thêm rủi ro.
- Bộ test Jest ổn định với CI không tốn kém: nếu test đã chạy nhanh và bạn không tốn nhiều tiền CI, đổi lại (2–3 tuần engineering time) có thể không xứng.
- Người dùng Interactive Snapshot Mode: watch mode của Jest cho phép bạn duyệt qua từng snapshot thất bại và approve hoặc update từng cái một. Vitest chưa có tính năng này — đang trong roadmap, nhưng còn thiếu. Team dùng nhiều snapshot sẽ nhận ra sự khác biệt.
Migration
Dự án Vite/React hoặc Vite/Vue
Thay dependencies:
npm uninstall jest @types/jest ts-jest babel-jest jest-environment-jsdom
npm install -D vitest @vitest/coverage-v8
Thêm config Vitest (hoặc merge vào vite.config.ts có sẵn):
// vite.config.ts
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: ['./src/setupTests.ts'],
coverage: { provider: 'v8' },
},
})
Cập nhật scripts trong package.json:
{
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage"
}
}
Nếu bạn dùng globals: true, thêm type reference vào tsconfig.json:
{
"compilerOptions": {
"types": ["vitest/globals"]
}
}
Sau khi đổi dependencies, tìm các vi.mock() factory tham chiếu đến biến module-scope (grep cho vi.mock và xem biến nào được khai báo phía trên mỗi lần gọi). Với bộ test dưới 5.000 test và setup Vite chuẩn, dự kiến khoảng một ngày migrate.
Dự án Next.js
Next.js dùng Webpack theo mặc định, không phải Vite. Hướng migrate rẽ nhánh:
Tùy chọn A — Giữ Webpack, dùng Vitest không có Vite pipeline đầy đủ. Cài vitest-environment-jsdom và cấu hình custom esbuild transform. Chạy được nhưng mất một số lợi ích Vite-native (lợi ích watch mode từ dependency graph bị giảm một phần). Setup thủ công hơn.
Tùy chọn B — Migrate dự án sang Vite trước. Nỗ lực ban đầu lớn hơn, nhưng bạn có đầy đủ lợi ích Vitest cộng thêm dev server nhanh hơn. Không phải lựa chọn phù hợp nếu các tính năng Next.js (Server Components, App Router middleware, Image optimization) là trọng tâm của bạn.
Tài liệu chính thức của Next.js tính đến 2026 đặt Jest và Vitest ngang nhau — không có tùy chọn nào được đề xuất hơn. Cộng đồng ngày càng nghiêng về Vitest, nhưng nếu bạn dùng Next.js + Turbopack, hãy chờ tích hợp Vitest/Turbopack rõ ràng hơn trước khi migrate — interop hiện vẫn chưa ổn.
Nếu bạn đang cân nhắc luôn cả JavaScript runtime trong khi hiện đại hóa stack, bài so sánh Bun vs Node.js của chúng tôi phân tích nơi test runner tích hợp của Bun phù hợp — đây là lựa chọn thứ ba giúp một số setup không cần phải chọn test runner nào cả.
Kết luận
Dự án mới trên Vite/TypeScript: dùng Vitest. Không còn câu hỏi nào nữa. Luận điểm hiệu suất là vững chắc, tương thích API là thực chất, và hệ sinh thái — Vue, Svelte, RedwoodJS — đã bỏ phiếu.
Bộ test Jest có sẵn: migrate nếu chi phí CI hoặc tốc độ watch mode đang làm phiền bạn. Đừng migrate nếu mọi thứ đang chạy tốt và chi phí engineering cao hơn lợi ích.
React Native, Angular, hoặc CJS nặng: ở lại Jest. Các khoảng cách của Vitest trong những hệ sinh thái đó là cụ thể, không phải giả thuyết.
Thời kỳ “có nên thử Vitest không?” đã qua. Câu hỏi năm 2026 là bạn có lý do cụ thể nào để không dùng hay không.
Cảnh báo
Các con số benchmark (cold start, watch mode, memory) đến từ nghiên cứu PkgPulse chạy trên bộ 500 test. Con số của bạn sẽ thay đổi theo kích thước bộ test, độ phức tạp TypeScript, và thông số máy CI. Các con số 5.6 lần và 28 lần đáng tin cậy về hướng đối với bộ TypeScript lớn; với bộ nhỏ hơn, xem như đơn vị bậc độ lớn.
Tiết kiệm chi phí CI được trích dẫn trong đoạn “Chi phí CI thực tế” đến từ một case study migration duy nhất có URL nguồn hiện trả về 403 và không thể xác minh. Con số này mang tính minh họa — khoản tiết kiệm thực tế của bạn phụ thuộc vào kích thước bộ test, thông số máy, và cấu hình GitHub Actions.
Bài này không có affiliate link. Cả Testing JavaScript (Kent C. Dodds) lẫn Codecov đều không có affiliate program công khai đã xác nhận; nếu điều đó thay đổi, chúng tôi sẽ cập nhật với disclosure đầy đủ.
Related reading
- Deno vs Node.js — cuộc tranh luận đã có hồi kết?
- Playwright vs Cypress 2026: Framework nào bạn nên dùng?
- Prisma vs Drizzle 2026 — So sánh chi tiết TypeScript ORM
Tài liệu tham khảo
- Vitest — Comparisons with Jest
- State of JS 2024 — Testing libraries
- PkgPulse — Vitest 3 vs Jest 30 (2026)
- LogRocket — Vitest 4 Adoption Guide
- johal.in — War Story: Migrating 10k+ Tests from Jest to Vitest (URL hiện trả về 403; các con số từ nguồn này được ghi chú là mang tính minh họa)
- Maarten Hus — Why I migrated from Jest to Vitest
- Carbonate — Migrating from Jest to Vitest
- vitest-dev/vitest Discussion #10160 — React Native support
- Speakeasy — Vitest vs Jest