import { Command } from "commander" ;
import { describe, expect, it, vi } from "vitest" ;
import { registerDnsCli } from "./dns-cli.js" ;
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" ;
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.each([
{ argv: ["node" , "openclaw" , "--help" ] },
{ argv: ["node" , "openclaw" , "-V" ] },
] as const )("skips respawn for argv %j" , ({ argv }) => {
expect(shouldSkipRespawnForArgv([...argv]), argv.join(" " )).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.each([
["parses 10kb" , "10kb" , 10 * 1024 ],
["parses 1mb" , "1mb" , 1024 * 1024 ],
["parses 2gb" , "2gb" , 2 * 1024 * 1024 * 1024 ],
["parses shorthand 5k" , "5k" , 5 * 1024 ],
["parses shorthand 1m" , "1m" , 1024 * 1024 ],
] as const )("%s" , (_name, input, expected) => {
expect(parseByteSize(input)).toBe(expected);
});
it("uses default unit when omitted" , () => {
expect(parseByteSize("123" )).toBe(123 );
});
it.each(["" , "nope" , "-5kb" ] as const )("rejects invalid value %j" , (input) => {
expect(() => parseByteSize(input)).toThrow();
});
});
describe("parseDurationMs" , () => {
it.each([
["parses bare ms" , "10000" , 10 _000 ],
["parses seconds suffix" , "10s" , 10 _000 ],
["parses minutes suffix" , "1m" , 60 _000 ],
["parses hours suffix" , "2h" , 7 _200 _000 ],
["parses days suffix" , "2d" , 172 _800 _000 ],
["supports decimals" , "0.5s" , 500 ],
["parses composite hours+minutes" , "1h30m" , 5 _400 _000 ],
["parses composite with milliseconds" , "2m500ms" , 120 _500 ],
] as const )("%s" , (_name, input, expected) => {
expect(parseDurationMs(input)).toBe(expected);
});
it("rejects invalid composite strings" , () => {
expect(() => parseDurationMs("1h30" )).toThrow();
expect(() => parseDurationMs("1h-30m" )).toThrow();
});
});
Messung V0.5 in Prozent C=100 H=100 G=100
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-06-09)
¤
*© Formatika GbR, Deutschland