Files
PolyMPR/tests/unit/enseignements_test.ts
T
djalim 2f4d8db1bf
Check Deno code / Check Deno code (pull_request) Failing after 6s
Tests / Unit tests (pull_request) Successful in 13s
Tests / Integration tests (pull_request) Failing after 1m14s
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)
2026-04-26 18:25:00 +02:00

180 lines
6.5 KiB
TypeScript

// 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);
});