2f4d8db1bf
- 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)
218 lines
6.0 KiB
TypeScript
218 lines
6.0 KiB
TypeScript
// E2E tests for /users endpoints — handler + real DB
|
|
|
|
import { assertEquals, assertExists } from "@std/assert";
|
|
import {
|
|
makeEmployeeContext,
|
|
makeGetRequest,
|
|
makeJsonRequest,
|
|
} from "../helpers/handler.ts";
|
|
import {
|
|
seedRoles,
|
|
seedUsers,
|
|
truncateAll,
|
|
} from "../helpers/db_integration.ts";
|
|
import { handler as usersHandler } from "$apps/admin/api/users.ts";
|
|
import { handler as userHandler } from "$apps/admin/api/users/[id].ts";
|
|
|
|
// --- GET /users ---
|
|
|
|
Deno.test({
|
|
name: "e2e users: GET /users returns all users",
|
|
async fn() {
|
|
await truncateAll();
|
|
await seedUsers([
|
|
{ id: "dupont.jean", nom: "Dupont", prenom: "Jean" },
|
|
{ id: "martin.alice", nom: "Martin", prenom: "Alice" },
|
|
]);
|
|
const res = await usersHandler.GET!(makeGetRequest("/users"), makeEmployeeContext());
|
|
assertEquals(res.status, 200);
|
|
const body = await res.json();
|
|
assertEquals(body.length, 2);
|
|
assertExists(body.find((u: { id: string }) => u.id === "dupont.jean"));
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name: "e2e users: GET /users returns empty when no users",
|
|
async fn() {
|
|
await truncateAll();
|
|
const res = await usersHandler.GET!(makeGetRequest("/users"), makeEmployeeContext());
|
|
assertEquals(res.status, 200);
|
|
const body = await res.json();
|
|
assertEquals(body.length, 0);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name: "e2e users: GET /users?idRole filters by role",
|
|
async fn() {
|
|
await truncateAll();
|
|
const [role1] = await seedRoles([{ nom: "admin" }]);
|
|
const [role2] = await seedRoles([{ nom: "employee" }]);
|
|
await seedUsers([
|
|
{ id: "admin.user", nom: "Admin", prenom: "User", idRole: role1.id },
|
|
{ id: "emp.user", nom: "Emp", prenom: "User", idRole: role2.id },
|
|
]);
|
|
const res = await usersHandler.GET!(
|
|
makeGetRequest("/users", { idRole: String(role1.id) }),
|
|
makeEmployeeContext(),
|
|
);
|
|
assertEquals(res.status, 200);
|
|
const body = await res.json();
|
|
assertEquals(body.length, 1);
|
|
assertEquals(body[0].id, "admin.user");
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
// --- POST /users ---
|
|
|
|
Deno.test({
|
|
name: "e2e users: POST /users creates user (201)",
|
|
async fn() {
|
|
await truncateAll();
|
|
const res = await usersHandler.POST!(
|
|
makeJsonRequest("/users", "POST", { id: "new.user", nom: "New", prenom: "User" }),
|
|
makeEmployeeContext(),
|
|
);
|
|
assertEquals(res.status, 201);
|
|
const body = await res.json();
|
|
assertEquals(body.id, "new.user");
|
|
assertEquals(body.nom, "New");
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name: "e2e users: POST /users 400 on missing fields",
|
|
async fn() {
|
|
await truncateAll();
|
|
const res = await usersHandler.POST!(
|
|
makeJsonRequest("/users", "POST", { id: "x" }),
|
|
makeEmployeeContext(),
|
|
);
|
|
assertEquals(res.status, 400);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name: "e2e users: POST /users 409 on duplicate id",
|
|
async fn() {
|
|
await truncateAll();
|
|
await seedUsers([{ id: "dupont.jean", nom: "Dupont", prenom: "Jean" }]);
|
|
const res = await usersHandler.POST!(
|
|
makeJsonRequest("/users", "POST", { id: "dupont.jean", nom: "Doublon", prenom: "X" }),
|
|
makeEmployeeContext(),
|
|
);
|
|
assertEquals(res.status, 409);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
// --- GET /users/:id ---
|
|
|
|
Deno.test({
|
|
name: "e2e users: GET /users/:id returns user",
|
|
async fn() {
|
|
await truncateAll();
|
|
await seedUsers([{ id: "bernard.lucie", nom: "Bernard", prenom: "Lucie" }]);
|
|
const res = await userHandler.GET!(
|
|
makeGetRequest("/users/bernard.lucie"),
|
|
makeEmployeeContext({ id: "bernard.lucie" }),
|
|
);
|
|
assertEquals(res.status, 200);
|
|
const body = await res.json();
|
|
assertEquals(body.id, "bernard.lucie");
|
|
assertEquals(body.nom, "Bernard");
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name: "e2e users: GET /users/:id 404 when not found",
|
|
async fn() {
|
|
await truncateAll();
|
|
const res = await userHandler.GET!(
|
|
makeGetRequest("/users/ghost.user"),
|
|
makeEmployeeContext({ id: "ghost.user" }),
|
|
);
|
|
assertEquals(res.status, 404);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
// --- PUT /users/:id ---
|
|
|
|
Deno.test({
|
|
name: "e2e users: PUT /users/:id updates user",
|
|
async fn() {
|
|
await truncateAll();
|
|
await seedUsers([{ id: "thomas.eva", nom: "Thomas", prenom: "Eva" }]);
|
|
const res = await userHandler.PUT!(
|
|
makeJsonRequest("/users/thomas.eva", "PUT", { nom: "Thomas-Modifié", prenom: "Eva", idRole: null }),
|
|
makeEmployeeContext({ id: "thomas.eva" }),
|
|
);
|
|
assertEquals(res.status, 200);
|
|
const body = await res.json();
|
|
assertEquals(body.nom, "Thomas-Modifié");
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name: "e2e users: PUT /users/:id 404 when not found",
|
|
async fn() {
|
|
await truncateAll();
|
|
const res = await userHandler.PUT!(
|
|
makeJsonRequest("/users/ghost.user", "PUT", { nom: "X", prenom: "Y", idRole: null }),
|
|
makeEmployeeContext({ id: "ghost.user" }),
|
|
);
|
|
assertEquals(res.status, 404);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
// --- DELETE /users/:id ---
|
|
|
|
Deno.test({
|
|
name: "e2e users: DELETE /users/:id returns 204",
|
|
async fn() {
|
|
await truncateAll();
|
|
await seedUsers([{ id: "petit.hugo", nom: "Petit", prenom: "Hugo" }]);
|
|
const res = await userHandler.DELETE!(
|
|
makeGetRequest("/users/petit.hugo"),
|
|
makeEmployeeContext({ id: "petit.hugo" }),
|
|
);
|
|
assertEquals(res.status, 204);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|
|
|
|
Deno.test({
|
|
name: "e2e users: DELETE /users/:id 404 when not found",
|
|
async fn() {
|
|
await truncateAll();
|
|
const res = await userHandler.DELETE!(
|
|
makeGetRequest("/users/ghost.user"),
|
|
makeEmployeeContext({ id: "ghost.user" }),
|
|
);
|
|
assertEquals(res.status, 404);
|
|
},
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
});
|