diff --git a/src/cli/cli-utils.test.ts b/src/cli/cli-utils.test.ts new file mode 100644 index 000000000..5e8bfee99 --- /dev/null +++ b/src/cli/cli-utils.test.ts @@ -0,0 +1,110 @@ +import { Command } from "commander"; +import { describe, expect, it, vi } from "vitest"; +import { parseCanvasSnapshotPayload } from "./nodes-canvas.js"; +import { parseByteSize } from "./parse-bytes.js"; +import { parseDurationMs } from "./parse-duration.js"; +import { shouldSkipRespawnForArgv } from "./respawn-policy.js"; +import { waitForever } from "./wait.js"; + +const { registerDnsCli } = await import("./dns-cli.js"); + +describe("waitForever", () => { + it("creates an unref'ed interval and returns a pending promise", () => { + const setIntervalSpy = vi.spyOn(global, "setInterval"); + const promise = waitForever(); + expect(setIntervalSpy).toHaveBeenCalledWith(expect.any(Function), 1_000_000); + expect(promise).toBeInstanceOf(Promise); + setIntervalSpy.mockRestore(); + }); +}); + +describe("shouldSkipRespawnForArgv", () => { + it("skips respawn for help/version calls", () => { + expect(shouldSkipRespawnForArgv(["node", "openclaw", "--help"])).toBe(true); + expect(shouldSkipRespawnForArgv(["node", "openclaw", "-V"])).toBe(true); + }); + + it("keeps respawn path for normal commands", () => { + expect(shouldSkipRespawnForArgv(["node", "openclaw", "status"])).toBe(false); + }); +}); + +describe("nodes canvas helpers", () => { + it("parses canvas.snapshot payload", () => { + expect(parseCanvasSnapshotPayload({ format: "png", base64: "aGk=" })).toEqual({ + format: "png", + base64: "aGk=", + }); + }); + + it("rejects invalid canvas.snapshot payload", () => { + expect(() => parseCanvasSnapshotPayload({ format: "png" })).toThrow( + /invalid canvas\.snapshot payload/i, + ); + }); +}); + +describe("dns cli", () => { + it("prints setup info (no apply)", async () => { + const log = vi.spyOn(console, "log").mockImplementation(() => {}); + try { + const program = new Command(); + registerDnsCli(program); + await program.parseAsync(["dns", "setup", "--domain", "openclaw.internal"], { from: "user" }); + const output = log.mock.calls.map((call) => call.join(" ")).join("\\n"); + expect(output).toContain("DNS setup"); + expect(output).toContain("openclaw.internal"); + } finally { + log.mockRestore(); + } + }); +}); + +describe("parseByteSize", () => { + it("parses bytes with units", () => { + expect(parseByteSize("10kb")).toBe(10 * 1024); + expect(parseByteSize("1mb")).toBe(1024 * 1024); + expect(parseByteSize("2gb")).toBe(2 * 1024 * 1024 * 1024); + }); + + it("parses shorthand units", () => { + expect(parseByteSize("5k")).toBe(5 * 1024); + expect(parseByteSize("1m")).toBe(1024 * 1024); + }); + + it("uses default unit when omitted", () => { + expect(parseByteSize("123")).toBe(123); + }); + + it("rejects invalid values", () => { + expect(() => parseByteSize("")).toThrow(); + expect(() => parseByteSize("nope")).toThrow(); + expect(() => parseByteSize("-5kb")).toThrow(); + }); +}); + +describe("parseDurationMs", () => { + it("parses bare ms", () => { + expect(parseDurationMs("10000")).toBe(10_000); + }); + + it("parses seconds suffix", () => { + expect(parseDurationMs("10s")).toBe(10_000); + }); + + it("parses minutes suffix", () => { + expect(parseDurationMs("1m")).toBe(60_000); + }); + + it("parses hours suffix", () => { + expect(parseDurationMs("2h")).toBe(7_200_000); + }); + + it("parses days suffix", () => { + expect(parseDurationMs("2d")).toBe(172_800_000); + }); + + it("supports decimals", () => { + expect(parseDurationMs("0.5s")).toBe(500); + }); +}); diff --git a/src/cli/dns-cli.test.ts b/src/cli/dns-cli.test.ts deleted file mode 100644 index 69d63dd28..000000000 --- a/src/cli/dns-cli.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Command } from "commander"; -import { describe, expect, it, vi } from "vitest"; - -const { registerDnsCli } = await import("./dns-cli.js"); - -describe("dns cli", () => { - it("prints setup info (no apply)", async () => { - const log = vi.spyOn(console, "log").mockImplementation(() => {}); - try { - const program = new Command(); - registerDnsCli(program); - await program.parseAsync(["dns", "setup", "--domain", "openclaw.internal"], { from: "user" }); - const output = log.mock.calls.map((call) => call.join(" ")).join("\n"); - expect(output).toContain("DNS setup"); - expect(output).toContain("openclaw.internal"); - } finally { - log.mockRestore(); - } - }); -}); diff --git a/src/cli/nodes-canvas.test.ts b/src/cli/nodes-canvas.test.ts deleted file mode 100644 index a3b7a3945..000000000 --- a/src/cli/nodes-canvas.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { parseCanvasSnapshotPayload } from "./nodes-canvas.js"; - -describe("nodes canvas helpers", () => { - it("parses canvas.snapshot payload", () => { - expect(parseCanvasSnapshotPayload({ format: "png", base64: "aGk=" })).toEqual({ - format: "png", - base64: "aGk=", - }); - }); - - it("rejects invalid canvas.snapshot payload", () => { - expect(() => parseCanvasSnapshotPayload({ format: "png" })).toThrow( - /invalid canvas\.snapshot payload/i, - ); - }); -}); diff --git a/src/cli/parse-bytes.test.ts b/src/cli/parse-bytes.test.ts deleted file mode 100644 index a0c1abcb0..000000000 --- a/src/cli/parse-bytes.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { parseByteSize } from "./parse-bytes.js"; - -describe("parseByteSize", () => { - it("parses bytes with units", () => { - expect(parseByteSize("10kb")).toBe(10 * 1024); - expect(parseByteSize("1mb")).toBe(1024 * 1024); - expect(parseByteSize("2gb")).toBe(2 * 1024 * 1024 * 1024); - }); - - it("parses shorthand units", () => { - expect(parseByteSize("5k")).toBe(5 * 1024); - expect(parseByteSize("1m")).toBe(1024 * 1024); - }); - - it("uses default unit when omitted", () => { - expect(parseByteSize("123")).toBe(123); - }); - - it("rejects invalid values", () => { - expect(() => parseByteSize("")).toThrow(); - expect(() => parseByteSize("nope")).toThrow(); - expect(() => parseByteSize("-5kb")).toThrow(); - }); -}); diff --git a/src/cli/parse-duration.test.ts b/src/cli/parse-duration.test.ts deleted file mode 100644 index ad9d6a3a6..000000000 --- a/src/cli/parse-duration.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { parseDurationMs } from "./parse-duration.js"; - -describe("parseDurationMs", () => { - it("parses bare ms", () => { - expect(parseDurationMs("10000")).toBe(10_000); - }); - - it("parses seconds suffix", () => { - expect(parseDurationMs("10s")).toBe(10_000); - }); - - it("parses minutes suffix", () => { - expect(parseDurationMs("1m")).toBe(60_000); - }); - - it("parses hours suffix", () => { - expect(parseDurationMs("2h")).toBe(7_200_000); - }); - - it("parses days suffix", () => { - expect(parseDurationMs("2d")).toBe(172_800_000); - }); - - it("supports decimals", () => { - expect(parseDurationMs("0.5s")).toBe(500); - }); -}); diff --git a/src/cli/respawn-policy.test.ts b/src/cli/respawn-policy.test.ts deleted file mode 100644 index 25e026b0a..000000000 --- a/src/cli/respawn-policy.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { shouldSkipRespawnForArgv } from "./respawn-policy.js"; - -describe("shouldSkipRespawnForArgv", () => { - it("skips respawn for help/version calls", () => { - expect(shouldSkipRespawnForArgv(["node", "openclaw", "--help"])).toBe(true); - expect(shouldSkipRespawnForArgv(["node", "openclaw", "-V"])).toBe(true); - }); - - it("keeps respawn path for normal commands", () => { - expect(shouldSkipRespawnForArgv(["node", "openclaw", "status"])).toBe(false); - }); -}); diff --git a/src/cli/wait.test.ts b/src/cli/wait.test.ts deleted file mode 100644 index 5af1ba32a..000000000 --- a/src/cli/wait.test.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { describe, expect, it, vi } from "vitest"; -import { waitForever } from "./wait.js"; - -describe("waitForever", () => { - it("creates an unref'ed interval and returns a pending promise", () => { - const setIntervalSpy = vi.spyOn(global, "setInterval"); - const promise = waitForever(); - expect(setIntervalSpy).toHaveBeenCalledWith(expect.any(Function), 1_000_000); - expect(promise).toBeInstanceOf(Promise); - setIntervalSpy.mockRestore(); - }); -});