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

推荐订阅源

U
Unit 42
博客园 - Franky
T
Tailwind CSS Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
月光博客
月光博客
人人都是产品经理
人人都是产品经理
雷峰网
雷峰网
Hugging Face - Blog
Hugging Face - Blog
有赞技术团队
有赞技术团队
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
阮一峰的网络日志
阮一峰的网络日志
C
Check Point Blog
爱范儿
爱范儿
T
The Blog of Author Tim Ferriss
aimingoo的专栏
aimingoo的专栏
Stack Overflow Blog
Stack Overflow Blog
博客园 - 聂微东
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
云风的 BLOG
云风的 BLOG
MyScale Blog
MyScale Blog
Microsoft Security Blog
Microsoft Security Blog
The Cloudflare Blog
博客园 - 三生石上(FineUI控件)

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: dedupe mattermost send mock calls · openclaw/opencl...
steipete · 2026-05-12 · via Recent Commits to openclaw:main

@@ -34,6 +34,70 @@ const mockState = vi.hoisted(() => ({

3434

uploadMattermostFile: vi.fn(),

3535

}));

363637+

type MattermostPostParams = {

38+

channelId?: string;

39+

message?: string;

40+

props?: {

41+

attachments?: Array<{

42+

actions?: Array<{ id?: string; name?: string }>;

43+

}>;

44+

};

45+

};

46+47+

type MattermostUploadParams = {

48+

channelId?: string;

49+

fileName?: string;

50+

contentType?: string;

51+

};

52+53+

type MattermostDirectRetryOptions = {

54+

maxRetries?: number;

55+

initialDelayMs?: number;

56+

maxDelayMs?: number;

57+

timeoutMs?: number;

58+

onRetry?: () => void;

59+

};

60+61+

function mockCall(mock: unknown, label: string, index = 0): unknown[] {

62+

const calls = (mock as { mock?: { calls?: unknown[][] } }).mock?.calls;

63+

const call = calls?.at(index);

64+

if (!call) {

65+

throw new Error(`Expected ${label} call ${index + 1}`);

66+

}

67+

return call;

68+

}

69+70+

function uploadMattermostFileCall() {

71+

return mockCall(mockState.uploadMattermostFile, "uploadMattermostFile") as [

72+

unknown,

73+

MattermostUploadParams?,

74+

];

75+

}

76+77+

function createMattermostPostParams() {

78+

const params = mockCall(mockState.createMattermostPost, "createMattermostPost")[1] as

79+

| MattermostPostParams

80+

| undefined;

81+

if (!params) {

82+

throw new Error("Expected createMattermostPost params");

83+

}

84+

return params;

85+

}

86+87+

function createMattermostPostCall() {

88+

return mockCall(mockState.createMattermostPost, "createMattermostPost") as [

89+

unknown,

90+

MattermostPostParams?,

91+

];

92+

}

93+94+

function directChannelRetryCall() {

95+

return mockCall(

96+

mockState.createMattermostDirectChannelWithRetry,

97+

"createMattermostDirectChannelWithRetry",

98+

) as [unknown, unknown, MattermostDirectRetryOptions?];

99+

}

100+37101

vi.mock("../../runtime-api.js", () => ({

38102

loadOutboundMediaFromUrl: mockState.loadOutboundMediaFromUrl,

39103

}));

@@ -257,7 +321,7 @@ describe("sendMessageMattermost", () => {

257321

mediaLocalRoots: ["/tmp/agent-workspace"],

258322

},

259323

);

260-

const uploadCall = mockState.uploadMattermostFile.mock.calls[0];

324+

const uploadCall = uploadMattermostFileCall();

261325

expect(uploadCall?.[0]).toEqual({});

262326

expect(uploadCall?.[1]?.channelId).toBe("town-square");

263327

expect(uploadCall?.[1]?.fileName).toBe("photo.png");

@@ -277,7 +341,7 @@ describe("sendMessageMattermost", () => {

277341

buttons: [[{ callback_data: "mdlprov", text: "Browse providers" }]],

278342

});

279343280-

const postCall = mockState.createMattermostPost.mock.calls[0];

344+

const postCall = createMattermostPostCall();

281345

expect(postCall?.[0]).toEqual({});

282346

expect(postCall?.[1]?.channelId).toBe("town-square");

283347

expect(postCall?.[1]?.message).toBe("Pick a model");

@@ -312,12 +376,12 @@ describe("sendMessageMattermost", () => {

312376

});

313377314378

expect(mockState.fetchMattermostUser).toHaveBeenCalledWith({}, userId);

315-

const dmRetryCall = mockState.createMattermostDirectChannelWithRetry.mock.calls[0];

379+

const dmRetryCall = directChannelRetryCall();

