diff --git a/extensions/microsoft/speech-provider.test.ts b/extensions/microsoft/speech-provider.test.ts index 9579389861e..8218ef750f2 100644 --- a/extensions/microsoft/speech-provider.test.ts +++ b/extensions/microsoft/speech-provider.test.ts @@ -25,6 +25,28 @@ import * as ttsModule from "./tts.js"; const TEST_CFG = {} as OpenClawConfig; +function requireFirstEdgeTtsCall(edgeSpy: ReturnType): { + config?: unknown; + outputPath: string; + text?: string; + timeoutMs?: number; +} { + const [call] = edgeSpy.mock.calls; + if (!call) { + throw new Error("expected Microsoft Edge TTS call"); + } + const [edgeCall] = call; + if (!edgeCall || typeof edgeCall !== "object" || Array.isArray(edgeCall)) { + throw new Error("expected Microsoft Edge TTS call"); + } + return edgeCall as { + config?: unknown; + outputPath: string; + text?: string; + timeoutMs?: number; + }; +} + describe("listMicrosoftVoices", () => { const proxyReset = installDebugProxyTestResetHooks(); @@ -213,10 +235,7 @@ describe("buildMicrosoftSpeechProvider", () => { }); expect(edgeSpy).toHaveBeenCalledOnce(); - const edgeCall = edgeSpy.mock.calls[0]?.[0]; - if (!edgeCall) { - throw new Error("expected Microsoft Edge TTS call"); - } + const edgeCall = requireFirstEdgeTtsCall(edgeSpy); expect(edgeCall.text).toBe("你好,这是一个测试 hello"); expect(path.basename(edgeCall.outputPath)).toBe("speech.mp3"); expect(edgeCall.timeoutMs).toBe(1000); @@ -258,10 +277,7 @@ describe("buildMicrosoftSpeechProvider", () => { }); expect(edgeSpy).toHaveBeenCalledOnce(); - const edgeCall = edgeSpy.mock.calls[0]?.[0]; - if (!edgeCall) { - throw new Error("expected Microsoft Edge TTS call"); - } + const edgeCall = requireFirstEdgeTtsCall(edgeSpy); expect(edgeCall.text).toBe("你好,这是一个测试 hello"); expect(path.basename(edgeCall.outputPath)).toBe("speech.mp3"); expect(edgeCall.timeoutMs).toBe(1000); diff --git a/extensions/nextcloud-talk/src/core.test.ts b/extensions/nextcloud-talk/src/core.test.ts index 16a5a43a0bb..0e66c40d7fd 100644 --- a/extensions/nextcloud-talk/src/core.test.ts +++ b/extensions/nextcloud-talk/src/core.test.ts @@ -33,6 +33,14 @@ async function makeTempDir(): Promise { return dir; } +function requireFirstTimingSafeEqualCall(mock: ReturnType): [unknown, unknown] { + const [call] = mock.mock.calls; + if (!call) { + throw new Error("expected timingSafeEqual call"); + } + return call as [unknown, unknown]; +} + describe("nextcloud talk core", () => { it("builds an outbound session route for normalized room targets", () => { const route = resolveNextcloudTalkOutboundSessionRoute({ @@ -216,7 +224,7 @@ describe("nextcloud talk core", () => { ).toBe(false); expect(timingSafeEqualMock).toHaveBeenCalledOnce(); - const [leftBuffer, rightBuffer] = timingSafeEqualMock.mock.calls[0] ?? []; + const [leftBuffer, rightBuffer] = requireFirstTimingSafeEqualCall(timingSafeEqualMock); expect(Buffer.isBuffer(leftBuffer)).toBe(true); expect(Buffer.isBuffer(rightBuffer)).toBe(true); if (!Buffer.isBuffer(leftBuffer) || !Buffer.isBuffer(rightBuffer)) { diff --git a/extensions/nextcloud-talk/src/inbound.behavior.test.ts b/extensions/nextcloud-talk/src/inbound.behavior.test.ts index 8d3db88c377..f7969fe4ec4 100644 --- a/extensions/nextcloud-talk/src/inbound.behavior.test.ts +++ b/extensions/nextcloud-talk/src/inbound.behavior.test.ts @@ -84,6 +84,22 @@ function createRuntimeEnv() { } as unknown as RuntimeEnv; } +function requireFirstMockArg(mock: ReturnType, label: string): unknown { + const [call] = mock.mock.calls; + if (!call) { + throw new Error(`expected ${label}`); + } + return call[0]; +} + +function requireFirstSendMessageCall(): [unknown, unknown, unknown] { + const [call] = sendMessageNextcloudTalkMock.mock.calls; + if (!call) { + throw new Error("expected Nextcloud Talk send call"); + } + return call as [unknown, unknown, unknown]; +} + function createAccount( overrides?: Partial, ): ResolvedNextcloudTalkAccount { @@ -154,17 +170,22 @@ describe("nextcloud-talk inbound behavior", () => { statusSink, }); - const challengeParams = issueChallenge.mock.calls[0]?.[0] as - | { meta?: { name?: string }; senderId?: string; senderIdLine?: string } - | undefined; - expect(challengeParams?.senderId).toBe("user-1"); - expect(challengeParams?.senderIdLine).toBe("Your Nextcloud user id: user-1"); - expect(challengeParams?.meta).toEqual({ name: "Alice" }); + const challengeParams = requireFirstMockArg( + issueChallenge, + "Nextcloud Talk pairing challenge", + ) as { + meta?: { name?: string }; + senderId?: string; + senderIdLine?: string; + }; + expect(challengeParams.senderId).toBe("user-1"); + expect(challengeParams.senderIdLine).toBe("Your Nextcloud user id: user-1"); + expect(challengeParams.meta).toEqual({ name: "Alice" }); expect(sendMessageNextcloudTalkMock).toHaveBeenCalledTimes(1); - const sendArgs = sendMessageNextcloudTalkMock.mock.calls[0]; - expect(sendArgs?.[0]).toBe("room-1"); - expect(sendArgs?.[1]).toBe("Pair with code 123456"); - expect(sendArgs?.[2]).toEqual({ + const sendArgs = requireFirstSendMessageCall(); + expect(sendArgs[0]).toBe("room-1"); + expect(sendArgs[1]).toBe("Pair with code 123456"); + expect(sendArgs[2]).toEqual({ cfg: { channels: { "nextcloud-talk": {} } }, accountId: "default", }); @@ -279,9 +300,10 @@ describe("nextcloud-talk inbound behavior", () => { runtime: createRuntimeEnv(), }); - const assembledRequest = ( - coreRuntime.channel.turn.runAssembled as unknown as { mock: { calls: unknown[][] } } - ).mock.calls[0]?.[0] as { replyPipeline?: unknown } | undefined; - expect(assembledRequest?.replyPipeline).toEqual({}); + const assembledRequest = requireFirstMockArg( + coreRuntime.channel.turn.runAssembled as ReturnType, + "Nextcloud Talk assembled request", + ) as { replyPipeline?: unknown }; + expect(assembledRequest.replyPipeline).toEqual({}); }); }); diff --git a/extensions/nextcloud-talk/src/room-info.test.ts b/extensions/nextcloud-talk/src/room-info.test.ts index c47749ecedf..13df427d89c 100644 --- a/extensions/nextcloud-talk/src/room-info.test.ts +++ b/extensions/nextcloud-talk/src/room-info.test.ts @@ -26,6 +26,18 @@ afterEach(() => { __testing.resetRoomCache(); }); +function requireFirstFetchParams(): { auditContext?: string; url?: string } { + const [call] = fetchWithSsrFGuard.mock.calls; + if (!call) { + throw new Error("expected Nextcloud Talk room info fetch call"); + } + const [fetchParams] = call; + if (!fetchParams || typeof fetchParams !== "object" || Array.isArray(fetchParams)) { + throw new Error("expected Nextcloud Talk room info fetch call"); + } + return fetchParams as { auditContext?: string; url?: string }; +} + describe("nextcloud talk room info", () => { it("resolves direct rooms from the room info endpoint", async () => { const release = vi.fn(async () => {}); @@ -56,11 +68,11 @@ describe("nextcloud talk room info", () => { }); expect(kind).toBe("direct"); - const fetchParams = fetchWithSsrFGuard.mock.calls[0]?.[0]; - expect(fetchParams?.url).toBe( + const fetchParams = requireFirstFetchParams(); + expect(fetchParams.url).toBe( "https://nc.example.com/ocs/v2.php/apps/spreed/api/v4/room/room-direct", ); - expect(fetchParams?.auditContext).toBe("nextcloud-talk.room-info"); + expect(fetchParams.auditContext).toBe("nextcloud-talk.room-info"); expect(release).toHaveBeenCalledTimes(1); });