Web Development

Testing JavaScript dengan Jest

Tutorial lengkap belajar testing JavaScript dengan Jest — unit testing, matchers, mocking, async testing, code coverage, dan pengenalan Test-Driven Development (TDD)

1. Pengenalan Testing & Jest

Unit testing adalah praktik menguji bagian-bagian kecil dari kode (fungsi, metode, komponen) secara terpisah untuk memastikan mereka berfungsi sesuai harapan. Testing adalah bagian penting dari pengembangan software profesional — ia mencegah bug, memudahkan refactoring, dan mendokumentasikan perilaku kode.

Jest adalah framework testing JavaScript yang dikembangkan oleh Meta (Facebook). Jest populer karena konfigurasi nol, API yang intuitif, built-in assertion, mocking, dan code coverage. Jest digunakan secara luas di proyek React, Node.js, dan ekosistem JavaScript lainnya.

Mengapa Testing Penting?

Manfaat Penjelasan
Cegah BugDetect kesalahan sebelum kode sampai ke production
Refactoring AmanUbah kode dengan percaya diri — jika test gagal, Anda tahu apa yang rusak
Dokumentasi HidupTest mendokumentasikan bagaimana kode seharusnya bekerja
Desain Lebih BaikKode yang mudah di-test biasanya lebih modular dan bersih
CollaborationTim bisa bekerja lebih cepat karena punya safety net otomatis
Deploy Percaya DiriCI/CD dengan test otomatis = deploy tanpa takut

Jenis-jenis Testing

Jenis Cakupan Kecepatan Contoh
Unit Test1 fungsi/1 komponen🟢 Sangat cepatTest fungsi kalkulasi
Integration TestBeberapa modul bersama🟡 SedangTest API + database
End-to-End (E2E)Seluruh aplikasi🔴 LambatTest flow login sampai checkout

Instalasi Jest

Bash — Instalasi Jest
# Instal Jest sebagai dev dependency
npm install --save-dev jest

# Atau dengan yarn
yarn add --dev jest

# Tambahkan script di package.json:
# "scripts": {
#   "test": "jest",
#   "test:watch": "jest --watch",
#   "test:coverage": "jest --coverage"
# }

# Jalankan test
npm test

# Jalankan test dalam mode watch (otomatis re-run saat file berubah)
npm run test:watch

Konvensi Penamaan File Test

File Structure
# Konvensi penamaan file test di Jest:
#
# src/
# ├── utils/
# │   ├── math.js              ← Kode sumber
# │   ├── math.test.js         ← Test file (berdampingan)
# │   └── __tests__/
# │       └── math.test.js     ← Atau di folder __tests__
# ├── components/
# │   ├── Button.jsx
# │   └── Button.test.jsx
# └── services/
#     ├── api.js
#     └── api.test.js
#
# Jest otomatis menemukan file yang:
# - Berakhiran .test.js / .test.ts / .test.jsx / .test.tsx
# - Berakhiran .spec.js / .spec.ts / .spec.jsx / .spec.tsx
# - Berada di dalam folder __tests__/
Diagram: Anatomy of a Test
┌───────────────────────────────────────────────────────┐
│               ANATOMI SEBUAH TEST                     │
│                                                       │
│  describe("Kalkulator", () => {        ← Test Suite   │
│                                                       │
│    test("menjumlahkan 2 angka", () => { ← Test Case   │
│                                                       │
│      const hasil = tambah(2, 3);       ← Arrange      │
│                                        (Siapkan data)  │
│                                                       │
│      expect(hasil).toBe(5);           ← Act & Assert   │
│                                        (Jalankan &     │
│                                         Verifikasi)    │
│    });                                                │
│                                                       │
│    test("membagi 2 angka", () => {     ← Test Case    │
│      expect(bagi(10, 2)).toBe(5);                      │
│    });                                                │
│                                                       │
│  });                                                  │
│                                                       │
│  describe = Grup test berdasarkan topik                │
│  test/it = Kasus uji individual                        │
│  expect = Assertion (klaim yang divalidasi)            │
└───────────────────────────────────────────────────────┘

