






















@@ -26,6 +26,38 @@ vi.mock("../terminal/note.js", () => ({
2626note: (...args: unknown[]) => noteMock(...args),
2727}));
282829+function requireMockCall(
30+mock: { mock: { calls: unknown[][] } },
31+callIndex: number,
32+label: string,
33+): unknown[] {
34+const call = mock.mock.calls.at(callIndex);
35+if (!call) {
36+throw new Error(`expected ${label} call ${callIndex}`);
37+}
38+return call;
39+}
40+41+function requireNoteMessage(callIndex = 0): string {
42+const [message] = requireMockCall(noteMock, callIndex, "doctor note");
43+if (typeof message !== "string") {
44+throw new Error(`expected doctor note message ${callIndex}`);
45+}
46+return message;
47+}
48+49+function requireNoteTitle(callIndex = 0): unknown {
50+const [, title] = requireMockCall(noteMock, callIndex, "doctor note");
51+return title;
52+}
53+54+function requireRecord(value: unknown, label: string): Record<string, unknown> {
55+if (!value || typeof value !== "object") {
56+throw new Error(`expected ${label} record`);
57+}
58+return value as Record<string, unknown>;
59+}
60+2961describe("noteDevicePairingHealth", () => {
3062let noteDevicePairingHealth: typeof import("./doctor-device-pairing.js").noteDevicePairingHealth;
3163@@ -95,8 +127,8 @@ describe("noteDevicePairingHealth", () => {
95127});
9612897129expect(noteMock).toHaveBeenCalledTimes(1);
98-const message = String(noteMock.mock.calls[0]?.[0] ?? "");
99-expect(noteMock.mock.calls[0]?.[1]).toBe("Device pairing");
130+const message = requireNoteMessage();
131+expect(requireNoteTitle()).toBe("Device pairing");
100132expect(message).toContain("Pending scope upgrade");
101133expect(message).toContain("operator.admin");
102134expect(message).toContain("openclaw devices approve");
@@ -122,8 +154,8 @@ describe("noteDevicePairingHealth", () => {
122154});
123155124156expect(noteMock).toHaveBeenCalledTimes(1);
125-const message = String(noteMock.mock.calls[0]?.[0] ?? "");
126-expect(noteMock.mock.calls[0]?.[1]).toBe("Device pairing");
157+const message = requireNoteMessage();
158+expect(requireNoteTitle()).toBe("Device pairing");
127159expect(message).toContain("paired.json");
128160expect(message).toContain("refused to treat it as empty");
129161expect(await fs.readFile(pairedPath, "utf8")).toBe("{not-json}");
@@ -164,7 +196,7 @@ describe("noteDevicePairingHealth", () => {
164196});
165197166198expect(noteMock).toHaveBeenCalledTimes(1);
167-const message = String(noteMock.mock.calls[0]?.[0] ?? "");
199+const message = requireNoteMessage();
168200expect(message).toContain("stale device-token pattern");
169201expect(message).toContain("openclaw devices rotate");
170202});
@@ -185,7 +217,7 @@ describe("noteDevicePairingHealth", () => {
185217});
186218187219expect(noteMock).toHaveBeenCalledTimes(1);
188-const message = String(noteMock.mock.calls[0]?.[0] ?? "");
220+const message = requireNoteMessage();
189221expect(message).toContain("Local cached node device auth");
190222expect(message).toContain("role is no longer approved");
191223expect(message).toContain("remove the stale cached node auth entry");
@@ -219,10 +251,11 @@ describe("noteDevicePairingHealth", () => {
219251});
220252221253expect(callGatewayMock).toHaveBeenCalledOnce();
222-const [gatewayRequest] = callGatewayMock.mock.calls[0] ?? [];
254+const [rawGatewayRequest] = requireMockCall(callGatewayMock, 0, "gateway call");
255+const gatewayRequest = requireRecord(rawGatewayRequest, "gateway request");
223256expect(gatewayRequest?.method).toBe("device.pair.list");
224257expect(noteMock).toHaveBeenCalledTimes(1);
225-expect(String(noteMock.mock.calls[0]?.[0] ?? "")).toContain("req-gateway-1");
258+expect(requireNoteMessage()).toContain("req-gateway-1");
226259});
227260228261it("sanitizes device labels before printing doctor notes", async () => {
@@ -250,7 +283,7 @@ describe("noteDevicePairingHealth", () => {
250283healthOk: true,
251284});
252285253-const message = String(noteMock.mock.calls[0]?.[0] ?? "");
286+const message = requireNoteMessage();
254287expect(message).toContain("bad\\nname");
255288expect(message).not.toContain("\u001b");
256289expect(message).not.toContain("control-ui\tclient");
@@ -296,7 +329,7 @@ describe("noteDevicePairingHealth", () => {
296329healthOk: true,
297330});
298331299-const message = String(noteMock.mock.calls[0]?.[0] ?? "");
332+const message = requireNoteMessage();
300333expect(message).toContain("openclaw devices remove 'device; echo pwn'");
301334expect(message).toContain(
302335"openclaw devices rotate --device 'device; echo pwn' --role 'operator; touch /tmp/pwn'",
@@ -321,7 +354,7 @@ describe("noteDevicePairingHealth", () => {
321354healthOk: false,
322355});
323356324-const message = String(noteMock.mock.calls[0]?.[0] ?? "");
357+const message = requireNoteMessage();
325358expect(message).toContain("has no active operator device token");
326359expect(message).not.toContain("no longer has a matching active gateway token");
327360});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。