Contract Testing — Testing

Apa itu Contract Testing? Contract testing memastikan bahwa dua sistem (misalnya frontend dan backend) sepakat tentang bentuk data yang dikirim dan diterima. Al

Apa itu Contract Testing?

Contract testing memastikan bahwa dua sistem (misalnya frontend dan backend) sepakat tentang bentuk data yang dikirim dan diterima. Alih-alih menguji integrasi secara langsung, kita menguji "kontrak" — spesifikasi API yang disepakati kedua pihak.

Mengapa Perlu Contract Testing?

Consumer-Driven Contracts

Pendekatan di mana consumer (frontend/client) mendefinisikan apa yang dibutuhkan, lalu provider (backend/API) memverifikasi bahwa kontrak tersebut terpenuhi:

// Consumer (Frontend) mendefinisikan kontrak:
// "Saya butuh GET /api/users/1 mengembalikan { id, name, email }"

// Provider (Backend) memverifikasi:
// "Apakah endpoint saya memenuhi kontrak ini?"

Pact — Framework Contract Testing

Pact adalah framework populer untuk consumer-driven contract testing. Workflow-nya:

Schema Validation dengan Zod

Cara yang lebih ringan: gunakan library validasi schema untuk mengecek API response di test:

import { z } from "zod";

// Definisikan schema (kontrak)
const UserSchema = z.object({
  id: z.number(),
  name: z.string(),
  email: z.string().email(),
  role: z.enum(["admin", "user"]),
  createdAt: z.string().datetime(),
});

type User = z.infer<typeof UserSchema>;

// Test bahwa API response sesuai kontrak
it("GET /api/users/1 sesuai schema", async () => {
  const response = await fetch("/api/users/1");
  const data = await response.json();

  // Jika data tidak sesuai schema, Zod melempar error
  const parsed = UserSchema.parse(data);
  expect(parsed.id).toBe(1);
  expect(parsed.name).toBeDefined();
});

Schema Validation dengan Joi

import Joi from "joi";

const userSchema = Joi.object({
  id: Joi.number().required(),
  name: Joi.string().required(),
  email: Joi.string().email().required(),
  role: Joi.string().valid("admin", "user").required(),
});

it("response sesuai kontrak", async () => {
  const data = await fetchUser(1);
  const { error } = userSchema.validate(data);
  expect(error).toBeUndefined();
});

Testing API Response Shape

Tanpa library validasi, kita bisa mengecek bentuk response secara manual:

it("response memiliki properti yang diharapkan", async () => {
  const response = await fetch("/api/users/1");
  const user = await response.json();

  // Cek structure, bukan value spesifik
  expect(user).toMatchObject({
    id: expect.any(Number),
    name: expect.any(String),
    email: expect.stringMatching(/@/),
    role: expect.stringMatching(/^(admin|user)$/),
  });

  // Pastikan tidak ada field yang hilang
  expect(Object.keys(user)).toEqual(
    expect.arrayContaining(["id", "name", "email", "role"])
  );
});

Best Practices

Yang akan kamu pelajari