2. Unit Testing Dasar

Unit test menguji satu fungsi atau satu unit logika secara terpisah. Ini adalah jenis test yang paling banyak dan paling cepat. Mari kita mulai dengan contoh sederhana.

Contoh Pertama: Test Fungsi Dasar

JavaScript — math.js (Kode Sumber)
// math.js — Kode yang akan di-test

function tambah(a, b) {
  return a + b;
}

function kurang(a, b) {
  return a - b;
}

function kali(a, b) {
  return a * b;
}

function bagi(a, b) {
  if (b === 0) {
    throw new Error('Tidak bisa membagi dengan nol!');
  }
  return a / b;
}

function faktorial(n) {
  if (n < 0) throw new Error('Faktorial tidak untuk bilangan negatif');
  if (n === 0 || n === 1) return 1;
  return n * faktorial(n - 1);
}

module.exports = { tambah, kurang, kali, bagi, faktorial };
JavaScript — math.test.js
// math.test.js — File test

const { tambah, kurang, kali, bagi, faktorial } = require('./math');

// describe = mengelompokkan test yang berhubungan
describe('Fungsi Kalkulator', () => {

  // test() atau it() — keduanya sama
  test('menjumlahkan 2 bilangan positif', () => {
    expect(tambah(2, 3)).toBe(5);
    expect(tambah(10, 20)).toBe(30);
    expect(tambah(0, 0)).toBe(0);
  });

  test('menjumlahkan bilangan negatif', () => {
    expect(tambah(-2, -3)).toBe(-5);
    expect(tambah(-5, 5)).toBe(0);
  });

  test('mengurangkan 2 bilangan', () => {
    expect(kurang(10, 3)).toBe(7);
    expect(kurang(3, 10)).toBe(-7);
  });

  test('mengalikan 2 bilangan', () => {
    expect(kali(4, 5)).toBe(20);
    expect(kali(0, 100)).toBe(0);
    expect(kali(-3, 4)).toBe(-12);
  });

  test('membagi 2 bilangan', () => {
    expect(bagi(10, 2)).toBe(5);
    expect(bagi(7, 2)).toBe(3.5);
  });

  test('membagi dengan nol melempar error', () => {
    expect(() => bagi(10, 0)).toThrow('Tidak bisa membagi dengan nol!');
  });
});

describe('Fungsi Faktorial', () => {
  test('faktorial dari 0 adalah 1', () => {
    expect(faktorial(0)).toBe(1);
  });

  test('faktorial dari 5 adalah 120', () => {
    expect(faktorial(5)).toBe(120);
  });

  test('faktorial negatif melempar error', () => {
    expect(() => faktorial(-1)).toThrow();
  });
});

Lifecycle Hooks

JavaScript — Lifecycle Hooks
// Jest menyediakan lifecycle hooks untuk setup dan teardown

describe('Database Tests', () => {
  let db;

  // Berjalan SEBELUM semua test dalam describe
  beforeAll(() => {
    db = connectToTestDatabase();
    console.log('Database connected');
  });

  // Berjalan SEBELUM setiap test
  beforeEach(() => {
    db.clear(); // Bersihkan data sebelum setiap test
    console.log('Database cleared');
  });

  // Berjalan SETELAH setiap test
  afterEach(() => {
    console.log('Test selesai');
  });

  // Berjalan SETELAH semua test dalam describe
  afterAll(() => {
    db.disconnect();
    console.log('Database disconnected');
  });

  test('menambahkan data', () => {
    db.insert({ nama: 'Budi' });
    expect(db.count()).toBe(1);
  });

  test('menghapus data', () => {
    db.insert({ nama: 'Budi' });
    db.delete('Budi');
    expect(db.count()).toBe(0);
  });

  // Kedua test di atas punya database bersih
  // berkat beforeEach yang membersihkan data
});

