Episode ini membekali kalian teknik menguji kode async: menangani promise dengan matchers resolves dan rejects, pola async/await, callback berbasis done, serta pengendalian waktu dengan fake timers agar test cepat dan deterministik.

Hampir semua aplikasi modern penuh dengan operasi asynchronous: mengambil data dari API, membaca file, menunggu timeout, atau menjalankan job di background. Jika kalian tidak tahu cara menguji kode async dengan benar, test akan sering gagal secara acak — atau lebih buruk, lulus tanpa benar-benar menguji apa-apa.
Episode 6 mengajarkan empat teknik inti: menguji promise dengan resolves dan rejects, menulis test memakai async/await, menguji callback berbasis done, dan mengendalikan timer dengan fake timers. Setelah episode ini, kalian akan bisa menulis test async yang cepat, deterministik, dan bebas dari flakiness.
Jest menyediakan dua matcher khusus untuk promise: resolves dan rejects. Keduanya membuat assertion terhadap promise tanpa perlu menangani then dan catch secara manual:
function ambilData(id) {
return new Promise((resolve, reject) => {
if (id > 0) {
resolve({ id, nama: "arif" });
} else {
reject(new Error("id tidak valid"));
}
});
}
test("resolve dengan data", () => {
return expect(ambilData(1)).resolves.toEqual({ id: 1, nama: "arif" });
});
test("reject dengan error", () => {
return expect(ambilData(0)).rejects.toThrow("id tidak valid");
});expect(ambilData(1)).resolves.toEqual(...) membaca bahwa promise akan resolve menjadi objek yang setara. Penting untuk mengembalikan assertion dengan return — tanpa itu Jest menganggap test selesai sebelum promise selesai, dan test selalu lulus.
Cara yang paling mudah dibaca adalah menulis fungsi test sebagai fungsi async dan memakai await untuk menunggu promise:
test("await langsung di test", async () => {
const data = await ambilData(2);
expect(data.nama).toBe("arif");
});
test("menunggu beberapa promise sekaligus", async () => {
const hasil = await Promise.all([ambilData(1), ambilData(2)]);
expect(hasil).toHaveLength(2);
});Dengan pola async () => {} di dalam test, Jest menunggu fungsi tersebut selesai sebelum menilai hasilnya. Kombinasi Promise.all sangat berguna untuk menguji beberapa operasi async yang saling independen sekaligus.
Untuk memeriksa bahwa sebuah operasi async melempar error, kalian menunggu reject dan menyatakannya:
test("async mengembalikan error", async () => {
await expect(ambilData(-1)).rejects.toThrow("id tidak valid");
});
test("try catch untuk menangkap error", async () => {
await expect(ambilData(-1)).rejects.toBeInstanceOf(Error);
});Pola await expect(...).rejects... menunggu reject yang diperkirakan terjadi. Tanpa await, assertion rejects tidak akan dievaluasi dan test akan lulus secara keliru.
Tidak semua kode menggunakan promise. Untuk fungsi berbasis callback, Jest menyediakan parameter done:
function prosesLambat(input, cb) {
setTimeout(() => {
if (input) {
cb(null, `hasil ${input}`);
} else {
cb(new Error("input kosong"));
}
}, 50);
}
test("callback sukses", (done) => {
prosesLambat("data", (err, hasil) => {
expect(err).toBeNull();
expect(hasil).toBe("hasil data");
done();
});
});
test("callback error", (done) => {
prosesLambat("", (err) => {
expect(err.message).toBe("input kosong");
done();
});
});Parameter done adalah fungsi yang harus dipanggil setelah assertion selesai. Jika done tidak pernah dipanggil, Jest akan gagalkan test karena timeout — ini melindungi kalian dari callback yang tidak pernah terpanggil.
Test yang menunggu setTimeout selama beberapa detik akan membuat suite lambat. Jest menyediakan fake timers: timer palsu yang bisa dimajukan secara instan. Dengan jest.useFakeTimers(), Jest mengganti setTimeout, setInterval, dan Date dengan versi yang bisa dikendalikan.
jest.useFakeTimers();
function penjadwal(ms, cb) {
setTimeout(cb, ms);
}
test("penjadwal berjalan lebih cepat", () => {
const cb = jest.fn();
penjadwal(10000, cb);
expect(cb).not.toHaveBeenCalled();
jest.advanceTimersByTime(10000);
expect(cb).toHaveBeenCalledTimes(1);
});jest.advanceTimersByTime(10000) memajukan waktu palsu sebanyak 10 detik dalam satu langkah, tanpa benar-benar menunggu. Inilah cara menguji logika timeout dan retry dengan kecepatan penuh. Selalu panggil jest.useRealTimers() setelah selesai, misalnya di dalam afterEach, agar timer nyata kembali normal.
Kadang kode async menggunakan timer sekaligus promise. Pastikan urutan eksekusi dipertimbangkan — jalankan jest.advanceTimersByTime lalu tunggu microtask dengan await Promise.resolve(). Pola ini membuat test tetap deterministik meskipun memakai kombinasi timer dan promise.
Episode 6 mengubah test async dari sumber flakiness menjadi alat yang andal: matcher resolves dan rejects untuk promise, pola async/await yang mudah dibaca, done untuk callback, dan fake timers untuk mengendalikan waktu.
Inti yang harus dibawa pulang:
return atau await assertion yang melibatkan promise.resolves dan rejects membuat assertion promise tanpa then dan catch.async menunggu selesai sebelum dinilai.done; tanpa dipanggil, test gagal karena timeout.advanceTimersByTime.jest.useRealTimers() setelah test selesai.Di episode 7 selanjutnya kita akan membahas snapshot testing — konsep membandingkan output serialized, penggunaan toMatchSnapshot(), cara memperbarui snapshot dengan aman lewat version control, hingga penerapannya untuk React components. Ini salah satu fitur khas yang membedakan Jest dari framework lain.