import { existsSync, readdirSync, readFileSync } from "node:fs"; import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it, vi } from "vitest"; import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler } from "../engine/registry"; import "./files"; function run(id: string, args: Record): Promise { const node: FlowNode = { id: "file-test", componentId: id, values: args, options: {}, position: { x: 0, y: 0 } }; const handler = getHandler(id)!; return Promise.resolve(handler({ signal: new AbortController().signal, log: vi.fn(), vars: {} } as unknown as RunContext, node, args, {} as CatalogComponent)) as Promise; } const temporary: string[] = []; afterEach(() => { for (const dir of temporary.splice(0)) rm(dir, { recursive: true, force: true }); }); describe("file compression path semantics", () => { it("defaults to a sibling archive and creates a copy instead of overwriting", async () => { const dir = await mkdtemp(path.join(os.tmpdir(), "rpa-file-compress-")); temporary.push(dir); const source = path.join(dir, "report.txt"); await writeFile(source, "hello", "utf8"); const first = await run("File_CompressFile", { file_type: "openFile", file_path: source, direct_type: "1" }); expect(first).toBe(path.join(dir, "report.txt.zip")); expect(existsSync(first)).toBe(true); const second = await run("File_CompressFile", { file_type: "openFile", file_path: source, direct_type: "1" }); expect(second).toBe(path.join(dir, "report.txt (1).zip")); expect(existsSync(second)).toBe(true); }); it("accepts an output directory when custom destination is selected", async () => { const dir = await mkdtemp(path.join(os.tmpdir(), "rpa-file-compress-")); temporary.push(dir); const source = path.join(dir, "logs"); const output = path.join(dir, "output"); await Promise.all([mkdir(source), mkdir(output)]); await writeFile(path.join(source, "app.log"), "log", "utf8"); const target = await run("File_CompressFile", { file_type: "openDirectory", folder_path: source, direct_type: "0", out_path: output }); expect(target).toBe(path.join(output, "logs.zip")); expect(existsSync(target)).toBe(true); }); it("extracts beside the archive by default and to the selected folder for custom mode", async () => { const dir = await mkdtemp(path.join(os.tmpdir(), "rpa-file-extract-")); temporary.push(dir); const source = path.join(dir, "logs.zip"); const AdmZip = (await import("adm-zip")).default; const zip = new AdmZip(); zip.addFile("app.log", Buffer.from("log", "utf8")); zip.writeZip(source); const defaultTarget = await run("File_DecompressFile", { folder_path: source, direct_type: "1" }); expect(defaultTarget).toBe(dir); expect(readFileSync(path.join(dir, "app.log"), "utf8")).toBe("log"); const custom = path.join(dir, "custom-output"); const customTarget = await run("File_DecompressFile", { folder_path: source, direct_type: "0", out_path: custom }); expect(customTarget).toBe(custom); expect(readdirSync(custom)).toContain("app.log"); }); });