From 6ed67fc873c922bfc5cbe451a790722fff0fdee3 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 20 Apr 2026 17:11:33 +0100 Subject: [PATCH] test: share speech tts payload fixture --- extensions/speech-core/src/tts.test.ts | 92 ++++++++++++-------------- 1 file changed, 41 insertions(+), 51 deletions(-) diff --git a/extensions/speech-core/src/tts.test.ts b/extensions/speech-core/src/tts.test.ts index 693e2b25959..d6fb3b164a8 100644 --- a/extensions/speech-core/src/tts.test.ts +++ b/extensions/speech-core/src/tts.test.ts @@ -1,7 +1,6 @@ import { rmSync } from "node:fs"; import path from "node:path"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; -import type { ReplyPayload } from "openclaw/plugin-sdk/reply-payload"; import type { SpeechProviderPlugin, SpeechSynthesisRequest } from "openclaw/plugin-sdk/speech-core"; import { afterEach, describe, expect, it, vi } from "vitest"; @@ -66,6 +65,35 @@ function createTtsConfig(prefsName: string): OpenClawConfig { }; } +async function expectTtsPayloadResult(params: { + channel: string; + prefsName: string; + text: string; + target: "voice-note" | "audio-file"; + audioAsVoice: true | undefined; +}) { + const cfg = createTtsConfig(params.prefsName); + let mediaDir: string | undefined; + try { + const result = await maybeApplyTtsToPayload({ + payload: { text: params.text }, + cfg, + channel: params.channel, + kind: "final", + }); + + expect(synthesizeMock).toHaveBeenCalledWith(expect.objectContaining({ target: params.target })); + expect(result.audioAsVoice).toBe(params.audioAsVoice); + expect(result.mediaUrl).toMatch(/voice-\d+\.ogg$/); + + mediaDir = result.mediaUrl ? path.dirname(result.mediaUrl) : undefined; + } finally { + if (mediaDir) { + rmSync(mediaDir, { recursive: true, force: true }); + } + } +} + describe("speech-core native voice-note routing", () => { afterEach(() => { synthesizeMock.mockClear(); @@ -81,60 +109,22 @@ describe("speech-core native voice-note routing", () => { }); it("marks Discord auto TTS replies as native voice messages", async () => { - const cfg = createTtsConfig("openclaw-speech-core-tts-test"); - const payload: ReplyPayload = { + await expectTtsPayloadResult({ + channel: "discord", + prefsName: "openclaw-speech-core-tts-test", text: "This Discord reply should be delivered as a native voice note.", - }; - - let mediaDir: string | undefined; - try { - const result = await maybeApplyTtsToPayload({ - payload, - cfg, - channel: "discord", - kind: "final", - }); - - expect(synthesizeMock).toHaveBeenCalledWith( - expect.objectContaining({ target: "voice-note" }), - ); - expect(result.audioAsVoice).toBe(true); - expect(result.mediaUrl).toMatch(/voice-\d+\.ogg$/); - - mediaDir = result.mediaUrl ? path.dirname(result.mediaUrl) : undefined; - } finally { - if (mediaDir) { - rmSync(mediaDir, { recursive: true, force: true }); - } - } + target: "voice-note", + audioAsVoice: true, + }); }); it("keeps non-native voice-note channels as regular audio files", async () => { - const cfg = createTtsConfig("openclaw-speech-core-tts-slack-test"); - const payload: ReplyPayload = { + await expectTtsPayloadResult({ + channel: "slack", + prefsName: "openclaw-speech-core-tts-slack-test", text: "Slack replies should be delivered as regular audio attachments.", - }; - - let mediaDir: string | undefined; - try { - const result = await maybeApplyTtsToPayload({ - payload, - cfg, - channel: "slack", - kind: "final", - }); - - expect(synthesizeMock).toHaveBeenCalledWith( - expect.objectContaining({ target: "audio-file" }), - ); - expect(result.audioAsVoice).toBeUndefined(); - expect(result.mediaUrl).toMatch(/voice-\d+\.ogg$/); - - mediaDir = result.mediaUrl ? path.dirname(result.mediaUrl) : undefined; - } finally { - if (mediaDir) { - rmSync(mediaDir, { recursive: true, force: true }); - } - } + target: "audio-file", + audioAsVoice: undefined, + }); }); });