import { EdgeTTS } from "node-edge-tts"; import { afterEach, expect, it, vi } from "vitest"; import { synthesizeEdgeSpeech } from "./edge-tts-service"; afterEach(() => vi.restoreAllMocks()); it("collects streamed MP3 bytes with the configured voice and a bounded timeout", async () => { const stream = vi.spyOn(EdgeTTS.prototype, "streamAudio").mockImplementation(async function* (this: EdgeTTS) { expect(this).toMatchObject({ voice: "zh-CN-XiaoxiaoNeural", timeout: 30_000 }); yield Buffer.from([73, 68]); yield { part: "测试", start: 0, end: 1 }; yield Buffer.from([51]); }); expect(await synthesizeEdgeSpeech("测试", "zh-CN-XiaoxiaoNeural")) .toEqual(Uint8Array.from([73, 68, 51])); expect(stream).toHaveBeenCalledWith("测试"); }); it("rejects empty audio and propagates upstream failures", async () => { const stream = vi.spyOn(EdgeTTS.prototype, "streamAudio").mockImplementation(async function* () {}); await expect(synthesizeEdgeSpeech("测试", "zh-CN-XiaoxiaoNeural")).rejects.toThrow("空音频"); stream.mockImplementation(async function* () { yield { part: "测试", start: 0, end: 1 }; throw new Error("upstream unavailable"); }); await expect(synthesizeEdgeSpeech("测试", "zh-CN-XiaoxiaoNeural")) .rejects.toThrow("upstream unavailable"); }); it("stops consuming an oversized audio stream", async () => { const closed = vi.fn(); vi.spyOn(EdgeTTS.prototype, "streamAudio").mockImplementation(async function* () { try { yield Buffer.alloc(5 * 1024 * 1024 + 1); throw new Error("must stop before consuming more audio"); } finally { closed(); } }); await expect(synthesizeEdgeSpeech("测试", "zh-CN-XiaoxiaoNeural")).rejects.toThrow("音频过大"); expect(closed).toHaveBeenCalledOnce(); });