mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-06 06:41:08 +00:00
102 lines
3.2 KiB
TypeScript
102 lines
3.2 KiB
TypeScript
import { execFile } from "node:child_process";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { configHandlers, resolveConfigOpenCommand } from "./config.js";
|
|
import { createConfigHandlerHarness } from "./config.test-helpers.js";
|
|
|
|
vi.mock("node:child_process", async (importOriginal) => {
|
|
const { mockNodeBuiltinModule } = await import("../../../test/helpers/node-builtin-mocks.js");
|
|
return mockNodeBuiltinModule(importOriginal, {
|
|
execFile: vi.fn(),
|
|
});
|
|
});
|
|
|
|
function invokeExecFileCallback(args: unknown[], error: Error | null) {
|
|
const callback = args.at(-1);
|
|
expect(callback).toEqual(expect.any(Function));
|
|
(callback as (error: Error | null) => void)(error);
|
|
}
|
|
|
|
describe("resolveConfigOpenCommand", () => {
|
|
it("uses open on macOS", () => {
|
|
expect(resolveConfigOpenCommand("/tmp/openclaw.json", "darwin")).toEqual({
|
|
command: "open",
|
|
args: ["/tmp/openclaw.json"],
|
|
});
|
|
});
|
|
|
|
it("uses xdg-open on Linux", () => {
|
|
expect(resolveConfigOpenCommand("/tmp/openclaw.json", "linux")).toEqual({
|
|
command: "xdg-open",
|
|
args: ["/tmp/openclaw.json"],
|
|
});
|
|
});
|
|
|
|
it("uses a quoted PowerShell literal on Windows", () => {
|
|
expect(resolveConfigOpenCommand(String.raw`C:\tmp\o'hai & calc.json`, "win32")).toEqual({
|
|
command: "powershell.exe",
|
|
args: [
|
|
"-NoProfile",
|
|
"-NonInteractive",
|
|
"-Command",
|
|
String.raw`Start-Process -LiteralPath 'C:\tmp\o''hai & calc.json'`,
|
|
],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("config.openFile", () => {
|
|
afterEach(() => {
|
|
delete process.env.OPENCLAW_CONFIG_PATH;
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it("opens the configured file without shell interpolation", async () => {
|
|
process.env.OPENCLAW_CONFIG_PATH = "/tmp/config $(touch pwned).json";
|
|
vi.mocked(execFile).mockImplementation(((...args: unknown[]) => {
|
|
expect(["open", "xdg-open", "powershell.exe"]).toContain(args[0]);
|
|
expect(args[1]).toEqual(["/tmp/config $(touch pwned).json"]);
|
|
invokeExecFileCallback(args, null);
|
|
return {} as never;
|
|
}) as unknown as typeof execFile);
|
|
|
|
const { options, respond } = createConfigHandlerHarness({ method: "config.openFile" });
|
|
await configHandlers["config.openFile"](options);
|
|
|
|
expect(respond).toHaveBeenCalledWith(
|
|
true,
|
|
{
|
|
ok: true,
|
|
path: "/tmp/config $(touch pwned).json",
|
|
},
|
|
undefined,
|
|
);
|
|
});
|
|
|
|
it("returns a generic error and logs details when the opener fails", async () => {
|
|
process.env.OPENCLAW_CONFIG_PATH = "/tmp/config.json";
|
|
vi.mocked(execFile).mockImplementation(((...args: unknown[]) => {
|
|
invokeExecFileCallback(
|
|
args,
|
|
Object.assign(new Error("spawn xdg-open ENOENT"), { code: "ENOENT" }),
|
|
);
|
|
return {} as never;
|
|
}) as unknown as typeof execFile);
|
|
|
|
const { options, respond, logGateway } = createConfigHandlerHarness({
|
|
method: "config.openFile",
|
|
});
|
|
await configHandlers["config.openFile"](options);
|
|
|
|
expect(respond).toHaveBeenCalledWith(
|
|
true,
|
|
{
|
|
ok: false,
|
|
path: "/tmp/config.json",
|
|
error: "failed to open config file",
|
|
},
|
|
undefined,
|
|
);
|
|
expect(logGateway.warn).toHaveBeenCalledWith(expect.stringContaining("spawn xdg-open ENOENT"));
|
|
});
|
|
});
|