TypeScript 98.3%
CSS 0.9%
Shell 0.7%
1import { describe, expect, it } from "vitest";2import { resolveCitations } from "../lib/rag/citations.ts";3import type { ContextBlock, RetrievedChunk } from "../lib/rag/search.ts";45function chunk(id: number): RetrievedChunk {6 return {7 id, document_id: 1, course_code: "IMM1003", space: "official-imm1003",8 ref_type: "slide", ref_number: 18, ref_label: "Séance 4 — Diapositive 18",9 section_title: "", title: "Titre", content: "Contenu de la diapositive.",10 box_types: "", week: 4, doc_title: "Séance 4", doc_path: "x.tex", filename: "seance04.tex", score: 1,11 };12}1314const context: ContextBlock = {15 text: "",16 sources: [17 { tag: "S1", chunk: chunk(11) },18 { tag: "S2", chunk: chunk(22) },19 ],20};2122describe("Validation des citations", () => {23 it("résout les balises valides en citations cliquables", () => {24 const { cleaned, citations, invalidCount } = resolveCitations("La valeur [S1] et le coût [S2].", context);25 expect(invalidCount).toBe(0);26 expect(citations).toHaveLength(2);27 expect(citations[0].chunkId).toBe(11);28 expect(cleaned).toContain("[S1]");29 });3031 it("NEUTRALISE toute balise inventée par le modèle", () => {32 const { cleaned, citations, invalidCount } = resolveCitations("Faux [S9] mais vrai [S1].", context);33 expect(invalidCount).toBe(1);34 expect(cleaned).not.toContain("[S9]");35 expect(cleaned).toContain("[S1]");36 expect(citations).toHaveLength(1);37 });3839 it("normalise les groupes [S1, S2]", () => {40 const { citations, cleaned } = resolveCitations("Ensemble [S1, S2].", context);41 expect(citations).toHaveLength(2);42 expect(cleaned).toContain("[S1][S2]");43 });4445 it("ne cite chaque source qu'une fois dans la liste résolue", () => {46 const { citations } = resolveCitations("[S1] puis encore [S1] et [S1].", context);47 expect(citations).toHaveLength(1);48 });49});50