Files
veille-reglementaire/server/articleReads.test.ts

45 lines
1.8 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { isDuplicateEntryError, persistArticleReads, readArticleIdsFromDb } from "./db";
function createReadDb(existingIds: number[] = []) {
const insertValues = vi.fn().mockResolvedValue(undefined);
const insert = vi.fn(() => ({ values: insertValues }));
const where = vi.fn().mockResolvedValue(existingIds.map((articleId) => ({ articleId })));
const from = vi.fn(() => ({ where }));
const select = vi.fn(() => ({ from }));
return { db: { select, insert }, insertValues };
}
describe("isDuplicateEntryError", () => {
it("identifie les erreurs de contrainte unique MySQL", () => {
expect(isDuplicateEntryError({ code: "ER_DUP_ENTRY" })).toBe(true);
expect(isDuplicateEntryError({ cause: { code: "ER_DUP_ENTRY" } })).toBe(true);
});
it("ne masque jamais une erreur SQL non liée à un doublon", () => {
expect(isDuplicateEntryError(new Error("Field 'readAt' doesn't have a default value"))).toBe(false);
expect(isDuplicateEntryError({ code: "ER_NO_DEFAULT_FOR_FIELD" })).toBe(false);
expect(isDuplicateEntryError(null)).toBe(false);
});
});
describe("persistance des articles lus", () => {
it("insère uniquement les articles encore non lus et déduplique la demande", async () => {
const { db, insertValues } = createReadDb([10]);
const inserted = await persistArticleReads(db, 2, "veille", [10, 12, 12, 13]);
expect(inserted).toBe(2);
expect(insertValues).toHaveBeenCalledWith([
{ userId: 2, articleType: "veille", articleId: 12 },
{ userId: 2, articleType: "veille", articleId: 13 },
]);
});
it("restaure les identifiants lus stockés pour le bon utilisateur et le bon flux", async () => {
const { db } = createReadDb([4, 9]);
await expect(readArticleIdsFromDb(db, 2, "aap")).resolves.toEqual([4, 9]);
});
});