3. Matchers: Berbagai Cara Assertion

Matchers adalah method yang digunakan dalam expect() untuk memverifikasi berbagai jenis hasil. Jest menyediakan banyak matcher built-in yang sangat ekspresif.

Equality Matchers

JavaScript — Equality Matchers
// === (strict equality)
test('toBe: strict equality', () => {
  expect(2 + 2).toBe(4);
  expect('hello').toBe('hello');
  expect(true).toBe(true);
});

// Deep equality untuk object/array
test('toEqual: deep equality', () => {
  expect({ nama: 'Budi', umur: 25 }).toEqual({ nama: 'Budi', umur: 25 });
  expect([1, 2, 3]).toEqual([1, 2, 3]);

  // toEqual cocok untuk object — tidak peduli referensi
  const a = { x: 1 };
  const b = { x: 1 };
  expect(a).toEqual(b); // ✅ Pass (sama isi)
  expect(a).toBe(b);    // ❌ Fail (beda referensi)
});

// Negasi
test('not: membalik assertion', () => {
  expect(2 + 2).not.toBe(5);
  expect('hello').not.toBe('world');
  expect([1, 2]).not.toEqual([3, 4]);
});

Truthiness Matchers

JavaScript — Truthiness
// Null, Undefined, Truthiness
test('truthiness matchers', () => {
  expect(null).toBeNull();
  expect(undefined).toBeUndefined();
  expect(7).toBeDefined();       // Bukan undefined
  expect(true).toBeTruthy();
  expect(false).toBeFalsy();
  expect(0).toBeFalsy();
  expect('').toBeFalsy();
  expect(null).toBeFalsy();

  // Contoh penggunaan praktis
  const user = { nama: 'Budi' };
  expect(user.nama).toBeTruthy();
  expect(user.email).toBeUndefined();
});

Number Matchers

JavaScript — Number Matchers
// Perbandingan angka
test('number matchers', () => {
  expect(10).toBeGreaterThan(5);
  expect(10).toBeGreaterThanOrEqual(10);
  expect(5).toBeLessThan(10);
  expect(5).toBeLessThanOrEqual(5);

  // Floating point (angka desimal)
  expect(0.1 + 0.2).toBeCloseTo(0.3); // Hindari masalah floating point
  expect(0.1 + 0.2).toBeCloseTo(0.3, 5); // Presisi 5 digit
});

// Fungsi yang menghitung harga diskon
function hitungDiskon(harga, persen) {
  return harga - (harga * persen / 100);
}

test('hitung diskon benar', () => {
  expect(hitungDiskon(100000, 10)).toBeCloseTo(90000);
  expect(hitungDiskon(50000, 20)).toBeCloseTo(40000);
  expect(hitungDiskon(200000, 0)).toBeCloseTo(200000);
});

String & Array Matchers

JavaScript — String & Array
// String matchers
test('string matchers', () => {
  expect('Hello World').toMatch(/World/);   // Regex match
  expect('Hello World').toMatch('World');   // Substring match
  expect('Budi Santoso').toMatch(/^Budi/); // Regex dengan anchor
  expect('email@test.com').toMatch(/@/);
});

// Array & Iterable matchers
test('array matchers', () => {
  const buah = ['apel', 'jeruk', 'mangga', 'pisang'];

  expect(buah).toContain('mangga');
  expect(buah).toHaveLength(4);
  expect(buah).not.toContain('durian');

  // Array of objects
  const produk = [
    { id: 1, nama: 'Laptop' },
    { id: 2, nama: 'Mouse' },
  ];
  expect(produk).toContainEqual({ id: 1, nama: 'Laptop' });
});

Error Matchers

JavaScript — Error Matchers
// Menguji error/exception
function validateAge(umur) {
  if (typeof umur !== 'number') throw new Error('Umur harus angka');
  if (umur < 0) throw new Error('Umur tidak boleh negatif');
  if (umur > 150) throw new Error('Umur tidak valid');
  return true;
}

