



























@@ -50,6 +50,34 @@ function mockNodeGateway(command?: string, payload?: Record<string, unknown>) {
5050});
5151}
525253+function nodeInvokeCalls(): Array<{
54+method?: unknown;
55+params: Record<string, unknown>;
56+commandParams: Record<string, unknown>;
57+}> {
58+return callGateway.mock.calls
59+.map((call) => call[0] as { method?: unknown; params?: Record<string, unknown> })
60+.filter((call) => call.method === "node.invoke")
61+.map((call) => {
62+const params = call.params ?? {};
63+const commandParams = (params.params ?? {}) as Record<string, unknown>;
64+return { method: call.method, params, commandParams };
65+});
66+}
67+68+function latestNodeInvokeCall() {
69+const call = nodeInvokeCalls().at(-1);
70+if (!call) {
71+throw new Error("expected node.invoke gateway call");
72+}
73+return call;
74+}
75+76+function expectNonEmptyString(value: unknown) {
77+expect(typeof value).toBe("string");
78+expect((value as string).length).toBeGreaterThan(0);
79+}
80+5381describe("cli program (nodes media)", () => {
5482let program: Command;
5583@@ -103,11 +131,9 @@ describe("cli program (nodes media)", () => {
103131104132await runNodesCommand(["nodes", "camera", "snap", "--node", "ios-node"]);
105133106-const invokeCalls = callGateway.mock.calls
107-.map((call) => call[0] as { method?: string; params?: Record<string, unknown> })
108-.filter((call) => call.method === "node.invoke");
134+const invokeCalls = nodeInvokeCalls();
109135const facings = invokeCalls
110-.map((call) => (call.params?.params as { facing?: string } | undefined)?.facing)
136+.map((call) => call.commandParams.facing)
111137.filter((facing): facing is string => Boolean(facing))
112138.toSorted((a, b) => a.localeCompare(b));
113139expect(facings).toEqual(["back", "front"]);
@@ -147,23 +173,16 @@ describe("cli program (nodes media)", () => {
147173148174await runNodesCommand(["nodes", "camera", "clip", "--node", "ios-node", "--duration", "3000"]);
149175150-expect(callGateway).toHaveBeenCalledWith(
151-expect.objectContaining({
152-method: "node.invoke",
153-params: expect.objectContaining({
154-nodeId: "ios-node",
155-command: "camera.clip",
156-timeoutMs: 90000,
157-idempotencyKey: expect.any(String),
158-params: expect.objectContaining({
159-facing: "front",
160-durationMs: 3000,
161-includeAudio: true,
162-format: "mp4",
163-}),
164-}),
165-}),
166-);
176+const invoke = latestNodeInvokeCall();
177+expect(invoke.method).toBe("node.invoke");
178+expect(invoke.params.nodeId).toBe("ios-node");
179+expect(invoke.params.command).toBe("camera.clip");
180+expect(invoke.params.timeoutMs).toBe(90000);
181+expectNonEmptyString(invoke.params.idempotencyKey);
182+expect(invoke.commandParams.facing).toBe("front");
183+expect(invoke.commandParams.durationMs).toBe(3000);
184+expect(invoke.commandParams.includeAudio).toBe(true);
185+expect(invoke.commandParams.format).toBe("mp4");
167186168187await expectLoggedSingleMediaFile({
169188expectedPathPattern: /openclaw-camera-clip-front-.*\.mp4$/,
@@ -191,24 +210,17 @@ describe("cli program (nodes media)", () => {
191210"cam-123",
192211]);
193212194-expect(callGateway).toHaveBeenCalledWith(
195-expect.objectContaining({
196-method: "node.invoke",
197-params: expect.objectContaining({
198-nodeId: "ios-node",
199-command: "camera.snap",
200-timeoutMs: 20000,
201-idempotencyKey: expect.any(String),
202-params: expect.objectContaining({
203-facing: "front",
204-maxWidth: 640,
205-quality: 0.8,
206-delayMs: 2000,
207-deviceId: "cam-123",
208-}),
209-}),
210-}),
211-);
213+const invoke = latestNodeInvokeCall();
214+expect(invoke.method).toBe("node.invoke");
215+expect(invoke.params.nodeId).toBe("ios-node");
216+expect(invoke.params.command).toBe("camera.snap");
217+expect(invoke.params.timeoutMs).toBe(20000);
218+expectNonEmptyString(invoke.params.idempotencyKey);
219+expect(invoke.commandParams.facing).toBe("front");
220+expect(invoke.commandParams.maxWidth).toBe(640);
221+expect(invoke.commandParams.quality).toBe(0.8);
222+expect(invoke.commandParams.delayMs).toBe(2000);
223+expect(invoke.commandParams.deviceId).toBe("cam-123");
212224213225await expectLoggedSingleMediaFile();
214226});
@@ -234,21 +246,14 @@ describe("cli program (nodes media)", () => {
234246"cam-123",
235247]);
236248237-expect(callGateway).toHaveBeenCalledWith(
238-expect.objectContaining({
239-method: "node.invoke",
240-params: expect.objectContaining({
241-nodeId: "ios-node",
242-command: "camera.clip",
243-timeoutMs: 90000,
244-idempotencyKey: expect.any(String),
245-params: expect.objectContaining({
246-includeAudio: false,
247-deviceId: "cam-123",
248-}),
249-}),
250-}),
251-);
249+const invoke = latestNodeInvokeCall();
250+expect(invoke.method).toBe("node.invoke");
251+expect(invoke.params.nodeId).toBe("ios-node");
252+expect(invoke.params.command).toBe("camera.clip");
253+expect(invoke.params.timeoutMs).toBe(90000);
254+expectNonEmptyString(invoke.params.idempotencyKey);
255+expect(invoke.commandParams.includeAudio).toBe(false);
256+expect(invoke.commandParams.deviceId).toBe("cam-123");
252257253258await expectLoggedSingleMediaFile();
254259});
@@ -263,16 +268,11 @@ describe("cli program (nodes media)", () => {
263268264269await runNodesCommand(["nodes", "camera", "clip", "--node", "ios-node", "--duration", "10s"]);
265270266-expect(callGateway).toHaveBeenCalledWith(
267-expect.objectContaining({
268-method: "node.invoke",
269-params: expect.objectContaining({
270-nodeId: "ios-node",
271-command: "camera.clip",
272-params: expect.objectContaining({ durationMs: 10_000 }),
273-}),
274-}),
275-);
271+const invoke = latestNodeInvokeCall();
272+expect(invoke.method).toBe("node.invoke");
273+expect(invoke.params.nodeId).toBe("ios-node");
274+expect(invoke.params.command).toBe("camera.clip");
275+expect(invoke.commandParams.durationMs).toBe(10_000);
276276});
277277278278it("fails nodes camera snap on invalid facing", async () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。