test: add full test coverage for notes, ues, ue-modules, ajustements, enseignements, users
- Unit tests (mock DB + API) for all missing endpoints - Integration tests (Drizzle direct) for all missing entities - E2E tests (handler + real DB) for all missing endpoints - Robustness tests: invalid inputs, SQL injection, type errors, business rule violations - Seed helpers: seedNotes, seedUeModules, seedEnseignements, seedAjustements - Add test:coverage and test:coverage:html tasks to deno.json Tests expose known handler bugs (marked [BUG] in test names): - ajustements PUT/DELETE: .where() without and() modifies all rows for student - Missing try/catch in modules, users, enseignements handlers - Whitespace accepted as valid string values - No type or business rule validation (note bounds, coeff >= 0)
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
// Unit tests for /enseignements endpoints — fixtures, mock API, mock DB
|
||||
|
||||
import { assertEquals, assertExists } from "@std/assert";
|
||||
import { mockFetch, restoreFetch } from "../helpers/api_mock.ts";
|
||||
import { createMockDb } from "../helpers/db_mock.ts";
|
||||
import { enseignements } from "../helpers/fixtures.ts";
|
||||
|
||||
interface Enseignement {
|
||||
idProf: string;
|
||||
idModule: string;
|
||||
idPromo: string;
|
||||
}
|
||||
|
||||
// --- Fixtures ---
|
||||
|
||||
Deno.test("enseignements: fixtures have correct shape", () => {
|
||||
assertEquals(enseignements.length, 3);
|
||||
assertEquals(typeof enseignements[0].idModule, "string");
|
||||
assertEquals(typeof enseignements[0].idPromo, "string");
|
||||
});
|
||||
|
||||
// --- Mock API ---
|
||||
|
||||
Deno.test("mock API: POST /enseignements creates enseignement (201) as employee", async () => {
|
||||
const newEns: Enseignement = { idProf: "prof.dupont", idModule: "JIN702C", idPromo: "4AFISE25/26" };
|
||||
mockFetch({ "/enseignements": { method: "POST", status: 201, body: newEns } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/enseignements", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(newEns),
|
||||
});
|
||||
assertEquals(res.status, 201);
|
||||
const data: Enseignement = await res.json();
|
||||
assertEquals(data.idModule, "JIN702C");
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: POST /enseignements 403 for non-employee", async () => {
|
||||
mockFetch({ "/enseignements": { method: "POST", status: 403 } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/enseignements", { method: "POST" });
|
||||
assertEquals(res.status, 403);
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: POST /enseignements 400 on missing fields", async () => {
|
||||
mockFetch({ "/enseignements": { method: "POST", status: 400 } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/enseignements", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({ idProf: "prof.dupont" }),
|
||||
});
|
||||
assertEquals(res.status, 400);
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: POST /enseignements 409 on duplicate", async () => {
|
||||
mockFetch({
|
||||
"/enseignements": { method: "POST", status: 409, body: { error: "Cet enseignement existe déjà." } },
|
||||
});
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/enseignements", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({ idProf: "prof.dupont", idModule: "JIN702C", idPromo: "4AFISE25/26" }),
|
||||
});
|
||||
assertEquals(res.status, 409);
|
||||
const data = await res.json();
|
||||
assertExists(data.error);
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: GET /enseignements/:idProf/:idModule/:idPromo returns enseignement (employee)", async () => {
|
||||
const ens: Enseignement = { idProf: "prof.dupont", idModule: "JIN702C", idPromo: "4AFISE25/26" };
|
||||
mockFetch({ "/enseignements/prof.dupont/JIN702C/4AFISE25": ens });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/enseignements/prof.dupont/JIN702C/4AFISE25%2F26");
|
||||
assertEquals(res.status, 200);
|
||||
const data: Enseignement = await res.json();
|
||||
assertEquals(data.idProf, "prof.dupont");
|
||||
assertEquals(data.idModule, "JIN702C");
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: GET /enseignements/:idProf/:idModule/:idPromo 403 for non-employee", async () => {
|
||||
mockFetch({ "/enseignements/prof.dupont/JIN702C/4AFISE25": { status: 403 } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/enseignements/prof.dupont/JIN702C/4AFISE25%2F26");
|
||||
assertEquals(res.status, 403);
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: GET /enseignements/:idProf/:idModule/:idPromo 404 when not found", async () => {
|
||||
mockFetch({ "/enseignements/ghost/GHOST/GHOST": { status: 404, body: { error: "Ressource introuvable" } } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/enseignements/ghost/GHOST/GHOST");
|
||||
assertEquals(res.status, 404);
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: DELETE /enseignements/:idProf/:idModule/:idPromo returns 204 (employee)", async () => {
|
||||
mockFetch({ "/enseignements/prof.dupont/JIN702C/4AFISE25": { method: "DELETE", status: 204 } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/enseignements/prof.dupont/JIN702C/4AFISE25%2F26", {
|
||||
method: "DELETE",
|
||||
});
|
||||
assertEquals(res.status, 204);
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("mock API: DELETE /enseignements/:idProf/:idModule/:idPromo 403 for non-employee", async () => {
|
||||
mockFetch({ "/enseignements/prof.dupont/JIN702C/4AFISE25": { method: "DELETE", status: 403 } });
|
||||
try {
|
||||
const res = await fetch("http://localhost/api/enseignements/prof.dupont/JIN702C/4AFISE25%2F26", {
|
||||
method: "DELETE",
|
||||
});
|
||||
assertEquals(res.status, 403);
|
||||
} finally {
|
||||
restoreFetch();
|
||||
}
|
||||
});
|
||||
|
||||
// --- Mock DB ---
|
||||
|
||||
Deno.test("mock DB: find enseignement by composite key", () => {
|
||||
const data = [
|
||||
{ idProf: "prof.dupont", idModule: "JIN702C", idPromo: "4AFISE25/26" },
|
||||
{ idProf: "prof.moreau", idModule: "JIN703C", idPromo: "4AFISE25/26" },
|
||||
];
|
||||
const db = createMockDb({ tables: { enseignements: data } });
|
||||
const e = db.findOne<Enseignement>("enseignements", (e) => e.idProf === "prof.dupont" && e.idModule === "JIN702C");
|
||||
assertExists(e);
|
||||
assertEquals(e.idPromo, "4AFISE25/26");
|
||||
});
|
||||
|
||||
Deno.test("mock DB: insert enseignement", () => {
|
||||
const db = createMockDb({ tables: { enseignements: [] } });
|
||||
db.insert<Enseignement>("enseignements", { idProf: "prof.dupont", idModule: "JIN702C", idPromo: "4AFISE25/26" });
|
||||
assertEquals(db.getTable("enseignements").length, 1);
|
||||
});
|
||||
|
||||
Deno.test("mock DB: delete enseignement", () => {
|
||||
const data = [
|
||||
{ idProf: "prof.dupont", idModule: "JIN702C", idPromo: "4AFISE25/26" },
|
||||
{ idProf: "prof.moreau", idModule: "JIN703C", idPromo: "4AFISE25/26" },
|
||||
];
|
||||
const db = createMockDb({ tables: { enseignements: data } });
|
||||
db.deleteWhere<Enseignement>("enseignements", (e) => e.idProf === "prof.dupont");
|
||||
assertEquals(db.getTable("enseignements").length, 1);
|
||||
});
|
||||
|
||||
Deno.test("mock DB: filter enseignements by idModule", () => {
|
||||
const data = [
|
||||
{ idProf: "prof.dupont", idModule: "JIN702C", idPromo: "4AFISE25/26" },
|
||||
{ idProf: "prof.dupont", idModule: "JIN702C", idPromo: "3AFISE25/26" },
|
||||
{ idProf: "prof.moreau", idModule: "JIN703C", idPromo: "4AFISE25/26" },
|
||||
];
|
||||
const db = createMockDb({ tables: { enseignements: data } });
|
||||
const rows = db.findMany<Enseignement>("enseignements", (e) => e.idModule === "JIN702C");
|
||||
assertEquals(rows.length, 2);
|
||||
});
|
||||
Reference in New Issue
Block a user