Skip to content

[TEST-DRAGONFLY-VITEST-SUITE] Standardisasi Unit Test Suite Vitest, Integrasi SonarQube LCOV, dan Kompatibilitas Graceful Cache DragonflyDB ​

Modul: Single Billing | Tipe: Refactoring | Stage Saat Ini: PRODUCTION | Tanggal Dokumen: 2026-09-07

PRODUCTION RELEASED

Dokumen ini telah berada dalam tahap PRODUCTION. Perubahan logika backend, migrasi skema/konfigurasi, dan rilis v1.9.2 telah diterapkan secara penuh di lingkungan Production via MR !232.

LIFECYCLE GUIDE — UPDATE BERTAHAP:

  1. Buat file ini saat selesai development. Isi semua section kecuali Staging & Production.
    • Tanggal Dokumen (Header) & Riwayat Update Log: Gunakan tanggal hari ini (pembuatan dokumen).
    • Baris Development (Lifecycle): Gunakan tanggal & jam commit terakhir terkait di branch development.
  2. Update baris Staging saat naik ke UAT. Ubah "Stage Saat Ini" di header menjadi STAGING.
  3. Update baris Production saat naik ke Prod. Ubah "Stage Saat Ini" di header menjadi PRODUCTION.
  4. Update entry di README.md setiap kali status berubah. -->

1. Informasi Tugas & Referensi Bisnis ​

  • Task ID / Nomor Referensi: TEST-DRAGONFLY-VITEST-SUITE

  • Sumber Instruksi: Standardisasi Testing Backend LNSW (Vitest Runner), Integrasi SonarQube LCOV, & Kompatibilitas Cache DragonflyDB

  • Dokumen Referensi / Lampiran: Tidak ada

  • Task / Dependensi Terkait (Cross-Service):

  • Modul Terkait: Single Billing

  • Service / Repository: single-billing-BE

  • PIC Pengembang: Muhamad Firly Ramadan & Hermansyah Efendi

  • Latar Belakang & Ringkasan Kebutuhan: Backend single-billing-BE sebelumnya belum memiliki automated unit test suite yang komprehensif, sehingga proses verifikasi regresi logika bisnis pasca-refactoring masih bergantung pada pengujian manual dan laporan SonarQube CI/CD belum memiliki metrik code coverage yang valid. Di sisi lain, inisialisasi koneksi Redis yang bersifat wajib (mandatory/tightly coupled) menyebabkan server gagal bootstrap jika dijalankan pada lingkungan lokal tanpa instans Redis atau saat terjadi migrasi ke DragonflyDB. Task ini mengadopsi Vitest sebagai test-runner modern berbasis V8 coverage, membangun 36 file test suite (524 test cases lulus 100%), memperbarui app/helpers/redis.js agar memiliki mekanisme safe fallback opsional (aplikasi tetap berjalan normal meskipun Redis offline) dengan parameter kompatibilitas DragonflyDB (enableReadyCheck: false), serta menyelaraskan pelaporan metrik SonarQube melalui berkas coverage/lcov.info.

  • Ruang Lingkup & Rincian Sub-Pekerjaan (Technical Scope & Milestones):

    • [x] Pemasangan dependensi vitest dan @vitest/coverage-v8 pada devDependencies
    • [x] Pembuatan konfigurasi vitest.config.mjs dan global mocks lingkungan pengujian di tests/setup.js
    • [x] Pembuatan 36 file unit test suite mencakup seluruh komponen kritis (helpers, models, middlewares, dynamic routes, validations, connection wrapper)
    • [x] Refactoring app/helpers/redis.js dengan fungsi resolveHost aman, kompatibilitas DragonflyDB, dan safe fallback saat REDIS_NODES tidak dikonfigurasi
    • [x] Penyesuaian properti sonar-project.properties untuk integrasi analisis coverage LCOV pada pipeline CI/CD SonarQube
    • [x] Verifikasi eksekusi pengujian lokal empiris: 36 file lolos, 524 assertions sukses tanpa kegagalan

2. Deployment Lifecycle ​

