From a791b8813d7573ed28decabb8821e42711b2648c Mon Sep 17 00:00:00 2001 From: Djalim Simaila Date: Sun, 26 Apr 2026 14:05:01 +0200 Subject: [PATCH] test(users): add integration and e2e tests for /users (#111) - integration: list, filter by role, create, get, update, delete, not-found - e2e: handler calls with mock context + real DB, covers 400/409/404 cases (unit tests already present from teammates) --- tests/e2e/users_test.ts | 222 ++++++++++++++++++++++++++++++++ tests/integration/users_test.ts | 103 ++++++++++++--- 2 files changed, 306 insertions(+), 19 deletions(-) create mode 100644 tests/e2e/users_test.ts diff --git a/tests/e2e/users_test.ts b/tests/e2e/users_test.ts new file mode 100644 index 0000000..7e7622a --- /dev/null +++ b/tests/e2e/users_test.ts @@ -0,0 +1,222 @@ +// #111 - E2E tests for /users endpoints + +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(); + const [role] = await seedRoles([{ nom: "employee" }]); + await seedUsers([ + { id: "dupont.jean", nom: "Dupont", prenom: "Jean", idRole: role.id }, + { id: "martin.alice", nom: "Martin", prenom: "Alice", idRole: role.id }, + ]); + 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?idRole filters by role", + async fn() { + await truncateAll(); + const [role1] = await seedRoles([{ nom: "admin" }]); + const [role2] = await seedRoles([{ nom: "employee" }]); + await seedUsers([ + { id: "u1", nom: "A", prenom: "A", idRole: role1.id }, + { id: "u2", nom: "B", prenom: "B", 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, "u1"); + }, + sanitizeResources: false, + sanitizeOps: false, +}); + +// --- POST /users --- + +Deno.test({ + name: "e2e users: POST /users creates user (201)", + async fn() { + await truncateAll(); + const [role] = await seedRoles([{ nom: "employee" }]); + const res = await usersHandler.POST!( + makeJsonRequest("/users", "POST", { + id: "nouveau.user", + nom: "Nouveau", + prenom: "User", + idRole: role.id, + }), + makeEmployeeContext(), + ); + assertEquals(res.status, 201); + const body = await res.json(); + assertEquals(body.id, "nouveau.user"); + assertExists(body.nom); + }, + sanitizeResources: false, + sanitizeOps: false, +}); + +Deno.test({ + name: "e2e users: POST /users 409 on duplicate id", + async fn() { + await truncateAll(); + const [role] = await seedRoles([{ nom: "employee" }]); + await seedUsers([{ id: "dup.user", nom: "A", prenom: "A", idRole: role.id }]); + const res = await usersHandler.POST!( + makeJsonRequest("/users", "POST", { + id: "dup.user", + nom: "B", + prenom: "B", + idRole: role.id, + }), + makeEmployeeContext(), + ); + assertEquals(res.status, 409); + }, + 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, +}); + +// --- GET /users/:id --- + +Deno.test({ + name: "e2e users: GET /users/:id returns user", + async fn() { + await truncateAll(); + const [role] = await seedRoles([{ nom: "employee" }]); + await seedUsers([{ id: "test.user", nom: "Test", prenom: "User", idRole: role.id }]); + const res = await userHandler.GET!( + makeGetRequest("/users/test.user"), + makeEmployeeContext({ id: "test.user" }), + ); + assertEquals(res.status, 200); + const body = await res.json(); + assertEquals(body.id, "test.user"); + }, + 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"), + makeEmployeeContext({ id: "ghost" }), + ); + 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(); + const [role] = await seedRoles([{ nom: "employee" }]); + await seedUsers([{ id: "upd.user", nom: "Old", prenom: "Name", idRole: role.id }]); + const res = await userHandler.PUT!( + makeJsonRequest("/users/upd.user", "PUT", { + nom: "New", + prenom: "Name", + idRole: role.id, + }), + makeEmployeeContext({ id: "upd.user" }), + ); + assertEquals(res.status, 200); + const body = await res.json(); + assertEquals(body.nom, "New"); + }, + 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", "PUT", { nom: "X", prenom: "Y", idRole: 1 }), + makeEmployeeContext({ id: "ghost" }), + ); + 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(); + const [role] = await seedRoles([{ nom: "employee" }]); + await seedUsers([{ id: "del.user", nom: "Del", prenom: "Me", idRole: role.id }]); + const res = await userHandler.DELETE!( + makeGetRequest("/users/del.user"), + makeEmployeeContext({ id: "del.user" }), + ); + 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"), + makeEmployeeContext({ id: "ghost" }), + ); + assertEquals(res.status, 404); + }, + sanitizeResources: false, + sanitizeOps: false, +}); diff --git a/tests/integration/users_test.ts b/tests/integration/users_test.ts index e0d5ae9..efe6adc 100644 --- a/tests/integration/users_test.ts +++ b/tests/integration/users_test.ts @@ -1,24 +1,24 @@ +// #111 - Integration tests for /users endpoints + import { assertEquals, assertExists } from "@std/assert"; import { - closeTestPool, seedRoles, seedUsers, testDb, truncateAll, } from "../helpers/db_integration.ts"; import { users } from "$root/databases/schema.ts"; +import { eq } from "npm:drizzle-orm@0.45.2"; Deno.test({ - name: "integration: GET /users - DB round trip", + name: "integration users: list all users", async fn() { await truncateAll(); - const [role] = await seedRoles([{ nom: "employee" }]); await seedUsers([ { id: "dupont.jean", nom: "Dupont", prenom: "Jean", idRole: role.id }, { id: "martin.alice", nom: "Martin", prenom: "Alice", idRole: role.id }, ]); - const rows = await testDb.select().from(users); assertEquals(rows.length, 2); assertExists(rows.find((u) => u.id === "dupont.jean")); @@ -28,30 +28,95 @@ Deno.test({ }); Deno.test({ - name: "integration: INSERT user and retrieve by id", + name: "integration users: filter by idRole", async fn() { await truncateAll(); - - const [role] = await seedRoles([{ nom: "admin" }]); - const [created] = await testDb.insert(users).values({ - id: "durand.claire", - nom: "Durand", - prenom: "Claire", - idRole: role.id, - }).returning(); - - assertExists(created); - assertEquals(created.id, "durand.claire"); - assertEquals(created.nom, "Durand"); + const [role1] = await seedRoles([{ nom: "admin" }]); + const [role2] = await seedRoles([{ nom: "employee" }]); + await seedUsers([ + { id: "u1", nom: "A", prenom: "A", idRole: role1.id }, + { id: "u2", nom: "B", prenom: "B", idRole: role2.id }, + ]); + const rows = await testDb + .select() + .from(users) + .where(eq(users.idRole, role1.id)); + assertEquals(rows.length, 1); + assertEquals(rows[0].id, "u1"); }, sanitizeResources: false, sanitizeOps: false, }); Deno.test({ - name: "integration: cleanup - close pool", + name: "integration users: create and retrieve by id", async fn() { - await closeTestPool(); + await truncateAll(); + const [role] = await seedRoles([{ nom: "admin" }]); + const [created] = await testDb + .insert(users) + .values({ id: "durand.claire", nom: "Durand", prenom: "Claire", idRole: role.id }) + .returning(); + assertExists(created); + assertEquals(created.id, "durand.claire"); + + const row = await testDb + .select() + .from(users) + .where(eq(users.id, "durand.claire")) + .then((r) => r[0] ?? null); + assertExists(row); + }, + sanitizeResources: false, + sanitizeOps: false, +}); + +Deno.test({ + name: "integration users: get by id returns null when not found", + async fn() { + await truncateAll(); + const row = await testDb + .select() + .from(users) + .where(eq(users.id, "nonexistent")) + .then((r) => r[0] ?? null); + assertEquals(row, null); + }, + sanitizeResources: false, + sanitizeOps: false, +}); + +Deno.test({ + name: "integration users: update user fields", + async fn() { + await truncateAll(); + const [role] = await seedRoles([{ nom: "employee" }]); + await seedUsers([{ id: "test.user", nom: "Test", prenom: "User", idRole: role.id }]); + const [updated] = await testDb + .update(users) + .set({ nom: "Updated", prenom: "Name" }) + .where(eq(users.id, "test.user")) + .returning(); + assertExists(updated); + assertEquals(updated.nom, "Updated"); + }, + sanitizeResources: false, + sanitizeOps: false, +}); + +Deno.test({ + name: "integration users: delete user", + async fn() { + await truncateAll(); + const [role] = await seedRoles([{ nom: "employee" }]); + await seedUsers([{ id: "to.delete", nom: "Del", prenom: "Me", idRole: role.id }]); + await testDb.delete(users).where(eq(users.id, "to.delete")); + const row = await testDb + .select() + .from(users) + .where(eq(users.id, "to.delete")) + .then((r) => r[0] ?? null); + assertEquals(row, null); }, sanitizeResources: false, sanitizeOps: false,