test : changed test format + added playwright support
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

This commit was merged in pull request #153.
This commit is contained in:
2026-05-03 21:52:02 +02:00
parent ed2fe69f54
commit 951c9c1fea
52 changed files with 3576 additions and 5212 deletions
+173 -81
View File
@@ -1,62 +1,134 @@
// Integration tests for /enseignements — Drizzle ORM direct on real DB
// E2E tests for /enseignements endpoints — handler + real DB
import { assertEquals, assertExists, assertRejects } from "@std/assert";
import { assertEquals, assertExists } from "@std/assert";
import {
makeContextWithAffiliation,
makeEmployeeContext,
makeGetRequest,
makeJsonRequest,
} from "../helpers/handler.ts";
import {
seedEnseignements,
seedModules,
seedPromotions,
seedUsers,
testDb,
truncateAll,
} from "../helpers/db_integration.ts";
import { enseignements } from "$root/databases/schema.ts";
import { and, eq } from "npm:drizzle-orm@0.45.2";
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: "integration enseignements: list all enseignements",
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" }, { id: "M2", nom: "Mod B" }]);
await seedModules([{ id: "M1", nom: "Mod A" }]);
await seedPromotions([{ id: "P1" }]);
await seedEnseignements([
{ idProf: "prof.dupont", idModule: "M1", idPromo: "P1" },
{ idProf: "prof.dupont", idModule: "M2", idPromo: "P1" },
]);
const rows = await testDb.select().from(enseignements);
assertEquals(rows.length, 2);
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: "integration enseignements: create and retrieve by composite key",
name: "e2e enseignements: POST /enseignements 403 for non-employee",
async fn() {
await truncateAll();
await seedUsers([{ id: "prof.moreau", nom: "Moreau", prenom: "Sophie" }]);
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,
});
const [created] = await testDb
.insert(enseignements)
.values({ idProf: "prof.moreau", idModule: "M1", idPromo: "P1" })
.returning();
assertExists(created);
assertEquals(created.idProf, "prof.moreau");
// --- GET /enseignements/:idProf/:idModule/:idPromo ---
const row = await testDb
.select()
.from(enseignements)
.where(
and(
eq(enseignements.idProf, "prof.moreau"),
eq(enseignements.idModule, "M1"),
eq(enseignements.idPromo, "P1"),
),
)
.then((r) => r[0] ?? null);
assertExists(row);
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,
@@ -64,28 +136,47 @@ Deno.test({
Deno.test({
name:
"integration enseignements: get by composite key returns null when not found",
"e2e enseignements: GET /enseignements/:idProf/:idModule/:idPromo 403 for non-employee",
async fn() {
await truncateAll();
const row = await testDb
.select()
.from(enseignements)
.where(
and(
eq(enseignements.idProf, "ghost"),
eq(enseignements.idModule, "GHOST"),
eq(enseignements.idPromo, "GHOST"),
),
)
.then((r) => r[0] ?? null);
assertEquals(row, null);
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: "integration enseignements: duplicate composite key insert fails",
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" }]);
@@ -96,52 +187,53 @@ Deno.test({
idModule: "M1",
idPromo: "P1",
}]);
await assertRejects(() =>
testDb.insert(enseignements).values({
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: "integration enseignements: delete removes the enseignement",
name:
"e2e enseignements: DELETE /enseignements/:idProf/:idModule/:idPromo 403 for non-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",
}]);
await testDb
.delete(enseignements)
.where(
and(
eq(enseignements.idProf, "prof.dupont"),
eq(enseignements.idModule, "M1"),
eq(enseignements.idPromo, "P1"),
),
);
const row = await testDb
.select()
.from(enseignements)
.where(
and(
eq(enseignements.idProf, "prof.dupont"),
eq(enseignements.idModule, "M1"),
eq(enseignements.idPromo, "P1"),
),
)
.then((r) => r[0] ?? null);
assertEquals(row, null);
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,