#EnvironmentTanggal & WaktuPICStatusCatatan
1Development2026-08-27 13:58Muhamad Firly Ramadan & Hermansyah EfendiDEPLOYEDBranch: development (Merged from feat/dragonfly-db-with-unit-test)
2Staging (UAT)2026-10-14 13:00Hermansyah Efendi / QADEPLOYEDRelease Candidate via MR Staging !230. Co-deployed: [FEAT-SIMPONI-V3-ISOLATION, TASK-SET-EXPIRED-BILLING-V3, FEAT-BILLING-REKAP-EXPIRED-DATE-PAYLOAD, REFACTOR-TAGIHAN-CONTROLLER-DEDUPLICATION, FIX-PAYMENT-WEBHOOK-RACE-CONDITION, FIX-TAGIHAN-PREVENT-PAID-INVOICE-REORDER, FEAT-REQUEST-LOGGER-POSTMAN, TEST-DRAGONFLY-VITEST-SUITE, FEAT-RUNTIME-ENV-VALIDATION, TASK-NON-BLOCKING-BILLING-DISPATCH-AND-RETRY-CONFIG]
3Production2026-10-14 20:06achmad fauziDEPLOYEDBranch: prod via MR !232 (Release v1.9.2). Co-deployed: [FEAT-SIMPONI-V3-ISOLATION, TASK-SET-EXPIRED-BILLING-V3, FEAT-BILLING-REKAP-EXPIRED-DATE-PAYLOAD, REFACTOR-TAGIHAN-CONTROLLER-DEDUPLICATION, FIX-PAYMENT-WEBHOOK-RACE-CONDITION, FIX-TAGIHAN-PREVENT-PAID-INVOICE-REORDER, FEAT-REQUEST-LOGGER-POSTMAN, TEST-DRAGONFLY-VITEST-SUITE, FEAT-RUNTIME-ENV-VALIDATION, TASK-NON-BLOCKING-BILLING-DISPATCH-AND-RETRY-CONFIG]

Riwayat Update Log ​

TanggalEnvironmentPerubahanPIC
2026-10-14ProductionStatus diupdate ke PRODUCTION (DEPLOYED, CLOSED), rilis Release v1.9.2 via MR !232Hermansyah Efendi
2026-09-07DevelopmentInisialisasi draft audit log dari context block backend (commit ac4ce9d)Muhamad Firly Ramadan & Hermansyah Efendi

