Vitest: Unit Testing Super Cepat
Setup dan tulis unit test dengan Vitest — test runner modern untuk Vite
Tujuan Pembelajaran
- Bisa setup Vitest di proyek
- Menguasai matcher dan assertion
- Mengerti mocking dasar
Analogi
Vitest = Test runner untuk Vite ecosystem
Features:
├── Native ESM support
├── TypeScript out of the box
├── Jest-compatible API
├── Watch mode super cepat
└── UI mode untuk debugging
Vitest adalah test runner modern yang designed untuk Vite ecosystem — cepat, native ESM, dan TypeScript support tanpa config
Penjelasan Konsep
Jest adalah test runner paling populer di ekosistem JavaScript. Tapi Jest dirilis sebelum ESM menjadi standar dan butuh banyak konfigurasi untuk TypeScript. Vitest datang sebagai alternatif modern yang designed untuk Vite ecosystem.
Kenapa Vitest?
- Native ESM: Vitest menggunakan native ES Modules — tidak perlu transformasi
- TypeScript built-in: Tulis test dalam.ts tanpa config tambahan
- Jest-compatible API: describe, it, expect — semuanya sama
- Super cepat: Menggunakan Vite’s transform pipeline — test jalan dalam milidetik
- UI Mode: Visual test runner untuk debugging
Setup Vitest
npm install -D vitest @vitest/ui
# atau
bun add -d vitest
Tambahkan ke package.json:
{
"scripts": {
"test": "vitest",
"test:ui": "vitest --ui",
"test:run": "vitest run"
}
}
Naming Convention
File test bisa dinamai:
nama.test.ts— file test terpisahnama.spec.ts— alternatif naming__tests__/nama.ts— di folder tests
Vitest otomatis mencari file yang match pattern: **/*.{test,spec}.{js,ts}
Assertion Matchers
Vitest (dan Jest) punya banyak matcher untuk berbagai kebutuhan:
toBe()— strict equality (===)toEqual()— deep equality (untuk object/array)toBeTruthy()/toBeFalsy()— truthy/falsy checktoBeNull()/toBeUndefined()— null/undefinedtoBeGreaterThan()/toBeLessThan()— perbandingantoContain()— array/string containstoThrow()— exception throwntoHaveLength()— panjang array/stringtoMatch()— regex matching
Grouping dengan describe
Organize test dengan describe yang nested:
describe('UserService',
() => {
describe('create', () => {
it('should create user with valid data', () => { ... });
it('should reject duplicate email', () => { ... });
});
describe('findById', () => {
it('should return user when found', () => { ... });
it('should return null when not found', () => { ... });
});
});
Inti yang Perlu Dipahami
Bagian ini berfokus pada bisa setup Vitest di proyek., menguasai matcher dan assertion., dan mengerti mocking dasar. Jangan terburu-buru menghafal istilahnya. Lebih penting untuk memahami peran setiap konsep dan kapan konsep itu muncul dalam pekerjaan web development.
Saat membaca Vitest, gunakan tujuan belajar sebagai penanda arah. Kalau kamu sudah bisa menjelaskan tujuan itu dengan kata-katamu sendiri, berarti fondasinya mulai terbentuk.
Cara Membayangkannya
Vitest adalah test runner modern yang designed untuk Vite ecosystem — cepat, native ESM, dan TypeScript support tanpa config. Analogi ini dipakai supaya konsep teknis tidak terasa melayang. Hubungkan setiap istilah dengan perannya: siapa yang meminta, siapa yang memproses, data apa yang berpindah, dan hasil apa yang diharapkan.
Kalau analoginya sudah terasa masuk akal, barulah lihat istilah teknisnya. Cara ini membuat materi lebih mudah dipahami daripada langsung menghafal definisi.
Saat Melihat Contoh Kode
Contoh kode pada chapter ini memakai bahasa typescript. Bacalah contoh kode sebagai ilustrasi alur, bukan sebagai bagian yang harus langsung dihafal. beforeEach() berjalan sebelum setiap test — setup fresh state. In-memory array sebagai mock database. toEqual() untuk deep comparison object.
Perhatikan nama fungsi, urutan langkah, dan data yang berpindah. Biasanya tiga hal itu sudah cukup untuk memahami hubungan antara teori dan praktik.
Konteks dalam Perjalanan Belajar
Setiap konsep di platform ini dipilih karena dipakai di industri. Fokus pada pemahaman, bukan hafalan.
Kamu sudah di bagian lanjutan. Mulai pikirkan bagaimana konsep ini dipakai di dunia kerja — bukan hanya untuk belajar, tapi untuk membangun produk nyata.
Gunakan pertanyaan reflektif dan prompt AI di akhir chapter sebagai latihan aktif. Membaca saja tidak cukup — kamu perlu menjelaskan ulang dengan kata-katamu sendiri.
Contoh Kode
// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true, // describe, it, expect global (tidak perlu import)
environment: 'node', // atau 'jsdom' untuk DOM testing
include: ['src/**/*.{test,spec}.{js,ts}'],
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
exclude: ['node_modules/', 'src/**/*.d.ts'],
},
},
resolve: {
alias: {
'@/': new URL('./src/', import.meta.url).pathname,
},
},
});
// UserService test
import { describe, it, expect, beforeEach } from 'vitest';
import { UserService } from './UserService';
// In-memory database untuk test
const users: User[] = [];
describe('UserService', () => {
let service: UserService;
beforeEach(() => {
users.length = 0; // Clear array
service = new UserService(users);
});
describe('create', () => {
it('creates user with valid data', () => {
const user = service.create({ name: 'Budi', email: 'budi@mail.com' });
expect(user.id).toBeDefined();
expect(user.name).toBe('Budi');
expect(users).toHaveLength(1);
});
it('rejects duplicate email', () => {
service.create({ name: 'Budi', email: 'budi@mail.com' });
expect(() =>
service.create({ name: 'Ani', email: 'budi@mail.com' })
).toThrow('Email already exists');
});
});
describe('findById', () => {
it('returns user when found', () => {
const created = service.create({ name: 'Budi', email: 'budi@mail.com' });
const found = service.findById(created.id);
expect(found).toEqual(created);
});
it('returns null when not found', () => {
const found = service.findById(999);
expect(found).toBeNull();
});
});
});Penjelasan Kode
Prompt AI
Setup Vitest di proyek Vite + TypeScript-mu. Tulis unit test untuk service layer yang sudah kamu buat (userService, productService, dll).
Pertanyaan Reflektif
Jalankan vitest --ui dan lihat visual test runner. Berapa persen code coverage-mu saat ini?