Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 07b6f1e347 | |||
| c5018d9ced | |||
| 367b0b2357 | |||
| e0ac451372 | |||
| ae5d5b64ac | |||
| 7be13737d5 | |||
| 32052ab1c9 | |||
| ce807391c6 | |||
| 182342aab0 | |||
| d32758b310 | |||
| f26b2b044f | |||
| af2562ef2b | |||
| f739f94403 | |||
| f66de20dad | |||
| ea61d83384 | |||
| 6402f802e9 |
@@ -6,26 +6,9 @@ on:
|
|||||||
- main
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-code:
|
|
||||||
name: "Check Deno code"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- uses: denoland/setup-deno@v2
|
|
||||||
with:
|
|
||||||
deno-version: v2.x
|
|
||||||
|
|
||||||
- name: Check formatting
|
|
||||||
run: deno fmt --check
|
|
||||||
|
|
||||||
- name: Check linting
|
|
||||||
run: deno lint
|
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
name: "Build Docker image"
|
name: "Build Docker image"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: check-code
|
|
||||||
steps:
|
steps:
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
|
|||||||
@@ -4,10 +4,6 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- develop
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- develop
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
+1
-3
@@ -2,9 +2,7 @@ import { defineConfig } from "drizzle-kit";
|
|||||||
import process from "node:process";
|
import process from "node:process";
|
||||||
|
|
||||||
const url = process.env.DATABASE_URL ??
|
const url = process.env.DATABASE_URL ??
|
||||||
`postgresql://${process.env.POSTGRES_USER}:${process.env.POSTGRES_PASS}@${
|
`postgresql://${process.env.POSTGRES_USER}:${process.env.POSTGRES_PASS}@${process.env.POSTGRES_HOST ?? "localhost"}:${process.env.POSTGRES_PORT ?? 5432}/${process.env.POSTGRES_DB}`;
|
||||||
process.env.POSTGRES_HOST ?? "localhost"
|
|
||||||
}:${process.env.POSTGRES_PORT ?? 5432}/${process.env.POSTGRES_DB}`;
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
dialect: "postgresql",
|
dialect: "postgresql",
|
||||||
|
|||||||
@@ -1,212 +0,0 @@
|
|||||||
// #110 - E2E tests for /promotions endpoints
|
|
||||||
|
|
||||||
import { assertEquals } 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,
|
|
||||||
});
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
// #110 - Integration tests for /promotions endpoints
|
|
||||||
|
|
||||||
import { assertEquals, assertExists } from "@std/assert";
|
|
||||||
import {
|
|
||||||
seedPromotions,
|
|
||||||
testDb,
|
|
||||||
truncateAll,
|
|
||||||
} from "../helpers/db_integration.ts";
|
|
||||||
import { promotions } from "$root/databases/schema.ts";
|
|
||||||
import { eq } from "npm:drizzle-orm@0.45.2";
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "integration promotions: list all",
|
|
||||||
async fn() {
|
|
||||||
await truncateAll();
|
|
||||||
await seedPromotions([
|
|
||||||
{ id: "PEIP1-2024", annee: "2024" },
|
|
||||||
{ id: "PEIP2-2024", annee: "2024" },
|
|
||||||
]);
|
|
||||||
const rows = await testDb.select().from(promotions);
|
|
||||||
assertEquals(rows.length, 2);
|
|
||||||
},
|
|
||||||
sanitizeResources: false,
|
|
||||||
sanitizeOps: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "integration promotions: create and retrieve by id",
|
|
||||||
async fn() {
|
|
||||||
await truncateAll();
|
|
||||||
const [created] = await testDb
|
|
||||||
.insert(promotions)
|
|
||||||
.values({ id: "INFO3-2025", annee: "2025" })
|
|
||||||
.returning();
|
|
||||||
assertExists(created);
|
|
||||||
assertEquals(created.id, "INFO3-2025");
|
|
||||||
assertEquals(created.annee, "2025");
|
|
||||||
|
|
||||||
const row = await testDb
|
|
||||||
.select()
|
|
||||||
.from(promotions)
|
|
||||||
.where(eq(promotions.id, "INFO3-2025"))
|
|
||||||
.then((r) => r[0] ?? null);
|
|
||||||
assertExists(row);
|
|
||||||
},
|
|
||||||
sanitizeResources: false,
|
|
||||||
sanitizeOps: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "integration promotions: get by id returns null when not found",
|
|
||||||
async fn() {
|
|
||||||
await truncateAll();
|
|
||||||
const row = await testDb
|
|
||||||
.select()
|
|
||||||
.from(promotions)
|
|
||||||
.where(eq(promotions.id, "NONEXISTENT"))
|
|
||||||
.then((r) => r[0] ?? null);
|
|
||||||
assertEquals(row, null);
|
|
||||||
},
|
|
||||||
sanitizeResources: false,
|
|
||||||
sanitizeOps: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "integration promotions: update annee",
|
|
||||||
async fn() {
|
|
||||||
await truncateAll();
|
|
||||||
await seedPromotions([{ id: "INFO3-2023", annee: "2023" }]);
|
|
||||||
const [updated] = await testDb
|
|
||||||
.update(promotions)
|
|
||||||
.set({ annee: "2024" })
|
|
||||||
.where(eq(promotions.id, "INFO3-2023"))
|
|
||||||
.returning();
|
|
||||||
assertExists(updated);
|
|
||||||
assertEquals(updated.annee, "2024");
|
|
||||||
},
|
|
||||||
sanitizeResources: false,
|
|
||||||
sanitizeOps: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "integration promotions: delete removes the row",
|
|
||||||
async fn() {
|
|
||||||
await truncateAll();
|
|
||||||
await seedPromotions([{ id: "INFO3-2022", annee: "2022" }]);
|
|
||||||
await testDb.delete(promotions).where(eq(promotions.id, "INFO3-2022"));
|
|
||||||
const row = await testDb
|
|
||||||
.select()
|
|
||||||
.from(promotions)
|
|
||||||
.where(eq(promotions.id, "INFO3-2022"))
|
|
||||||
.then((r) => r[0] ?? null);
|
|
||||||
assertEquals(row, null);
|
|
||||||
},
|
|
||||||
sanitizeResources: false,
|
|
||||||
sanitizeOps: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "integration promotions: update non-existent returns empty",
|
|
||||||
async fn() {
|
|
||||||
await truncateAll();
|
|
||||||
const result = await testDb
|
|
||||||
.update(promotions)
|
|
||||||
.set({ annee: "2099" })
|
|
||||||
.where(eq(promotions.id, "GHOST"))
|
|
||||||
.returning();
|
|
||||||
assertEquals(result.length, 0);
|
|
||||||
},
|
|
||||||
sanitizeResources: false,
|
|
||||||
sanitizeOps: false,
|
|
||||||
});
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
import { assertEquals, assertExists } from "@std/assert";
|
|
||||||
import {
|
|
||||||
closeTestPool,
|
|
||||||
seedRoles,
|
|
||||||
seedUsers,
|
|
||||||
testDb,
|
|
||||||
truncateAll,
|
|
||||||
} from "../helpers/db_integration.ts";
|
|
||||||
import { users } from "$root/databases/schema.ts";
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "integration: GET /users - DB round trip",
|
|
||||||
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"));
|
|
||||||
},
|
|
||||||
sanitizeResources: false,
|
|
||||||
sanitizeOps: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "integration: INSERT user and retrieve by id",
|
|
||||||
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");
|
|
||||||
},
|
|
||||||
sanitizeResources: false,
|
|
||||||
sanitizeOps: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "integration: cleanup - close pool",
|
|
||||||
async fn() {
|
|
||||||
await closeTestPool();
|
|
||||||
},
|
|
||||||
sanitizeResources: false,
|
|
||||||
sanitizeOps: false,
|
|
||||||
});
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
// #110 - Unit tests for /promotions endpoints
|
|
||||||
|
|
||||||
import { assertEquals, assertExists } from "@std/assert";
|
|
||||||
import { mockFetch, restoreFetch } from "../helpers/api_mock.ts";
|
|
||||||
import { createMockDb } from "../helpers/db_mock.ts";
|
|
||||||
import { type Promotion, promotions } from "../helpers/fixtures.ts";
|
|
||||||
|
|
||||||
// --- Fixtures ---
|
|
||||||
|
|
||||||
Deno.test("promotions: fixtures have correct shape", () => {
|
|
||||||
assertEquals(promotions.length, 3);
|
|
||||||
assertEquals(typeof promotions[0].idPromo, "string");
|
|
||||||
assertEquals(typeof promotions[0].annee, "string");
|
|
||||||
});
|
|
||||||
|
|
||||||
// --- Mock API ---
|
|
||||||
|
|
||||||
Deno.test("mock API: GET /promotions returns list", async () => {
|
|
||||||
mockFetch({ "/promotions": promotions });
|
|
||||||
try {
|
|
||||||
const res = await fetch("http://localhost/api/promotions");
|
|
||||||
assertEquals(res.status, 200);
|
|
||||||
const data: Promotion[] = await res.json();
|
|
||||||
assertEquals(data.length, 3);
|
|
||||||
assertExists(data.find((p) => p.idPromo === "4AFISE25/26"));
|
|
||||||
} finally {
|
|
||||||
restoreFetch();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test("mock API: GET /promotions/:id returns one", async () => {
|
|
||||||
mockFetch({ "/promotions/4AFISE25%2F26": promotions[0] });
|
|
||||||
try {
|
|
||||||
const res = await fetch("http://localhost/api/promotions/4AFISE25%2F26");
|
|
||||||
assertEquals(res.status, 200);
|
|
||||||
const data: Promotion = await res.json();
|
|
||||||
assertEquals(data.idPromo, "4AFISE25/26");
|
|
||||||
} finally {
|
|
||||||
restoreFetch();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test("mock API: GET /promotions/:id 404 when not found", async () => {
|
|
||||||
mockFetch({
|
|
||||||
"/promotions/UNKNOWN": {
|
|
||||||
status: 404,
|
|
||||||
body: { error: "Ressource introuvable" },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
const res = await fetch("http://localhost/api/promotions/UNKNOWN");
|
|
||||||
assertEquals(res.status, 404);
|
|
||||||
} finally {
|
|
||||||
restoreFetch();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test("mock API: POST /promotions creates promotion (201)", async () => {
|
|
||||||
const newPromo: Promotion = { idPromo: "NEW2025", annee: "2025" };
|
|
||||||
mockFetch({ "/promotions": { method: "POST", status: 201, body: newPromo } });
|
|
||||||
try {
|
|
||||||
const res = await fetch("http://localhost/api/promotions", {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "content-type": "application/json" },
|
|
||||||
body: JSON.stringify({ idPromo: "NEW2025", annee: "2025" }),
|
|
||||||
});
|
|
||||||
assertEquals(res.status, 201);
|
|
||||||
const data: Promotion = await res.json();
|
|
||||||
assertEquals(data.idPromo, "NEW2025");
|
|
||||||
} finally {
|
|
||||||
restoreFetch();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test("mock API: POST /promotions 400 on missing fields", async () => {
|
|
||||||
mockFetch({ "/promotions": { method: "POST", status: 400 } });
|
|
||||||
try {
|
|
||||||
const res = await fetch("http://localhost/api/promotions", {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "content-type": "application/json" },
|
|
||||||
body: JSON.stringify({ idPromo: "NEW2025" }),
|
|
||||||
});
|
|
||||||
assertEquals(res.status, 400);
|
|
||||||
} finally {
|
|
||||||
restoreFetch();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test("mock API: PUT /promotions/:id updates promotion", async () => {
|
|
||||||
const updated = { idPromo: "4AFISE25/26", annee: "2026" };
|
|
||||||
mockFetch({
|
|
||||||
"/promotions/4AFISE25%2F26": { method: "PUT", status: 200, body: updated },
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
const res = await fetch("http://localhost/api/promotions/4AFISE25%2F26", {
|
|
||||||
method: "PUT",
|
|
||||||
headers: { "content-type": "application/json" },
|
|
||||||
body: JSON.stringify({ annee: "2026" }),
|
|
||||||
});
|
|
||||||
assertEquals(res.status, 200);
|
|
||||||
const data: Promotion = await res.json();
|
|
||||||
assertEquals(data.annee, "2026");
|
|
||||||
} finally {
|
|
||||||
restoreFetch();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test("mock API: DELETE /promotions/:id returns 204", async () => {
|
|
||||||
mockFetch({ "/promotions/4AFISE25%2F26": { method: "DELETE", status: 204 } });
|
|
||||||
try {
|
|
||||||
const res = await fetch("http://localhost/api/promotions/4AFISE25%2F26", {
|
|
||||||
method: "DELETE",
|
|
||||||
});
|
|
||||||
assertEquals(res.status, 204);
|
|
||||||
} finally {
|
|
||||||
restoreFetch();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// --- Mock DB ---
|
|
||||||
|
|
||||||
Deno.test("mock DB: find promotion by idPromo", () => {
|
|
||||||
const db = createMockDb({ tables: { promotions: [...promotions] } });
|
|
||||||
const p = db.findOne<Promotion>(
|
|
||||||
"promotions",
|
|
||||||
(r) => r.idPromo === "4AFISE25/26",
|
|
||||||
);
|
|
||||||
assertExists(p);
|
|
||||||
assertEquals(p.annee, "2025");
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test("mock DB: insert promotion", () => {
|
|
||||||
const db = createMockDb({ tables: { promotions: [...promotions] } });
|
|
||||||
db.insert<Promotion>("promotions", { idPromo: "NEW2025", annee: "2025" });
|
|
||||||
assertEquals(db.getTable("promotions").length, 4);
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test("mock DB: update promotion annee", () => {
|
|
||||||
const db = createMockDb({ tables: { promotions: [...promotions] } });
|
|
||||||
db.updateWhere<Promotion>(
|
|
||||||
"promotions",
|
|
||||||
(p) => p.idPromo === "4AFISE25/26",
|
|
||||||
{ annee: "2026" },
|
|
||||||
);
|
|
||||||
assertEquals(
|
|
||||||
db.findOne<Promotion>("promotions", (p) => p.idPromo === "4AFISE25/26")
|
|
||||||
?.annee,
|
|
||||||
"2026",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test("mock DB: delete promotion", () => {
|
|
||||||
const db = createMockDb({ tables: { promotions: [...promotions] } });
|
|
||||||
const count = db.deleteWhere<Promotion>(
|
|
||||||
"promotions",
|
|
||||||
(p) => p.idPromo === "4AFISE25/26",
|
|
||||||
);
|
|
||||||
assertEquals(count, 1);
|
|
||||||
assertEquals(db.getTable("promotions").length, 2);
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user