// 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( "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("notes", (n) => n.numEtud === 21212006); assertEquals(rows.length, 2); }); Deno.test("mock DB: insert note", () => { const db = createMockDb({ tables: { notes: [...notes] } }); db.insert("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( "notes", (n) => n.numEtud === 21212006 && n.idModule === "JIN702C", { note: 20.0 }, ); assertEquals( db.findOne( "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( "notes", (n) => n.numEtud === 21212006 && n.idModule === "JIN702C", ); assertEquals(db.getTable("notes").length, 3); });