test('validasi umur berhasil', () => {
  expect(validateAge(25)).toBe(true);
  expect(validateAge(0)).toBe(true);
});

test('validasi umur gagal untuk input non-angka', () => {
  expect(() => validateAge('abc')).toThrow('Umur harus angka');
});

test('validasi umur gagal untuk umur negatif', () => {
  expect(() => validateAge(-5)).toThrow('Umur tidak boleh negatif');
});

test('validasi umur gagal untuk umur terlalu besar', () => {
  expect(() => validateAge(200)).toThrow(/tidak valid/);
});

4. Mocking: Mengisolasi Dependensi

Mocking adalah teknik mengganti dependensi eksternal (API, database, layanan lain) dengan "tiruan" yang perilakunya bisa dikontrol. Ini memastikan kita menguji hanya kode yang sedang dibahas, bukan dependensi luar.

Mock Function (jest.fn)

JavaScript — Mock Functions
// jest.fn() membuat fungsi tiruan yang melacak semua pemanggilan

test('mock function dasar', () => {
  const mockCallback = jest.fn();

  // Gunakan mock sebagai callback
  [1, 2, 3].forEach(mockCallback);

  // Verifikasi mock dipanggil 3 kali
  expect(mockCallback).toHaveBeenCalledTimes(3);

  // Verifikasi argumen setiap pemanggilan
  expect(mockCallback).toHaveBeenCalledWith(1);
  expect(mockCallback).toHaveBeenCalledWith(2);
  expect(mockCallback).toHaveBeenCalledWith(3);

  // Akses detail pemanggilan
  expect(mockCallback.mock.calls.length).toBe(3);
  expect(mockCallback.mock.calls[0]).toEqual([1]); // Panggilan pertama
  expect(mockCallback.mock.calls[1]).toEqual([2]); // Panggilan kedua
});

// Mock dengan return value
test('mock dengan return value', () => {
  const mockFetch = jest.fn();

  // Set return value untuk setiap pemanggilan
  mockFetch
    .mockReturnValueOnce({ status: 200, data: 'OK' })
    .mockReturnValueOnce({ status: 404, data: 'Not Found' });

  expect(mockFetch()).toEqual({ status: 200, data: 'OK' });
  expect(mockFetch()).toEqual({ status: 404, data: 'Not Found' });
});

// Mock dengan implementasi custom
test('mock dengan implementasi', () => {
  const mockTambah = jest.fn((a, b) => a * 2); // Salah sengaja!

  expect(mockTambah(3, 4)).toBe(6); // 3 * 2 = 6 (bukan 7)
});

Mocking Module

JavaScript — Module Mocking
// Misal ada modul API:
// api.js
// export async function getUsers() {
//   const res = await fetch('https://api.example.com/users');
//   return res.json();
// }

// api.test.js — Mock seluruh modul api
jest.mock('./api'); // Auto-mock semua export dari api.js

const { getUsers } = require('./api');

test('menggunakan mock getUsers', async () => {
  // Atur return value mock
  getUsers.mockResolvedValue([
    { id: 1, nama: 'Budi' },
    { id: 2, nama: 'Sari' },
  ]);

  const users = await getUsers();
  expect(users).toHaveLength(2);
  expect(users[0].nama).toBe('Budi');
  expect(getUsers).toHaveBeenCalledTimes(1);
});

// Mocking dengan partial mock
jest.mock('./api', () => ({
  ...jest.requireActual('./api'), // Pertahankan implementasi asli
  getUsers: jest.fn(), // Override hanya getUsers
}));

Mocking HTTP Request (fetch)

JavaScript — Fetch Mock
// Mock global fetch
global.fetch = jest.fn();

// Fungsi yang akan di-test
async function ambilProduk(id) {
  const response = await fetch(`/api/produk/${id}`);
  if (!response.ok) {
    throw new Error('Produk tidak ditemukan');
  }
  return response.json();
}

