951c9c1fea
Check Deno code / Check Deno code (pull_request) Has been cancelled
Tests / Unit tests (pull_request) Has been cancelled
Tests / Integration tests (pull_request) Has been cancelled
Check Deno code / Check Deno code (push) Has been cancelled
Tests / Unit tests (push) Has been cancelled
Tests / Integration tests (push) Has been cancelled
313 lines
9.4 KiB
TypeScript
313 lines
9.4 KiB
TypeScript
// E2E tests for /ue-modules endpoints — handler + real DB
|
|
|
|
import { assertEquals, assertExists } from "@std/assert";
|
|
import {
|
|
makeContextWithAffiliation,
|
|
makeEmployeeContext,
|
|
makeGetRequest,
|
|
makeJsonRequest,
|
|
} from "../helpers/handler.ts";
|
|
import {
|
|
seedModules,
|
|
seedPromotions,
|
|
seedUeModules,
|
|
seedUes,
|
|
truncateAll,
|
|
} from "../helpers/db_integration.ts";
|
|
import { handler as ueModulesHandler } from "$apps/admin/api/ue-modules.ts";
|
|
import { handler as ueModuleHandler } from "$apps/admin/api/ue-modules/[idModule]/[idUE]/[idPromo].ts";
|
|
import { ueModules as ueModulesTable } from "$root/databases/schema.ts";
|
|
import { testDb } from "../helpers/db_integration.ts";
|
|
|
|
// --- GET /ue-modules ---
|
|
|
|
Deno.test({
|
|
name: "e2e ue_modules: GET /ue-modules returns all associations",
|
|
async fn() {
|
|
await truncateAll();
|
|
await seedPromotions([{ id: "P1" }]);
|
|
await seedModules([{ id: "M1", nom: "Mod A" }, { id: "M2", nom: "Mod B" }]);
|
|
const [ue] = await seedUes([{ nom: "UE Info" }]);
|
|
await seedUeModules([
|
|
{ idModule: "M1", idUE: ue.id, idPromo: "P1", coeff: 2.0 },
|
|
{ idModule: "M2", idUE: ue.id, idPromo: "P1", coeff: 3.0 },
|
|
]);
|
|
const res = await ueModulesHandler.GET!(
|
|
makeGetRequest("/ue-modules"),
|
|
makeEmployeeContext(),
|
|
);
|
|
assertEquals(res.status, 200);
|
|
const body = await res.json();
|
|
assertEquals(body.length, 2);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name: "e2e ue_modules: GET /ue-modules?idPromo filters by promo",
|
|
async fn() {
|
|
await truncateAll();
|
|
await seedPromotions([{ id: "P1" }, { id: "P2" }]);
|
|
await seedModules([{ id: "M1", nom: "Mod A" }]);
|
|
const [ue] = await seedUes([{ nom: "UE Info" }]);
|
|
await seedUeModules([
|
|
{ idModule: "M1", idUE: ue.id, idPromo: "P1", coeff: 2.0 },
|
|
{ idModule: "M1", idUE: ue.id, idPromo: "P2", coeff: 3.0 },
|
|
]);
|
|
const res = await ueModulesHandler.GET!(
|
|
makeGetRequest("/ue-modules", { idPromo: "P1" }),
|
|
makeEmployeeContext(),
|
|
);
|
|
assertEquals(res.status, 200);
|
|
const body = await res.json();
|
|
assertEquals(body.length, 1);
|
|
assertEquals(body[0].idPromo, "P1");
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
// --- POST /ue-modules ---
|
|
|
|
Deno.test({
|
|
name: "e2e ue_modules: POST /ue-modules creates association (201)",
|
|
async fn() {
|
|
await truncateAll();
|
|
await seedPromotions([{ id: "P1" }]);
|
|
await seedModules([{ id: "M1", nom: "Mod A" }]);
|
|
const [ue] = await seedUes([{ nom: "UE Info" }]);
|
|
const res = await ueModulesHandler.POST!(
|
|
makeJsonRequest("/ue-modules", "POST", {
|
|
idModule: "M1",
|
|
idUE: ue.id,
|
|
idPromo: "P1",
|
|
coeff: 4.0,
|
|
}),
|
|
makeEmployeeContext(),
|
|
);
|
|
assertEquals(res.status, 201);
|
|
const body = await res.json();
|
|
assertExists(body.idModule);
|
|
assertEquals(body.coeff, 4.0);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name: "e2e ue_modules: POST /ue-modules 400 on missing fields",
|
|
async fn() {
|
|
await truncateAll();
|
|
const res = await ueModulesHandler.POST!(
|
|
makeJsonRequest("/ue-modules", "POST", { idModule: "M1" }),
|
|
makeEmployeeContext(),
|
|
);
|
|
assertEquals(res.status, 400);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
// --- GET /ue-modules/:idModule/:idUE/:idPromo ---
|
|
|
|
Deno.test({
|
|
name:
|
|
"e2e ue_modules: GET /ue-modules/:idModule/:idUE/:idPromo returns correct association (employee)",
|
|
async fn() {
|
|
await truncateAll();
|
|
await seedPromotions([{ id: "P1" }, { id: "P2" }]);
|
|
await seedModules([{ id: "M1", nom: "Mod A" }, { id: "M2", nom: "Mod B" }]);
|
|
const [ue1, ue2] = await seedUes([{ nom: "UE Info" }, { nom: "UE Maths" }]);
|
|
// Plusieurs lignes qui partagent idModule="M1" — le handler doit discriminer par idUE ET idPromo
|
|
await seedUeModules([
|
|
{ idModule: "M1", idUE: ue1.id, idPromo: "P1", coeff: 3.5 },
|
|
{ idModule: "M1", idUE: ue2.id, idPromo: "P1", coeff: 1.0 },
|
|
{ idModule: "M1", idUE: ue1.id, idPromo: "P2", coeff: 2.0 },
|
|
{ idModule: "M2", idUE: ue1.id, idPromo: "P1", coeff: 4.0 },
|
|
]);
|
|
const res = await ueModuleHandler.GET!(
|
|
makeGetRequest(`/ue-modules/M1/${ue1.id}/P1`),
|
|
makeEmployeeContext({
|
|
idModule: "M1",
|
|
idUE: String(ue1.id),
|
|
idPromo: "P1",
|
|
}),
|
|
);
|
|
assertEquals(res.status, 200);
|
|
const body = await res.json();
|
|
// Doit retourner exactement M1/ue1/P1 avec coeff 3.5, pas une autre ligne
|
|
assertEquals(body.coeff, 3.5);
|
|
assertEquals(body.idPromo, "P1");
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name:
|
|
"e2e ue_modules: GET /ue-modules/:idModule/:idUE/:idPromo 403 for non-employee",
|
|
async fn() {
|
|
await truncateAll();
|
|
const res = await ueModuleHandler.GET!(
|
|
makeGetRequest("/ue-modules/M1/1/P1"),
|
|
makeContextWithAffiliation("student", {
|
|
idModule: "M1",
|
|
idUE: "1",
|
|
idPromo: "P1",
|
|
}),
|
|
);
|
|
assertEquals(res.status, 403);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name:
|
|
"e2e ue_modules: GET /ue-modules/:idModule/:idUE/:idPromo 404 when not found",
|
|
async fn() {
|
|
await truncateAll();
|
|
const res = await ueModuleHandler.GET!(
|
|
makeGetRequest("/ue-modules/GHOST/1/GHOST"),
|
|
makeEmployeeContext({ idModule: "GHOST", idUE: "1", idPromo: "GHOST" }),
|
|
);
|
|
assertEquals(res.status, 404);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
// --- PUT /ue-modules/:idModule/:idUE/:idPromo ---
|
|
|
|
Deno.test({
|
|
name:
|
|
"e2e ue_modules: PUT /ue-modules/:idModule/:idUE/:idPromo updates only the targeted row (employee)",
|
|
async fn() {
|
|
await truncateAll();
|
|
await seedPromotions([{ id: "P1" }, { id: "P2" }]);
|
|
await seedModules([{ id: "M1", nom: "Mod A" }]);
|
|
const [ue1, ue2] = await seedUes([{ nom: "UE Info" }, { nom: "UE Maths" }]);
|
|
// Deux lignes avec même idModule — le PUT ne doit modifier que celle ciblée
|
|
await seedUeModules([
|
|
{ idModule: "M1", idUE: ue1.id, idPromo: "P1", coeff: 2.0 },
|
|
{ idModule: "M1", idUE: ue2.id, idPromo: "P2", coeff: 9.0 },
|
|
]);
|
|
const res = await ueModuleHandler.PUT!(
|
|
makeJsonRequest(`/ue-modules/M1/${ue1.id}/P1`, "PUT", { coeff: 5.0 }),
|
|
makeEmployeeContext({
|
|
idModule: "M1",
|
|
idUE: String(ue1.id),
|
|
idPromo: "P1",
|
|
}),
|
|
);
|
|
assertEquals(res.status, 200);
|
|
const body = await res.json();
|
|
assertEquals(body.coeff, 5.0);
|
|
assertEquals(body.idPromo, "P1");
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name:
|
|
"e2e ue_modules: PUT /ue-modules/:idModule/:idUE/:idPromo 403 for non-employee",
|
|
async fn() {
|
|
await truncateAll();
|
|
const res = await ueModuleHandler.PUT!(
|
|
makeJsonRequest("/ue-modules/M1/1/P1", "PUT", { coeff: 5.0 }),
|
|
makeContextWithAffiliation("student", {
|
|
idModule: "M1",
|
|
idUE: "1",
|
|
idPromo: "P1",
|
|
}),
|
|
);
|
|
assertEquals(res.status, 403);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name:
|
|
"e2e ue_modules: PUT /ue-modules/:idModule/:idUE/:idPromo 404 when not found",
|
|
async fn() {
|
|
await truncateAll();
|
|
const res = await ueModuleHandler.PUT!(
|
|
makeJsonRequest("/ue-modules/GHOST/1/GHOST", "PUT", { coeff: 5.0 }),
|
|
makeEmployeeContext({ idModule: "GHOST", idUE: "1", idPromo: "GHOST" }),
|
|
);
|
|
assertEquals(res.status, 404);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
// --- DELETE /ue-modules/:idModule/:idUE/:idPromo ---
|
|
|
|
Deno.test({
|
|
name:
|
|
"e2e ue_modules: DELETE /ue-modules/:idModule/:idUE/:idPromo deletes only targeted row (employee)",
|
|
async fn() {
|
|
await truncateAll();
|
|
await seedPromotions([{ id: "P1" }, { id: "P2" }]);
|
|
await seedModules([{ id: "M1", nom: "Mod A" }]);
|
|
const [ue1, ue2] = await seedUes([{ nom: "UE Info" }, { nom: "UE Maths" }]);
|
|
// Deux lignes avec même idModule — seule celle ciblée doit être supprimée
|
|
await seedUeModules([
|
|
{ idModule: "M1", idUE: ue1.id, idPromo: "P1", coeff: 2.0 },
|
|
{ idModule: "M1", idUE: ue2.id, idPromo: "P2", coeff: 4.0 },
|
|
]);
|
|
const res = await ueModuleHandler.DELETE!(
|
|
makeGetRequest(`/ue-modules/M1/${ue1.id}/P1`),
|
|
makeEmployeeContext({
|
|
idModule: "M1",
|
|
idUE: String(ue1.id),
|
|
idPromo: "P1",
|
|
}),
|
|
);
|
|
assertEquals(res.status, 204);
|
|
// L'autre ligne doit toujours exister
|
|
const remaining = await testDb.select().from(ueModulesTable);
|
|
assertEquals(remaining.length, 1);
|
|
assertEquals(remaining[0].idUE, ue2.id);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name:
|
|
"e2e ue_modules: DELETE /ue-modules/:idModule/:idUE/:idPromo 403 for non-employee",
|
|
async fn() {
|
|
await truncateAll();
|
|
const res = await ueModuleHandler.DELETE!(
|
|
makeGetRequest("/ue-modules/M1/1/P1"),
|
|
makeContextWithAffiliation("student", {
|
|
idModule: "M1",
|
|
idUE: "1",
|
|
idPromo: "P1",
|
|
}),
|
|
);
|
|
assertEquals(res.status, 403);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name:
|
|
"e2e ue_modules: DELETE /ue-modules/:idModule/:idUE/:idPromo 404 when not found",
|
|
async fn() {
|
|
await truncateAll();
|
|
const res = await ueModuleHandler.DELETE!(
|
|
makeGetRequest("/ue-modules/GHOST/1/GHOST"),
|
|
makeEmployeeContext({ idModule: "GHOST", idUE: "1", idPromo: "GHOST" }),
|
|
);
|
|
assertEquals(res.status, 404);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|