Files
echo-du-huit/agenda-mairie.test.ts
Pierre MartinandClaude Opus 4.8 6c4f4219f1 feat: derive event publication status from the mairie agenda
Pure matching (date locale Cugnaux + titre normalisé) and paginated
transport, both fully tested. HTML extraction via DOMParser stays impure
and untested (absent from Bun), like formulaire-mairie.js.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 18:18:15 +02:00

118 lines
3.8 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import {
calculerPeriode,
construireUrlPage,
recupererAgendaPublie,
} from "./extension/agenda-mairie.js";
function evenement(surcharges: Record<string, unknown> = {}) {
return {
uid: "uid-1",
titre: "Atelier",
debut: new Date("2026-07-10T16:00:00Z"),
fin: new Date("2026-07-10T18:00:00Z"),
journeeEntiere: false,
...surcharges,
};
}
describe("calculerPeriode", () => {
test("debut = mois d'aujourd'hui ; fin = mois du dernier début", () => {
const evenements = [
evenement({ debut: new Date("2026-07-20T10:00:00Z") }),
evenement({ debut: new Date("2026-09-05T10:00:00Z") }),
evenement({ debut: new Date("2026-08-01T10:00:00Z") }),
];
const aujourdhui = new Date("2026-07-17T09:00:00Z");
expect(calculerPeriode(evenements, aujourdhui)).toEqual({
debut: "07/2026",
fin: "09/2026",
});
});
test("liste vide → période bornée au mois courant", () => {
const aujourdhui = new Date("2026-07-17T09:00:00Z");
expect(calculerPeriode([], aujourdhui)).toEqual({ debut: "07/2026", fin: "07/2026" });
});
});
describe("construireUrlPage", () => {
const periode = { debut: "07/2026", fin: "09/2026" };
test("page 1 → URL de base sans segment /page/", () => {
const url = construireUrlPage(1, periode);
expect(url).toBe(
"https://www.ville-cugnaux.fr/mes-loisirs/agenda/?f=1&theme=&date=periode&date_debut=07%2F2026&date_fin=09%2F2026&public=",
);
});
test("page 3 → segment /page/3/", () => {
const url = construireUrlPage(3, periode);
expect(url).toContain("/mes-loisirs/agenda/page/3/?f=1");
expect(url).toContain("date_debut=07%2F2026");
expect(url).toContain("date_fin=09%2F2026");
});
});
describe("recupererAgendaPublie", () => {
const periode = { debut: "07/2026", fin: "09/2026" };
const reponseOk = (html: string) => Promise.resolve({ ok: true, text: () => Promise.resolve(html) });
test("3 pages non vides puis une vide → cartes agrégées, arrêt sur la vide", async () => {
const pages = [
[{ date: "2026-07-01", titre: "A", lien: "l1" }],
[{ date: "2026-07-02", titre: "B", lien: "l2" }],
[{ date: "2026-07-03", titre: "C", lien: "l3" }],
[],
];
const fetchImpl = (url: string) => reponseOk(url);
let appel = 0;
const extraire = () => pages[appel++];
const res = await recupererAgendaPublie(fetchImpl, extraire, periode);
expect(res).toEqual({
ok: true,
cartes: [
{ date: "2026-07-01", titre: "A", lien: "l1" },
{ date: "2026-07-02", titre: "B", lien: "l2" },
{ date: "2026-07-03", titre: "C", lien: "l3" },
],
});
expect(appel).toBe(4); // 3 pages pleines + la vide qui stoppe
});
test("plafond de sécurité respecté (extracteur toujours non vide)", async () => {
let appels = 0;
const fetchImpl = (url: string) => {
appels++;
return reponseOk(url);
};
const extraire = () => [{ date: "2026-07-01", titre: "A", lien: "l" }];
const res = await recupererAgendaPublie(fetchImpl, extraire, periode);
expect(res.ok).toBe(true);
expect(appels).toBe(12); // plafond
});
test("fetch qui throw → { ok:false } (jamais d'exception)", async () => {
const fetchImpl = () => Promise.reject(new Error("réseau"));
const extraire = () => [];
const res = await recupererAgendaPublie(fetchImpl, extraire, periode);
expect(res).toEqual({ ok: false });
});
test("réponse HTTP non-ok (500) → { ok:false }", async () => {
const fetchImpl = () => Promise.resolve({ ok: false, text: () => Promise.resolve("") });
const extraire = () => [{ date: "2026-07-01", titre: "A", lien: "l" }];
const res = await recupererAgendaPublie(fetchImpl, extraire, periode);
expect(res).toEqual({ ok: false });
});
});