test(modules): add unit, integration and e2e tests for /modules (#113)
- unit: fixture shapes, mock API (GET/POST/PUT/DELETE + 409), mock DB CRUD - integration: list, create, get, duplicate rejection, update, delete - e2e: handler calls with mock context + real DB, covers 400/403/404/409
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
// #113 - Unit tests for /modules endpoints
|
||||
|
||||
import { assertEquals, assertExists } from "@std/assert";
|
||||
import { mockFetch, restoreFetch } from "../helpers/api_mock.ts";
|
||||
import { createMockDb } from "../helpers/db_mock.ts";
|
||||
import { type Module, modules } from "../helpers/fixtures.ts";
|
||||
|
||||
// --- Fixtures ---
|
||||
|
||||
Deno.test("modules: fixtures have correct shape", () => {
|
||||
assertEquals(modules.length, 3);
|
||||
assertEquals(typeof modules[0].id, "string");
|
||||
assertEquals(typeof modules[0].nom, "string");
|
||||
});
|
||||
|
||||
// --- Mock API ---
|
||||
|
||||
Deno.test("mock API: GET /modules returns list", async () => {
|
||||
mockFetch({ "/modules": modules });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/modules");
|
||||
assertEquals(res.status, 200);
|
||||
const data: Module[] = await res.json();
|
||||
assertEquals(data.length, 3);
|
||||
assertExists(data.find((m) => m.id === "JIN702C"));
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: GET /modules/:id returns one module", async () => {
|
||||
mockFetch({ "/modules/JIN702C": modules[0] });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/modules/JIN702C");
|
||||
assertEquals(res.status, 200);
|
||||
const data: Module = await res.json();
|
||||
assertEquals(data.id, "JIN702C");
|
||||
assertEquals(data.nom, "Optimisation");
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: GET /modules/:id 404 when not found", async () => {
|
||||
mockFetch({ "/modules/UNKNOWN": { status: 404, body: { error: "Ressource introuvable" } } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/modules/UNKNOWN");
|
||||
assertEquals(res.status, 404);
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: POST /modules creates module (201)", async () => {
|
||||
const newModule: Module = { id: "NEW101", nom: "Nouveau Module" };
|
||||
mockFetch({ "/modules": { method: "POST", status: 201, body: newModule } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/modules", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(newModule),
|
||||
});
|
||||
assertEquals(res.status, 201);
|
||||
const data: Module = await res.json();
|
||||
assertEquals(data.id, "NEW101");
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: POST /modules 409 on duplicate id", async () => {
|
||||
mockFetch({ "/modules": { method: "POST", status: 409, body: { error: "Un module avec cet identifiant existe déjà" } } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/modules", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(modules[0]),
|
||||
});
|
||||
assertEquals(res.status, 409);
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: POST /modules 400 on missing fields", async () => {
|
||||
mockFetch({ "/modules": { method: "POST", status: 400 } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/modules", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({ id: "X" }),
|
||||
});
|
||||
assertEquals(res.status, 400);
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: PUT /modules/:id updates nom", async () => {
|
||||
const updated: Module = { id: "JIN702C", nom: "Optimisation avancée" };
|
||||
mockFetch({ "/modules/JIN702C": { method: "PUT", status: 200, body: updated } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/modules/JIN702C", {
|
||||
method: "PUT",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({ nom: "Optimisation avancée" }),
|
||||
});
|
||||
assertEquals(res.status, 200);
|
||||
const data: Module = await res.json();
|
||||
assertEquals(data.nom, "Optimisation avancée");
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: DELETE /modules/:id returns 204", async () => {
|
||||
mockFetch({ "/modules/JIN702C": { method: "DELETE", status: 204 } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/modules/JIN702C", { method: "DELETE" });
|
||||
assertEquals(res.status, 204);
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
// --- Mock DB ---
|
||||
|
||||
Deno.test("mock DB: find module by id", () => {
|
||||
const db = createMockDb({ tables: { modules: [...modules] } });
|
||||
const m = db.findOne<Module>("modules", (m) => m.id === "JIN702C");
|
||||
assertExists(m);
|
||||
assertEquals(m.nom, "Optimisation");
|
||||
});
|
||||
|
||||
Deno.test("mock DB: insert module", () => {
|
||||
const db = createMockDb({ tables: { modules: [...modules] } });
|
||||
db.insert<Module>("modules", { id: "NEW101", nom: "Nouveau" });
|
||||
assertEquals(db.getTable("modules").length, 4);
|
||||
});
|
||||
|
||||
Deno.test("mock DB: update module nom", () => {
|
||||
const db = createMockDb({ tables: { modules: [...modules] } });
|
||||
db.updateWhere<Module>("modules", (m) => m.id === "JIN702C", { nom: "Updated" });
|
||||
assertEquals(db.findOne<Module>("modules", (m) => m.id === "JIN702C")?.nom, "Updated");
|
||||
});
|
||||
|
||||
Deno.test("mock DB: delete module", () => {
|
||||
const db = createMockDb({ tables: { modules: [...modules] } });
|
||||
db.deleteWhere<Module>("modules", (m) => m.id === "JIN702C");
|
||||
assertEquals(db.getTable("modules").length, 2);
|
||||
});
|
||||
Reference in New Issue
Block a user