// Test suite
describe('ambilProduk', () => {
  beforeEach(() => {
    fetch.mockClear(); // Reset mock sebelum setiap test
  });

  test('berhasil mengambil produk', async () => {
    // Setup mock response
    fetch.mockResolvedValueOnce({
      ok: true,
      json: async () => ({ id: 1, nama: 'Laptop', harga: 12000000 }),
    });

    const produk = await ambilProduk(1);
    expect(produk.nama).toBe('Laptop');
    expect(produk.harga).toBe(12000000);
    expect(fetch).toHaveBeenCalledWith('/api/produk/1');
  });

  test('gagal jika produk tidak ditemukan', async () => {
    fetch.mockResolvedValueOnce({
      ok: false,
      status: 404,
    });

    await expect(ambilProduk(999)).rejects.toThrow('Produk tidak ditemukan');
  });
});
💡 Kapan Menggunakan Mock?

Mock digunakan untuk mengisolasi kode yang sedang di-test dari dependensi eksternal. Aturan praktis: mock hal-hal yang tidak Anda kontrol (API eksternal, database, filesystem, waktu). Jangan mock hal-hal yang Anda kontrol (fungsi utilitas internal, pure functions) — test mereka secara langsung.

5. Async Testing

Banyak kode JavaScript modern bersifat asinkron — Promises, async/await, callbacks. Jest menyediakan cara yang jelas untuk menguji kode async.

Testing dengan Promises

JavaScript — Async Testing
// Fungsi async yang akan di-test
async function fetchUser(id) {
  const response = await fetch(`https://api.example.com/users/${id}`);
  const user = await response.json();
  return user;
}

async function fetchUserPosts(userId) {
  const response = await fetch(`https://api.example.com/users/${userId}/posts`);
  if (!response.ok) throw new Error('Gagal mengambil posts');
  return response.json();
}

// Cara 1: Menggunakan async/await (DIREKOMENDASIKAN)
test('fetchUser mengembalikan data user', async () => {
  global.fetch = jest.fn().mockResolvedValue({
    json: jest.fn().mockResolvedValue({ id: 1, nama: 'Budi' }),
  });

  const user = await fetchUser(1);
  expect(user.nama).toBe('Budi');
  expect(user.id).toBe(1);
});

// Cara 2: Menggunakan .resolves / .rejects
test('fetchUser mengembalikan data (dengan resolves)', async () => {
  global.fetch = jest.fn().mockResolvedValue({
    json: jest.fn().mockResolvedValue({ id: 1, nama: 'Sari' }),
  });

  await expect(fetchUser(1)).resolves.toEqual({ id: 1, nama: 'Sari' });
});

// Testing error async
test('fetchUserPosts melempar error saat gagal', async () => {
  global.fetch = jest.fn().mockResolvedValue({
    ok: false,
    status: 500,
  });

  await expect(fetchUserPosts(1)).rejects.toThrow('Gagal mengambil posts');
});

// Cara 3: Menggunakan .then() (kurang direkomendasikan)
test('fetchUser dengan .then()', () => {
  global.fetch = jest.fn().mockResolvedValue({
    json: jest.fn().mockResolvedValue({ id: 1, nama: 'Andi' }),
  });

  return fetchUser(1).then(user => {
    expect(user.nama).toBe('Andi');
  });
});

Testing dengan Timer Mock

JavaScript — Timer Mocks
// Fungsi dengan setTimeout
function delayedGreeting(name, callback) {
  setTimeout(() => {
    callback(`Halo, ${name}!`);
  }, 2000);
}

// Menggunakan fake timers
jest.useFakeTimers();

test('delayedGreeting memanggil callback setelah 2 detik', () => {
  const callback = jest.fn();

  delayedGreeting('Budi', callback);

  // Belum dipanggil (belum 2 detik)
  expect(callback).not.toHaveBeenCalled();

  // Majukan waktu 2 detik
  jest.advanceTimersByTime(2000);

  // Sekarang seharusnya dipanggil
  expect(callback).toHaveBeenCalledTimes(1);
  expect(callback).toHaveBeenCalledWith('Halo, Budi!');
});

