@@ -48,4 +48,75 @@ describe("minimaxTTS", () => {
|
48 | 48 | }); |
49 | 49 | expect(fetchWithSsrFGuardMock.mock.calls[0]?.[0]?.init?.signal).toBeInstanceOf(AbortSignal); |
50 | 50 | }); |
| 51 | + |
| 52 | +it("throws on base_resp envelope error even when data.audio is present (regression #76904)", async () => { |
| 53 | +fetchWithSsrFGuardMock.mockResolvedValue({ |
| 54 | +response: new Response( |
| 55 | +JSON.stringify({ |
| 56 | +data: { audio: Buffer.from("placeholder").toString("hex") }, |
| 57 | +base_resp: { status_code: 1002, status_msg: "Quota exceeded" }, |
| 58 | +}), |
| 59 | +{ status: 200, headers: { "content-type": "application/json" } }, |
| 60 | +), |
| 61 | +release: vi.fn(async () => undefined), |
| 62 | +}); |
| 63 | + |
| 64 | +await expect( |
| 65 | +minimaxTTS({ |
| 66 | +text: "hello", |
| 67 | +apiKey: "sk-test", |
| 68 | +baseUrl: "https://api.minimax.io", |
| 69 | +model: "speech-2.8-hd", |
| 70 | +voiceId: "English_expressive_narrator", |
| 71 | +timeoutMs: 10_000, |
| 72 | +}), |
| 73 | +).rejects.toThrow("MiniMax TTS API error (1002): Quota exceeded"); |
| 74 | +}); |
| 75 | + |
| 76 | +it("throws on base_resp envelope error with empty audio", async () => { |
| 77 | +fetchWithSsrFGuardMock.mockResolvedValue({ |
| 78 | +response: new Response( |
| 79 | +JSON.stringify({ |
| 80 | +base_resp: { status_code: 1001, status_msg: "Rate limit" }, |
| 81 | +}), |
| 82 | +{ status: 200, headers: { "content-type": "application/json" } }, |
| 83 | +), |
| 84 | +release: vi.fn(async () => undefined), |
| 85 | +}); |
| 86 | + |
| 87 | +await expect( |
| 88 | +minimaxTTS({ |
| 89 | +text: "hello", |
| 90 | +apiKey: "sk-test", |
| 91 | +baseUrl: "https://api.minimax.io", |
| 92 | +model: "speech-2.8-hd", |
| 93 | +voiceId: "English_expressive_narrator", |
| 94 | +timeoutMs: 10_000, |
| 95 | +}), |
| 96 | +).rejects.toThrow("MiniMax TTS API error (1001): Rate limit"); |
| 97 | +}); |
| 98 | + |
| 99 | +it("succeeds when base_resp.status_code is 0", async () => { |
| 100 | +fetchWithSsrFGuardMock.mockResolvedValue({ |
| 101 | +response: new Response( |
| 102 | +JSON.stringify({ |
| 103 | +data: { audio: Buffer.from("real-audio").toString("hex") }, |
| 104 | +base_resp: { status_code: 0, status_msg: "success" }, |
| 105 | +}), |
| 106 | +{ status: 200, headers: { "content-type": "application/json" } }, |
| 107 | +), |
| 108 | +release: vi.fn(async () => undefined), |
| 109 | +}); |
| 110 | + |
| 111 | +const audio = await minimaxTTS({ |
| 112 | +text: "hello", |
| 113 | +apiKey: "sk-test", |
| 114 | +baseUrl: "https://api.minimax.io", |
| 115 | +model: "speech-2.8-hd", |
| 116 | +voiceId: "English_expressive_narrator", |
| 117 | +timeoutMs: 10_000, |
| 118 | +}); |
| 119 | + |
| 120 | +expect(audio.toString()).toBe("real-audio"); |
| 121 | +}); |
51 | 122 | }); |