Regulasi privasi dan kepatuhan global, seperti rancangan undang-undang semacam GUARD Act di Amerika Serikat atau standar verifikasi usia di berbagai yurisdiksi, mewajibkan platform memverifikasi umur pengguna secara ketat. Integrasi langsung ke penyedia identitas eksternal (Identity Provider / IdP) pada pipeline automated test menimbulkan masalah reliabilitas: latensi jaringan acak, kuota API rate-limiting, dan downtime sandbox yang memicu flaky test di CI/CD.

Menguji alur kepatuhan ini membutuhkan pendekatan deterministik tanpa mengeksekusi HTTP request langsung ke server vendor di setiap commit. Artikel ini mengulas strategi pengujian integrasi verifikasi usia menggunakan pendekatan deterministic mocking, penanganan skenario kegagalan, serta proteksi data pribadi (Personally Identifiable Information / PII) agar tidak bocor ke log pengujian.

Arsitektur Pengujian: Integrasi Nyata vs Deterministic Mocking

Memanggil API pihak ketiga langsung di pipeline CI menciptakan dependensi eksternal yang melanggar prinsip isolasi testing. Terdapat dua pendekatan utama untuk mengisolasi pengujian:

  • WireMock (HTTP Boundary Mocking): Menjalankan proses HTTP server lokal terpisah yang menangkap request out-of-process. Cocok untuk microservices backend multi-bahasa (Go, Java, Python).
  • Mock Service Worker / MSW (Network-Level Interception): Memotong request pada layer Node.js (via fetch/interceptor) tanpa perlu menjalankan container mock eksternal terpisah. Efisien untuk runtime JavaScript/TypeScript.

Kedua pendekatan ini memungkinkan pipeline CI mereplikasi respons vendor secara konsisten tanpa latensi acak atau kegagalan autentikasi API key.

Validasi Kontrak Schema ID Token

Penyedia verifikasi usia umumnya mengembalikan token bertanda tangan kriptografis atau payload JSON yang menyatakan status verifikasi (misalnya: verified, underage, rejected). Mengabaikan perubahan skema dari pihak ketiga adalah penyebab umum kegagalan produksi.

Validasi kontrak harus diuji pada layer adaptasi internal sebelum memproses data domain aplikasi:

// age_verifier.ts
import { z } from "zod";

export const AgeVerificationResponseSchema = z.object({
  verification_id: z.string().uuid(),
  status: z.enum(["VERIFIED", "UNDERAGE", "REJECTED"]),
  verified_age: z.number().int().min(0).max(120),
  risk_score: z.number().min(0).max(1),
  signature: z.string().min(1)
});

export type AgeVerificationResponse = z.infer<typeof AgeVerificationResponseSchema>;

export async function processAgeVerification(apiUrl: string, token: string): Promise<AgeVerificationResponse> {
  const response = await fetch(`${apiUrl}/v1/verify`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${token}`
    },
    body: JSON.stringify({ assertion_token: token })
  });

  if (!response.ok) {
    throw new Error(`IdP request failed with status: ${response.status}`);
  }

  const data = await response.json();
  return AgeVerificationResponseSchema.parse(data);
}

Implementasi Mock dan Assert Skenario Pengujian

Berikut adalah contoh implementasi suite pengujian integrasi deterministik menggunakan Vitest dan msw. Pengujian ini memastikan aplikasi menangani respons sukses, penolakan usia, dan error skema secara lokal.

// age_verifier.spec.ts
import { describe, it, expect, beforeAll, afterAll, afterEach } from "vitest";
import { setupServer } from "msw/node";
import { http, HttpResponse } from "msw";
import { processAgeVerification } from "./age_verifier";

const MOCK_API_URL = "https://api.external-verifier.test";

const server = setupServer(
  http.post(`${MOCK_API_URL}/v1/verify`, () => {
    return HttpResponse.json({
      verification_id: "d3b07384-d113-494a-a5e2-04e3b1c678a1",
      status: "VERIFIED",
      verified_age: 21,
      risk_score: 0.05,
      signature: "sig_valid_hex_bytes_test"
    });
  })
);

beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

describe("Age Verification Service Integration", () => {
  it("mengembalikan status usia valid ketika IdP merespons sesuai kontrak", async () => {
    const result = await processAgeVerification(MOCK_API_URL, "token_sample_abc");

    expect(result.status).toBe("VERIFIED");
    expect(result.verified_age).toBeGreaterThanOrEqual(18);
  });

  it("menolak payload yang merusak kontrak skema", async () => {
    server.use(
      http.post(`${MOCK_API_URL}/v1/verify`, () => {
        return HttpResponse.json({
          verification_id: "invalid-uuid",
          status: "INVALID_STATUS",
          verified_age: -5
        });
      })
    );

    await expect(processAgeVerification(MOCK_API_URL, "token_invalid"))
      .rejects
      .toThrow();
  });
});

Simulasi Skenario Kegagalan Jaringan dan Fallback

API verifikasi usia eksternal sering mengalami lonjakan latensi atau error sementara (5xx). Sistem harus menguji strategi ketahanan: timeout deterministik, circuit breaker, dan fallback aman (membatasi akses fitur, bukan meloloskan verifikasi).

Uji skenario kegagalan jaringan seperti timeout tanpa perlu memutus koneksi internet server pengujian:

it("menangani gateway timeout dari IdP secara deterministik", async () => {
  server.use(
    http.post(`${MOCK_API_URL}/v1/verify`, () => {
      return HttpResponse.json({ error: "Gateway Timeout" }, { status: 504 });
    })
  );

  await expect(processAgeVerification(MOCK_API_URL, "token_timeout"))
    .rejects
    .toThrow("IdP request failed with status: 504");
});

Pendekatan lazy developer: jika tidak memerlukan pengujian boundary HTTP mentah lintas bahasa, gunakan network interceptor lokal seperti MSW daripada mengonfigurasi instance Docker WireMock tambahan di CI runner.

Mencegah Kebocoran PII pada Test Log CI/CD

Layanan verifikasi usia kerap mentransmisikan data sensitif seperti tanggal lahir, nomor dokumen identitas, atau foto wajah via metadata assertions. Menyimpan payload mentah ke log CI melanggar kepatuhan perlindungan data (seperti GDPR atau UU PDP).

Langkah wajib audit logging pada test fixture:

  1. Masking Logger: Terapkan interceptor logger yang menyaring key sensitif (seperti id_number, dob, raw_document) sebelum output dikirim ke stdout CI runner.
  2. Synthesized PII Only: Jangan gunakan sampel data produksi di fixture testing. Gunakan fixed synthetic UUID dan tanggal placeholder statis.
  3. Redaksi Header Otorisasi: Pastikan header Authorization atau assertion token tidak dicetak utuh ketika logging assertion error terjadi saat test suite gagal.

Dengan mengkombinasikan mock jaringan deterministik, validasi kontrak schema Zod, dan sanitasi payload data sensitif, pipeline pengujian integrasi verifikasi usia menjadi stabil, cepat, dan aman untuk automasi CI/CD.