






















@@ -118,6 +118,42 @@ function mockLocalPairingFallback(message?: string) {
118118summarizeDeviceTokens.mockReturnValue(undefined);
119119}
120120121+function requireRecord(value: unknown, label: string): Record<string, unknown> {
122+expect(typeof value).toBe("object");
123+expect(value).not.toBeNull();
124+if (typeof value !== "object" || value === null) {
125+throw new Error(`${label} was not an object`);
126+}
127+return value as Record<string, unknown>;
128+}
129+130+function expectRecordFields(record: Record<string, unknown>, fields: Record<string, unknown>) {
131+for (const [key, value] of Object.entries(fields)) {
132+expect(record[key]).toEqual(value);
133+}
134+}
135+136+function requireGatewayCall(index: number): Record<string, unknown> {
137+const call = (callGateway.mock.calls as unknown[][])[index]?.[0];
138+return requireRecord(call, `gateway call ${index + 1}`);
139+}
140+141+function expectGatewayCall(index: number, fields: Record<string, unknown>) {
142+expectRecordFields(requireGatewayCall(index), fields);
143+}
144+145+function hasGatewayMethod(method: string): boolean {
146+return (callGateway.mock.calls as unknown[][]).some((call) => {
147+const params = call[0];
148+return (
149+typeof params === "object" &&
150+params !== null &&
151+"method" in params &&
152+params.method === method
153+);
154+});
155+}
156+121157describe("devices cli approve", () => {
122158it("uses admin scope when approving an admin-scope request", async () => {
123159callGateway
@@ -130,20 +166,12 @@ describe("devices cli approve", () => {
130166await runDevicesApprove(["req-123"]);
131167132168expect(callGateway).toHaveBeenCalledTimes(2);
133-expect(callGateway).toHaveBeenNthCalledWith(
134-1,
135-expect.objectContaining({
136-method: "device.pair.list",
137-}),
138-);
139-expect(callGateway).toHaveBeenNthCalledWith(
140-2,
141-expect.objectContaining({
142-method: "device.pair.approve",
143-params: { requestId: "req-123" },
144-scopes: ["operator.admin"],
145-}),
146-);
169+expectGatewayCall(0, { method: "device.pair.list" });
170+expectGatewayCall(1, {
171+method: "device.pair.approve",
172+params: { requestId: "req-123" },
173+scopes: ["operator.admin"],
174+});
147175});
148176149177it("keeps pairing scope for non-admin device approvals", async () => {
@@ -161,14 +189,11 @@ describe("devices cli approve", () => {
161189162190await runDevicesApprove(["req-pairing"]);
163191164-expect(callGateway).toHaveBeenNthCalledWith(
165-2,
166-expect.objectContaining({
167-method: "device.pair.approve",
168-params: { requestId: "req-pairing" },
169-scopes: ["operator.pairing"],
170-}),
171-);
192+expectGatewayCall(1, {
193+method: "device.pair.approve",
194+params: { requestId: "req-pairing" },
195+scopes: ["operator.pairing"],
196+});
172197});
173198174199it("retries explicit approval with admin scope when a paired-device session is ownership-denied", async () => {
@@ -183,22 +208,16 @@ describe("devices cli approve", () => {
183208await runDevicesApprove(["req-cross-device"]);
184209185210expect(callGateway).toHaveBeenCalledTimes(3);
186-expect(callGateway).toHaveBeenNthCalledWith(
187-2,
188-expect.objectContaining({
189-method: "device.pair.approve",
190-params: { requestId: "req-cross-device" },
191-scopes: undefined,
192-}),
193-);
194-expect(callGateway).toHaveBeenNthCalledWith(
195-3,
196-expect.objectContaining({
197-method: "device.pair.approve",
198-params: { requestId: "req-cross-device" },
199-scopes: ["operator.admin"],
200-}),
201-);
211+expectGatewayCall(1, {
212+method: "device.pair.approve",
213+params: { requestId: "req-cross-device" },
214+scopes: undefined,
215+});
216+expectGatewayCall(2, {
217+method: "device.pair.approve",
218+params: { requestId: "req-cross-device" },
219+scopes: ["operator.admin"],
220+});
202221});
203222204223it("uses admin scope when a repair approval would inherit an admin token", async () => {
@@ -220,14 +239,11 @@ describe("devices cli approve", () => {
220239221240await runDevicesApprove(["req-repair"]);
222241223-expect(callGateway).toHaveBeenNthCalledWith(
224-2,
225-expect.objectContaining({
226-method: "device.pair.approve",
227-params: { requestId: "req-repair" },
228-scopes: ["operator.admin"],
229-}),
230-);
242+expectGatewayCall(1, {
243+method: "device.pair.approve",
244+params: { requestId: "req-repair" },
245+scopes: ["operator.admin"],
246+});
231247});
232248233249it("prints selected details and exits when implicit approval is used", async () => {
@@ -256,9 +272,7 @@ describe("devices cli approve", () => {
256272await runDevicesApprove([]);
257273258274expect(callGateway).toHaveBeenCalledTimes(1);
259-expect(callGateway).toHaveBeenCalledWith(
260-expect.objectContaining({ method: "device.pair.list" }),
261-);
275+expectGatewayCall(0, { method: "device.pair.list" });
262276const logOutput = runtime.log.mock.calls.map((c) => readRuntimeCallText(c)).join("\n");
263277expect(logOutput).toContain("req-abc");
264278expect(logOutput).toContain("Device Nine");
@@ -268,9 +282,7 @@ describe("devices cli approve", () => {
268282expect.stringContaining("openclaw devices approve req-abc"),
269283);
270284expect(runtime.exit).toHaveBeenCalledWith(1);
271-expect(callGateway).not.toHaveBeenCalledWith(
272-expect.objectContaining({ method: "device.pair.approve" }),
273-);
285+expect(hasGatewayMethod("device.pair.approve")).toBe(false);
274286});
275287276288it("sanitizes preview ip output for implicit approval", async () => {
@@ -329,13 +341,8 @@ describe("devices cli approve", () => {
329341330342await runDevicesApprove(args);
331343332-expect(callGateway).toHaveBeenNthCalledWith(
333-1,
334-expect.objectContaining({ method: "device.pair.list" }),
335-);
336-expect(callGateway).not.toHaveBeenCalledWith(
337-expect.objectContaining({ method: "device.pair.approve" }),
338-);
344+expectGatewayCall(0, { method: "device.pair.list" });
345+expect(hasGatewayMethod("device.pair.approve")).toBe(false);
339346expect(runtime.error).toHaveBeenCalledWith(
340347expect.stringContaining(`openclaw devices approve ${expectedRequestId}`),
341348);
@@ -360,9 +367,7 @@ describe("devices cli approve", () => {
360367expect(runtime.error).toHaveBeenCalledWith(
361368expect.stringContaining("openclaw devices approve req-blank"),
362369);
363-expect(callGateway).not.toHaveBeenCalledWith(
364-expect.objectContaining({ method: "device.pair.approve" }),
365-);
370+expect(hasGatewayMethod("device.pair.approve")).toBe(false);
366371});
367372368373it("includes explicit gateway flags in the rerun approval command", async () => {
@@ -386,9 +391,7 @@ describe("devices cli approve", () => {
386391);
387392expect(errorOutput).toContain("Reuse the same --token option when rerunning.");
388393expect(errorOutput).not.toContain("secret-token");
389-expect(callGateway).not.toHaveBeenCalledWith(
390-expect.objectContaining({ method: "device.pair.approve" }),
391-);
394+expect(hasGatewayMethod("device.pair.approve")).toBe(false);
392395});
393396394397it("returns JSON for implicit approval preview in JSON mode", async () => {
@@ -415,9 +418,7 @@ describe("devices cli approve", () => {
415418},
416419});
417420expect(runtime.exit).toHaveBeenCalledWith(1);
418-expect(callGateway).not.toHaveBeenCalledWith(
419-expect.objectContaining({ method: "device.pair.approve" }),
420-);
421+expect(hasGatewayMethod("device.pair.approve")).toBe(false);
421422});
422423423424it("prints an error and exits when no pending requests are available", async () => {
@@ -426,14 +427,10 @@ describe("devices cli approve", () => {
426427await runDevicesApprove([]);
427428428429expect(callGateway).toHaveBeenCalledTimes(1);
429-expect(callGateway).toHaveBeenCalledWith(
430-expect.objectContaining({ method: "device.pair.list" }),
431-);
430+expectGatewayCall(0, { method: "device.pair.list" });
432431expect(runtime.error).toHaveBeenCalledWith("No pending device pairing requests to approve");
433432expect(runtime.exit).toHaveBeenCalledWith(1);
434-expect(callGateway).not.toHaveBeenCalledWith(
435-expect.objectContaining({ method: "device.pair.approve" }),
436-);
433+expect(hasGatewayMethod("device.pair.approve")).toBe(false);
437434});
438435});
439436@@ -444,12 +441,10 @@ describe("devices cli remove", () => {
444441await runDevicesCommand(["remove", "device-1"]);
445442446443expect(callGateway).toHaveBeenCalledTimes(1);
447-expect(callGateway).toHaveBeenCalledWith(
448-expect.objectContaining({
449-method: "device.pair.remove",
450-params: { deviceId: "device-1" },
451-}),
452-);
444+expectGatewayCall(0, {
445+method: "device.pair.remove",
446+params: { deviceId: "device-1" },
447+});
453448});
454449});
455450@@ -474,22 +469,10 @@ describe("devices cli clear", () => {
474469475470await runDevicesCommand(["clear", "--yes", "--pending"]);
476471477-expect(callGateway).toHaveBeenNthCalledWith(
478-1,
479-expect.objectContaining({ method: "device.pair.list" }),
480-);
481-expect(callGateway).toHaveBeenNthCalledWith(
482-2,
483-expect.objectContaining({ method: "device.pair.remove", params: { deviceId: "device-1" } }),
484-);
485-expect(callGateway).toHaveBeenNthCalledWith(
486-3,
487-expect.objectContaining({ method: "device.pair.remove", params: { deviceId: "device-2" } }),
488-);
489-expect(callGateway).toHaveBeenNthCalledWith(
490-4,
491-expect.objectContaining({ method: "device.pair.reject", params: { requestId: "req-1" } }),
492-);
472+expectGatewayCall(0, { method: "device.pair.list" });
473+expectGatewayCall(1, { method: "device.pair.remove", params: { deviceId: "device-1" } });
474+expectGatewayCall(2, { method: "device.pair.remove", params: { deviceId: "device-2" } });
475+expectGatewayCall(3, { method: "device.pair.reject", params: { requestId: "req-1" } });
493476});
494477});
495478@@ -531,7 +514,7 @@ describe("devices cli tokens", () => {
531514])("$label", async ({ argv, expectedCall }) => {
532515callGateway.mockResolvedValueOnce({ ok: true });
533516await runDevicesCommand(argv);
534-expect(callGateway).toHaveBeenCalledWith(expect.objectContaining(expectedCall));
517+expectGatewayCall(0, expectedCall);
535518});
536519537520it("rejects blank device or role values", async () => {
@@ -553,9 +536,7 @@ describe("devices cli local fallback", () => {
553536554537await runDevicesCommand(["list"]);
555538556-expect(callGateway).toHaveBeenCalledWith(
557-expect.objectContaining({ method: "device.pair.list" }),
558-);
539+expectGatewayCall(0, { method: "device.pair.list" });
559540expect(listDevicePairing).toHaveBeenCalledTimes(1);
560541expect(runtime.log).toHaveBeenCalledWith(expect.stringContaining(fallbackNotice));
561542});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。