test: dedupe and optimize test suites
This commit is contained in:
@@ -30,6 +30,24 @@ async function expectLoggedSingleMediaFile(params?: {
|
||||
return mediaPath;
|
||||
}
|
||||
|
||||
function expectParserAcceptsUrlWithoutBase64(
|
||||
parse: (payload: Record<string, unknown>) => { url?: string; base64?: string },
|
||||
payload: Record<string, unknown>,
|
||||
expectedUrl: string,
|
||||
) {
|
||||
const result = parse(payload);
|
||||
expect(result.url).toBe(expectedUrl);
|
||||
expect(result.base64).toBeUndefined();
|
||||
}
|
||||
|
||||
function expectParserRejectsMissingMedia(
|
||||
parse: (payload: Record<string, unknown>) => unknown,
|
||||
payload: Record<string, unknown>,
|
||||
expectedMessage: string,
|
||||
) {
|
||||
expect(() => parse(payload)).toThrow(expectedMessage);
|
||||
}
|
||||
|
||||
const IOS_NODE = {
|
||||
nodeId: "ios-node",
|
||||
displayName: "iOS Node",
|
||||
@@ -61,6 +79,31 @@ function mockNodeGateway(command?: string, payload?: Record<string, unknown>) {
|
||||
const { buildProgram } = await import("./program.js");
|
||||
|
||||
describe("cli program (nodes media)", () => {
|
||||
function createProgramWithCleanRuntimeLog() {
|
||||
const program = buildProgram();
|
||||
runtime.log.mockClear();
|
||||
return program;
|
||||
}
|
||||
|
||||
async function runNodesCommand(argv: string[]) {
|
||||
const program = createProgramWithCleanRuntimeLog();
|
||||
await program.parseAsync(argv, { from: "user" });
|
||||
}
|
||||
|
||||
async function runAndExpectUrlPayloadMediaFile(params: {
|
||||
command: "camera.snap" | "camera.clip";
|
||||
payload: Record<string, unknown>;
|
||||
argv: string[];
|
||||
expectedPathPattern: RegExp;
|
||||
}) {
|
||||
mockNodeGateway(params.command, params.payload);
|
||||
await runNodesCommand(params.argv);
|
||||
await expectLoggedSingleMediaFile({
|
||||
expectedPathPattern: params.expectedPathPattern,
|
||||
expectedContent: "url-content",
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
runTui.mockResolvedValue(undefined);
|
||||
@@ -69,9 +112,7 @@ describe("cli program (nodes media)", () => {
|
||||
it("runs nodes camera snap and prints two MEDIA paths", async () => {
|
||||
mockNodeGateway("camera.snap", { format: "jpg", base64: "aGk=", width: 1, height: 1 });
|
||||
|
||||
const program = buildProgram();
|
||||
runtime.log.mockClear();
|
||||
await program.parseAsync(["nodes", "camera", "snap", "--node", "ios-node"], { from: "user" });
|
||||
await runNodesCommand(["nodes", "camera", "snap", "--node", "ios-node"]);
|
||||
|
||||
const invokeCalls = callGateway.mock.calls
|
||||
.map((call) => call[0] as { method?: string; params?: Record<string, unknown> })
|
||||
@@ -107,12 +148,7 @@ describe("cli program (nodes media)", () => {
|
||||
hasAudio: true,
|
||||
});
|
||||
|
||||
const program = buildProgram();
|
||||
runtime.log.mockClear();
|
||||
await program.parseAsync(
|
||||
["nodes", "camera", "clip", "--node", "ios-node", "--duration", "3000"],
|
||||
{ from: "user" },
|
||||
);
|
||||
await runNodesCommand(["nodes", "camera", "clip", "--node", "ios-node", "--duration", "3000"]);
|
||||
|
||||
expect(callGateway).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
@@ -140,28 +176,23 @@ describe("cli program (nodes media)", () => {
|
||||
it("runs nodes camera snap with facing front and passes params", async () => {
|
||||
mockNodeGateway("camera.snap", { format: "jpg", base64: "aGk=", width: 1, height: 1 });
|
||||
|
||||
const program = buildProgram();
|
||||
runtime.log.mockClear();
|
||||
await program.parseAsync(
|
||||
[
|
||||
"nodes",
|
||||
"camera",
|
||||
"snap",
|
||||
"--node",
|
||||
"ios-node",
|
||||
"--facing",
|
||||
"front",
|
||||
"--max-width",
|
||||
"640",
|
||||
"--quality",
|
||||
"0.8",
|
||||
"--delay-ms",
|
||||
"2000",
|
||||
"--device-id",
|
||||
"cam-123",
|
||||
],
|
||||
{ from: "user" },
|
||||
);
|
||||
await runNodesCommand([
|
||||
"nodes",
|
||||
"camera",
|
||||
"snap",
|
||||
"--node",
|
||||
"ios-node",
|
||||
"--facing",
|
||||
"front",
|
||||
"--max-width",
|
||||
"640",
|
||||
"--quality",
|
||||
"0.8",
|
||||
"--delay-ms",
|
||||
"2000",
|
||||
"--device-id",
|
||||
"cam-123",
|
||||
]);
|
||||
|
||||
expect(callGateway).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
@@ -193,23 +224,18 @@ describe("cli program (nodes media)", () => {
|
||||
hasAudio: false,
|
||||
});
|
||||
|
||||
const program = buildProgram();
|
||||
runtime.log.mockClear();
|
||||
await program.parseAsync(
|
||||
[
|
||||
"nodes",
|
||||
"camera",
|
||||
"clip",
|
||||
"--node",
|
||||
"ios-node",
|
||||
"--duration",
|
||||
"3000",
|
||||
"--no-audio",
|
||||
"--device-id",
|
||||
"cam-123",
|
||||
],
|
||||
{ from: "user" },
|
||||
);
|
||||
await runNodesCommand([
|
||||
"nodes",
|
||||
"camera",
|
||||
"clip",
|
||||
"--node",
|
||||
"ios-node",
|
||||
"--duration",
|
||||
"3000",
|
||||
"--no-audio",
|
||||
"--device-id",
|
||||
"cam-123",
|
||||
]);
|
||||
|
||||
expect(callGateway).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
@@ -238,12 +264,7 @@ describe("cli program (nodes media)", () => {
|
||||
hasAudio: true,
|
||||
});
|
||||
|
||||
const program = buildProgram();
|
||||
runtime.log.mockClear();
|
||||
await program.parseAsync(
|
||||
["nodes", "camera", "clip", "--node", "ios-node", "--duration", "10s"],
|
||||
{ from: "user" },
|
||||
);
|
||||
await runNodesCommand(["nodes", "camera", "clip", "--node", "ios-node", "--duration", "10s"]);
|
||||
|
||||
expect(callGateway).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
@@ -260,12 +281,7 @@ describe("cli program (nodes media)", () => {
|
||||
it("runs nodes canvas snapshot and prints MEDIA path", async () => {
|
||||
mockNodeGateway("canvas.snapshot", { format: "png", base64: "aGk=" });
|
||||
|
||||
const program = buildProgram();
|
||||
runtime.log.mockClear();
|
||||
await program.parseAsync(
|
||||
["nodes", "canvas", "snapshot", "--node", "ios-node", "--format", "png"],
|
||||
{ from: "user" },
|
||||
);
|
||||
await runNodesCommand(["nodes", "canvas", "snapshot", "--node", "ios-node", "--format", "png"]);
|
||||
|
||||
await expectLoggedSingleMediaFile({
|
||||
expectedPathPattern: /openclaw-canvas-snapshot-.*\.png$/,
|
||||
@@ -307,62 +323,86 @@ describe("cli program (nodes media)", () => {
|
||||
globalThis.fetch = originalFetch;
|
||||
});
|
||||
|
||||
it("runs nodes camera snap with url payload", async () => {
|
||||
mockNodeGateway("camera.snap", {
|
||||
format: "jpg",
|
||||
url: "https://example.com/photo.jpg",
|
||||
width: 640,
|
||||
height: 480,
|
||||
});
|
||||
|
||||
const program = buildProgram();
|
||||
runtime.log.mockClear();
|
||||
await program.parseAsync(
|
||||
["nodes", "camera", "snap", "--node", "ios-node", "--facing", "front"],
|
||||
{ from: "user" },
|
||||
);
|
||||
|
||||
await expectLoggedSingleMediaFile({
|
||||
it.each([
|
||||
{
|
||||
label: "runs nodes camera snap with url payload",
|
||||
command: "camera.snap" as const,
|
||||
payload: {
|
||||
format: "jpg",
|
||||
url: "https://example.com/photo.jpg",
|
||||
width: 640,
|
||||
height: 480,
|
||||
},
|
||||
argv: ["nodes", "camera", "snap", "--node", "ios-node", "--facing", "front"],
|
||||
expectedPathPattern: /openclaw-camera-snap-front-.*\.jpg$/,
|
||||
expectedContent: "url-content",
|
||||
});
|
||||
});
|
||||
|
||||
it("runs nodes camera clip with url payload", async () => {
|
||||
mockNodeGateway("camera.clip", {
|
||||
format: "mp4",
|
||||
url: "https://example.com/clip.mp4",
|
||||
durationMs: 5000,
|
||||
hasAudio: true,
|
||||
});
|
||||
|
||||
const program = buildProgram();
|
||||
runtime.log.mockClear();
|
||||
await program.parseAsync(
|
||||
["nodes", "camera", "clip", "--node", "ios-node", "--duration", "5000"],
|
||||
{ from: "user" },
|
||||
);
|
||||
|
||||
await expectLoggedSingleMediaFile({
|
||||
},
|
||||
{
|
||||
label: "runs nodes camera clip with url payload",
|
||||
command: "camera.clip" as const,
|
||||
payload: {
|
||||
format: "mp4",
|
||||
url: "https://example.com/clip.mp4",
|
||||
durationMs: 5000,
|
||||
hasAudio: true,
|
||||
},
|
||||
argv: ["nodes", "camera", "clip", "--node", "ios-node", "--duration", "5000"],
|
||||
expectedPathPattern: /openclaw-camera-clip-front-.*\.mp4$/,
|
||||
expectedContent: "url-content",
|
||||
},
|
||||
])("$label", async ({ command, payload, argv, expectedPathPattern }) => {
|
||||
await runAndExpectUrlPayloadMediaFile({
|
||||
command,
|
||||
payload,
|
||||
argv,
|
||||
expectedPathPattern,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseCameraSnapPayload with url", () => {
|
||||
it("accepts url without base64", () => {
|
||||
const result = parseCameraSnapPayload({
|
||||
format: "jpg",
|
||||
url: "https://example.com/photo.jpg",
|
||||
width: 640,
|
||||
height: 480,
|
||||
});
|
||||
expect(result.url).toBe("https://example.com/photo.jpg");
|
||||
expect(result.base64).toBeUndefined();
|
||||
});
|
||||
describe("url payload parsers", () => {
|
||||
const parserCases = [
|
||||
{
|
||||
label: "camera snap parser",
|
||||
parse: (payload: Record<string, unknown>) => parseCameraSnapPayload(payload),
|
||||
validPayload: {
|
||||
format: "jpg",
|
||||
url: "https://example.com/photo.jpg",
|
||||
width: 640,
|
||||
height: 480,
|
||||
},
|
||||
invalidPayload: { format: "jpg", width: 640, height: 480 },
|
||||
expectedUrl: "https://example.com/photo.jpg",
|
||||
expectedError: "invalid camera.snap payload",
|
||||
},
|
||||
{
|
||||
label: "camera clip parser",
|
||||
parse: (payload: Record<string, unknown>) => parseCameraClipPayload(payload),
|
||||
validPayload: {
|
||||
format: "mp4",
|
||||
url: "https://example.com/clip.mp4",
|
||||
durationMs: 3000,
|
||||
hasAudio: true,
|
||||
},
|
||||
invalidPayload: { format: "mp4", durationMs: 3000, hasAudio: true },
|
||||
expectedUrl: "https://example.com/clip.mp4",
|
||||
expectedError: "invalid camera.clip payload",
|
||||
},
|
||||
] as const;
|
||||
|
||||
it("accepts both base64 and url", () => {
|
||||
it.each(parserCases)(
|
||||
"accepts url without base64: $label",
|
||||
({ parse, validPayload, expectedUrl }) => {
|
||||
expectParserAcceptsUrlWithoutBase64(parse, validPayload, expectedUrl);
|
||||
},
|
||||
);
|
||||
|
||||
it.each(parserCases)(
|
||||
"rejects payload with neither base64 nor url: $label",
|
||||
({ parse, invalidPayload, expectedError }) => {
|
||||
expectParserRejectsMissingMedia(parse, invalidPayload, expectedError);
|
||||
},
|
||||
);
|
||||
|
||||
it("snap parser accepts both base64 and url", () => {
|
||||
const result = parseCameraSnapPayload({
|
||||
format: "jpg",
|
||||
base64: "aGk=",
|
||||
@@ -373,30 +413,5 @@ describe("cli program (nodes media)", () => {
|
||||
expect(result.base64).toBe("aGk=");
|
||||
expect(result.url).toBe("https://example.com/photo.jpg");
|
||||
});
|
||||
|
||||
it("rejects payload with neither base64 nor url", () => {
|
||||
expect(() => parseCameraSnapPayload({ format: "jpg", width: 640, height: 480 })).toThrow(
|
||||
"invalid camera.snap payload",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseCameraClipPayload with url", () => {
|
||||
it("accepts url without base64", () => {
|
||||
const result = parseCameraClipPayload({
|
||||
format: "mp4",
|
||||
url: "https://example.com/clip.mp4",
|
||||
durationMs: 3000,
|
||||
hasAudio: true,
|
||||
});
|
||||
expect(result.url).toBe("https://example.com/clip.mp4");
|
||||
expect(result.base64).toBeUndefined();
|
||||
});
|
||||
|
||||
it("rejects payload with neither base64 nor url", () => {
|
||||
expect(() =>
|
||||
parseCameraClipPayload({ format: "mp4", durationMs: 3000, hasAudio: true }),
|
||||
).toThrow("invalid camera.clip payload");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user