316380

expect(dmRetryCall?.[0]).toEqual({});

317381

expect(dmRetryCall?.[1]).toEqual(["bot-user", userId]);

318382

expect(Object.keys(dmRetryCall?.[2] ?? {})).toEqual(["onRetry"]);

319383

expect(dmRetryCall?.[2]?.onRetry).toBeTypeOf("function");

320-

const uploadCall = mockState.uploadMattermostFile.mock.calls[0];

384+

const uploadCall = uploadMattermostFileCall();

321385

expect(uploadCall?.[0]).toEqual({});

322386

expect(uploadCall?.[1]?.channelId).toBe("dm-channel-1");

323387

expect(result.channelId).toBe("dm-channel-1");

@@ -349,7 +413,7 @@ describe("sendMessageMattermost", () => {

349413350414

expect(mockState.fetchMattermostUser).toHaveBeenCalledWith({}, channelId);

351415

expect(mockState.createMattermostDirectChannelWithRetry).not.toHaveBeenCalled();

352-

const uploadCall = mockState.uploadMattermostFile.mock.calls[0];

416+

const uploadCall = uploadMattermostFileCall();

353417

expect(uploadCall?.[0]).toEqual({});

354418

expect(uploadCall?.[1]?.channelId).toBe(channelId);

355419

expect(result.channelId).toBe(channelId);

@@ -471,7 +535,7 @@ describe("sendMessageMattermost user-first resolution", () => {

471535472536

expect(mockState.fetchMattermostUser).toHaveBeenCalledTimes(1);

473537

expect(mockState.createMattermostDirectChannelWithRetry).toHaveBeenCalledTimes(1);

474-

const params = mockState.createMattermostPost.mock.calls[0]?.[1];

538+

const params = createMattermostPostParams();

475539

expect(params.channelId).toBe("dm-channel-id");

476540

expect(res.channelId).toBe("dm-channel-id");

477541

expect(res.messageId).toBe("post-id");

@@ -490,7 +554,7 @@ describe("sendMessageMattermost user-first resolution", () => {

490554491555

expect(mockState.fetchMattermostUser).toHaveBeenCalledTimes(1);

492556

expect(mockState.createMattermostDirectChannelWithRetry).not.toHaveBeenCalled();

493-

const params = mockState.createMattermostPost.mock.calls[0]?.[1];

557+

const params = createMattermostPostParams();

494558

expect(params.channelId).toBe(channelId);

495559

expect(res.channelId).toBe(channelId);

496560

});

@@ -545,7 +609,7 @@ describe("sendMessageMattermost user-first resolution", () => {

545609546610

expect(mockState.fetchMattermostUser).not.toHaveBeenCalled();

547611

expect(mockState.createMattermostDirectChannelWithRetry).not.toHaveBeenCalled();

548-

const params = mockState.createMattermostPost.mock.calls[0]?.[1];

612+

const params = createMattermostPostParams();

549613

expect(params.channelId).toBe(chanId);

550614

expect(res.channelId).toBe(chanId);

551615

});

@@ -567,7 +631,7 @@ describe("sendMessageMattermost user-first resolution", () => {

567631

dmRetryOptions: retryOptions,

568632

});

569633570-

const retryCall = mockState.createMattermostDirectChannelWithRetry.mock.calls[0];

634+

const retryCall = directChannelRetryCall();

571635

expect(retryCall?.[0]).toEqual({});

572636

expect(retryCall?.[1]).toEqual(["bot-id", userId]);

573637

expect(retryCall?.[2]?.maxRetries).toBe(retryOptions.maxRetries);

@@ -595,7 +659,7 @@ describe("sendMessageMattermost user-first resolution", () => {

595659596660

await sendMessageMattermost(`user:${userId}`, "hello", { cfg: TEST_CFG });

597661598-

const retryCall = mockState.createMattermostDirectChannelWithRetry.mock.calls[0];

662+

const retryCall = directChannelRetryCall();

599663

expect(retryCall?.[0]).toEqual({});

600664

expect(retryCall?.[1]).toEqual(["bot-id", userId]);

601665

expect(retryCall?.[2]?.maxRetries).toBe(4);

@@ -629,7 +693,7 @@ describe("sendMessageMattermost user-first resolution", () => {

629693

dmRetryOptions: overrideOptions,

630694

});

631695632-

const retryCall = mockState.createMattermostDirectChannelWithRetry.mock.calls[0];

696+

const retryCall = directChannelRetryCall();

633697

expect(retryCall?.[0]).toEqual({});

634698

expect(retryCall?.[1]).toEqual(["bot-id", userId]);

635699

expect(retryCall?.[2]?.maxRetries).toBe(overrideOptions.maxRetries);