Files
PolyMPR/tests/e2e/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

186 lines
6.1 KiB
TypeScript

// E2E tests for /enseignements endpoints — handler + real DB
import { assertEquals, assertExists } from "@std/assert";
import {
makeContextWithAffiliation,
makeEmployeeContext,
makeGetRequest,
makeJsonRequest,
} from "../helpers/handler.ts";
import {
seedEnseignements,
seedModules,
seedPromotions,
seedUsers,
truncateAll,
} from "../helpers/db_integration.ts";
import { handler as enseignementsHandler } from "$apps/admin/api/enseignements.ts";
import { handler as enseignementHandler } from "$apps/admin/api/enseignements/[idProf]/[idModule]/[idPromo].ts";
// --- POST /enseignements ---
Deno.test({
name: "e2e enseignements: POST /enseignements creates enseignement (201) as employee",
async fn() {
await truncateAll();
await seedUsers([{ id: "prof.dupont", nom: "Dupont", prenom: "Jean" }]);
await seedModules([{ id: "M1", nom: "Mod A" }]);
await seedPromotions([{ id: "P1" }]);
const res = await enseignementsHandler.POST!(
makeJsonRequest("/enseignements", "POST", { idProf: "prof.dupont", idModule: "M1", idPromo: "P1" }),
makeEmployeeContext(),
);
assertEquals(res.status, 201);
const body = await res.json();
assertExists(body.idProf);
assertEquals(body.idModule, "M1");
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: "e2e enseignements: POST /enseignements 403 for non-employee",
async fn() {
await truncateAll();
const res = await enseignementsHandler.POST!(
makeJsonRequest("/enseignements", "POST", { idProf: "p", idModule: "M1", idPromo: "P1" }),
makeContextWithAffiliation("student"),
);
assertEquals(res.status, 403);
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: "e2e enseignements: POST /enseignements 400 on missing fields",
async fn() {
await truncateAll();
const res = await enseignementsHandler.POST!(
makeJsonRequest("/enseignements", "POST", { idProf: "prof.dupont" }),
makeEmployeeContext(),
);
assertEquals(res.status, 400);
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: "e2e enseignements: POST /enseignements 409 on duplicate",
async fn() {
await truncateAll();
await seedUsers([{ id: "prof.dupont", nom: "Dupont", prenom: "Jean" }]);
await seedModules([{ id: "M1", nom: "Mod A" }]);
await seedPromotions([{ id: "P1" }]);
await seedEnseignements([{ idProf: "prof.dupont", idModule: "M1", idPromo: "P1" }]);
const res = await enseignementsHandler.POST!(
makeJsonRequest("/enseignements", "POST", { idProf: "prof.dupont", idModule: "M1", idPromo: "P1" }),
makeEmployeeContext(),
);
assertEquals(res.status, 409);
},
sanitizeResources: false,
sanitizeOps: false,
});
// --- GET /enseignements/:idProf/:idModule/:idPromo ---
Deno.test({
name: "e2e enseignements: GET /enseignements/:idProf/:idModule/:idPromo returns enseignement (employee)",
async fn() {
await truncateAll();
await seedUsers([{ id: "prof.dupont", nom: "Dupont", prenom: "Jean" }]);
await seedModules([{ id: "M1", nom: "Mod A" }]);
await seedPromotions([{ id: "P1" }]);
await seedEnseignements([{ idProf: "prof.dupont", idModule: "M1", idPromo: "P1" }]);
const res = await enseignementHandler.GET!(
makeGetRequest("/enseignements/prof.dupont/M1/P1"),
makeEmployeeContext({ idProf: "prof.dupont", idModule: "M1", idPromo: "P1" }),
);
assertEquals(res.status, 200);
const body = await res.json();
assertEquals(body.idProf, "prof.dupont");
assertEquals(body.idModule, "M1");
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: "e2e enseignements: GET /enseignements/:idProf/:idModule/:idPromo 403 for non-employee",
async fn() {
await truncateAll();
const res = await enseignementHandler.GET!(
makeGetRequest("/enseignements/p/M1/P1"),
makeContextWithAffiliation("student", { idProf: "p", idModule: "M1", idPromo: "P1" }),
);
assertEquals(res.status, 403);
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: "e2e enseignements: GET /enseignements/:idProf/:idModule/:idPromo 404 when not found",
async fn() {
await truncateAll();
const res = await enseignementHandler.GET!(
makeGetRequest("/enseignements/ghost/GHOST/GHOST"),
makeEmployeeContext({ idProf: "ghost", idModule: "GHOST", idPromo: "GHOST" }),
);
assertEquals(res.status, 404);
},
sanitizeResources: false,
sanitizeOps: false,
});
// --- DELETE /enseignements/:idProf/:idModule/:idPromo ---
Deno.test({
name: "e2e enseignements: DELETE /enseignements/:idProf/:idModule/:idPromo returns 204 (employee)",
async fn() {
await truncateAll();
await seedUsers([{ id: "prof.dupont", nom: "Dupont", prenom: "Jean" }]);
await seedModules([{ id: "M1", nom: "Mod A" }]);
await seedPromotions([{ id: "P1" }]);
await seedEnseignements([{ idProf: "prof.dupont", idModule: "M1", idPromo: "P1" }]);
const res = await enseignementHandler.DELETE!(
makeGetRequest("/enseignements/prof.dupont/M1/P1"),
makeEmployeeContext({ idProf: "prof.dupont", idModule: "M1", idPromo: "P1" }),
);
assertEquals(res.status, 204);
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: "e2e enseignements: DELETE /enseignements/:idProf/:idModule/:idPromo 403 for non-employee",
async fn() {
await truncateAll();
const res = await enseignementHandler.DELETE!(
makeGetRequest("/enseignements/p/M1/P1"),
makeContextWithAffiliation("student", { idProf: "p", idModule: "M1", idPromo: "P1" }),
);
assertEquals(res.status, 403);
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: "e2e enseignements: DELETE /enseignements/:idProf/:idModule/:idPromo 404 when not found",
async fn() {
await truncateAll();
const res = await enseignementHandler.DELETE!(
makeGetRequest("/enseignements/ghost/GHOST/GHOST"),
makeEmployeeContext({ idProf: "ghost", idModule: "GHOST", idPromo: "GHOST" }),
);
assertEquals(res.status, 404);
},
sanitizeResources: false,
sanitizeOps: false,
});