Episode ini membahas pembuatan matcher dan helper kustom: custom matchers dengan expect.extend, fungsi helper yang reusable, menguji logika domain-spesifik, serta membagikan helper lintas project.

Matcher bawaan Jest mencakup kebutuhan umum, tetapi setiap domain punya assertion yang khas: "angka ini adalah harga yang valid", "objek ini berstatus aktif", atau "string ini adalah format UUID". Episode 16 membahas custom matchers & helpers — membuat matcher kustom dengan expect.extend(), menulis fungsi helper yang reusable, menguji logika domain-spesifik, dan membagikan helper lintas project.
Dengan matcher kustom, assertion menjadi ekspresif seperti bahasa domain itu sendiri — test lebih mudah dibaca, error lebih jelas, dan logika domain diuji satu kali untuk dipakai di mana-mana.
expect.extend() menerima objek berisi fungsi matcher. Setiap fungsi menerima nilai yang diuji dan mengembalikan objek dengan field pass dan message:
expect.extend({
toBeDalamRentang(nilai, min, maks) {
const pass = nilai >= min && nilai <= maks;
return {
pass,
message: () =>
`diharapkan ${nilai} dalam rentang ${min}-${maks}, ` +
`tetapi ${pass ? "masuk" : "tidak masuk"} rentang`,
};
},
});
test("usia dalam rentang valid", () => {
expect(25).toBeDalamRentang(18, 60);
});expect(25).toBeDalamRentang(18, 60) adalah assertion baru yang dibuat sendiri. Field pass menentukan hasil, dan message menghasilkan pesan error yang jelas saat test gagal — jauh lebih terbaca daripada membandingkan dua kondisi terpisah.
Matcher yang baik memvalidasi argumennya dan memakai expect untuk komposisi. Jika argumen salah, lempar error dengan pesan yang membantu — bukan gagal diam-diam. Matcher kustom juga bisa memakai this.utils untuk memformat nilai dalam pesan error secara konsisten.
Tidak semua kode ulang adalah matcher. Helper function biasa — fungsi yang menyusun data test, men-generate objek factory, atau menormalkan input — sering lebih tepat:
function buatTransaksi(overrides = {}) {
return {
id: 1,
jumlah: 100000,
status: "sukses",
tanggal: "2026-08-10",
...overrides,
};
}
test("transaksi berstatus sukses", () => {
const t = buatTransaksi();
expect(t.status).toBe("sukses");
});
test("transaksi gagal bisa dioverride", () => {
const t = buatTransaksi({ status: "gagal", jumlah: 0 });
expect(t.jumlah).toBe(0);
});buatTransaksi({ status: "gagal" }) menghasilkan objek lengkap dengan satu nilai di-override. Pola factory ini menghilangkan repetisi menyusun objek test dan membuat perubahan struktur hanya perlu diubah di satu tempat.
Ketika assertion mengulang logika yang sama di banyak test, ubah menjadi matcher domain. Contoh untuk sistem e-commerce:
expect.extend({
toBeDiskonValid(diskon, hargaAsli) {
const pass =
diskon >= 0 &&
diskon < hargaAsli &&
Number.isFinite(diskon);
return {
pass,
message: () =>
`diskon ${diskon} tidak valid untuk harga ${hargaAsli}`,
};
},
});
test("diskon harus lebih kecil dari harga", () => {
expect(50).toBeDiskonValid(100);
});expect(50).toBeDiskonValid(100) menguji aturan bisnis: diskon non-negatif, lebih kecil dari harga, dan angka yang valid. Matcher ini mengekapkan aturan diskon sekali dan dipakai di banyak test — perubahan aturan hanya menyentuh satu tempat.
Agar helper dan matcher bisa dipakai di banyak project, tempatkan di satu paket yang dibagikan:
const matchers = {
toBeDalamRentang: (nilai, min, maks) => {
const pass = nilai >= min && nilai <= maks;
return {
pass,
message: () =>
`diharapkan ${nilai} dalam rentang ${min}-${maks}`,
};
},
};
module.exports = { matchers };Paket ini bisa dipublikasikan sebagai npm package internal atau di-import dari repository bersama. Di setiap project, aktifkan matcher sekali di setupFilesAfterEnv:
const { matchers } = require("@tim/shared-jest-matchers");
expect.extend(matchers);require("@tim/shared-jest-matchers") memuat matcher bersama, lalu expect.extend(matchers) mendaftarkannya. Pendekatan ini menjaga assertion domain konsisten di seluruh organisasi tanpa menyalin kode.
Episode 16 membahas custom matchers dan helpers: membuat matcher dengan expect.extend(), menulis fungsi helper reusable dengan pola factory, menguji logika domain-spesifik lewat matcher yang ekspresif, serta membagikan helper lintas project.
Inti yang harus dibawa pulang:
expect.extend() membuat matcher dengan objek berisi pass dan message.setupFilesAfterEnv.Di episode 17 selanjutnya kita akan membahas monorepos & multi-project testing — mengelola Jest dalam struktur monorepo, konfigurasi multi-project, menjalankan test secara selektif per paket, serta keputusan config terpusat versus per-paket.