惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
G
Google Developers Blog
V
V2EX
美团技术团队
H
Help Net Security
月光博客
月光博客
爱范儿
爱范儿
Engineering at Meta
Engineering at Meta
The Cloudflare Blog
U
Unit 42
大猫的无限游戏
大猫的无限游戏
Recent Announcements
Recent Announcements
A
About on SuperTechFans
博客园 - Franky
The GitHub Blog
The GitHub Blog
N
Netflix TechBlog - Medium
人人都是产品经理
人人都是产品经理
博客园 - 司徒正美
MyScale Blog
MyScale Blog
B
Blog
雷峰网
雷峰网
Y
Y Combinator Blog
云风的 BLOG
云风的 BLOG
T
The Blog of Author Tim Ferriss

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
test: guard device pairing doctor mock calls · openclaw/o...
steipete · 2026-05-12 · via Recent Commits to openclaw:main

@@ -26,6 +26,38 @@ vi.mock("../terminal/note.js", () => ({

2626

note: (...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+2961

describe("noteDevicePairingHealth", () => {

3062

let noteDevicePairingHealth: typeof import("./doctor-device-pairing.js").noteDevicePairingHealth;

3163

@@ -95,8 +127,8 @@ describe("noteDevicePairingHealth", () => {

95127

});

9612897129

expect(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");

100132

expect(message).toContain("Pending scope upgrade");

101133

expect(message).toContain("operator.admin");

102134

expect(message).toContain("openclaw devices approve");

@@ -122,8 +154,8 @@ describe("noteDevicePairingHealth", () => {

122154

});

123155124156

expect(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");

127159

expect(message).toContain("paired.json");

128160

expect(message).toContain("refused to treat it as empty");

129161

expect(await fs.readFile(pairedPath, "utf8")).toBe("{not-json}");

@@ -164,7 +196,7 @@ describe("noteDevicePairingHealth", () => {

164196

});

165197166198

expect(noteMock).toHaveBeenCalledTimes(1);

167-

const message = String(noteMock.mock.calls[0]?.[0] ?? "");

199+

const message = requireNoteMessage();

168200

expect(message).toContain("stale device-token pattern");

169201

expect(message).toContain("openclaw devices rotate");

170202

});

@@ -185,7 +217,7 @@ describe("noteDevicePairingHealth", () => {

185217

});

186218187219

expect(noteMock).toHaveBeenCalledTimes(1);

188-

const message = String(noteMock.mock.calls[0]?.[0] ?? "");

220+

const message = requireNoteMessage();

189221

expect(message).toContain("Local cached node device auth");

190222

expect(message).toContain("role is no longer approved");

191223

expect(message).toContain("remove the stale cached node auth entry");

@@ -219,10 +251,11 @@ describe("noteDevicePairingHealth", () => {

219251

});

220252221253

expect(callGatewayMock).toHaveBeenCalledOnce();

222-

const [gatewayRequest] = callGatewayMock.mock.calls[0] ?? [];

254+

const [rawGatewayRequest] = requireMockCall(callGatewayMock, 0, "gateway call");

255+

const gatewayRequest = requireRecord(rawGatewayRequest, "gateway request");

223256

expect(gatewayRequest?.method).toBe("device.pair.list");

224257

expect(noteMock).toHaveBeenCalledTimes(1);

225-

expect(String(noteMock.mock.calls[0]?.[0] ?? "")).toContain("req-gateway-1");

258+

expect(requireNoteMessage()).toContain("req-gateway-1");

226259

});

227260228261

it("sanitizes device labels before printing doctor notes", async () => {

@@ -250,7 +283,7 @@ describe("noteDevicePairingHealth", () => {

250283

healthOk: true,

251284

});

252285253-

const message = String(noteMock.mock.calls[0]?.[0] ?? "");

286+

const message = requireNoteMessage();

254287

expect(message).toContain("bad\\nname");

255288

expect(message).not.toContain("\u001b");

256289

expect(message).not.toContain("control-ui\tclient");

@@ -296,7 +329,7 @@ describe("noteDevicePairingHealth", () => {

296329

healthOk: true,

297330

});

298331299-

const message = String(noteMock.mock.calls[0]?.[0] ?? "");

332+

const message = requireNoteMessage();

300333

expect(message).toContain("openclaw devices remove 'device; echo pwn'");

301334

expect(message).toContain(

302335

"openclaw devices rotate --device 'device; echo pwn' --role 'operator; touch /tmp/pwn'",

@@ -321,7 +354,7 @@ describe("noteDevicePairingHealth", () => {

321354

healthOk: false,

322355

});

323356324-

const message = String(noteMock.mock.calls[0]?.[0] ?? "");

357+

const message = requireNoteMessage();

325358

expect(message).toContain("has no active operator device token");

326359

expect(message).not.toContain("no longer has a matching active gateway token");

327360

});