BangSo/apps/mobile/lib/voice.test.ts

74 lines
2.2 KiB
TypeScript
Raw Permalink Normal View History

2026-09-01 16:51:19 +00:00
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { captureApiRequestContext, currentApiBase, rpc } from "./api";
import { speakText } from "./voice";
vi.mock("expo-file-system", () => ({ File: class {}, Paths: {} }));
vi.mock("./api", () => ({
authHeaders: vi.fn(),
captureApiRequestContext: vi.fn(),
currentApiBase: vi.fn(() => "https://api.example"),
rpc: vi.fn(),
}));
class FakeAudio {
onended: (() => void) | null = null;
onerror: (() => void) | null = null;
src = "";
async play() {
setTimeout(() => this.onended?.(), 0);
}
pause() {}
}
describe("mobile speech", () => {
beforeEach(() => {
vi.mocked(captureApiRequestContext).mockResolvedValue({
apiBase: "https://support.example",
headers: {
authorization: "Bearer support-token",
"x-rakazo-space-id": "space-support",
},
});
vi.mocked(rpc).mockImplementation(async () => {
vi.mocked(currentApiBase).mockReturnValue("https://finance.example");
return { ready: true, utterances: ["First", "Second"] } as never;
});
vi.stubGlobal("Audio", FakeAudio);
vi.stubGlobal(
"fetch",
vi.fn(async () => new Response(new Uint8Array([1, 2, 3]), { status: 200 })),
);
});
afterEach(() => {
vi.restoreAllMocks();
vi.unstubAllGlobals();
});
it("keeps every request on the server and space captured before preparation", async () => {
await expect(speakText("Read this", { botId: "bot-1" })).resolves.toBe(true);
const requestContext = {
apiBase: "https://support.example",
headers: {
authorization: "Bearer support-token",
"x-rakazo-space-id": "space-support",
},
};
expect(rpc).toHaveBeenCalledWith(
"voice/prepare",
{ text: "Read this", voiceId: undefined, botId: "bot-1" },
{ requestContext },
);
expect(captureApiRequestContext).toHaveBeenCalledTimes(1);
const fetchMock = vi.mocked(fetch);
expect(fetchMock).toHaveBeenCalledTimes(2);
for (const [url, init] of fetchMock.mock.calls) {
expect(url).toBe("https://support.example/api/voice/speak");
expect(init?.headers).toMatchObject(requestContext.headers);
}
});
});