import { describe, it, expect } from "vitest"; import { makeFakePool, rows } from "./helpers/fakePool.js"; /** * Méta-tests du harnais. * * Presque toutes les assertions du projet s'appuient sur `makeFakePool` : * si ce double se met à tout avaler en silence (un `find` qui renvoie toujours * undefined, un `throws` ignoré, un compteur qui ne s'incrémente pas), des * dizaines de tests passeraient au vert sans plus rien vérifier. * * Ces tests vérifient donc l'outil de mesure lui-même. */ describe("makeFakePool — enregistrement", () => { it("enregistre chaque requête avec son SQL et ses paramètres", async () => { const pool = makeFakePool(); await pool.query("SELECT 1 FROM bands WHERE ma_id = $1", [42]); expect(pool.calls).toHaveLength(1); expect(pool.calls[0].sql).toContain("FROM bands"); expect(pool.calls[0].values).toEqual([42]); }); it("normalise l'absence de paramètres en tableau vide", async () => { const pool = makeFakePool(); await pool.query("SELECT 1"); expect(pool.calls[0].values).toEqual([]); }); it("accepte la forme objet { text }", async () => { const pool = makeFakePool(); await pool.query({ text: "SELECT 1 FROM bands" }, []); expect(pool.calls[0].sql).toBe("SELECT 1 FROM bands"); }); }); describe("makeFakePool — recherche", () => { it("find() trouve par sous-chaîne ET renvoie undefined quand rien ne matche", async () => { const pool = makeFakePool(); await pool.query("UPDATE bands SET name = $1", ["x"]); expect(pool.find("UPDATE bands")).toBeDefined(); // Le cas qui compte : un find() qui renverrait toujours undefined ferait // passer au vert tous les `expect(pool.find(...)).toBeUndefined()`. expect(pool.find("DELETE FROM bands")).toBeUndefined(); }); it("find() accepte une RegExp", async () => { const pool = makeFakePool(); await pool.query("SELECT a, b FROM bands"); expect(pool.find(/SELECT\s+a,\s*b/)).toBeDefined(); expect(pool.find(/SELECT\s+z/)).toBeUndefined(); }); it("findAll() renvoie toutes les occurrences, pas seulement la première", async () => { const pool = makeFakePool(); await pool.query("INSERT INTO bands VALUES (1)"); await pool.query("INSERT INTO bands VALUES (2)"); await pool.query("SELECT 1"); expect(pool.findAll("INSERT INTO bands")).toHaveLength(2); expect(pool.findAll("DELETE")).toHaveLength(0); }); it("sequence() reflète l'ordre réel d'exécution", async () => { const pool = makeFakePool(); await pool.query("BEGIN"); await pool.query("UPDATE bands SET x = 1"); await pool.query("COMMIT"); expect(pool.sequence(["COMMIT", "BEGIN", "UPDATE bands"])) .toEqual(["BEGIN", "UPDATE bands", "COMMIT"]); }); }); describe("makeFakePool — handlers", () => { it("renvoie le résultat du premier handler qui matche", async () => { const pool = makeFakePool([ { match: "FROM bands", result: rows({ ma_id: 1 }) }, { match: "FROM bands", result: rows({ ma_id: 2 }) }, ]); expect((await pool.query("SELECT * FROM bands")).rows[0].ma_id).toBe(1); }); it("renvoie un résultat vide quand aucun handler ne matche", async () => { const pool = makeFakePool([{ match: "FROM autre", result: rows({ x: 1 }) }]); expect(await pool.query("SELECT * FROM bands")).toEqual({ rows: [], rowCount: 0 }); }); // Si `throws` était ignoré, tous les tests de chemin d'erreur (rollback, // 500 sans fuite d'information) passeraient sans rien exercer. it("throws fait bien lever la requête", async () => { const pool = makeFakePool([{ match: "FROM bands", throws: new Error("boum") }]); await expect(pool.query("SELECT * FROM bands")).rejects.toThrow("boum"); }); it("result peut être une fonction du SQL et des paramètres", async () => { const pool = makeFakePool([ { match: "FROM bands", result: (_sql, values) => rows({ echo: values[0] }) }, ]); expect((await pool.query("SELECT * FROM bands WHERE id=$1", [7])).rows[0].echo).toBe(7); }); it("rows() produit un rowCount cohérent", () => { expect(rows()).toEqual({ rows: [], rowCount: 0 }); expect(rows({ a: 1 }, { a: 2 }).rowCount).toBe(2); }); }); describe("makeFakePool — transactions", () => { it("connect() renvoie un client qui partage le journal des requêtes", async () => { const pool = makeFakePool(); const client = await pool.connect(); await client.query("SELECT 1 FROM bands"); expect(pool.find("FROM bands")).toBeDefined(); }); it("détecte COMMIT et ROLLBACK séparément", async () => { const committed = makeFakePool(); const c1 = await committed.connect(); await c1.query("COMMIT"); expect(committed.committed).toBe(true); expect(committed.rolledBack).toBe(false); const rolled = makeFakePool(); const c2 = await rolled.connect(); await c2.query("ROLLBACK"); expect(rolled.rolledBack).toBe(true); expect(rolled.committed).toBe(false); }); it("compte les connexions ouvertes et libérées", async () => { const pool = makeFakePool(); const client = await pool.connect(); expect(pool.connections).toBe(1); expect(pool.released).toBe(0); client.release(); expect(pool.released).toBe(1); }); it("un pool neuf ne rapporte ni commit ni rollback", () => { const pool = makeFakePool(); expect(pool.committed).toBe(false); expect(pool.rolledBack).toBe(false); expect(pool.connections).toBe(0); expect(pool.released).toBe(0); }); });