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

推荐订阅源

美团技术团队
J
Java Code Geeks
有赞技术团队
有赞技术团队
GbyAI
GbyAI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 叶小钗
阮一峰的网络日志
阮一峰的网络日志
Microsoft Security Blog
Microsoft Security Blog
IT之家
IT之家
G
Google Developers Blog
月光博客
月光博客
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
S
SegmentFault 最新的问题
博客园 - 三生石上(FineUI控件)
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - Franky
腾讯CDC
V
Visual Studio Blog
博客园 - 【当耐特】
D
Docker
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Engineering at Meta
Engineering at Meta
L
LangChain Blog

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 voice call twilio mock calls · openclaw/openc...
steipete · 2026-05-12 · via Recent Commits to openclaw:main

@@ -58,6 +58,26 @@ function createApiRequestMock(impl?: TwilioApiRequest) {

5858

return vi.fn<TwilioApiRequest>(impl ?? (async () => ({})));

5959

}

606061+

function requireApiRequestCall(

62+

apiRequest: ReturnType<typeof createApiRequestMock>,

63+

index = 0,

64+

): Parameters<TwilioApiRequest> {

65+

const call = apiRequest.mock.calls[index];

66+

if (!call) {

67+

throw new Error(`expected Twilio API request call ${index}`);

68+

}

69+

return call;

70+

}

71+72+

function expectApiRequestEndpoint(

73+

apiRequest: ReturnType<typeof createApiRequestMock>,

74+

index: number,

75+

endpoint: string,

76+

): void {

77+

const [actualEndpoint] = requireApiRequestCall(apiRequest, index);

78+

expect(actualEndpoint).toBe(endpoint);

79+

}

80+6181

function createTwilioCallStateRaceError(): TwilioApiError {

6282

return new TwilioApiError(

6383

400,

@@ -107,15 +127,15 @@ describe("TwilioProvider", () => {

107127108128

expect(result).toEqual({ providerCallId: "CA123", status: "queued" });

109129

expect(apiRequest).toHaveBeenCalledTimes(1);

110-

const [endpoint, params] = apiRequest.mock.calls[0] ?? [];

130+

const [endpoint, params] = requireApiRequestCall(apiRequest);

111131

expect(endpoint).toBe("/Calls.json");

112-

expect(params?.To).toBe("+14155550123");

113-

expect(params?.From).toBe("+14155550100");

114-

expect(params?.Twiml).toBe("<Response><Say>Hello</Say></Response>");

115-

expect(params?.StatusCallback).toBe(

132+

expect(params.To).toBe("+14155550123");

133+

expect(params.From).toBe("+14155550100");

134+

expect(params.Twiml).toBe("<Response><Say>Hello</Say></Response>");

135+

expect(params.StatusCallback).toBe(

116136

"https://example.ngrok.app/voice/webhook?callId=call-1&type=status",

117137

);

118-

expect(params?.StatusCallbackEvent).toEqual(["initiated", "ringing", "answered", "completed"]);

138+

expect(params.StatusCallbackEvent).toEqual(["initiated", "ringing", "answered", "completed"]);

119139

expect(params).not.toHaveProperty("Url");

120140

});

121141

@@ -136,10 +156,10 @@ describe("TwilioProvider", () => {

136156

});

137157138158

expect(apiRequest).toHaveBeenCalledTimes(1);

139-

const [endpoint, params] = apiRequest.mock.calls[0] ?? [];

159+

const [endpoint, params] = requireApiRequestCall(apiRequest);

140160

expect(endpoint).toBe("/Calls.json");

141-

expect(params?.Url).toBe("https://example.ngrok.app/voice/webhook?callId=call-1");

142-

expect(params?.StatusCallback).toBe(

161+

expect(params.Url).toBe("https://example.ngrok.app/voice/webhook?callId=call-1");

162+

expect(params.StatusCallback).toBe(

143163

"https://example.ngrok.app/voice/webhook?callId=call-1&type=status",

144164

);

145165

expect(params).not.toHaveProperty("Twiml");

@@ -376,9 +396,7 @@ describe("TwilioProvider", () => {

376396

}),

377397

).resolves.toBeUndefined();

378398

expect(apiRequest).toHaveBeenCalledTimes(1);

379-

const call = apiRequest.mock.calls[0];

380-

const endpoint = call[0];

381-

const params = call[1] as { Twiml?: string };

399+

const [endpoint, params] = requireApiRequestCall(apiRequest) as [string, { Twiml?: string }];

382400

expect(endpoint).toBe("/Calls/CA-nostream.json");

383401

expect(params.Twiml).toContain("<Say");

384402

});

@@ -404,8 +422,8 @@ describe("TwilioProvider", () => {

404422

await expect(playback).resolves.toBeUndefined();

405423406424

expect(apiRequest).toHaveBeenCalledTimes(2);

407-

expect(apiRequest.mock.calls[0]?.[0]).toBe("/Calls/CA-race-play.json");

408-

expect(apiRequest.mock.calls[1]?.[0]).toBe("/Calls/CA-race-play.json");

425+

expectApiRequestEndpoint(apiRequest, 0, "/Calls/CA-race-play.json");

426+

expectApiRequestEndpoint(apiRequest, 1, "/Calls/CA-race-play.json");

409427

expect(warn).toHaveBeenCalledWith(

410428

"[voice-call] Twilio playTts update hit call state race (21220); retrying in 250ms",

411429

);

@@ -429,9 +447,7 @@ describe("TwilioProvider", () => {

429447

).resolves.toBeUndefined();

430448431449

expect(apiRequest).toHaveBeenCalledTimes(1);

432-

const call = apiRequest.mock.calls[0];

433-

const endpoint = call[0];

434-

const params = call[1] as { Twiml?: string };

450+

const [endpoint, params] = requireApiRequestCall(apiRequest) as [string, { Twiml?: string }];

435451

expect(endpoint).toBe("/Calls/CA-dtmf.json");

436452

expect(params.Twiml).toContain('<Play digits="ww123#"');

437453

expect(params.Twiml).toContain("<Redirect");

@@ -458,8 +474,8 @@ describe("TwilioProvider", () => {

458474

await expect(listening).resolves.toBeUndefined();

459475460476

expect(apiRequest).toHaveBeenCalledTimes(2);

461-

expect(apiRequest.mock.calls[0]?.[0]).toBe("/Calls/CA-race-listen.json");

462-

expect(apiRequest.mock.calls[1]?.[0]).toBe("/Calls/CA-race-listen.json");

477+

expectApiRequestEndpoint(apiRequest, 0, "/Calls/CA-race-listen.json");

478+

expectApiRequestEndpoint(apiRequest, 1, "/Calls/CA-race-listen.json");

463479

expect(warn).toHaveBeenCalledWith(

464480

"[voice-call] Twilio startListening update hit call state race (21220); retrying in 250ms",

465481

);