64 lines
3.8 KiB
TypeScript
64 lines
3.8 KiB
TypeScript
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
import ExcelJS from "exceljs";
|
|
import { getHandler } from "../../src/engine/registry";
|
|
import type { CatalogComponent, FlowNode } from "../../src/types";
|
|
import type { RunContext } from "../../src/engine/types";
|
|
import "../../src/capabilities/excel-com";
|
|
|
|
const directories: string[] = [];
|
|
const context = {} as RunContext;
|
|
const component = {} as CatalogComponent;
|
|
const node = (id: string): FlowNode => ({ id, componentId: id, position: { x: 0, y: 0 }, values: {}, options: {} });
|
|
async function run(id: string, args: Record<string, unknown>) {
|
|
const handler = getHandler(id);
|
|
expect(handler, id).toBeTruthy();
|
|
return handler!(context, node(id), args, component);
|
|
}
|
|
afterEach(async () => Promise.all(directories.splice(0).map((directory) => rm(directory, { recursive: true, force: true }))));
|
|
|
|
const registered = [
|
|
"Excel_Cs_Group", "Excel_Cs_DeletePicture", "Excel_Cs_RefreshPivotTable", "Excel_Cs_DeletePictureV2",
|
|
"Excel_Cs_Encrypt", "Excel_Cs_Move", "Excel_Cs_InsertPicture", "Excel_Cs_Merge", "Excel_InsertImage",
|
|
"Excel_Cs_InsertPivotView", "Excel_Cs_Interop", "Excel_Cs_InsertPivotTable", "Excel_Cs_RunMacro",
|
|
"Excel_Loop", "Excel_Cs_Export", "Excel_Cs_ExcelAddin", "Excel_Cs_InsertPictureV2",
|
|
"Excel_Cs_FilterPivotTable", "Excel_Cs_RunMacroV2", "Excel_Cs_SetSlicer", "Excel_ExecuteMacro",
|
|
"Excel_Cs_RefreshAll", "Excel_DeleteImage", "Excel_ExportRangeAsPicture"
|
|
];
|
|
|
|
describe("Excel COM capabilities", () => {
|
|
it("registers every Excel COM capability", () => { for (const id of registered) expect(getHandler(id), id).toBeTruthy(); });
|
|
|
|
it("groups rows, moves sheets, reads dynamic properties and loops content", async () => {
|
|
if (process.platform !== "win32") return;
|
|
const directory = await mkdtemp(path.join(os.tmpdir(), "rpa-excel-com-")); directories.push(directory);
|
|
const filePath = path.join(directory, "workbook.xlsx");
|
|
const workbook = new ExcelJS.Workbook();
|
|
workbook.addWorksheet("Sheet1").getCell("A1").value = "A1";
|
|
workbook.addWorksheet("Second").getCell("A1").value = "S1";
|
|
await workbook.xlsx.writeFile(filePath);
|
|
|
|
await expect(run("Excel_Cs_Group", { workbook: { path: filePath }, sheet: "Sheet1", group: 0, groupType: 0, startRow: 1, endRow: 2, save: true })).resolves.toMatchObject({ grouped: true });
|
|
await expect(run("Excel_Cs_Interop", { workbook: { path: filePath }, obj: 2, sheet: "Sheet1", property: "Name" })).resolves.toMatchObject({ value: "Sheet1" });
|
|
await expect(run("Excel_Cs_Move", { workbook: { path: filePath }, sheet: "Second", mode: "按序号", index: 1, save: true })).resolves.toMatchObject({ moved: true });
|
|
await expect(run("Excel_Cs_RefreshAll", { workbook: { path: filePath }, save: true })).resolves.toMatchObject({ refreshed: true });
|
|
const loop = await run("Excel_Loop", { objExcel: { path: filePath } }) as unknown[][];
|
|
expect(loop.length).toBeGreaterThanOrEqual(2);
|
|
expect(loop.flat().join(",")).toContain("A1");
|
|
}, 120000);
|
|
|
|
it("exports a workbook to PDF through Excel COM", async () => {
|
|
if (process.platform !== "win32") return;
|
|
const directory = await mkdtemp(path.join(os.tmpdir(), "rpa-excel-pdf-")); directories.push(directory);
|
|
const filePath = path.join(directory, "source.xlsx");
|
|
const workbook = new ExcelJS.Workbook();
|
|
workbook.addWorksheet("Report").getCell("A1").value = "PDF";
|
|
await workbook.xlsx.writeFile(filePath);
|
|
const output = await run("Excel_Cs_Export", { workbook: { path: filePath }, option: "全部", path: directory, name: "report.pdf", cover: true }) as string;
|
|
expect(output).toBe(path.join(directory, "report.pdf"));
|
|
expect((await readFile(output)).subarray(0, 5).toString()).toMatch(/^%PDF-/);
|
|
}, 120000);
|
|
});
|