- engine/(registry/types/runtime/expression)物理迁入包, 解耦shared/types(域类型归包, 宿主type-only re-export) - 31个纯Node能力+27个测试迁入包; 宿主留守Electron/浏览器/AI依赖能力, index.ts经@rpa/core/capabilities拉起 - 新增createEngine()/defaultEngine: excel缓存/Excel句柄/db连接/FTP客户端/OCR实例/拟真设置挂引擎实例 - remaining-core子流程依赖改为host-bridge注入, 包内不再import宿主flows - 宿主main/index.ts启动时注入子流程源; electron-vite/vitest/tsconfig配@rpa/core源码别名 - 验证: typecheck绿, 快照909个id diff为零, 332测试过(2个桌面冒烟因会话无交互SetForegroundWindow被拒, 环境阻塞)
68 lines
3.2 KiB
TypeScript
68 lines
3.2 KiB
TypeScript
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<string, unknown>): Promise<string> {
|
|
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<string>;
|
|
}
|
|
|
|
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");
|
|
});
|
|
});
|