import { mkdtemp, 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 "../../shared/types"; import type { RunContext } from "../engine/types"; import { getHandler } from "../engine/registry"; import "./office"; import "./extended"; import "./office-file-extended"; import "./office-aliases"; import "./excel-common"; import "./common-final"; const dirs: 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) { const handler = getHandler(id); expect(handler, id).toBeTruthy(); return handler!(context, node(id), args, component); } afterEach(async () => Promise.all(dirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })))); describe("excel shared workbook store", () => { it("keeps widths/heights set by office-file-extended when excel-common saves afterwards", async () => { const directory = await mkdtemp(path.join(os.tmpdir(), "rpa-store-")); dirs.push(directory); const handle = await run("Excel_NewExcel", { filePath: directory, name: "a.xlsx", isMakedirs: "True" }) as { path: string }; await run("Excel_Cs_WriteRangeV2", { workbook: handle, sheet: "Sheet1", row: "1", column: "A", contents: [["名称", "数量", "备注"], ["鼠标", 20, "A;B"]], isSave: "True" }); await run("Excel_Cs_SetWidth", { workbook: handle, sheet: "Sheet1", columns: "A:C", width: "20", save: "True" }); await run("Excel_Cs_SetHeight", { workbook: handle, sheet: "Sheet1", rows: "1", height: "26", save: "True" }); await run("Excel_Cs_MergeCells", { workbook: handle, sheet: "Sheet1", range: "A1:C1", merge: "0", save: "True" }); await run("Excel_Cs_SetRangeBackground", { workbook: handle, sheet: "Sheet1", range: "A1:C1", color: "FFF2CC", save: "True" }); await run("Excel_SetCellFontColor", { objExcel: handle, sheet: "Sheet1", cellPos: "A1", cellColor: "FF0000", isSave: "True" }); const wb = new ExcelJS.Workbook(); await wb.xlsx.readFile(handle.path); const ws = wb.worksheets[0]; expect(ws.getColumn("A").width).toBe(20); expect(ws.getRow(1).height).toBe(26); expect(ws.model.merges).toContain("A1:C1"); expect((ws.getCell("A1").fill as ExcelJS.FillPattern).fgColor?.argb).toBe("FFFFF2CC"); expect((ws.getCell("A1").font?.color as { argb?: string } | undefined)?.argb).toBe("FFFF0000"); expect(ws.getCell("A1").value).toBe("名称"); }); it("keeps copied sheets created by office-file-extended when sheets are created and deleted later", async () => { const directory = await mkdtemp(path.join(os.tmpdir(), "rpa-store-")); dirs.push(directory); const handle = await run("Excel_NewExcel", { filePath: directory, name: "b.xlsx", isMakedirs: "True" }) as { path: string }; await run("Excel_Cs_WriteRangeV2", { workbook: handle, sheet: "Sheet1", row: "1", column: "A", contents: [["名称"]], isSave: "True" }); await run("Excel_Cs_CopyV2", { workbook: handle, sheet: "Sheet1", newSheet: "Sheet1副本", override: "True", save: "True" }); await run("Excel_CreateSheet", { workbook: handle, sheet: "临时表", save: "True" }); await run("Excel_DeleteSheet", { workbook: handle, sheet: "临时表", save: "True" }); const wb = new ExcelJS.Workbook(); await wb.xlsx.readFile(handle.path); expect(wb.worksheets.map((sheet) => sheet.name)).toEqual(["Sheet1", "Sheet1副本"]); }); it("keeps the shared instance usable after save-as switches the handle path", async () => { const directory = await mkdtemp(path.join(os.tmpdir(), "rpa-store-")); dirs.push(directory); const handle = await run("Excel_NewExcel", { filePath: directory, name: "c.xlsx", isMakedirs: "True" }) as { path: string }; await run("Excel_Cs_SetWidth", { workbook: handle, sheet: "Sheet1", columns: "A", width: "18", save: "True" }); const saved = await run("Excel_Cs_SaveAs", { workbook: handle, path: path.join(directory, "d.xlsx") }) as { path: string }; expect(saved.path).toBe(path.resolve(directory, "d.xlsx")); await run("Excel_Cs_SetHeight", { workbook: handle, sheet: "Sheet1", rows: "1", height: "30", save: "True" }); const wb = new ExcelJS.Workbook(); await wb.xlsx.readFile(path.resolve(directory, "d.xlsx")); expect(wb.worksheets[0].getColumn("A").width).toBe(18); expect(wb.worksheets[0].getRow(1).height).toBe(30); }); });