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
-224
View File
@@ -1,224 +0,0 @@
// Unit tests for /ajustements endpoints — fixtures, mock API, mock DB
import { assertEquals, assertExists } from "@std/assert";
import { mockFetch, restoreFetch } from "../helpers/api_mock.ts";
import { createMockDb } from "../helpers/db_mock.ts";
import { type Ajustement, ajustements } from "../helpers/fixtures.ts";
// --- Fixtures ---
Deno.test("ajustements: fixtures have correct shape", () => {
assertEquals(ajustements.length, 2);
assertEquals(typeof ajustements[0].numEtud, "number");
assertEquals(typeof ajustements[0].idUE, "number");
assertEquals(typeof ajustements[0].valeur, "number");
});
// --- Mock API ---
Deno.test("mock API: GET /ajustements returns list", async () => {
mockFetch({ "/ajustements": ajustements });
try {
const res = await fetch("http://localhost/api/ajustements");
assertEquals(res.status, 200);
const data: Ajustement[] = await res.json();
assertEquals(data.length, 2);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /ajustements?numEtud filters by student", async () => {
const filtered = ajustements.filter((a) => a.numEtud === 21212006);
mockFetch({ "/ajustements": filtered });
try {
const res = await fetch(
"http://localhost/api/ajustements?numEtud=21212006",
);
const data: Ajustement[] = await res.json();
assertEquals(data.length, 1);
assertEquals(data[0].numEtud, 21212006);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /ajustements?numEtud=NaN returns 400", async () => {
mockFetch({ "/ajustements": { status: 400 } });
try {
const res = await fetch("http://localhost/api/ajustements?numEtud=abc");
assertEquals(res.status, 400);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /ajustements creates ajustement (201) as employee", async () => {
const newAjust: Ajustement = { numEtud: 21212007, idUE: 2, valeur: 14.0 };
mockFetch({
"/ajustements": { method: "POST", status: 201, body: newAjust },
});
try {
const res = await fetch("http://localhost/api/ajustements", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(newAjust),
});
assertEquals(res.status, 201);
const data: Ajustement = await res.json();
assertEquals(data.numEtud, 21212007);
assertEquals(data.valeur, 14.0);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /ajustements 403 for non-employee", async () => {
mockFetch({ "/ajustements": { method: "POST", status: 403 } });
try {
const res = await fetch("http://localhost/api/ajustements", {
method: "POST",
});
assertEquals(res.status, 403);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /ajustements 400 on missing fields", async () => {
mockFetch({ "/ajustements": { method: "POST", status: 400 } });
try {
const res = await fetch("http://localhost/api/ajustements", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ numEtud: 21212006 }),
});
assertEquals(res.status, 400);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /ajustements/:numEtud/:idUE returns ajustement (employee)", async () => {
mockFetch({ "/ajustements/21212006/1": ajustements[0] });
try {
const res = await fetch("http://localhost/api/ajustements/21212006/1");
assertEquals(res.status, 200);
const data: Ajustement = await res.json();
assertEquals(data.valeur, 13.25);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /ajustements/:numEtud/:idUE 403 for non-employee", async () => {
mockFetch({ "/ajustements/21212006/1": { status: 403 } });
try {
const res = await fetch("http://localhost/api/ajustements/21212006/1");
assertEquals(res.status, 403);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /ajustements/:numEtud/:idUE 404 when not found", async () => {
mockFetch({
"/ajustements/99999/9": {
status: 404,
body: { error: "Ajustement introuvable" },
},
});
try {
const res = await fetch("http://localhost/api/ajustements/99999/9");
assertEquals(res.status, 404);
} finally {
restoreFetch();
}
});
Deno.test("mock API: PUT /ajustements/:numEtud/:idUE updates valeur", async () => {
const updated: Ajustement = { ...ajustements[0], valeur: 18.0 };
mockFetch({
"/ajustements/21212006/1": { method: "PUT", status: 200, body: updated },
});
try {
const res = await fetch("http://localhost/api/ajustements/21212006/1", {
method: "PUT",
headers: { "content-type": "application/json" },
body: JSON.stringify({ valeur: 18.0 }),
});
assertEquals(res.status, 200);
const data: Ajustement = await res.json();
assertEquals(data.valeur, 18.0);
} finally {
restoreFetch();
}
});
Deno.test("mock API: DELETE /ajustements/:numEtud/:idUE returns 204", async () => {
mockFetch({ "/ajustements/21212006/1": { method: "DELETE", status: 204 } });
try {
const res = await fetch("http://localhost/api/ajustements/21212006/1", {
method: "DELETE",
});
assertEquals(res.status, 204);
} finally {
restoreFetch();
}
});
// --- Mock DB ---
Deno.test("mock DB: find ajustement by composite key", () => {
const db = createMockDb({ tables: { ajustements: [...ajustements] } });
const a = db.findOne<Ajustement>(
"ajustements",
(a) => a.numEtud === 21212006 && a.idUE === 1,
);
assertExists(a);
assertEquals(a.valeur, 13.25);
});
Deno.test("mock DB: filter ajustements by numEtud", () => {
const db = createMockDb({ tables: { ajustements: [...ajustements] } });
const rows = db.findMany<Ajustement>(
"ajustements",
(a) => a.numEtud === 21212006,
);
assertEquals(rows.length, 1);
});
Deno.test("mock DB: insert ajustement", () => {
const db = createMockDb({ tables: { ajustements: [...ajustements] } });
db.insert<Ajustement>("ajustements", {
numEtud: 21212007,
idUE: 2,
valeur: 14.0,
});
assertEquals(db.getTable("ajustements").length, 3);
});
Deno.test("mock DB: update ajustement valeur", () => {
const db = createMockDb({ tables: { ajustements: [...ajustements] } });
db.updateWhere<Ajustement>(
"ajustements",
(a) => a.numEtud === 21212006 && a.idUE === 1,
{ valeur: 20.0 },
);
assertEquals(
db.findOne<Ajustement>(
"ajustements",
(a) => a.numEtud === 21212006 && a.idUE === 1,
)?.valeur,
20.0,
);
});
Deno.test("mock DB: delete ajustement", () => {
const db = createMockDb({ tables: { ajustements: [...ajustements] } });
db.deleteWhere<Ajustement>(
"ajustements",
(a) => a.numEtud === 21212006 && a.idUE === 1,
);
assertEquals(db.getTable("ajustements").length, 1);
});
-239
View File
@@ -1,239 +0,0 @@
// Unit tests for /enseignements endpoints — fixtures, mock API, mock DB
import { assertEquals, assertExists } from "@std/assert";
import { mockFetch, restoreFetch } from "../helpers/api_mock.ts";
import { createMockDb } from "../helpers/db_mock.ts";
import { enseignements } from "../helpers/fixtures.ts";
interface Enseignement {
idProf: string;
idModule: string;
idPromo: string;
}
// --- Fixtures ---
Deno.test("enseignements: fixtures have correct shape", () => {
assertEquals(enseignements.length, 3);
assertEquals(typeof enseignements[0].idModule, "string");
assertEquals(typeof enseignements[0].idPromo, "string");
});
// --- Mock API ---
Deno.test("mock API: POST /enseignements creates enseignement (201) as employee", async () => {
const newEns: Enseignement = {
idProf: "prof.dupont",
idModule: "JIN702C",
idPromo: "4AFISE25/26",
};
mockFetch({
"/enseignements": { method: "POST", status: 201, body: newEns },
});
try {
const res = await fetch("http://localhost/api/enseignements", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(newEns),
});
assertEquals(res.status, 201);
const data: Enseignement = await res.json();
assertEquals(data.idModule, "JIN702C");
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /enseignements 403 for non-employee", async () => {
mockFetch({ "/enseignements": { method: "POST", status: 403 } });
try {
const res = await fetch("http://localhost/api/enseignements", {
method: "POST",
});
assertEquals(res.status, 403);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /enseignements 400 on missing fields", async () => {
mockFetch({ "/enseignements": { method: "POST", status: 400 } });
try {
const res = await fetch("http://localhost/api/enseignements", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ idProf: "prof.dupont" }),
});
assertEquals(res.status, 400);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /enseignements 409 on duplicate", async () => {
mockFetch({
"/enseignements": {
method: "POST",
status: 409,
body: { error: "Cet enseignement existe déjà." },
},
});
try {
const res = await fetch("http://localhost/api/enseignements", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
idProf: "prof.dupont",
idModule: "JIN702C",
idPromo: "4AFISE25/26",
}),
});
assertEquals(res.status, 409);
const data = await res.json();
assertExists(data.error);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /enseignements/:idProf/:idModule/:idPromo returns enseignement (employee)", async () => {
const ens: Enseignement = {
idProf: "prof.dupont",
idModule: "JIN702C",
idPromo: "4AFISE25/26",
};
mockFetch({ "/enseignements/prof.dupont/JIN702C/4AFISE25": ens });
try {
const res = await fetch(
"http://localhost/api/enseignements/prof.dupont/JIN702C/4AFISE25%2F26",
);
assertEquals(res.status, 200);
const data: Enseignement = await res.json();
assertEquals(data.idProf, "prof.dupont");
assertEquals(data.idModule, "JIN702C");
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /enseignements/:idProf/:idModule/:idPromo 403 for non-employee", async () => {
mockFetch({ "/enseignements/prof.dupont/JIN702C/4AFISE25": { status: 403 } });
try {
const res = await fetch(
"http://localhost/api/enseignements/prof.dupont/JIN702C/4AFISE25%2F26",
);
assertEquals(res.status, 403);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /enseignements/:idProf/:idModule/:idPromo 404 when not found", async () => {
mockFetch({
"/enseignements/ghost/GHOST/GHOST": {
status: 404,
body: { error: "Ressource introuvable" },
},
});
try {
const res = await fetch(
"http://localhost/api/enseignements/ghost/GHOST/GHOST",
);
assertEquals(res.status, 404);
} finally {
restoreFetch();
}
});
Deno.test("mock API: DELETE /enseignements/:idProf/:idModule/:idPromo returns 204 (employee)", async () => {
mockFetch({
"/enseignements/prof.dupont/JIN702C/4AFISE25": {
method: "DELETE",
status: 204,
},
});
try {
const res = await fetch(
"http://localhost/api/enseignements/prof.dupont/JIN702C/4AFISE25%2F26",
{
method: "DELETE",
},
);
assertEquals(res.status, 204);
} finally {
restoreFetch();
}
});
Deno.test("mock API: DELETE /enseignements/:idProf/:idModule/:idPromo 403 for non-employee", async () => {
mockFetch({
"/enseignements/prof.dupont/JIN702C/4AFISE25": {
method: "DELETE",
status: 403,
},
});
try {
const res = await fetch(
"http://localhost/api/enseignements/prof.dupont/JIN702C/4AFISE25%2F26",
{
method: "DELETE",
},
);
assertEquals(res.status, 403);
} finally {
restoreFetch();
}
});
// --- Mock DB ---
Deno.test("mock DB: find enseignement by composite key", () => {
const data = [
{ idProf: "prof.dupont", idModule: "JIN702C", idPromo: "4AFISE25/26" },
{ idProf: "prof.moreau", idModule: "JIN703C", idPromo: "4AFISE25/26" },
];
const db = createMockDb({ tables: { enseignements: data } });
const e = db.findOne<Enseignement>(
"enseignements",
(e) => e.idProf === "prof.dupont" && e.idModule === "JIN702C",
);
assertExists(e);
assertEquals(e.idPromo, "4AFISE25/26");
});
Deno.test("mock DB: insert enseignement", () => {
const db = createMockDb({ tables: { enseignements: [] } });
db.insert<Enseignement>("enseignements", {
idProf: "prof.dupont",
idModule: "JIN702C",
idPromo: "4AFISE25/26",
});
assertEquals(db.getTable("enseignements").length, 1);
});
Deno.test("mock DB: delete enseignement", () => {
const data = [
{ idProf: "prof.dupont", idModule: "JIN702C", idPromo: "4AFISE25/26" },
{ idProf: "prof.moreau", idModule: "JIN703C", idPromo: "4AFISE25/26" },
];
const db = createMockDb({ tables: { enseignements: data } });
db.deleteWhere<Enseignement>(
"enseignements",
(e) => e.idProf === "prof.dupont",
);
assertEquals(db.getTable("enseignements").length, 1);
});
Deno.test("mock DB: filter enseignements by idModule", () => {
const data = [
{ idProf: "prof.dupont", idModule: "JIN702C", idPromo: "4AFISE25/26" },
{ idProf: "prof.dupont", idModule: "JIN702C", idPromo: "3AFISE25/26" },
{ idProf: "prof.moreau", idModule: "JIN703C", idPromo: "4AFISE25/26" },
];
const db = createMockDb({ tables: { enseignements: data } });
const rows = db.findMany<Enseignement>(
"enseignements",
(e) => e.idModule === "JIN702C",
);
assertEquals(rows.length, 2);
});
+70
View File
@@ -0,0 +1,70 @@
import { assertEquals } from "@std/assert";
import {
calculateWeightedAverage,
getEffectiveNote,
applyAjustement,
Note,
UEModule,
Ajustement
} from "../../logic/grades.ts";
Deno.test("grades logic: getEffectiveNote uses session 2 if present", () => {
const note: Note = { note: 12, noteSession2: 15 };
assertEquals(getEffectiveNote(note), 15);
});
Deno.test("grades logic: getEffectiveNote uses session 1 if session 2 is null", () => {
const note: Note = { note: 12, noteSession2: null };
assertEquals(getEffectiveNote(note), 12);
});
Deno.test("grades logic: calculateWeightedAverage computes correctly", () => {
const ueModules: UEModule[] = [
{ idModule: "M1", coeff: 2 },
{ idModule: "M2", coeff: 3 },
];
const notesMap: Record<string, Note> = {
"M1": { note: 10, noteSession2: null },
"M2": { note: 15, noteSession2: null },
};
// (10*2 + 15*3) / 5 = (20 + 45) / 5 = 65 / 5 = 13
assertEquals(calculateWeightedAverage(ueModules, notesMap), 13);
});
Deno.test("grades logic: calculateWeightedAverage handles missing notes", () => {
const ueModules: UEModule[] = [
{ idModule: "M1", coeff: 2 },
{ idModule: "M2", coeff: 3 },
];
const notesMap: Record<string, Note> = {
"M1": { note: 10, noteSession2: null },
// M2 manquante
};
// (10*2) / 2 = 10
assertEquals(calculateWeightedAverage(ueModules, notesMap), 10);
});
Deno.test("grades logic: calculateWeightedAverage returns null if no notes", () => {
const ueModules: UEModule[] = [
{ idModule: "M1", coeff: 2 },
];
const notesMap: Record<string, Note> = {};
assertEquals(calculateWeightedAverage(ueModules, notesMap), null);
});
Deno.test("grades logic: applyAjustement replaces calculated average", () => {
const calculatedAvg = 12;
const ajustement: Ajustement = { valeur: 14, malus: 0 };
assertEquals(applyAjustement(calculatedAvg, ajustement), 14);
});
Deno.test("grades logic: applyAjustement subtracts malus", () => {
const calculatedAvg = 12;
const ajustement: Ajustement = { valeur: 14, malus: 2 };
assertEquals(applyAjustement(calculatedAvg, ajustement), 12);
});
Deno.test("grades logic: applyAjustement returns calculated average if no ajustement", () => {
const calculatedAvg = 12;
assertEquals(applyAjustement(calculatedAvg, null), 12);
});
-171
View File
@@ -1,171 +0,0 @@
// #113 - Unit tests for /modules endpoints
import { assertEquals, assertExists } from "@std/assert";
import { mockFetch, restoreFetch } from "../helpers/api_mock.ts";
import { createMockDb } from "../helpers/db_mock.ts";
import { type Module, modules } from "../helpers/fixtures.ts";
// --- Fixtures ---
Deno.test("modules: fixtures have correct shape", () => {
assertEquals(modules.length, 3);
assertEquals(typeof modules[0].id, "string");
assertEquals(typeof modules[0].nom, "string");
});
// --- Mock API ---
Deno.test("mock API: GET /modules returns list", async () => {
mockFetch({ "/modules": modules });
try {
const res = await fetch("http://localhost/api/modules");
assertEquals(res.status, 200);
const data: Module[] = await res.json();
assertEquals(data.length, 3);
assertExists(data.find((m) => m.id === "JIN702C"));
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /modules/:id returns one module", async () => {
mockFetch({ "/modules/JIN702C": modules[0] });
try {
const res = await fetch("http://localhost/api/modules/JIN702C");
assertEquals(res.status, 200);
const data: Module = await res.json();
assertEquals(data.id, "JIN702C");
assertEquals(data.nom, "Optimisation");
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /modules/:id 404 when not found", async () => {
mockFetch({
"/modules/UNKNOWN": {
status: 404,
body: { error: "Ressource introuvable" },
},
});
try {
const res = await fetch("http://localhost/api/modules/UNKNOWN");
assertEquals(res.status, 404);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /modules creates module (201)", async () => {
const newModule: Module = { id: "NEW101", nom: "Nouveau Module" };
mockFetch({ "/modules": { method: "POST", status: 201, body: newModule } });
try {
const res = await fetch("http://localhost/api/modules", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(newModule),
});
assertEquals(res.status, 201);
const data: Module = await res.json();
assertEquals(data.id, "NEW101");
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /modules 409 on duplicate id", async () => {
mockFetch({
"/modules": {
method: "POST",
status: 409,
body: { error: "Un module avec cet identifiant existe déjà" },
},
});
try {
const res = await fetch("http://localhost/api/modules", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(modules[0]),
});
assertEquals(res.status, 409);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /modules 400 on missing fields", async () => {
mockFetch({ "/modules": { method: "POST", status: 400 } });
try {
const res = await fetch("http://localhost/api/modules", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ id: "X" }),
});
assertEquals(res.status, 400);
} finally {
restoreFetch();
}
});
Deno.test("mock API: PUT /modules/:id updates nom", async () => {
const updated: Module = { id: "JIN702C", nom: "Optimisation avancée" };
mockFetch({
"/modules/JIN702C": { method: "PUT", status: 200, body: updated },
});
try {
const res = await fetch("http://localhost/api/modules/JIN702C", {
method: "PUT",
headers: { "content-type": "application/json" },
body: JSON.stringify({ nom: "Optimisation avancée" }),
});
assertEquals(res.status, 200);
const data: Module = await res.json();
assertEquals(data.nom, "Optimisation avancée");
} finally {
restoreFetch();
}
});
Deno.test("mock API: DELETE /modules/:id returns 204", async () => {
mockFetch({ "/modules/JIN702C": { method: "DELETE", status: 204 } });
try {
const res = await fetch("http://localhost/api/modules/JIN702C", {
method: "DELETE",
});
assertEquals(res.status, 204);
} finally {
restoreFetch();
}
});
// --- Mock DB ---
Deno.test("mock DB: find module by id", () => {
const db = createMockDb({ tables: { modules: [...modules] } });
const m = db.findOne<Module>("modules", (m) => m.id === "JIN702C");
assertExists(m);
assertEquals(m.nom, "Optimisation");
});
Deno.test("mock DB: insert module", () => {
const db = createMockDb({ tables: { modules: [...modules] } });
db.insert<Module>("modules", { id: "NEW101", nom: "Nouveau" });
assertEquals(db.getTable("modules").length, 4);
});
Deno.test("mock DB: update module nom", () => {
const db = createMockDb({ tables: { modules: [...modules] } });
db.updateWhere<Module>("modules", (m) => m.id === "JIN702C", {
nom: "Updated",
});
assertEquals(
db.findOne<Module>("modules", (m) => m.id === "JIN702C")?.nom,
"Updated",
);
});
Deno.test("mock DB: delete module", () => {
const db = createMockDb({ tables: { modules: [...modules] } });
db.deleteWhere<Module>("modules", (m) => m.id === "JIN702C");
assertEquals(db.getTable("modules").length, 2);
});
-224
View File
@@ -1,224 +0,0 @@
// Unit tests for /notes endpoints — fixtures, mock API, mock DB
import { assertEquals, assertExists } from "@std/assert";
import { mockFetch, restoreFetch } from "../helpers/api_mock.ts";
import { createMockDb } from "../helpers/db_mock.ts";
import { type Note, notes } from "../helpers/fixtures.ts";
// --- Fixtures ---
Deno.test("notes: fixtures have correct shape", () => {
assertEquals(notes.length, 4);
assertEquals(typeof notes[0].note, "number");
assertEquals(typeof notes[0].numEtud, "number");
assertEquals(typeof notes[0].idModule, "string");
});
Deno.test("notes: fixtures use decimal values", () => {
assertEquals(notes[0].note, 15.5);
});
// --- Mock API ---
Deno.test("mock API: GET /notes returns list", async () => {
mockFetch({ "/notes": notes });
try {
const res = await fetch("http://localhost/api/notes");
assertEquals(res.status, 200);
const data: Note[] = await res.json();
assertEquals(data.length, 4);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /notes?numEtud filters by student", async () => {
const filtered = notes.filter((n) => n.numEtud === 21212006);
mockFetch({ "/notes": filtered });
try {
const res = await fetch("http://localhost/api/notes?numEtud=21212006");
const data: Note[] = await res.json();
assertEquals(data.length, 2);
assertEquals(data.every((n) => n.numEtud === 21212006), true);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /notes?idModule filters by module", async () => {
const filtered = notes.filter((n) => n.idModule === "JIN702C");
mockFetch({ "/notes": filtered });
try {
const res = await fetch("http://localhost/api/notes?idModule=JIN702C");
const data: Note[] = await res.json();
assertEquals(data.length, 2);
assertEquals(data.every((n) => n.idModule === "JIN702C"), true);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /notes?numEtud=NaN returns 400", async () => {
mockFetch({ "/notes": { status: 400 } });
try {
const res = await fetch("http://localhost/api/notes?numEtud=abc");
assertEquals(res.status, 400);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /notes creates note (201)", async () => {
const newNote: Note = { note: 14.0, numEtud: 21212006, idModule: "JIN704C" };
mockFetch({ "/notes": { method: "POST", status: 201, body: newNote } });
try {
const res = await fetch("http://localhost/api/notes", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(newNote),
});
assertEquals(res.status, 201);
const data: Note = await res.json();
assertEquals(data.note, 14.0);
assertEquals(data.numEtud, 21212006);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /notes 400 on missing fields", async () => {
mockFetch({ "/notes": { method: "POST", status: 400 } });
try {
const res = await fetch("http://localhost/api/notes", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ numEtud: 21212006 }),
});
assertEquals(res.status, 400);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /notes/:numEtud/:idModule returns note", async () => {
mockFetch({ "/notes/21212006/JIN702C": notes[0] });
try {
const res = await fetch("http://localhost/api/notes/21212006/JIN702C");
assertEquals(res.status, 200);
const data: Note = await res.json();
assertEquals(data.note, 15.5);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /notes/:numEtud/:idModule 404 when not found", async () => {
mockFetch({
"/notes/99999/GHOST": {
status: 404,
body: { error: "Ressource introuvable" },
},
});
try {
const res = await fetch("http://localhost/api/notes/99999/GHOST");
assertEquals(res.status, 404);
} finally {
restoreFetch();
}
});
Deno.test("mock API: PUT /notes/:numEtud/:idModule updates note", async () => {
const updated: Note = { ...notes[0], note: 17.0 };
mockFetch({
"/notes/21212006/JIN702C": { method: "PUT", status: 200, body: updated },
});
try {
const res = await fetch("http://localhost/api/notes/21212006/JIN702C", {
method: "PUT",
headers: { "content-type": "application/json" },
body: JSON.stringify({ note: 17.0 }),
});
assertEquals(res.status, 200);
const data: Note = await res.json();
assertEquals(data.note, 17.0);
} finally {
restoreFetch();
}
});
Deno.test("mock API: DELETE /notes/:numEtud/:idModule returns 204", async () => {
mockFetch({ "/notes/21212006/JIN702C": { method: "DELETE", status: 204 } });
try {
const res = await fetch("http://localhost/api/notes/21212006/JIN702C", {
method: "DELETE",
});
assertEquals(res.status, 204);
} finally {
restoreFetch();
}
});
Deno.test("mock API: DELETE /notes/:numEtud/:idModule 404 when not found", async () => {
mockFetch({ "/notes/99999/GHOST": { method: "DELETE", status: 404 } });
try {
const res = await fetch("http://localhost/api/notes/99999/GHOST", {
method: "DELETE",
});
assertEquals(res.status, 404);
} finally {
restoreFetch();
}
});
// --- Mock DB ---
Deno.test("mock DB: find note by composite key", () => {
const db = createMockDb({ tables: { notes: [...notes] } });
const n = db.findOne<Note>(
"notes",
(n) => n.numEtud === 21212006 && n.idModule === "JIN702C",
);
assertExists(n);
assertEquals(n.note, 15.5);
});
Deno.test("mock DB: filter notes by numEtud", () => {
const db = createMockDb({ tables: { notes: [...notes] } });
const rows = db.findMany<Note>("notes", (n) => n.numEtud === 21212006);
assertEquals(rows.length, 2);
});
Deno.test("mock DB: insert note", () => {
const db = createMockDb({ tables: { notes: [...notes] } });
db.insert<Note>("notes", {
note: 10.0,
numEtud: 21212006,
idModule: "JIN704C",
});
assertEquals(db.getTable("notes").length, 5);
});
Deno.test("mock DB: update note value", () => {
const db = createMockDb({ tables: { notes: [...notes] } });
db.updateWhere<Note>(
"notes",
(n) => n.numEtud === 21212006 && n.idModule === "JIN702C",
{ note: 20.0 },
);
assertEquals(
db.findOne<Note>(
"notes",
(n) => n.numEtud === 21212006 && n.idModule === "JIN702C",
)?.note,
20.0,
);
});
Deno.test("mock DB: delete note", () => {
const db = createMockDb({ tables: { notes: [...notes] } });
db.deleteWhere<Note>(
"notes",
(n) => n.numEtud === 21212006 && n.idModule === "JIN702C",
);
assertEquals(db.getTable("notes").length, 3);
});
-65
View File
@@ -1,65 +0,0 @@
// #115 - Unit tests for GET /permissions
import { assertEquals, assertExists } from "@std/assert";
import { mockFetch, restoreFetch } from "../helpers/api_mock.ts";
interface Permission {
id: string;
nom: string;
}
const EXPECTED_PERMISSIONS: Permission[] = [
{ id: "student_read", nom: "Consulter les élèves" },
{ id: "student_write", nom: "Gérer les élèves" },
{ id: "note_read", nom: "Consulter les notes" },
{ id: "note_write", nom: "Gérer les notes" },
{ id: "module_read", nom: "Consulter les modules" },
{ id: "module_write", nom: "Gérer les modules" },
{ id: "user_read", nom: "Consulter les utilisateurs" },
{ id: "user_write", nom: "Gérer les utilisateurs" },
{ id: "role_write", nom: "Gérer les rôles" },
];
Deno.test("permissions: known permission ids", () => {
const ids = EXPECTED_PERMISSIONS.map((p) => p.id);
assertEquals(ids.includes("student_read"), true);
assertEquals(ids.includes("student_write"), true);
assertEquals(ids.includes("note_read"), true);
assertEquals(ids.includes("role_write"), true);
assertEquals(ids.length, 9);
});
Deno.test("permissions: all permissions have string id and nom", () => {
for (const p of EXPECTED_PERMISSIONS) {
assertEquals(typeof p.id, "string");
assertEquals(typeof p.nom, "string");
}
});
Deno.test("mock API: GET /permissions returns all permissions", async () => {
mockFetch({ "/permissions": EXPECTED_PERMISSIONS });
try {
const res = await fetch("http://localhost/api/permissions");
assertEquals(res.status, 200);
const data: Permission[] = await res.json();
assertEquals(data.length, 9);
assertExists(data.find((p) => p.id === "student_read"));
assertExists(data.find((p) => p.id === "role_write"));
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /permissions - each permission has id and nom", async () => {
mockFetch({ "/permissions": EXPECTED_PERMISSIONS });
try {
const res = await fetch("http://localhost/api/permissions");
const data: Permission[] = await res.json();
for (const p of data) {
assertExists(p.id);
assertExists(p.nom);
}
} finally {
restoreFetch();
}
});
-160
View File
@@ -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);
});
-159
View File
@@ -1,159 +0,0 @@
// #112 - Unit tests for /roles endpoints
import { assertEquals, assertExists } from "@std/assert";
import { mockFetch, restoreFetch } from "../helpers/api_mock.ts";
import { createMockDb } from "../helpers/db_mock.ts";
interface Role {
id: number;
nom: string;
permissions: string[];
}
const roles: Role[] = [
{ id: 1, nom: "admin", permissions: ["student_read", "student_write"] },
{ id: 2, nom: "employee", permissions: ["student_read"] },
];
// --- Fixtures ---
Deno.test("roles: fixtures have correct shape", () => {
assertEquals(roles.length, 2);
assertEquals(typeof roles[0].id, "number");
assertEquals(typeof roles[0].nom, "string");
assertEquals(Array.isArray(roles[0].permissions), true);
});
Deno.test("roles: permissions are strings", () => {
assertEquals(roles[0].permissions.every((p) => typeof p === "string"), true);
});
// --- Mock API ---
Deno.test("mock API: GET /roles returns list with permissions", async () => {
mockFetch({ "/roles": roles });
try {
const res = await fetch("http://localhost/api/roles");
assertEquals(res.status, 200);
const data: Role[] = await res.json();
assertEquals(data.length, 2);
assertExists(data.find((r) => r.nom === "admin"));
assertEquals(data[0].permissions.length, 2);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /roles/:id returns role", async () => {
mockFetch({ "/roles/1": roles[0] });
try {
const res = await fetch("http://localhost/api/roles/1");
assertEquals(res.status, 200);
const data: Role = await res.json();
assertEquals(data.nom, "admin");
assertEquals(data.permissions.length, 2);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /roles/:id 404 when not found", async () => {
mockFetch({
"/roles/99": { status: 404, body: { error: "Ressource introuvable" } },
});
try {
const res = await fetch("http://localhost/api/roles/99");
assertEquals(res.status, 404);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /roles creates role (201)", async () => {
const newRole: Role = { id: 3, nom: "viewer", permissions: [] };
mockFetch({ "/roles": { method: "POST", status: 201, body: newRole } });
try {
const res = await fetch("http://localhost/api/roles", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ nom: "viewer" }),
});
assertEquals(res.status, 201);
const data: Role = await res.json();
assertEquals(data.nom, "viewer");
assertEquals(data.permissions.length, 0);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /roles 400 on missing nom", async () => {
mockFetch({ "/roles": { method: "POST", status: 400 } });
try {
const res = await fetch("http://localhost/api/roles", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({}),
});
assertEquals(res.status, 400);
} finally {
restoreFetch();
}
});
Deno.test("mock API: PUT /roles/:id updates role and permissions", async () => {
const updated: Role = { id: 2, nom: "teacher", permissions: ["note_read"] };
mockFetch({ "/roles/2": { method: "PUT", status: 200, body: updated } });
try {
const res = await fetch("http://localhost/api/roles/2", {
method: "PUT",
headers: { "content-type": "application/json" },
body: JSON.stringify({ nom: "teacher", permissions: ["note_read"] }),
});
assertEquals(res.status, 200);
const data: Role = await res.json();
assertEquals(data.nom, "teacher");
assertEquals(data.permissions, ["note_read"]);
} finally {
restoreFetch();
}
});
Deno.test("mock API: DELETE /roles/:id returns 204", async () => {
mockFetch({ "/roles/2": { method: "DELETE", status: 204 } });
try {
const res = await fetch("http://localhost/api/roles/2", {
method: "DELETE",
});
assertEquals(res.status, 204);
} finally {
restoreFetch();
}
});
// --- Mock DB ---
Deno.test("mock DB: find role by id", () => {
const db = createMockDb({ tables: { roles: [...roles] } });
const r = db.findOne<Role>("roles", (r) => r.id === 1);
assertExists(r);
assertEquals(r.nom, "admin");
});
Deno.test("mock DB: insert role", () => {
const db = createMockDb({ tables: { roles: [...roles] } });
db.insert<Role>("roles", { id: 3, nom: "viewer", permissions: [] });
assertEquals(db.getTable("roles").length, 3);
});
Deno.test("mock DB: update role nom", () => {
const db = createMockDb({ tables: { roles: [...roles] } });
db.updateWhere<Role>("roles", (r) => r.id === 2, { nom: "teacher" });
assertEquals(db.findOne<Role>("roles", (r) => r.id === 2)?.nom, "teacher");
});
Deno.test("mock DB: delete role", () => {
const db = createMockDb({ tables: { roles: [...roles] } });
db.deleteWhere<Role>("roles", (r) => r.id === 1);
assertEquals(db.getTable("roles").length, 1);
});
-216
View File
@@ -1,216 +0,0 @@
// #109 - Unit tests for /students endpoints
// Tests purs : fixtures, mock API, mock DB — aucun appel réseau réel
import { assertEquals, assertExists } from "@std/assert";
import { getFetchCalls, mockFetch, restoreFetch } from "../helpers/api_mock.ts";
import { createMockDb } from "../helpers/db_mock.ts";
import { type Student, students } from "../helpers/fixtures.ts";
// --- Fixtures ---
Deno.test("students: fixtures have correct shape", () => {
assertEquals(students.length, 3);
assertEquals(typeof students[0].numEtud, "number");
assertEquals(typeof students[0].nom, "string");
assertEquals(typeof students[0].prenom, "string");
assertEquals(typeof students[0].idPromo, "string");
});
Deno.test("students: two students belong to the same promo", () => {
const promo4 = students.filter((s) => s.idPromo === "4AFISE25/26");
assertEquals(promo4.length, 2);
});
// --- Mock API - GET /students ---
Deno.test("mock API: GET /students returns list", async () => {
mockFetch({ "/students": students });
try {
const res = await fetch("http://localhost/api/students");
assertEquals(res.status, 200);
const data: Student[] = await res.json();
assertEquals(data.length, 3);
assertExists(data.find((s) => s.nom === "Dupont"));
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /students?idPromo filters by promo", async () => {
const filtered = students.filter((s) => s.idPromo === "4AFISE25/26");
mockFetch({ "/students": filtered });
try {
const res = await fetch(
"http://localhost/api/students?idPromo=4AFISE25/26",
);
const data: Student[] = await res.json();
assertEquals(data.length, 2);
assertEquals(data.every((s) => s.idPromo === "4AFISE25/26"), true);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /students/:numEtud returns one student", async () => {
mockFetch({ "/students/21212006": students[0] });
try {
const res = await fetch("http://localhost/api/students/21212006");
assertEquals(res.status, 200);
const data: Student = await res.json();
assertEquals(data.numEtud, 21212006);
assertEquals(data.nom, "Dupont");
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /students/:numEtud 404 when not found", async () => {
mockFetch({
"/students/99999": {
status: 404,
body: { error: "Ressource introuvable" },
},
});
try {
const res = await fetch("http://localhost/api/students/99999");
assertEquals(res.status, 404);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /students creates student", async () => {
const newStudent = students[0];
mockFetch({ "/students": { method: "POST", status: 201, body: newStudent } });
try {
const res = await fetch("http://localhost/api/students", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
nom: "Dupont",
prenom: "Jean",
idPromo: "4AFISE25/26",
}),
});
assertEquals(res.status, 201);
const data: Student = await res.json();
assertEquals(data.nom, "Dupont");
} finally {
restoreFetch();
}
});
Deno.test("mock API: PUT /students/:numEtud updates student", async () => {
const updated = { ...students[0], nom: "Dupont-Modifié" };
mockFetch({
"/students/21212006": { method: "PUT", status: 200, body: updated },
});
try {
const res = await fetch("http://localhost/api/students/21212006", {
method: "PUT",
headers: { "content-type": "application/json" },
body: JSON.stringify({
nom: "Dupont-Modifié",
prenom: "Jean",
idPromo: "4AFISE25/26",
}),
});
assertEquals(res.status, 200);
const data: Student = await res.json();
assertEquals(data.nom, "Dupont-Modifié");
} finally {
restoreFetch();
}
});
Deno.test("mock API: DELETE /students/:numEtud returns 204", async () => {
mockFetch({ "/students/21212006": { method: "DELETE", status: 204 } });
try {
const res = await fetch("http://localhost/api/students/21212006", {
method: "DELETE",
});
assertEquals(res.status, 204);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /students 400 on missing fields", async () => {
mockFetch({ "/students": { method: "POST", status: 400 } });
try {
const res = await fetch("http://localhost/api/students", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ nom: "Test" }),
});
assertEquals(res.status, 400);
} finally {
restoreFetch();
}
});
// --- Mock DB ---
Deno.test("mock DB: find student by numEtud", () => {
const db = createMockDb({ tables: { students: [...students] } });
const s = db.findOne<Student>("students", (r) => r.numEtud === 21212006);
assertExists(s);
assertEquals(s.nom, "Dupont");
});
Deno.test("mock DB: filter students by idPromo", () => {
const db = createMockDb({ tables: { students: [...students] } });
const rows = db.findMany<Student>(
"students",
(s) => s.idPromo === "4AFISE25/26",
);
assertEquals(rows.length, 2);
});
Deno.test("mock DB: insert student increments count", () => {
const db = createMockDb({ tables: { students: [...students] } });
db.insert<Student>("students", {
numEtud: 21212099,
nom: "Test",
prenom: "Ing",
idPromo: "4AFISE25/26",
});
assertEquals(db.getTable("students").length, 4);
});
Deno.test("mock DB: update student nom", () => {
const db = createMockDb({ tables: { students: [...students] } });
const count = db.updateWhere<Student>(
"students",
(s) => s.numEtud === 21212006,
{ nom: "Nouveau" },
);
assertEquals(count, 1);
assertEquals(
db.findOne<Student>("students", (s) => s.numEtud === 21212006)?.nom,
"Nouveau",
);
});
Deno.test("mock DB: delete student removes exactly one", () => {
const db = createMockDb({ tables: { students: [...students] } });
const count = db.deleteWhere<Student>(
"students",
(s) => s.numEtud === 21212006,
);
assertEquals(count, 1);
assertEquals(db.getTable("students").length, 2);
});
Deno.test("mock API: getFetchCalls tracks student requests", async () => {
mockFetch({ "/students": students });
try {
await fetch("http://localhost/api/students");
await fetch("http://localhost/api/students?idPromo=4AFISE25/26");
const calls = getFetchCalls();
assertEquals(calls.length, 2);
assertEquals(calls[0].method, "GET");
} finally {
restoreFetch();
}
});
-222
View File
@@ -1,222 +0,0 @@
// Unit tests for /ue-modules endpoints — fixtures, mock API, mock DB
import { assertEquals, assertExists } from "@std/assert";
import { mockFetch, restoreFetch } from "../helpers/api_mock.ts";
import { createMockDb } from "../helpers/db_mock.ts";
import { type UeModule, ueModules } from "../helpers/fixtures.ts";
// --- Fixtures ---
Deno.test("ue_modules: fixtures have correct shape", () => {
assertEquals(ueModules.length, 3);
assertEquals(typeof ueModules[0].idModule, "string");
assertEquals(typeof ueModules[0].idUE, "number");
assertEquals(typeof ueModules[0].idPromo, "string");
assertEquals(typeof ueModules[0].coeff, "number");
});
// --- Mock API ---
Deno.test("mock API: GET /ue-modules returns list", async () => {
mockFetch({ "/ue-modules": ueModules });
try {
const res = await fetch("http://localhost/api/ue-modules");
assertEquals(res.status, 200);
const data: UeModule[] = await res.json();
assertEquals(data.length, 3);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /ue-modules?idPromo filters by promo", async () => {
const filtered = ueModules.filter((u) => u.idPromo === "4AFISE25/26");
mockFetch({ "/ue-modules": filtered });
try {
const res = await fetch(
"http://localhost/api/ue-modules?idPromo=4AFISE25%2F26",
);
const data: UeModule[] = await res.json();
assertEquals(data.length, 2);
assertEquals(data.every((u) => u.idPromo === "4AFISE25/26"), true);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /ue-modules?idUE filters by UE", async () => {
const filtered = ueModules.filter((u) => u.idUE === 1);
mockFetch({ "/ue-modules": filtered });
try {
const res = await fetch("http://localhost/api/ue-modules?idUE=1");
const data: UeModule[] = await res.json();
assertEquals(data.length, 2);
assertEquals(data.every((u) => u.idUE === 1), true);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /ue-modules creates association (201)", async () => {
const newUeModule: UeModule = {
idModule: "JIN705C",
idUE: 2,
idPromo: "3AFISE25/26",
coeff: 3.0,
};
mockFetch({
"/ue-modules": { method: "POST", status: 201, body: newUeModule },
});
try {
const res = await fetch("http://localhost/api/ue-modules", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(newUeModule),
});
assertEquals(res.status, 201);
const data: UeModule = await res.json();
assertEquals(data.idModule, "JIN705C");
assertEquals(data.coeff, 3.0);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /ue-modules 400 on missing fields", async () => {
mockFetch({ "/ue-modules": { method: "POST", status: 400 } });
try {
const res = await fetch("http://localhost/api/ue-modules", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ idModule: "X" }),
});
assertEquals(res.status, 400);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /ue-modules/:idModule/:idUE/:idPromo returns association (employee)", async () => {
mockFetch({ "/ue-modules/JIN702C/1/4AFISE25": ueModules[0] });
try {
const res = await fetch(
"http://localhost/api/ue-modules/JIN702C/1/4AFISE25%2F26",
);
assertEquals(res.status, 200);
const data: UeModule = await res.json();
assertEquals(data.coeff, 3.0);
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /ue-modules/:idModule/:idUE/:idPromo 403 for non-employee", async () => {
mockFetch({ "/ue-modules/JIN702C/1/4AFISE25": { status: 403 } });
try {
const res = await fetch(
"http://localhost/api/ue-modules/JIN702C/1/4AFISE25%2F26",
);
assertEquals(res.status, 403);
} finally {
restoreFetch();
}
});
Deno.test("mock API: PUT /ue-modules/:idModule/:idUE/:idPromo updates coeff", async () => {
const updated: UeModule = { ...ueModules[0], coeff: 5.0 };
mockFetch({
"/ue-modules/JIN702C/1/4AFISE25": {
method: "PUT",
status: 200,
body: updated,
},
});
try {
const res = await fetch(
"http://localhost/api/ue-modules/JIN702C/1/4AFISE25%2F26",
{
method: "PUT",
headers: { "content-type": "application/json" },
body: JSON.stringify({ coeff: 5.0 }),
},
);
assertEquals(res.status, 200);
const data: UeModule = await res.json();
assertEquals(data.coeff, 5.0);
} finally {
restoreFetch();
}
});
Deno.test("mock API: DELETE /ue-modules/:idModule/:idUE/:idPromo returns 204", async () => {
mockFetch({
"/ue-modules/JIN702C/1/4AFISE25": { method: "DELETE", status: 204 },
});
try {
const res = await fetch(
"http://localhost/api/ue-modules/JIN702C/1/4AFISE25%2F26",
{ method: "DELETE" },
);
assertEquals(res.status, 204);
} finally {
restoreFetch();
}
});
// --- Mock DB ---
Deno.test("mock DB: find ue-module by composite key", () => {
const db = createMockDb({ tables: { ueModules: [...ueModules] } });
const u = db.findOne<UeModule>(
"ueModules",
(u) =>
u.idModule === "JIN702C" && u.idUE === 1 && u.idPromo === "4AFISE25/26",
);
assertExists(u);
assertEquals(u.coeff, 3.0);
});
Deno.test("mock DB: filter ue-modules by promo", () => {
const db = createMockDb({ tables: { ueModules: [...ueModules] } });
const rows = db.findMany<UeModule>(
"ueModules",
(u) => u.idPromo === "4AFISE25/26",
);
assertEquals(rows.length, 2);
});
Deno.test("mock DB: insert ue-module", () => {
const db = createMockDb({ tables: { ueModules: [...ueModules] } });
db.insert<UeModule>("ueModules", {
idModule: "JIN705C",
idUE: 2,
idPromo: "3AFISE25/26",
coeff: 1.5,
});
assertEquals(db.getTable("ueModules").length, 4);
});
Deno.test("mock DB: update ue-module coeff", () => {
const db = createMockDb({ tables: { ueModules: [...ueModules] } });
db.updateWhere<UeModule>(
"ueModules",
(u) => u.idModule === "JIN702C" && u.idUE === 1,
{ coeff: 6.0 },
);
assertEquals(
db.findOne<UeModule>(
"ueModules",
(u) => u.idModule === "JIN702C" && u.idUE === 1,
)?.coeff,
6.0,
);
});
Deno.test("mock DB: delete ue-module", () => {
const db = createMockDb({ tables: { ueModules: [...ueModules] } });
db.deleteWhere<UeModule>(
"ueModules",
(u) => u.idModule === "JIN702C" && u.idUE === 1,
);
assertEquals(db.getTable("ueModules").length, 2);
});
-164
View File
@@ -1,164 +0,0 @@
// Unit tests for /ues endpoints — fixtures, mock API, mock DB
import { assertEquals, assertExists } from "@std/assert";
import { mockFetch, restoreFetch } from "../helpers/api_mock.ts";
import { createMockDb } from "../helpers/db_mock.ts";
import { type UE, ues } from "../helpers/fixtures.ts";
// --- Fixtures ---
Deno.test("ues: fixtures have correct shape", () => {
assertEquals(ues.length, 2);
assertEquals(typeof ues[0].id, "number");
assertEquals(typeof ues[0].nom, "string");
});
// --- Mock API ---
Deno.test("mock API: GET /ues returns list", async () => {
mockFetch({ "/ues": ues });
try {
const res = await fetch("http://localhost/api/ues");
assertEquals(res.status, 200);
const data: UE[] = await res.json();
assertEquals(data.length, 2);
assertExists(data.find((u) => u.nom === "UE Informatique"));
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /ues/:id returns one UE", async () => {
mockFetch({ "/ues/1": ues[0] });
try {
const res = await fetch("http://localhost/api/ues/1");
assertEquals(res.status, 200);
const data: UE = await res.json();
assertEquals(data.id, 1);
assertEquals(data.nom, "UE Informatique");
} finally {
restoreFetch();
}
});
Deno.test("mock API: GET /ues/:id 404 when not found", async () => {
mockFetch({
"/ues/99": { status: 404, body: { error: "Ressource introuvable" } },
});
try {
const res = await fetch("http://localhost/api/ues/99");
assertEquals(res.status, 404);
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /ues creates UE (201)", async () => {
const newUE: UE = { id: 3, nom: "UE Physique" };
mockFetch({ "/ues": { method: "POST", status: 201, body: newUE } });
try {
const res = await fetch("http://localhost/api/ues", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ nom: "UE Physique" }),
});
assertEquals(res.status, 201);
const data: UE = await res.json();
assertEquals(data.nom, "UE Physique");
} finally {
restoreFetch();
}
});
Deno.test("mock API: POST /ues 400 on missing nom", async () => {
mockFetch({ "/ues": { method: "POST", status: 400 } });
try {
const res = await fetch("http://localhost/api/ues", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({}),
});
assertEquals(res.status, 400);
} finally {
restoreFetch();
}
});
Deno.test("mock API: PUT /ues/:id updates nom", async () => {
const updated: UE = { id: 1, nom: "UE Informatique avancée" };
mockFetch({ "/ues/1": { method: "PUT", status: 200, body: updated } });
try {
const res = await fetch("http://localhost/api/ues/1", {
method: "PUT",
headers: { "content-type": "application/json" },
body: JSON.stringify({ nom: "UE Informatique avancée" }),
});
assertEquals(res.status, 200);
const data: UE = await res.json();
assertEquals(data.nom, "UE Informatique avancée");
} finally {
restoreFetch();
}
});
Deno.test("mock API: PUT /ues/:id 404 when not found", async () => {
mockFetch({ "/ues/99": { method: "PUT", status: 404 } });
try {
const res = await fetch("http://localhost/api/ues/99", {
method: "PUT",
body: JSON.stringify({ nom: "X" }),
});
assertEquals(res.status, 404);
} finally {
restoreFetch();
}
});
Deno.test("mock API: DELETE /ues/:id returns 204", async () => {
mockFetch({ "/ues/1": { method: "DELETE", status: 204 } });
try {
const res = await fetch("http://localhost/api/ues/1", { method: "DELETE" });
assertEquals(res.status, 204);
} finally {
restoreFetch();
}
});
Deno.test("mock API: DELETE /ues/:id 404 when not found", async () => {
mockFetch({ "/ues/99": { method: "DELETE", status: 404 } });
try {
const res = await fetch("http://localhost/api/ues/99", {
method: "DELETE",
});
assertEquals(res.status, 404);
} finally {
restoreFetch();
}
});
// --- Mock DB ---
Deno.test("mock DB: find UE by id", () => {
const db = createMockDb({ tables: { ues: [...ues] } });
const u = db.findOne<UE>("ues", (u) => u.id === 1);
assertExists(u);
assertEquals(u.nom, "UE Informatique");
});
Deno.test("mock DB: insert UE", () => {
const db = createMockDb({ tables: { ues: [...ues] } });
db.insert<UE>("ues", { id: 3, nom: "UE Physique" });
assertEquals(db.getTable("ues").length, 3);
});
Deno.test("mock DB: update UE nom", () => {
const db = createMockDb({ tables: { ues: [...ues] } });
db.updateWhere<UE>("ues", (u) => u.id === 1, { nom: "Updated" });
assertEquals(db.findOne<UE>("ues", (u) => u.id === 1)?.nom, "Updated");
});
Deno.test("mock DB: delete UE", () => {
const db = createMockDb({ tables: { ues: [...ues] } });
db.deleteWhere<UE>("ues", (u) => u.id === 1);
assertEquals(db.getTable("ues").length, 1);
});