import { describe, it, expect, vi } from "vitest"; import { PDFDocument } from "pdf-lib"; import { pdfWatermarkPlugin, type PdfWatermarkOptions } from "./index"; import { runPdfWatermark } from "./run"; import { MAX_WATERMARK_CHARS } from "./watermark"; import type { ToolContext } from "../../core/plugins/plugin-types"; const mockContext: ToolContext = { signal: new AbortController().signal, reportProgress: vi.fn(), logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() }, }; const defaultOptions: PdfWatermarkOptions = { text: "CONFIDENTIAL", orientation: "diagonal", opacity: 30, color: "light-grey", }; async function makePdfFile(): Promise { const doc = await PDFDocument.create(); doc.addPage([595, 842]); const bytes = await doc.save(); return new File([bytes as unknown as BlobPart], "sample.pdf", { type: "application/pdf", }); } describe("PDF Watermark Plugin", () => { it("should have correct manifest", () => { expect(pdfWatermarkPlugin.manifest.id).toBe("pdf-watermark"); expect(pdfWatermarkPlugin.manifest.category).toBe("pdf"); expect(pdfWatermarkPlugin.manifest.input.type).toBe("files"); expect(pdfWatermarkPlugin.manifest.output.type).toBe("files"); }); it("should throw if no file provided", async () => { await expect( runPdfWatermark({ files: [] }, defaultOptions, mockContext) ).rejects.toThrow("No PDF file provided."); }); it("should throw if watermark text is empty", async () => { const file = await makePdfFile(); await expect( runPdfWatermark({ files: [file] }, { ...defaultOptions, text: " " }, mockContext) ).rejects.toThrow("Watermark text is required."); }); it("should produce a watermarked PDF", async () => { const file = await makePdfFile(); const result = await runPdfWatermark( { files: [file] }, defaultOptions, mockContext ); expect(result.type).toBe("files"); if (result.type !== "files") throw new Error("unexpected result"); expect(result.files).toHaveLength(1); expect(result.files[0].name).toBe("sample_watermarked.pdf"); expect(result.files[0].mimeType).toBe("application/pdf"); expect(result.files[0].blob.size).toBeGreaterThan(0); // Output should still be a loadable PDF with the same page count. const out = await result.files[0].blob.arrayBuffer(); const reloaded = await PDFDocument.load(new Uint8Array(out)); expect(reloaded.getPageCount()).toBe(1); }); it.each(["horizontal", "vertical", "diagonal"] as const)( "should handle %s orientation", async (orientation) => { const file = await makePdfFile(); const result = await runPdfWatermark( { files: [file] }, { ...defaultOptions, orientation }, mockContext ); expect(result.type).toBe("files"); } ); it("should truncate text beyond the max length", async () => { const file = await makePdfFile(); const longText = "A".repeat(MAX_WATERMARK_CHARS + 50); const result = await runPdfWatermark( { files: [file] }, { ...defaultOptions, text: longText }, mockContext ); expect(result.type).toBe("files"); }); });