Episode ini menguji API dengan tools modern: test runner bawaan node:test, pengujian endpoint HTTP dengan supertest, mocking untuk isolasi, serta pengukuran coverage. Kalian mengunci perilaku API agar perubahan tidak merusak fitur.

Kode yang tidak diuji adalah bom waktu: satu perubahan kecil bisa merusak fitur yang tidak terduga. Testing mengubah itu — kalian menulis ekspektasi sebagai kode, lalu menjalankannya setiap kali aplikasi berubah. Di dunia Node.js, tools testing kini semakin sederhana.
Episode 18 mempraktikkan pengujian API modern: test runner bawaan node:test, pengujian endpoint HTTP dengan supertest, mocking untuk mengisolasi database, dan pengukuran coverage. Di akhir episode, kalian punya suite test yang berjalan di terminal dan siap dipakai di CI.
Mulai dari Node.js versi 18, test runner tersedia tanpa install apa pun. Modul node:test menyediakan test dan assert:
import { test } from "node:test";
import assert from "node:assert/strict";
function tambah(a, b) {
return a + b;
}
test("tambah menjumlahkan dua angka", () => {
assert.equal(tambah(2, 3), 5);
});test("nama", () => ...) mendefinisikan kasus uji, dan assert.equal(tambah(2, 3), 5) memeriksa hasil. Jalankan dengan node --test: runner menemukan file test, menjalankannya, dan melaporkan hasilnya.
node --testnode --test mencari file yang cocok dengan pola seperti *.test.js dan menjalankannya. Tambahkan "test": "node --test" ke scripts di package.json agar seluruh tim memakai perintah yang sama — kelak di episode 22, perintah ini dipakai oleh pipeline CI.
supertest memungkinkan menguji server HTTP tanpa membukanya ke port — request dikirim ke fungsi server secara langsung:
npm install --save-dev supertestnpm install --save-dev supertest menambahkan supertest ke devDependencies karena hanya dipakai saat development dan testing.
import { test } from "node:test";
import assert from "node:assert/strict";
import request from "supertest";
import { app } from "./app.js";
test("GET /api/pengguna mengembalikan daftar", async () => {
const respons = await request(app).get("/api/pengguna");
assert.equal(respons.status, 200);
assert.equal(respons.body.status, "success");
assert.ok(Array.isArray(respons.body.data));
});request(app).get("/api/pengguna") mengirim request ke aplikasi Express tanpa menyalakan server. Perhatikan bahwa app harus diekspor dari modul terpisah, dan app.listen dipindah ke file lain — pola ini membuat aplikasi mudah diuji. Assertion memeriksa status code dan bentuk body.
Test yang bergantung pada database sungguhan lambat dan rapuh. Gunakan mocking untuk mengganti bagian eksternal dengan perilaku yang kita kendalikan. Cara paling sederhana: terima dependensi sebagai parameter:
export function buatHandler(database) {
return async (req, res) => {
const data = await database.ambilSemua();
res.json(data);
};
}Dengan pola dependency injection di atas, test bisa memasukkan database tiruan. database.ambilSemua() diimplementasikan sebagai fungsi yang mengembalikan data palsu — tanpa koneksi nyata. node:test juga menyediakan mock.fn dan mock.method untuk membuat pengganti fungsi ini.
Jangan hanya menguji jalan sukses. Uji juga respons error agar aplikasi berperilaku benar saat sesuatu gagal:
test("404 ketika pengguna tidak ada", async () => {
const respons = await request(app).get("/api/pengguna/999");
assert.equal(respons.status, 404);
assert.equal(respons.body.status, "error");
});Test di atas memastikan pengguna dengan id yang tidak ada mendapat 404. Kasus error yang diuji dengan baik mencegah bug yang hanya muncul di kondisi tertentu — dan memberi keyakinan saat melakukan refactor.
Coverage menunjukkan persentase kode yang dieksekusi oleh test. Node.js punya coverage bawaan via V8:
node --test --experimental-test-coveragenode --test --experimental-test-coverage melaporkan baris, fungsi, dan branch yang tercakup test. Target yang wajar bukan 100 persen, tapi coverage yang stabil dan terarah pada kode penting — coverage tinggi tidak menjamin kode benar, hanya memberi sinyal mana yang belum diuji.
Test yang tidak berjalan otomatis hanya sekedar naskah. Di episode 22, kita akan menyambungkan npm test ke pipeline CI sehingga setiap push menjalankan seluruh suite — perubahan yang merusak test langsung menggagalkan build.
Inti yang harus dibawa pulang:
node:test menyediakan runner dan assertion bawaan tanpa install.app dari listen agar mudah diuji.Di episode 19 selanjutnya kita akan membahas performance tuning, event loop, dan profiling — fase-fase event loop, penyebab blocking, profiling CPU dengan Node Inspector, load testing dengan autocannon, dan deteksi kebocoran memori. Kalian akan membuat API yang cepat dan stabil di bawah beban.