// Interval test
test('interval berjalan dengan benar', () => {
  const callback = jest.fn();

  setInterval(callback, 1000);

  jest.advanceTimersByTime(3000); // Maju 3 detik

  expect(callback).toHaveBeenCalledTimes(3);
});

// Kembalikan timer normal setelah test
afterEach(() => {
  jest.useRealTimers();
});

6. Code Coverage

Code coverage mengukur berapa persen dari kode Anda yang dijalankan selama test. Ini membantu menemukan bagian kode yang belum ter-test.

Menjalankan Coverage

Bash — Code Coverage
# Jalankan test dengan coverage
npm test -- --coverage

# Output:
# ----------|---------|----------|---------|---------|
# File      | % Stmts | % Branch | % Funcs | % Lines |
# ----------|---------|----------|---------|---------|
# math.js   |   95.45 |    83.33 |     100 |   95.45 |
# api.js    |   72.73 |       50 |   66.67 |   72.73 |
# utils.js  |     100 |      100 |     100 |     100 |
# ----------|---------|----------|---------|---------|

# Coverage metrics:
# - % Stmts   = Statement coverage (baris kode yang dijalankan)
# - % Branch  = Branch coverage (if/else yang ter-test semua)
# - % Funcs   = Function coverage (fungsi yang dipanggil)
# - % Lines   = Line coverage (baris yang ter-execution)

# Threshold di jest.config.js:
# coverageThreshold: {
#   global: {
#     branches: 80,
#     functions: 80,
#     lines: 80,
#     statements: 80,
#   }
# }
⚠️ Coverage 100% Bukan Jaminan Kualitas

Coverage tinggi bagus, tapi bukan segalanya. Test yang tidak bermakna bisa mencapai 100% coverage tanpa benar-benar menguji logika. Fokus pada test yang bermakna — uji behavior, edge cases, dan skenario error — bukan sekadar mengejar angka coverage.

7. Pengenalan Test-Driven Development (TDD)

Test-Driven Development (TDD) adalah metodologi pengembangan di mana Anda menulis test TERLEBIH DAHULU, baru menulis kode yang memenuhi test tersebut. Siklus TDD dikenal sebagai Red → Green → Refactor.

Siklus TDD: Red → Green → Refactor

Diagram: Siklus TDD
┌───────────────────────────────────────────────────────┐
│              SIKLUS TDD: RED → GREEN → REFACTOR       │
│                                                       │
│     ┌──────────────┐                                  │
│     │   1. RED     │  Tulis test yang GAGAL           │
│     │   🔴 FAIL    │  (kode belum ada)                │
│     └──────┬───────┘                                  │
│            │                                          │
│            ▼                                          │
│     ┌──────────────┐                                  │
│     │  2. GREEN    │  Tulis kode secukupnya           │
│     │   ✅ PASS    │  agar test LULUS                 │
│     └──────┬───────┘                                  │
│            │                                          │
│            ▼                                          │
│     ┌──────────────┐                                  │
│     │ 3. REFACTOR  │  Perbaiki kode tanpa             │
│     │   🔄 IMPROVE │  mengubah behavior               │
│     └──────┬───────┘                                  │
│            │                                          │
│            └──────────▶ Kembali ke RED                │
│                                                       │
│  Ulangi siklus ini untuk setiap fitur/tambah          │
└───────────────────────────────────────────────────────┘

Contoh TDD: Membuat Shopping Cart

JavaScript — TDD Shopping Cart
// === LANGKAH 1: RED — Tulis test dulu (belum ada kode) ===

