Files
clawdbot/src/cli/nodes-cli.coverage.test.ts
2026-01-04 00:54:44 +01:00

205 lines
4.9 KiB
TypeScript

import { Command } from "commander";
import { describe, expect, it, vi } from "vitest";
const callGateway = vi.fn(async (opts: { method?: string }) => {
if (opts.method === "node.list") {
return {
nodes: [
{
nodeId: "mac-1",
displayName: "Mac",
platform: "macos",
caps: ["canvas"],
connected: true,
permissions: { screenRecording: true },
},
],
};
}
if (opts.method === "node.invoke") {
return {
payload: {
stdout: "",
stderr: "",
exitCode: 0,
success: true,
timedOut: false,
},
};
}
return { ok: true };
});
const randomIdempotencyKey = vi.fn(() => "rk_test");
const runtimeLogs: string[] = [];
const runtimeErrors: string[] = [];
const defaultRuntime = {
log: (msg: string) => runtimeLogs.push(msg),
error: (msg: string) => runtimeErrors.push(msg),
exit: (code: number) => {
throw new Error(`__exit__:${code}`);
},
};
vi.mock("../gateway/call.js", () => ({
callGateway: (opts: unknown) => callGateway(opts as { method?: string }),
randomIdempotencyKey: () => randomIdempotencyKey(),
}));
vi.mock("../runtime.js", () => ({
defaultRuntime,
}));
describe("nodes-cli coverage", () => {
it("lists nodes via node.list", async () => {
runtimeLogs.length = 0;
runtimeErrors.length = 0;
callGateway.mockClear();
const { registerNodesCli } = await import("./nodes-cli.js");
const program = new Command();
program.exitOverride();
registerNodesCli(program);
await program.parseAsync(["nodes", "status"], { from: "user" });
expect(callGateway).toHaveBeenCalled();
expect(callGateway.mock.calls[0]?.[0]?.method).toBe("node.list");
expect(runtimeErrors).toHaveLength(0);
});
it("invokes system.run with parsed params", async () => {
runtimeLogs.length = 0;
runtimeErrors.length = 0;
callGateway.mockClear();
randomIdempotencyKey.mockClear();
const { registerNodesCli } = await import("./nodes-cli.js");
const program = new Command();
program.exitOverride();
registerNodesCli(program);
await program.parseAsync(
[
"nodes",
"run",
"--node",
"mac-1",
"--cwd",
"/tmp",
"--env",
"FOO=bar",
"--command-timeout",
"1200",
"--needs-screen-recording",
"--invoke-timeout",
"5000",
"echo",
"hi",
],
{ from: "user" },
);
const invoke = callGateway.mock.calls.find(
(call) => call[0]?.method === "node.invoke",
)?.[0];
expect(invoke).toBeTruthy();
expect(invoke?.params?.idempotencyKey).toBe("rk_test");
expect(invoke?.params?.command).toBe("system.run");
expect(invoke?.params?.params).toEqual({
command: ["echo", "hi"],
cwd: "/tmp",
env: { FOO: "bar" },
timeoutMs: 1200,
needsScreenRecording: true,
});
expect(invoke?.params?.timeoutMs).toBe(5000);
});
it("invokes system.notify with provided fields", async () => {
runtimeLogs.length = 0;
runtimeErrors.length = 0;
callGateway.mockClear();
const { registerNodesCli } = await import("./nodes-cli.js");
const program = new Command();
program.exitOverride();
registerNodesCli(program);
await program.parseAsync(
[
"nodes",
"notify",
"--node",
"mac-1",
"--title",
"Ping",
"--body",
"Gateway ready",
"--delivery",
"overlay",
],
{ from: "user" },
);
const invoke = callGateway.mock.calls.find(
(call) => call[0]?.method === "node.invoke",
)?.[0];
expect(invoke).toBeTruthy();
expect(invoke?.params?.command).toBe("system.notify");
expect(invoke?.params?.params).toEqual({
title: "Ping",
body: "Gateway ready",
sound: undefined,
priority: undefined,
delivery: "overlay",
});
});
it("invokes location.get with params", async () => {
runtimeLogs.length = 0;
runtimeErrors.length = 0;
callGateway.mockClear();
const { registerNodesCli } = await import("./nodes-cli.js");
const program = new Command();
program.exitOverride();
registerNodesCli(program);
await program.parseAsync(
[
"nodes",
"location",
"get",
"--node",
"mac-1",
"--accuracy",
"precise",
"--max-age",
"1000",
"--location-timeout",
"5000",
"--invoke-timeout",
"6000",
],
{ from: "user" },
);
const invoke = callGateway.mock.calls.find(
(call) => call[0]?.method === "node.invoke",
)?.[0];
expect(invoke).toBeTruthy();
expect(invoke?.params?.command).toBe("location.get");
expect(invoke?.params?.params).toEqual({
maxAgeMs: 1000,
desiredAccuracy: "precise",
timeoutMs: 5000,
});
expect(invoke?.params?.timeoutMs).toBe(6000);
});
});