132 lines
4.5 KiB
TypeScript
132 lines
4.5 KiB
TypeScript
/**
|
|
* Tests for src/modules/pdf-utils/injectPdfMetadata.ts
|
|
*
|
|
* Uses pdf-lib to create a real in-memory PDF and verifies
|
|
* metadata injection behavior.
|
|
*/
|
|
|
|
import { describe, test, expect } from "bun:test";
|
|
import { PDFDocument } from "pdf-lib";
|
|
import {
|
|
injectPdfMetadata,
|
|
type DownloadMetadata,
|
|
} from "../../src/modules/pdf-utils/injectPdfMetadata";
|
|
|
|
async function createBlankPdf(keywords?: string): Promise<Uint8Array> {
|
|
const doc = await PDFDocument.create();
|
|
doc.addPage([612, 792]);
|
|
if (keywords) {
|
|
doc.setKeywords([keywords]);
|
|
}
|
|
return doc.save();
|
|
}
|
|
|
|
describe("injectPdfMetadata", () => {
|
|
test("injects required metadata keywords into a blank PDF", async () => {
|
|
const pdfBytes = await createBlankPdf();
|
|
const metadata: DownloadMetadata = {
|
|
downloadedAt: "2026-03-01T12:00:00Z",
|
|
downloadedById: "user-42",
|
|
};
|
|
|
|
const result = await injectPdfMetadata(pdfBytes, metadata);
|
|
|
|
// Result should be a Uint8Array (valid PDF)
|
|
expect(result).toBeInstanceOf(Uint8Array);
|
|
expect(result.length).toBeGreaterThan(0);
|
|
|
|
// Re-parse and check keywords
|
|
const doc = await PDFDocument.load(result);
|
|
const keywords = doc.getKeywords();
|
|
expect(keywords).toContain("downloadedAt:2026-03-01T12:00:00Z");
|
|
expect(keywords).toContain("downloadedById:user-42");
|
|
});
|
|
|
|
test("appends to existing keywords with separator", async () => {
|
|
const existingKeywords = "createdBy:system; theme:default";
|
|
const pdfBytes = await createBlankPdf(existingKeywords);
|
|
const metadata: DownloadMetadata = {
|
|
downloadedAt: "2026-03-01T12:00:00Z",
|
|
downloadedById: "user-42",
|
|
};
|
|
|
|
const result = await injectPdfMetadata(pdfBytes, metadata);
|
|
const doc = await PDFDocument.load(result);
|
|
const keywords = doc.getKeywords() ?? "";
|
|
|
|
// Should start with existing keywords
|
|
expect(keywords).toContain("createdBy:system; theme:default");
|
|
// Should have separator then new keywords
|
|
expect(keywords).toContain("; downloadedAt:");
|
|
expect(keywords).toContain("downloadedById:user-42");
|
|
});
|
|
|
|
test("includes optional name and email when provided", async () => {
|
|
const pdfBytes = await createBlankPdf();
|
|
const metadata: DownloadMetadata = {
|
|
downloadedAt: "2026-03-01T12:00:00Z",
|
|
downloadedById: "user-42",
|
|
downloadedByName: "Jane Doe",
|
|
downloadedByEmail: "jane@example.com",
|
|
};
|
|
|
|
const result = await injectPdfMetadata(pdfBytes, metadata);
|
|
const doc = await PDFDocument.load(result);
|
|
const keywords = doc.getKeywords() ?? "";
|
|
|
|
expect(keywords).toContain("downloadedByName:Jane Doe");
|
|
expect(keywords).toContain("downloadedByEmail:jane@example.com");
|
|
});
|
|
|
|
test("omits optional name/email when not provided", async () => {
|
|
const pdfBytes = await createBlankPdf();
|
|
const metadata: DownloadMetadata = {
|
|
downloadedAt: "2026-03-01T12:00:00Z",
|
|
downloadedById: "user-42",
|
|
};
|
|
|
|
const result = await injectPdfMetadata(pdfBytes, metadata);
|
|
const doc = await PDFDocument.load(result);
|
|
const keywords = doc.getKeywords() ?? "";
|
|
|
|
expect(keywords).not.toContain("downloadedByName");
|
|
expect(keywords).not.toContain("downloadedByEmail");
|
|
});
|
|
|
|
test("updates ModificationDate (save() applies current time by default)", async () => {
|
|
const pdfBytes = await createBlankPdf();
|
|
const metadata: DownloadMetadata = {
|
|
downloadedAt: "2026-03-01T12:00:00Z",
|
|
downloadedById: "user-42",
|
|
};
|
|
|
|
const before = Date.now();
|
|
const result = await injectPdfMetadata(pdfBytes, metadata);
|
|
const after = Date.now();
|
|
const doc = await PDFDocument.load(result);
|
|
const modDate = doc.getModificationDate();
|
|
|
|
expect(modDate).toBeInstanceOf(Date);
|
|
// pdf-lib's save() overrides ModificationDate with current time (updateMetadata defaults to true),
|
|
// so we just verify the date is recent rather than matching downloadedAt exactly.
|
|
expect(modDate!.getTime()).toBeGreaterThanOrEqual(before - 2000);
|
|
expect(modDate!.getTime()).toBeLessThanOrEqual(after + 2000);
|
|
});
|
|
|
|
test("works with Buffer input", async () => {
|
|
const pdfBytes = await createBlankPdf();
|
|
const bufferInput = Buffer.from(pdfBytes);
|
|
const metadata: DownloadMetadata = {
|
|
downloadedAt: "2026-03-01T12:00:00Z",
|
|
downloadedById: "user-1",
|
|
};
|
|
|
|
const result = await injectPdfMetadata(bufferInput, metadata);
|
|
expect(result).toBeInstanceOf(Uint8Array);
|
|
|
|
const doc = await PDFDocument.load(result);
|
|
const keywords = doc.getKeywords() ?? "";
|
|
expect(keywords).toContain("downloadedById:user-1");
|
|
});
|
|
});
|