test(promotions): add unit, integration and e2e tests for /promotions (#110)
- unit: fixture shapes, mock API (GET/POST/PUT/DELETE), mock DB CRUD - integration: real DB list, create, get, update, delete, not-found cases - e2e: handler calls with mock context + real DB, covers 400/403/404 cases
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
// #110 - E2E tests for /promotions endpoints
|
||||
|
||||
import { assertEquals, assertExists } from "@std/assert";
|
||||
import {
|
||||
makeContextWithAffiliation,
|
||||
makeEmployeeContext,
|
||||
makeGetRequest,
|
||||
makeJsonRequest,
|
||||
} from "../helpers/handler.ts";
|
||||
import { seedPromotions, truncateAll } from "../helpers/db_integration.ts";
|
||||
import { handler as promotionsHandler } from "$apps/students/api/promotions.ts";
|
||||
import { handler as promotionHandler } from "$apps/students/api/promotions/[idPromo].ts";
|
||||
|
||||
// --- GET /promotions ---
|
||||
|
||||
Deno.test({
|
||||
name: "e2e promotions: GET /promotions returns all as employee",
|
||||
async fn() {
|
||||
await truncateAll();
|
||||
await seedPromotions([
|
||||
{ id: "PEIP1-2024", annee: "2024" },
|
||||
{ id: "PEIP2-2024", annee: "2024" },
|
||||
]);
|
||||
const res = await promotionsHandler.GET!(
|
||||
makeGetRequest("/promotions"),
|
||||
makeEmployeeContext(),
|
||||
);
|
||||
assertEquals(res.status, 200);
|
||||
const body = await res.json();
|
||||
assertEquals(body.length, 2);
|
||||
},
|
||||
sanitizeResources: false,
|
||||
sanitizeOps: false,
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "e2e promotions: GET /promotions returns empty for non-employee",
|
||||
async fn() {
|
||||
await truncateAll();
|
||||
await seedPromotions([{ id: "PEIP1-2024", annee: "2024" }]);
|
||||
const res = await promotionsHandler.GET!(
|
||||
makeGetRequest("/promotions"),
|
||||
makeContextWithAffiliation("student"),
|
||||
);
|
||||
assertEquals(res.status, 200);
|
||||
const body = await res.json();
|
||||
assertEquals(body.length, 0);
|
||||
},
|
||||
sanitizeResources: false,
|
||||
sanitizeOps: false,
|
||||
});
|
||||
|
||||
// --- POST /promotions ---
|
||||
|
||||
Deno.test({
|
||||
name: "e2e promotions: POST /promotions creates promotion (201)",
|
||||
async fn() {
|
||||
await truncateAll();
|
||||
const res = await promotionsHandler.POST!(
|
||||
makeJsonRequest("/promotions", "POST", { idPromo: "INFO3-2025", annee: "2025" }),
|
||||
makeEmployeeContext(),
|
||||
);
|
||||
assertEquals(res.status, 201);
|
||||
const body = await res.json();
|
||||
assertEquals(body.id, "INFO3-2025");
|
||||
assertEquals(body.annee, "2025");
|
||||
},
|
||||
sanitizeResources: false,
|
||||
sanitizeOps: false,
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "e2e promotions: POST /promotions 403 for non-employee",
|
||||
async fn() {
|
||||
await truncateAll();
|
||||
const res = await promotionsHandler.POST!(
|
||||
makeJsonRequest("/promotions", "POST", { idPromo: "X", annee: "2025" }),
|
||||
makeContextWithAffiliation("student"),
|
||||
);
|
||||
assertEquals(res.status, 403);
|
||||
},
|
||||
sanitizeResources: false,
|
||||
sanitizeOps: false,
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "e2e promotions: POST /promotions 400 on missing fields",
|
||||
async fn() {
|
||||
await truncateAll();
|
||||
const res = await promotionsHandler.POST!(
|
||||
makeJsonRequest("/promotions", "POST", { idPromo: "X" }),
|
||||
makeEmployeeContext(),
|
||||
);
|
||||
assertEquals(res.status, 400);
|
||||
},
|
||||
sanitizeResources: false,
|
||||
sanitizeOps: false,
|
||||
});
|
||||
|
||||
// --- GET /promotions/:idPromo ---
|
||||
|
||||
Deno.test({
|
||||
name: "e2e promotions: GET /promotions/:id returns promotion",
|
||||
async fn() {
|
||||
await truncateAll();
|
||||
await seedPromotions([{ id: "INFO3-2024", annee: "2024" }]);
|
||||
const res = await promotionHandler.GET!(
|
||||
makeGetRequest("/promotions/INFO3-2024"),
|
||||
makeEmployeeContext({ idPromo: "INFO3-2024" }),
|
||||
);
|
||||
assertEquals(res.status, 200);
|
||||
const body = await res.json();
|
||||
assertEquals(body.id, "INFO3-2024");
|
||||
},
|
||||
sanitizeResources: false,
|
||||
sanitizeOps: false,
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "e2e promotions: GET /promotions/:id 404 when not found",
|
||||
async fn() {
|
||||
await truncateAll();
|
||||
const res = await promotionHandler.GET!(
|
||||
makeGetRequest("/promotions/GHOST"),
|
||||
makeEmployeeContext({ idPromo: "GHOST" }),
|
||||
);
|
||||
assertEquals(res.status, 404);
|
||||
},
|
||||
sanitizeResources: false,
|
||||
sanitizeOps: false,
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "e2e promotions: GET /promotions/:id 403 for non-employee",
|
||||
async fn() {
|
||||
await truncateAll();
|
||||
const res = await promotionHandler.GET!(
|
||||
makeGetRequest("/promotions/INFO3-2024"),
|
||||
makeContextWithAffiliation("student", { idPromo: "INFO3-2024" }),
|
||||
);
|
||||
assertEquals(res.status, 403);
|
||||
},
|
||||
sanitizeResources: false,
|
||||
sanitizeOps: false,
|
||||
});
|
||||
|
||||
// --- PUT /promotions/:idPromo ---
|
||||
|
||||
Deno.test({
|
||||
name: "e2e promotions: PUT /promotions/:id updates annee",
|
||||
async fn() {
|
||||
await truncateAll();
|
||||
await seedPromotions([{ id: "INFO3-2023", annee: "2023" }]);
|
||||
const res = await promotionHandler.PUT!(
|
||||
makeJsonRequest("/promotions/INFO3-2023", "PUT", { annee: "2024" }),
|
||||
makeEmployeeContext({ idPromo: "INFO3-2023" }),
|
||||
);
|
||||
assertEquals(res.status, 200);
|
||||
const body = await res.json();
|
||||
assertEquals(body.annee, "2024");
|
||||
},
|
||||
sanitizeResources: false,
|
||||
sanitizeOps: false,
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "e2e promotions: PUT /promotions/:id 404 when not found",
|
||||
async fn() {
|
||||
await truncateAll();
|
||||
const res = await promotionHandler.PUT!(
|
||||
makeJsonRequest("/promotions/GHOST", "PUT", { annee: "2025" }),
|
||||
makeEmployeeContext({ idPromo: "GHOST" }),
|
||||
);
|
||||
assertEquals(res.status, 404);
|
||||
},
|
||||
sanitizeResources: false,
|
||||
sanitizeOps: false,
|
||||
});
|
||||
|
||||
// --- DELETE /promotions/:idPromo ---
|
||||
|
||||
Deno.test({
|
||||
name: "e2e promotions: DELETE /promotions/:id returns 204",
|
||||
async fn() {
|
||||
await truncateAll();
|
||||
await seedPromotions([{ id: "INFO3-2022", annee: "2022" }]);
|
||||
const res = await promotionHandler.DELETE!(
|
||||
makeGetRequest("/promotions/INFO3-2022"),
|
||||
makeEmployeeContext({ idPromo: "INFO3-2022" }),
|
||||
);
|
||||
assertEquals(res.status, 204);
|
||||
},
|
||||
sanitizeResources: false,
|
||||
sanitizeOps: false,
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "e2e promotions: DELETE /promotions/:id 404 when not found",
|
||||
async fn() {
|
||||
await truncateAll();
|
||||
const res = await promotionHandler.DELETE!(
|
||||
makeGetRequest("/promotions/GHOST"),
|
||||
makeEmployeeContext({ idPromo: "GHOST" }),
|
||||
);
|
||||
assertEquals(res.status, 404);
|
||||
},
|
||||
sanitizeResources: false,
|
||||
sanitizeOps: false,
|
||||
});
|
||||
Reference in New Issue
Block a user