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>
This commit is contained in:
Pierre Martin
2026-07-17 18:18:15 +02:00
co-authored by Claude Opus 4.8
parent a7b780876b
commit 6c4f4219f1
4 changed files with 424 additions and 0 deletions
+135
View File
@@ -0,0 +1,135 @@
import { describe, expect, test } from "bun:test";
import {
dateLocaleCugnaux,
indexerCartes,
normaliserTitre,
trouverPublication,
} from "./extension/publication.js";
// Fixtures = Event littéraux (comme presentation.test.ts) : le parsing vit
// ailleurs. Ici on éprouve le matching, vrai risque produit.
function evenement(surcharges: Record<string, unknown> = {}) {
return {
uid: "uid-1",
titre: "Atelier dessin",
description: "",
lieu: "",
debut: new Date("2026-07-10T16:00:00Z"),
fin: new Date("2026-07-10T18:00:00Z"),
categories: [],
journeeEntiere: false,
...surcharges,
};
}
function carte(surcharges: Record<string, unknown> = {}) {
return {
date: "2026-07-10",
titre: "Atelier dessin",
lien: "https://www.ville-cugnaux.fr/agenda/atelier-dessin-2/",
...surcharges,
};
}
describe("normaliserTitre", () => {
test("accents supprimés (NFD)", () => {
expect(normaliserTitre("Soirée jazz")).toBe("soiree jazz");
});
test("casse repliée", () => {
expect(normaliserTitre("ATELIER Dessin")).toBe("atelier dessin");
});
test("apostrophes droites et typographiques retirées", () => {
expect(normaliserTitre("L'atelier")).toBe(normaliserTitre("L’atelier"));
expect(normaliserTitre("L'atelier")).toBe("latelier");
});
test("tirets simples et cadratins retirés", () => {
expect(normaliserTitre("ciné-club")).toBe(normaliserTitre("ciné–club"));
});
test("deux-points et ponctuation retirés sans insérer d'espace", () => {
// « Atelier B.D. » == « Atelier BD » une fois la ponctuation retirée.
expect(normaliserTitre("Atelier B.D.")).toBe(normaliserTitre("Atelier BD"));
});
test("emojis retirés", () => {
expect(normaliserTitre("Fête \u{1F389} du village")).toBe("fete du village");
});
test("espaces multiples compressés et bords élagués", () => {
expect(normaliserTitre(" Atelier dessin ")).toBe("atelier dessin");
});
});
describe("dateLocaleCugnaux", () => {
test("horodaté à 22:00 Paris (été) → même jour", () => {
// 20:00 UTC = 22:00 Paris l'été.
const ev = evenement({ debut: new Date("2026-07-10T20:00:00Z") });
expect(dateLocaleCugnaux(ev)).toBe("2026-07-10");
});
test("horodaté à 00:30 Paris = 22:30 UTC la veille → jour de Cugnaux, pas UTC", () => {
const ev = evenement({ debut: new Date("2026-07-09T22:30:00Z") });
expect(dateLocaleCugnaux(ev)).toBe("2026-07-10");
});
test("journée entière → composantes locales, sans glissement de fuseau", () => {
// Date flottante : composantes locales (cf. presentation.js / DECISIONS.md).
const ev = evenement({ debut: new Date(2026, 6, 10), journeeEntiere: true });
expect(dateLocaleCugnaux(ev)).toBe("2026-07-10");
});
});
describe("trouverPublication", () => {
test("même date + titre normalisé identique → publié avec le bon lien", () => {
const index = indexerCartes([carte()]);
expect(trouverPublication(evenement(), index)).toEqual({
publie: true,
lien: "https://www.ville-cugnaux.fr/agenda/atelier-dessin-2/",
});
});
test("même titre mais date différente → non publié", () => {
const index = indexerCartes([carte({ date: "2026-07-11" })]);
expect(trouverPublication(evenement(), index)).toEqual({ publie: false });
});
test("même date mais titre différent → non publié", () => {
const index = indexerCartes([carte({ titre: "Concert" })]);
expect(trouverPublication(evenement(), index)).toEqual({ publie: false });
});
test("titre ne différant que par accents/emoji/casse/ponctuation → match", () => {
const index = indexerCartes([
carte({ titre: "Atelier Dessin \u{1F3A8}", lien: "https://x/agenda/a/" }),
]);
expect(trouverPublication(evenement({ titre: "atelier dessin" }), index)).toEqual({
publie: true,
lien: "https://x/agenda/a/",
});
});
test("titre proche mais non strictement identique le même jour → non publié (biais précision v1)", () => {
const index = indexerCartes([carte({ titre: "Atelier peinture libre" })]);
expect(trouverPublication(evenement({ titre: "Atelier peinture" }), index)).toEqual({
publie: false,
});
});
test("index vide (agenda injoignable) → non publié", () => {
expect(trouverPublication(evenement(), new Map())).toEqual({ publie: false });
});
test("deux cartes le même jour, titres distincts → la bonne est choisie", () => {
const index = indexerCartes([
carte({ titre: "Concert", lien: "https://x/agenda/concert/" }),
carte({ titre: "Atelier dessin", lien: "https://x/agenda/atelier-dessin/" }),
]);
expect(trouverPublication(evenement(), index)).toEqual({
publie: true,
lien: "https://x/agenda/atelier-dessin/",
});
});
});