Files
demat-facturation/server/invoiceDisputes.test.ts
Manus a6d90a90c3
Some checks failed
Validation applicative / TypeScript, tests et build (push) Failing after 2m14s
feat: ajouter les factures litiges et leurs commentaires (recette)
2026-11-03 14:45:05 +00:00

56 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { TrpcContext } from "./_core/context";
const db = vi.hoisted(() => ({ getDisputedInvoices: vi.fn(), getInvoiceById: vi.fn(), updateInvoice: vi.fn() }));
vi.mock("./db", () => db);
import { listDisputes, setDispute } from "./invoiceDisputes";
import { router } from "./_core/trpc";
const routes = router({ listDisputes, setDispute });
function caller(role = "user", id = 2) {
return routes.createCaller({ user: { id, role }, req: {}, res: {} } as TrpcContext);
}
beforeEach(() => {
vi.clearAllMocks();
db.getInvoiceById.mockResolvedValue({ id: 10, userId: 2, isDisputed: 0, disputeComment: "existant", bapValidated: 1, exportStatus: "exported" });
db.getDisputedInvoices.mockResolvedValue([]);
});
describe("Factures litiges", () => {
it("ajoute le litige et son commentaire sans modifier BAP, score ou export", async () => {
await caller().setDispute({ id: 10, isDisputed: true, comment: " À vérifier " });
expect(db.updateInvoice).toHaveBeenCalledWith(10, { isDisputed: 1, disputeComment: "À vérifier" });
});
it("modifie le commentaire", async () => {
await caller().setDispute({ id: 10, isDisputed: true, comment: "Nouveau commentaire" });
expect(db.updateInvoice).toHaveBeenCalledWith(10, { isDisputed: 1, disputeComment: "Nouveau commentaire" });
});
it.each([null, "", " "])("efface le commentaire avec %s sans retirer le litige", async comment => {
await caller().setDispute({ id: 10, isDisputed: true, comment });
expect(db.updateInvoice).toHaveBeenCalledWith(10, { isDisputed: 1, disputeComment: null });
});
it("retire le litige sans supprimer la facture ni son commentaire", async () => {
await caller().setDispute({ id: 10, isDisputed: false });
expect(db.updateInvoice).toHaveBeenCalledWith(10, { isDisputed: 0 });
});
it("empêche l’accès à une facture d’un autre utilisateur", async () => {
await expect(caller("user", 3).setDispute({ id: 10, isDisputed: true })).rejects.toMatchObject({ code: "NOT_FOUND" });
expect(db.updateInvoice).not.toHaveBeenCalled();
});
it("autorise l’administrateur sur les factures globales", async () => {
await caller("admin", 3).setDispute({ id: 10, isDisputed: true });
expect(db.updateInvoice).toHaveBeenCalledOnce();
await caller("admin", 3).listDisputes();
expect(db.getDisputedInvoices).toHaveBeenCalledWith(undefined);
});
it("limite la liste aux factures de l’utilisateur", async () => {
await caller().listDisputes();
expect(db.getDisputedInvoices).toHaveBeenCalledWith(2);
});
it("interdit la modification en lecture seule", async () => {
await expect(caller("readonly").setDispute({ id: 10, isDisputed: true })).rejects.toMatchObject({ code: "FORBIDDEN" });
expect(db.updateInvoice).not.toHaveBeenCalled();
});
it("exige une session et limite les commentaires à 5000 caractères", async () => {
await expect(routes.createCaller({ user: null } as TrpcContext).listDisputes()).rejects.toMatchObject({ code: "UNAUTHORIZED" });
await expect(caller().setDispute({ id: 10, isDisputed: true, comment: "x".repeat(5001) })).rejects.toMatchObject({ code: "BAD_REQUEST" });
});
});