test(promotions): add unit, integration and e2e tests for /promotions (#110)
- unit: fixture shapes, mock API (GET/POST/PUT/DELETE), mock DB CRUD - integration: real DB list, create, get, update, delete, not-found cases - e2e: handler calls with mock context + real DB, covers 400/403/404 cases
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
// #110 - Unit tests for /promotions endpoints
|
||||
|
||||
import { assertEquals, assertExists } from "@std/assert";
|
||||
import { mockFetch, restoreFetch } from "../helpers/api_mock.ts";
|
||||
import { createMockDb } from "../helpers/db_mock.ts";
|
||||
import { type Promotion, promotions } from "../helpers/fixtures.ts";
|
||||
|
||||
// --- Fixtures ---
|
||||
|
||||
Deno.test("promotions: fixtures have correct shape", () => {
|
||||
assertEquals(promotions.length, 3);
|
||||
assertEquals(typeof promotions[0].idPromo, "string");
|
||||
assertEquals(typeof promotions[0].annee, "string");
|
||||
});
|
||||
|
||||
// --- Mock API ---
|
||||
|
||||
Deno.test("mock API: GET /promotions returns list", async () => {
|
||||
mockFetch({ "/promotions": promotions });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/promotions");
|
||||
assertEquals(res.status, 200);
|
||||
const data: Promotion[] = await res.json();
|
||||
assertEquals(data.length, 3);
|
||||
assertExists(data.find((p) => p.idPromo === "4AFISE25/26"));
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: GET /promotions/:id returns one", async () => {
|
||||
mockFetch({ "/promotions/4AFISE25%2F26": promotions[0] });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/promotions/4AFISE25%2F26");
|
||||
assertEquals(res.status, 200);
|
||||
const data: Promotion = await res.json();
|
||||
assertEquals(data.idPromo, "4AFISE25/26");
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: GET /promotions/:id 404 when not found", async () => {
|
||||
mockFetch({ "/promotions/UNKNOWN": { status: 404, body: { error: "Ressource introuvable" } } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/promotions/UNKNOWN");
|
||||
assertEquals(res.status, 404);
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: POST /promotions creates promotion (201)", async () => {
|
||||
const newPromo: Promotion = { idPromo: "NEW2025", annee: "2025" };
|
||||
mockFetch({ "/promotions": { method: "POST", status: 201, body: newPromo } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/promotions", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({ idPromo: "NEW2025", annee: "2025" }),
|
||||
});
|
||||
assertEquals(res.status, 201);
|
||||
const data: Promotion = await res.json();
|
||||
assertEquals(data.idPromo, "NEW2025");
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: POST /promotions 400 on missing fields", async () => {
|
||||
mockFetch({ "/promotions": { method: "POST", status: 400 } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/promotions", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({ idPromo: "NEW2025" }),
|
||||
});
|
||||
assertEquals(res.status, 400);
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: PUT /promotions/:id updates promotion", async () => {
|
||||
const updated = { idPromo: "4AFISE25/26", annee: "2026" };
|
||||
mockFetch({ "/promotions/4AFISE25%2F26": { method: "PUT", status: 200, body: updated } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/promotions/4AFISE25%2F26", {
|
||||
method: "PUT",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({ annee: "2026" }),
|
||||
});
|
||||
assertEquals(res.status, 200);
|
||||
const data: Promotion = await res.json();
|
||||
assertEquals(data.annee, "2026");
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: DELETE /promotions/:id returns 204", async () => {
|
||||
mockFetch({ "/promotions/4AFISE25%2F26": { method: "DELETE", status: 204 } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/promotions/4AFISE25%2F26", {
|
||||
method: "DELETE",
|
||||
});
|
||||
assertEquals(res.status, 204);
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
// --- Mock DB ---
|
||||
|
||||
Deno.test("mock DB: find promotion by idPromo", () => {
|
||||
const db = createMockDb({ tables: { promotions: [...promotions] } });
|
||||
const p = db.findOne<Promotion>(
|
||||
"promotions",
|
||||
(r) => r.idPromo === "4AFISE25/26",
|
||||
);
|
||||
assertExists(p);
|
||||
assertEquals(p.annee, "2025");
|
||||
});
|
||||
|
||||
Deno.test("mock DB: insert promotion", () => {
|
||||
const db = createMockDb({ tables: { promotions: [...promotions] } });
|
||||
db.insert<Promotion>("promotions", { idPromo: "NEW2025", annee: "2025" });
|
||||
assertEquals(db.getTable("promotions").length, 4);
|
||||
});
|
||||
|
||||
Deno.test("mock DB: update promotion annee", () => {
|
||||
const db = createMockDb({ tables: { promotions: [...promotions] } });
|
||||
db.updateWhere<Promotion>(
|
||||
"promotions",
|
||||
(p) => p.idPromo === "4AFISE25/26",
|
||||
{ annee: "2026" },
|
||||
);
|
||||
assertEquals(
|
||||
db.findOne<Promotion>("promotions", (p) => p.idPromo === "4AFISE25/26")
|
||||
?.annee,
|
||||
"2026",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("mock DB: delete promotion", () => {
|
||||
const db = createMockDb({ tables: { promotions: [...promotions] } });
|
||||
const count = db.deleteWhere<Promotion>(
|
||||
"promotions",
|
||||
(p) => p.idPromo === "4AFISE25/26",
|
||||
);
|
||||
assertEquals(count, 1);
|
||||
assertEquals(db.getTable("promotions").length, 2);
|
||||
});
|
||||
Reference in New Issue
Block a user