import { mkdtemp, readFile, readdir, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import ExcelJS from "exceljs"; import { afterEach, describe, expect, it } from "vitest"; import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler } from "../engine/registry"; import "./extended"; const directories: string[] = []; const context = {} as RunContext; const component = {} as CatalogComponent; const node = (componentId: string): FlowNode => ({ id: `extended_${componentId}`, componentId, position: { x: 0, y: 0 }, values: {}, options: {} }); async function temporaryDirectory(): Promise { const directory = await mkdtemp(path.join(os.tmpdir(), "rpa-extended-")); directories.push(directory); return directory; } async function run(componentId: string, args: Record): Promise { 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 local capabilities", () => { it("registers every audited component id", () => { for (const id of [ "File_GetFileList_V1", "File_GetFolderList", "File_GetFolderList_V1", "File_MoveFolder", "File_Write_V1", "File_Copy_V1", "File_Rename_V1", "File_ReadXml", "File_EmptyFolder", "Bivartable_ReadDfShape", "Bivartable_SortDf", "Bivartable_DoSort", "Bivartable_DelDfColRow", "Bivartable_ReadTable", "Excel_Cs_ReadCell", "Excel_GetRowsCount", "Excel_GetColumnsCount", "Excel_Cs_GetEditRange" ]) expect(getHandler(id), id).toBeTruthy(); }); it("performs file listing, copy, rename, XML read, move, and empty operations", async () => { const root = await temporaryDirectory(); const source = path.join(root, "source"); const nested = path.join(source, "nested"); await run("File_Write_V1", { path: path.join(source, "alpha.xml"), content: "RPA" }); await run("File_Write_V1", { path: path.join(nested, "beta.txt"), content: "beta" }); await expect(run("File_GetFileList_V1", { folder_path: source, recursive: "1", is_full_path: "0" })) .resolves.toEqual(["alpha.xml", "beta.txt"]); await expect(run("File_GetFolderList", { folder_path: source, recursive: "1" })) .resolves.toEqual([nested]); await expect(run("File_ReadXml", { path: path.join(source, "alpha.xml") })) .resolves.toBe("RPA"); const copied = await run("File_Copy_V1", { file_type: "file", file_path: path.join(source, "alpha.xml"), target_path: root, rename: "1", name: "copied.xml", action: "1" }) as string; await expect(readFile(copied, "utf8")).resolves.toContain("RPA"); const renamed = await run("File_Rename_V1", { file_type: "file", file_path: copied, name: "renamed.xml", action: "1" }) as string; await expect(readFile(renamed, "utf8")).resolves.toContain("RPA"); const moved = path.join(root, "moved"); await run("File_MoveFolder", { pathSrc: nested, pathDest: moved, overwrite: "True" }); await expect(readFile(path.join(moved, "beta.txt"), "utf8")).resolves.toBe("beta"); await run("File_EmptyFolder", { folder_path: moved }); await expect(readdir(moved)).resolves.toEqual([]); }); it("sorts, measures, deletes, and selects two-dimensional data", async () => { const input = [["name", "score"], ["B", 2], ["A", 3], ["C", 1]]; await expect(run("Bivartable_ReadDfShape", { df: input })).resolves.toEqual([4, 2]); await expect(run("Bivartable_SortDf", { df: input, name: "score", sort: "True" })) .resolves.toEqual([["name", "score"], ["C", 1], ["B", 2], ["A", 3]]); await expect(run("Bivartable_DoSort", { df: [[3], [1], [2]], sortby: "1", basceeding: "False" })) .resolves.toEqual([[3], [2], [1]]); await expect(run("Bivartable_DelDfColRow", { df: input, delRange: "col", delType: "name", del_col_name_list: ["score"] })) .resolves.toEqual([["name"], ["B"], ["A"], ["C"]]); await expect(run("Bivartable_ReadTable", { df: input, start_row: "2", end_row: "3", start_column: "A", end_column: "B" })) .resolves.toEqual([["B", 2], ["A", 3]]); }); it("reads Excel cells, dimensions, and the edited range", async () => { const root = await temporaryDirectory(); const filePath = path.join(root, "extended.xlsx"); const workbook = new ExcelJS.Workbook(); const sheet = workbook.addWorksheet("Data"); sheet.getCell("B2").value = "RPA"; sheet.getCell("D5").value = 42; await workbook.xlsx.writeFile(filePath); await expect(run("Excel_Cs_ReadCell", { workbook: filePath, sheet: "Data", column: "B", row: "2" })).resolves.toBe("RPA"); await expect(run("Excel_GetRowsCount", { objExcel: filePath, sheet: "Data" })).resolves.toBe(5); await expect(run("Excel_GetColumnsCount", { objExcel: filePath, sheet: "Data" })).resolves.toBe(4); await expect(run("Excel_Cs_GetEditRange", { workbook: { path: filePath }, sheet: "Data" })).resolves.toEqual({ startRow: 2, startColumn: 2, endRow: 5, endColumn: 4, range: "B2:D5" }); }); });