3. Analisis Teknis & Rincian Perubahan ​

  • Alur Logika & Bisnis:

    1. Safe Fallback & Kompatibilitas Cache DragonflyDB (app/helpers/redis.js):
      • Konfigurasi cache runtime menggunakan 4 variabel lingkungan: REDIS_NODES (format host:port atau multi-node cluster host1:port1,host2:port2), REDIS_KEY_PREFIX (namespace cache, e.g. single-billing:), REDIS_PASSWORD, dan REDIS_USERNAME.
      • Variabel lingkungan REDIS_NODES diparsing menggunakan helper resolveHost(). Helper ini memvalidasi input string, memecah node cluster berdasarkan delimiter koma, dan menetapkan fallback port default 6379.
      • Apabila REDIS_NODES tidak dikonfigurasi atau string kosong, redisClient diinisialisasi null tanpa memicu fatal exception saat proses bootstrap aplikasi. Sistem mencatat log: "[redis]: REDIS_NODES is not configured. Running without Redis (distributed locking disabled)".
      • Fungsi acquireLock() dan releaseLock() mengimplementasikan mekanisme non-blocking graceful fallback saat Redis tidak aktif, menjamin proses CI/CD runner dan development lokal dapat berjalan mulus tanpa ketergantungan wajib pada Redis container eksternal.
      • Penambahan opsi konfigurasi enableReadyCheck: false pada driver ioredis Cluster untuk kompatibilitas protokol DragonflyDB yang tidak merespon perintah pemeriksaan kesiapan info Redis standar.
    2. Standardisasi Framework Pengujian Vitest & LCOV SonarQube:
      • Mengadopsi Vitest sebagai pengganti atau inisiasi test-runner modern dengan coverage engine @vitest/coverage-v8.
      • File tests/setup.js menyediakan mocking terpusat untuk koneksi database (connection.js), logger winston, dan external HTTP gateway guna memastikan seluruh unit test bersifat terisolasi (hermetic), deterministik, dan bebas side-effect jaringan.
      • Penyelarasan konfigurasi sonar-project.properties dengan menyertakan direktori tests/ dan mengarahkan path report ke coverage/lcov.info guna pemenuhan metrik Quality Gate SonarQube.
    3. Klasifikasi File yang Berubah:
      • vitest.config.mjs (Config NEW — runner & coverage v8 settings)
      • sonar-project.properties (Config — routing lcov report ke SonarQube)
      • app/helpers/redis.js (Helper — safe connection parsing, fallback non-blocking, DragonflyDB mode)
      • package.json & package-lock.json (Chore — vitest & coverage-v8 dependencies)
      • tests/** (36 unit test files covering helpers, models, middlewares, validations, utils)
  • Perubahan Database (DDL / DML):

    sql
    -- Tidak ada migration file yang terdeteksi — pembaruan infrastruktur testing dan koneksi cache in-memory.
  • Kontrak API & Response Payload: Tidak ada penambahan atau perubahan kontrak API publik. Penambahan script runner NPM pada package.json:

    • "test": "vitest run --coverage"
    • "test:only": "vitest run"
    • "test:watch": "vitest"

4. Bukti Teknis (Technical Proof & Audit Trail) ​

  • Repository: single-billing-BE
  • Branch Utama: development
  • Merge Request / PR: !232 (Release v1.9.2 — Merged to prod) | Staging: !230

Daftar Commit Terkait (Multi-Commit Trail) ​

Commit IDBranchAuthorTanggal & JamRingkasan Perubahan
2499b45feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:53chore(deps): add vitest and coverage-v8
8104e10feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:53chore(vitest): add config and global module mocks
96c6585feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:53chore(git): ignore coverage output
a79b160feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(helpers): cover status, zod and sql guard helpers
533b336feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(helpers): cover banking helper utilities
c29cce8feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(helpers): cover simponi billing and inquiry senders
75cca03feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(helpers): cover bmri response templates
35ec298feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(helpers): cover billing receipt builder
88199cafeat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(middlewares): cover method and mandatory field validation
f093034feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(middlewares): cover token introspection
e777f87feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(middlewares): cover schema validation
79e824bfeat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(utils): cover dynamic route registration
b1d9851feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(validations): cover dashboard query schema
1fc337bfeat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(connection): cover pool query wrapper
49c9969feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(models): cover banking raw query templates
72bb0d7feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(models): cover inquiry and payment schemas
f538521feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(models): cover satker and va schemas
eec3df77feat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(models): cover banking model definitions
5fcd6eafeat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-19 12:54test(models): cover tagihan schemas and va padding
8f05a6dfeat/dragonfly-db-with-unit-testMuhamad Firly Ramadan2026-08-24 10:00feat(dragonfly): add dragonflydb compability config
bfc73affeat/dragonfly-db-with-unit-testHermansyah Efendi2026-08-27 12:31fix(redis): make connection optional and add safe env parsing
de0e6c3feat/dragonfly-db-with-unit-testHermansyah Efendi2026-08-27 12:33chore(sonar): align configuration with vitest and lcov coverage
ac4ce9dfeat/dragonfly-db-with-unit-testHermansyah Efendi2026-08-27 13:58test(helpers): cover helpers and middlewares suites

Cuplikan Kode / Implementasi Inti ​

javascript
// app/helpers/redis.js (Graceful Redis / DragonflyDB Fallback & Safe Host Parsing)
const resolveHost = (raw) => {
  if (!raw || typeof raw !== "string" || !raw.trim()) return [];
  return raw
    .split(",")
    .map((entry) => entry.trim())
    .filter(Boolean)
    .map((entry) => {
      const [host, port] = entry.split(":");
      return { host: host?.trim(), port: Number(port?.trim() || 6379) };
    })
    .filter((node) => Boolean(node.host));
};

const redisClusterNodes = resolveHost(process.env.REDIS_NODES);
const isRedisConfigured = redisClusterNodes.length > 0;

let redisClient = null;

if (isRedisConfigured) {
  redisClient = new Cluster(redisClusterNodes, {
    redisOptions: {
      username: process.env.REDIS_USERNAME || undefined,
      password: process.env.REDIS_PASSWORD || undefined,
      enableReadyCheck: false, // DragonflyDB compatibility
      keyPrefix: redisKeyPrefix,
    },
    // ... retry strategy
  });
} else {
  console.log("[redis]: REDIS_NODES is not configured. Running without Redis (distributed locking disabled)");
}

5. Bukti Verifikasi Pengujian (QA / Unit Test / API Verification) ​

A. Verifikasi Unit Test (Development Stage) ​

  • Test Suite File: tests/** (36 test suites: helpers, models, middlewares, dynamic routes, validations, connection wrapper)
  • Status Eksekusi CLI: PASSED
text
 RUN  v4.1.11 D:/WORK/LNSW/single-billing-BE

 Test Files  36 passed (36)
      Tests  524 passed (524)
   Start at  13:15:11
   Duration  2.66s (transform 2.97s, setup 3.15s, import 4.71s, tests 1.08s, environment 11ms)

B. Panduan Pengujian QA & Verifikasi Staging (QA Playbook) ​

Diisi saat development sebagai panduan eksekusi pengujian QA, kemudian dilengkapi bukti response JSON saat verifikasi di Staging.

  • Cakupan / Surface Pengujian: Worker / DB / Cron Only & CLI Runner
  • Kebutuhan Akses / Role Akun: Terminal akses repo backend single-billing-BE.
  • Hasil Pengujian UAT: PASSED
  • Catatan QA: Verifikasi unit test suite Vitest, eksekusi 36 suites, dan graceful cache fallback DragonflyDB berhasil lolos pengujian UAT.
Skenario Pengujian QA (Test Scenarios) ​
  1. Skenario 1 — Eksekusi Seluruh Test Suite Vitest:

    • Pre-kondisi: Dependensi devDependencies telah terpasang (npm install).
    • Trigger / Command: Jalankan perintah npm test atau npx vitest run.
    • Ekspektasi Output: Seluruh 36 file test dinyatakan passed, 524 test cases sukses, summary coverage ter-generate di folder coverage/.
    • Verifikasi Database / Log: Log runner terminal menampilkan status 36 passed (36) tanpa error assertion.
  2. Skenario 2 — Verifikasi Bootstrap Server Tanpa Redis:

    • Pre-kondisi: Kosongkan nilai variabel REDIS_NODES pada .env.
    • Trigger / Command: Jalankan npm run dev.
    • Ekspektasi Output: Server berhasil menyala normal pada port target tanpa crash/unhandled exception.
    • Verifikasi Database / Log: Tampil log info graceful: [redis]: REDIS_NODES is not configured. Running without Redis (distributed locking disabled).
  3. Skenario 3 — Verifikasi Output LCOV untuk SonarQube:

    • Pre-kondisi: Test suite telah dijalankan dengan flag --coverage.
    • Trigger / Command: Jalankan npm run test lalu periksa file coverage/lcov.info.
    • Ekspektasi Output: Berkas coverage/lcov.info terbentuk dan berisi data line coverage yang siap di-ingest oleh scanner SonarQube.
    • Verifikasi Database / Log: Ukuran berkas coverage/lcov.info valid dan memetakan baris kode komponen app/.
Bukti Response Verifikasi Staging (Diisi saat UAT) ​
json
{
  "status": "PASSED",
  "note": "Pengujian verifikasi UAT dan validasi integrasi berhasil lolos, rilis production v1.9.2 telah live."
}

Single Source of Truth (SSOT) Arsitektur & Perubahan Teknis Backend