127 lines
6.5 KiB
TypeScript
127 lines
6.5 KiB
TypeScript
import ExcelJS from "exceljs";
|
|
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { PDFDocument } from "pdf-lib";
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
import type { CatalogComponent, FlowNode } from "../../shared/types";
|
|
import { getHandler } from "../engine/registry";
|
|
import type { RunContext } from "../engine/types";
|
|
import "./office-file-extended";
|
|
|
|
const directories: string[] = [];
|
|
const context = {} as RunContext;
|
|
const component = {} as CatalogComponent;
|
|
const node = (componentId: string): FlowNode => ({
|
|
id: `office_file_extended_${componentId}`,
|
|
componentId,
|
|
position: { x: 0, y: 0 },
|
|
values: {},
|
|
options: {}
|
|
});
|
|
|
|
async function temporaryDirectory(): Promise<string> {
|
|
const directory = await mkdtemp(path.join(os.tmpdir(), "rpa-office-file-extended-"));
|
|
directories.push(directory);
|
|
return directory;
|
|
}
|
|
|
|
async function run(componentId: string, args: Record<string, unknown>): Promise<unknown> {
|
|
const handler = getHandler(componentId);
|
|
expect(handler, `${componentId} should be registered`).toBeTruthy();
|
|
return handler!(context, node(componentId), args, component);
|
|
}
|
|
|
|
afterEach(async () => {
|
|
await Promise.all(directories.splice(0).map((directory) => rm(directory, { recursive: true, force: true })));
|
|
});
|
|
|
|
describe("extended Office and file capabilities", () => {
|
|
it("registers audited catalog component ids", async () => {
|
|
const catalog = JSON.parse(await readFile(path.resolve("resources/catalog.json"), "utf8")) as { components: Array<{ id: string }> };
|
|
const catalogIds = new Set(catalog.components.map((item) => item.id));
|
|
for (const id of [
|
|
"Excel_Cs_ReadRowCount", "Excel_Cs_ReadCellFormula", "Excel_Cs_GetPath", "Excel_GetPath",
|
|
"Excel_Cs_ConvertColumn", "Excel_Cs_GetEmptyCell", "Excel_Cs_ReadColumn", "Excel_GetColDataNew",
|
|
"Excel_Cs_DeleteRow", "Excel_Cs_DeleteColumn", "Excel_Cs_ClearRangeV4", "Excel_Cs_MergeCells",
|
|
"Excel_Cs_SetHeight", "Excel_Cs_SetWidth", "Excel_Cs_CopyV2", "PDF_CreateNewPdf", "PDF_GetPdfInformation"
|
|
]) {
|
|
expect(catalogIds.has(id), `${id} should exist in catalog.json`).toBe(true);
|
|
expect(getHandler(id), `${id} should be registered`).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
it("reads formulas, rows, columns, paths, and empty cells from a real workbook", async () => {
|
|
const directory = await temporaryDirectory();
|
|
const filePath = path.join(directory, "read.xlsx");
|
|
const workbook = new ExcelJS.Workbook();
|
|
const sheet = workbook.addWorksheet("Data");
|
|
sheet.getCell("A1").value = "name";
|
|
sheet.getCell("A2").value = "alpha";
|
|
sheet.getCell("A3").value = "beta";
|
|
sheet.getCell("B1").value = 2;
|
|
sheet.getCell("B2").value = 3;
|
|
sheet.getCell("B3").value = { formula: "SUM(B1:B2)", result: 5 };
|
|
await workbook.xlsx.writeFile(filePath);
|
|
|
|
await expect(run("Excel_Cs_ReadRowCount", { workbook: filePath, sheet: "Data", range: "all" })).resolves.toBe(3);
|
|
await expect(run("Excel_Cs_ReadCellFormula", { workbook: filePath, sheet: "Data", column: "B", row: 3 })).resolves.toBe("SUM(B1:B2)");
|
|
await expect(run("Excel_Cs_GetEmptyCell", { workbook: filePath, sheet: "Data", column: "A", row: 1 })).resolves.toBe("A4");
|
|
await expect(run("Excel_Cs_ReadColumn", { workbook: filePath, sheet: "Data", columnName: "A" })).resolves.toEqual(["name", "alpha", "beta"]);
|
|
await expect(run("Excel_GetColDataNew", { objExcel: filePath, sheet: "Data", column: "B" })).resolves.toEqual([2, 3, 5]);
|
|
await expect(run("Excel_Cs_GetPath", { workbook: { path: filePath } })).resolves.toBe(filePath);
|
|
await expect(run("Excel_GetPath", { objExcel: filePath })).resolves.toBe(filePath);
|
|
await expect(run("Excel_Cs_ConvertColumn", { convertInput: 28, convertType: "0" })).resolves.toBe("AB");
|
|
await expect(run("Excel_Cs_ConvertColumn", { convertInput: "AB", convertType: "1" })).resolves.toBe(28);
|
|
});
|
|
|
|
it("mutates rows, columns, ranges, dimensions, merged cells, and sheets on disk", async () => {
|
|
const directory = await temporaryDirectory();
|
|
const filePath = path.join(directory, "mutate.xlsx");
|
|
const workbook = new ExcelJS.Workbook();
|
|
const sheet = workbook.addWorksheet("Data");
|
|
sheet.addRows([["a", "b", "c"], [1, 2, 3], [4, 5, 6]]);
|
|
await workbook.xlsx.writeFile(filePath);
|
|
|
|
await run("Excel_Cs_SetHeight", { workbook: filePath, sheet: "Data", rows: "1-2", height: 25, save: "1" });
|
|
await run("Excel_Cs_SetWidth", { workbook: filePath, sheet: "Data", columns: "A,B", width: 18, save: "1" });
|
|
await run("Excel_Cs_ClearRangeV4", { workbook: filePath, sheet: "Data", excelRng: "B2:B2", save: "1" });
|
|
await run("Excel_Cs_MergeCells", { workbook: filePath, sheet: "Data", range: "A4:B4", merge: "0", save: "1" });
|
|
await run("Excel_Cs_CopyV2", { workbook: filePath, sheet: "Data", newSheet: "Copy", save: "1" });
|
|
await run("Excel_Cs_DeleteRow", { workbook: filePath, sheet: "Copy", row: 2, mode: "single", save: "1" });
|
|
await run("Excel_Cs_DeleteColumn", { workbook: filePath, sheet: "Copy", column: "C", mode: "single", save: "1" });
|
|
|
|
const saved = new ExcelJS.Workbook();
|
|
await saved.xlsx.readFile(filePath);
|
|
const data = saved.getWorksheet("Data")!;
|
|
const copy = saved.getWorksheet("Copy")!;
|
|
expect(data.getRow(1).height).toBe(25);
|
|
expect(data.getColumn("A").width).toBe(18);
|
|
expect(data.getCell("B2").value).toBeNull();
|
|
expect(data.getCell("A4").isMerged).toBe(true);
|
|
expect(copy.getCell("A2").value).toBe(4);
|
|
expect(copy.getCell("C1").value).toBeNull();
|
|
});
|
|
|
|
it("extracts selected pages and returns metadata from real PDF files", async () => {
|
|
const directory = await temporaryDirectory();
|
|
const sourcePath = path.join(directory, "source.pdf");
|
|
const document = await PDFDocument.create();
|
|
document.setTitle("RPA Test");
|
|
document.setAuthor("Codex");
|
|
document.addPage([100, 100]);
|
|
document.addPage([200, 200]);
|
|
document.addPage([300, 300]);
|
|
await writeFile(sourcePath, await document.save());
|
|
|
|
const output = await run("PDF_CreateNewPdf", { fileInPath: sourcePath, pdfRange: "pages", pdfNum: "1,3", newPdfPath: directory }) as string;
|
|
const extracted = await PDFDocument.load(await readFile(output));
|
|
expect(extracted.getPageCount()).toBe(2);
|
|
expect(extracted.getPage(0).getWidth()).toBe(100);
|
|
expect(extracted.getPage(1).getWidth()).toBe(300);
|
|
await expect(run("PDF_GetPdfInformation", { fileInPath: sourcePath })).resolves.toMatchObject({
|
|
path: sourcePath, fileName: "source.pdf", pageCount: 3, title: "RPA Test", author: "Codex"
|
|
});
|
|
});
|
|
});
|