import { ContractViewModelBuilder, ContractSignatureView } from "./contract-view-model.builder"; /** * The EDR side of a contract is sealed with the ONE global company stamp, read * live at render time; the client side keeps whatever stamp the customer * uploaded. These specs pin that asymmetry — the standing rule is that * centralizing the EDR seal must not touch customer stamps. */ describe("ContractViewModelBuilder.attachProviderStamp", () => { const STAMP = "data:image/png;base64,RURS"; const build = (stampImageUrl: string | null = STAMP) => { const getStampImageUrl = jest.fn().mockResolvedValue(stampImageUrl); const builder = Object.create( ContractViewModelBuilder.prototype, ) as ContractViewModelBuilder; Object.assign(builder, { stampSettings: { getStampImageUrl } }); return { builder, getStampImageUrl }; }; const sig = (role: "STAFF" | "CUSTOMER", extra: Partial = {}) => ({ role, signerDisplayName: `${role} signer`, signedAt: "1 January 2026", signatureImageUrl: "https://minio.local/sig.png", ...extra, }) as ContractSignatureView; it("stamps the EDR side with the global stamp", async () => { const { builder } = build(); const signatures = [sig("STAFF")]; await builder.attachProviderStamp(signatures); expect(signatures[0]!.stampImageUrl).toBe(STAMP); }); it("leaves the customer side untouched", async () => { const { builder } = build(); const customerStamp = "data:image/png;base64,Q1VTVA=="; const signatures = [ sig("CUSTOMER", { stampImageUrl: customerStamp }), sig("STAFF"), ]; await builder.attachProviderStamp(signatures); expect(signatures[0]!.stampImageUrl).toBe(customerStamp); expect(signatures[1]!.stampImageUrl).toBe(STAMP); }); it("does not read the stamp at all when EDR has not signed yet", async () => { const { builder, getStampImageUrl } = build(); const signatures = [sig("CUSTOMER")]; await builder.attachProviderStamp(signatures); expect(getStampImageUrl).not.toHaveBeenCalled(); expect(signatures[0]!.stampImageUrl).toBeUndefined(); }); it("renders unstamped rather than failing when no stamp is configured", async () => { const { builder } = build(null); const signatures = [sig("STAFF")]; await expect(builder.attachProviderStamp(signatures)).resolves.toBeUndefined(); expect(signatures[0]!.stampImageUrl).toBeNull(); }); it("reads the stamp once for every EDR signature row", async () => { const { builder, getStampImageUrl } = build(); const signatures = [sig("STAFF"), sig("STAFF")]; await builder.attachProviderStamp(signatures); expect(getStampImageUrl).toHaveBeenCalledTimes(1); expect(signatures.map((s) => s.stampImageUrl)).toEqual([STAMP, STAMP]); }); it("is applied by loadSignatures, so the HTML view and the PDF agree", async () => { const { builder } = build(); Object.assign(builder, { bookingsRepository: { findContractSignatures: jest.fn().mockResolvedValue([ { signerRole: "STAFF", signerDisplayName: "EDR", signedAt: new Date() }, ]), }, }); const views = await ( builder as unknown as { loadSignatures(id: string): Promise; } ).loadSignatures("b-1"); expect(views[0]!.stampImageUrl).toBe(STAMP); }); });