实现报销材料连续预览(07-27-yang-jun-reimbursement-readiness)
这个提交包含在:
@@ -0,0 +1,65 @@
|
||||
const {
|
||||
MaterialPreviewError,
|
||||
createReimbursementMaterialPreviewStore,
|
||||
} = require("../../../src/services/reimbursementMaterialPreview");
|
||||
|
||||
describe("reimbursement material preview store", () => {
|
||||
it("keeps material and PDF page order in a bounded short-lived bundle", async () => {
|
||||
let currentTime = 1_000;
|
||||
const store = createReimbursementMaterialPreviewStore({
|
||||
now: () => currentTime,
|
||||
randomUUID: () => "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
|
||||
rasterizePdf: vi.fn().mockResolvedValue([Buffer.from("pdf-page-1"), Buffer.from("pdf-page-2")]),
|
||||
normalizeImage: vi.fn().mockResolvedValue(Buffer.from("image-page")),
|
||||
});
|
||||
|
||||
const created = await store.createBundle({
|
||||
actorId: "actor-1",
|
||||
reimbursementId: "reimbursement-1",
|
||||
expiresAt: 2_000,
|
||||
materials: [
|
||||
{ id: "invoice-1", materialType: "invoice", materialIndex: 1, mimeType: "application/pdf", fileSize: 10 },
|
||||
{ id: "attachment-1", materialType: "attachment", materialIndex: 1, mimeType: "image/png", fileSize: 10 },
|
||||
],
|
||||
readSource: async (material) => Buffer.from(material.id),
|
||||
});
|
||||
|
||||
expect(created.bundle.pages.map((page) => [page.materialType, page.materialIndex, page.pageNumber])).toEqual([
|
||||
["invoice", 1, 1],
|
||||
["invoice", 1, 2],
|
||||
["attachment", 1, 1],
|
||||
]);
|
||||
expect(store.getPage({ bundleId: created.bundleId, pageIndex: 1 })?.page.buffer.toString()).toBe("pdf-page-2");
|
||||
|
||||
currentTime = 2_001;
|
||||
expect(store.getPage({ bundleId: created.bundleId, pageIndex: 0 })).toBeNull();
|
||||
});
|
||||
|
||||
it("rejects source and page limits without keeping a partial bundle", async () => {
|
||||
const store = createReimbursementMaterialPreviewStore({
|
||||
limits: { maxMaterials: 1, maxSourceBytes: 10, maxPages: 1 },
|
||||
rasterizePdf: vi.fn().mockResolvedValue([Buffer.from("one"), Buffer.from("two")]),
|
||||
});
|
||||
|
||||
await expect(store.createBundle({
|
||||
actorId: "actor-1",
|
||||
reimbursementId: "reimbursement-1",
|
||||
expiresAt: Date.now() + 1_000,
|
||||
materials: [
|
||||
{ id: "one", materialType: "invoice", materialIndex: 1, mimeType: "application/pdf", fileSize: 6 },
|
||||
{ id: "two", materialType: "attachment", materialIndex: 1, mimeType: "image/png", fileSize: 6 },
|
||||
],
|
||||
readSource: async () => Buffer.from("source"),
|
||||
})).rejects.toMatchObject({ code: "material_preview_material_limit" });
|
||||
|
||||
await expect(store.createBundle({
|
||||
actorId: "actor-1",
|
||||
reimbursementId: "reimbursement-1",
|
||||
expiresAt: Date.now() + 1_000,
|
||||
materials: [
|
||||
{ id: "one", materialType: "invoice", materialIndex: 1, mimeType: "application/pdf", fileSize: 6 },
|
||||
],
|
||||
readSource: async () => Buffer.from("source"),
|
||||
})).rejects.toBeInstanceOf(MaterialPreviewError);
|
||||
});
|
||||
});
|
||||
在新工单中引用
屏蔽一个用户