eCourt-Doc-Edit/addin/src/services/fileService.test.ts

99 lines
3.6 KiB
TypeScript
Raw Normal View History

2026-08-19 21:35:07 +07:00
import { getCurrentDocumentFile, DOCX_CONTENT_TYPE } from "./fileService";
interface FileMockState {
getFileCalls: number;
requestedSlices: number[];
closeCalls: number;
}
/** mock Office.context.document.getFileAsync + File.getSliceAsync/closeAsync */
function installOfficeFileMock(
slices: Uint8Array[],
options: { failSliceIndex?: number; failClose?: boolean; sliceDataForm?: "buffer" | "view" } = {}
): FileMockState {
const state: FileMockState = { getFileCalls: 0, requestedSlices: [], closeCalls: 0 };
const file = {
sliceCount: slices.length,
getSliceAsync: (index: number, callback: (result: unknown) => void) => {
state.requestedSlices.push(index);
if (options.failSliceIndex === index) {
callback({ status: "failed", error: { message: `อ่าน slice ${index} พัง (mock)` } });
} else {
// host จริงอาจส่งมาเป็น ArrayBuffer หรือ view — ทดสอบทั้งคู่
const data = options.sliceDataForm === "view" ? slices[index] : slices[index].buffer;
callback({ status: "succeeded", value: { index, data, size: slices[index].byteLength } });
}
},
closeAsync: (callback?: (result: unknown) => void) => {
state.closeCalls++;
callback?.({ status: options.failClose ? "failed" : "succeeded" });
},
};
(globalThis as unknown as Record<string, unknown>).Office = {
FileType: { Compressed: "compressed", Text: "text" },
AsyncResultStatus: { Succeeded: "succeeded", Failed: "failed" },
context: {
document: {
getFileAsync: (
_fileType: unknown,
_options: unknown,
callback: (result: unknown) => void
) => {
state.getFileCalls++;
callback({ status: "succeeded", value: file });
},
},
},
};
return state;
}
function bytes(...values: number[]): Uint8Array {
return new Uint8Array(values);
}
describe("getCurrentDocumentFile", () => {
it("ประกอบ slice หลากขนาดเป็น Blob เดียว อ่านครบทุก slice ตามลำดับ และ closeAsync หนึ่งครั้ง", async () => {
const state = installOfficeFileMock([
bytes(1, 2, 3),
bytes(4, 5),
new Uint8Array(2048).fill(9),
]);
const blob = await getCurrentDocumentFile();
expect(blob.type).toBe(DOCX_CONTENT_TYPE);
expect(blob.size).toBe(3 + 2 + 2048);
expect(state.requestedSlices).toEqual([0, 1, 2]);
expect(state.getFileCalls).toBe(1);
expect(state.closeCalls).toBe(1);
});
it("slice มาเป็น typed array view (ไม่ใช่ ArrayBuffer) ก็ประกอบได้", async () => {
const state = installOfficeFileMock([bytes(10, 20), bytes(30)], { sliceDataForm: "view" });
const blob = await getCurrentDocumentFile();
expect(blob.size).toBe(3);
expect(state.closeCalls).toBe(1);
});
it("อ่าน slice กลางที่พัง → reject พร้อม error แต่ยังเรียก closeAsync เสมอ", async () => {
const state = installOfficeFileMock([bytes(1), bytes(2), bytes(3)], { failSliceIndex: 1 });
await expect(getCurrentDocumentFile()).rejects.toThrow("อ่าน slice 1 พัง (mock)");
expect(state.closeCalls).toBe(1);
expect(state.requestedSlices).toEqual([0, 1]);
});
it("closeAsync fail เอง → ไม่ทำ flow พัง (blob ยังคืนมา)", async () => {
installOfficeFileMock([bytes(7, 8, 9)], { failClose: true });
const blob = await getCurrentDocumentFile();
expect(blob.size).toBe(3);
});
});