// shopping-cart.test.js
describe('ShoppingCart', () => {
  let cart;

  beforeEach(() => {
    cart = new ShoppingCart();
  });

  test('keranjang baru kosong', () => {
    expect(cart.getItems()).toEqual([]);
    expect(cart.getTotal()).toBe(0);
  });

  test('menambahkan produk ke keranjang', () => {
    cart.addItem({ id: 1, nama: 'Laptop', harga: 12000000 });
    expect(cart.getItems()).toHaveLength(1);
    expect(cart.getItems()[0].nama).toBe('Laptop');
  });

  test('menghitung total harga', () => {
    cart.addItem({ id: 1, nama: 'Laptop', harga: 12000000 });
    cart.addItem({ id: 2, nama: 'Mouse', harga: 250000 });
    expect(cart.getTotal()).toBe(12250000);
  });

  test('menghapus produk dari keranjang', () => {
    cart.addItem({ id: 1, nama: 'Laptop', harga: 12000000 });
    cart.removeItem(1);
    expect(cart.getItems()).toHaveLength(0);
  });

  test('menambah quantity produk yang sama', () => {
    cart.addItem({ id: 1, nama: 'Laptop', harga: 12000000 });
    cart.addItem({ id: 1, nama: 'Laptop', harga: 12000000 });
    expect(cart.getItems()).toHaveLength(1);
    expect(cart.getItems()[0].quantity).toBe(2);
    expect(cart.getTotal()).toBe(24000000);
  });
});

// === LANGKAH 2: GREEN — Tulis kode agar test lulus ===

// shopping-cart.js
class ShoppingCart {
  constructor() {
    this.items = [];
  }

  getItems() {
    return this.items;
  }

  addItem(product) {
    const existing = this.items.find(item => item.id === product.id);
    if (existing) {
      existing.quantity += 1;
    } else {
      this.items.push({ ...product, quantity: 1 });
    }
  }

  removeItem(productId) {
    this.items = this.items.filter(item => item.id !== productId);
  }

  getTotal() {
    return this.items.reduce((sum, item) => sum + item.harga * item.quantity, 0);
  }
}

// === LANGKAH 3: REFACTOR — Perbaiki kode ===
// (Tambah validasi, optimasi, clean code — test tetap pass!)
💡 Manfaat TDD

TDD memaksa Anda berpikir tentang behavior kode SEBELUM menulis kode. Hasilnya: kode yang lebih modular, lebih terdokumentasi, dan lebih mudah di-maintain. TDD juga mengurangi waktu debugging karena Anda punya test yang mendeteksi masalah sejak awal.

8. Quiz: Uji Pemahamanmu!

Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang testing dengan Jest:

Pertanyaan 1: Apa perbedaan antara toBe() dan toEqual() di Jest?

a) Tidak ada perbedaan, keduanya sama
b) toBe() untuk referensi (===), toEqual() untuk deep equality (cocok untuk objek/array)
c) toBe() untuk angka, toEqual() untuk string
d) toBe() lebih cepat dari toEqual()

Pertanyaan 2: Apa fungsi jest.fn() dalam testing?

a) Membuat file test baru
b) Menjalankan test secara paralel
c) Membuat fungsi tiruan (mock) yang melacak pemanggilan
d) Menghapus file test yang tidak diperlukan

Pertanyaan 3: Apa urutan siklus TDD yang benar?

a) Green → Red → Refactor
b) Refactor → Green → Red
c) Red → Green → Refactor
d) Write Code → Write Test → Refactor

Pertanyaan 4: Bagaimana cara menguji kode async (Promise) di Jest?

a) Gunakan test.sync()
b) Gunakan async/await atau .resolves/.rejects di dalam test()
c) Tidak bisa menguji kode async di Jest
d) Gunakan setTimeout() di dalam test

Pertanyaan 5: Apa yang diukur oleh "code coverage"?

a) Kecepatan eksekusi test
b) Berapa persen kode yang dijalankan selama test berjalan
c) Jumlah test yang berhasil
d) Ukuran file test dalam bytes
🔍 Zoom
100%
🎨 Tema