import { expect, test } from "@playwright/test"; import { captureScreenshot, completeOnboarding, openUserSettings, rpc, signup } from "./helpers"; test("voice settings connect a key, speak a reply, and open a call", async ({ page }, testInfo) => { const stamp = Date.now(); const userName = `Voice ${stamp}`; await signup(page, `voice-${stamp}@rakazo.test`, "password12", userName); await completeOnboarding(page); await expect(page.getByRole("button", { name: "Call", exact: true })).toHaveCount(0); await expect( page.getByTestId("composer-bar").getByRole("button", { name: "Voice", exact: true }), ).toHaveCount(1); await captureScreenshot(page, testInfo, "voice-composer"); await page .getByTestId("composer-bar") .getByRole("button", { name: "Voice", exact: true }) .click(); await expect(page.getByTestId("voice-settings")).toBeVisible(); await page.getByRole("button", { name: "Other voice providers" }).click(); await expect(page.getByLabel("API key", { exact: true })).toBeVisible(); await expect(page.getByRole("button", { name: "Dictate", exact: true })).toHaveCount(0); await captureScreenshot(page, testInfo, "voice-settings"); await page.getByRole("button", { name: "Close voice settings" }).click(); await expect(page.getByTestId("voice-settings")).toHaveCount(0); const preparedOff = await rpc<{ ready: boolean }>(page, "voice/prepare", { text: "Hello there.", }); expect(preparedOff.ready).toBe(false); await openUserSettings(page, "voice"); await expect(page.getByTestId("voice-settings")).toBeVisible(); await page.getByRole("button", { name: "Other voice providers" }).click(); await page.getByLabel("Provider", { exact: true }).selectOption("scripted"); const apiKeyInput = page.getByPlaceholder(/Paste your API key/); await expect(apiKeyInput).toHaveAttribute("autocomplete", "new-password"); await apiKeyInput.fill("fake-scripted-voice-key"); await page.getByRole("button", { name: "Connect", exact: true }).click(); await expect(page.getByText("Connected Scripted.")).toBeVisible(); await expect(page.getByRole("button", { name: "Replace key" })).toBeVisible(); await expect(page.getByRole("button", { name: "Disconnect", exact: true })).toBeVisible(); await captureScreenshot(page, testInfo, "voice-settings-connected"); const credentials = await rpc>( page, "voice/credentials", {}, ); expect(credentials).toEqual([expect.objectContaining({ hasKey: true, provider: "scripted" })]); expect(JSON.stringify(credentials)).not.toContain("fake-scripted-voice-key"); await page.getByRole("button", { name: "Close voice settings" }).click(); const composer = page.getByPlaceholder(/Message/); await composer.fill("say hello"); await expect( page.getByTestId("composer-bar").getByRole("button", { name: "Voice", exact: true }), ).toHaveCount(0); await captureScreenshot(page, testInfo, "voice-composer-typing"); await page.keyboard.press("Enter"); // A reply can render more than one text bubble; speak the latest one. const speakReply = page.getByRole("button", { name: "Speak this reply" }).last(); await expect(speakReply).toBeVisible({ timeout: 30_000, }); const replySpoken = page.waitForResponse( (response) => response.url().includes("/api/voice/speak") && response.ok(), ); await speakReply.click(); await replySpoken; await openUserSettings(page, "voice"); await page.getByRole("button", { name: "Other voice providers" }).click(); await page.getByLabel("Provider", { exact: true }).selectOption("scripted"); await expect(page.getByRole("button", { name: "Replace key" })).toBeVisible(); await expect(page.getByRole("button", { name: "Disconnect", exact: true })).toBeVisible(); await page.getByRole("button", { name: "Close voice settings" }).click(); await page .getByTestId("composer-bar") .getByRole("button", { name: "Voice", exact: true }) .click(); await expect(page.getByTestId("call-view")).toBeVisible(); await expect(page.getByTestId("voice-panel")).toBeVisible(); await expect(page.getByRole("button", { name: "Interrupt" })).toBeVisible(); await expect(page.getByRole("button", { name: "Hang up" })).toBeVisible(); await captureScreenshot(page, testInfo, "voice-stage"); await page.getByRole("button", { name: "Hang up" }).click(); await expect(page.getByTestId("call-view")).toHaveCount(0); await openUserSettings(page, "voice"); const settings = page.getByTestId("voice-settings"); await settings.getByRole("button", { name: "Other voice providers" }).click(); await settings.getByPlaceholder(/Paste a replacement key/).fill("leftover-voice-key"); await settings.getByRole("button", { name: "Disconnect", exact: true }).click(); await expect(settings.getByRole("button", { name: "Disconnect", exact: true })).toHaveCount(0); await expect(settings.getByRole("button", { name: "Connect", exact: true })).toBeVisible(); await expect(settings.getByLabel("API key", { exact: true })).toHaveValue(""); await expect(rpc>(page, "voice/credentials", {})).resolves.toEqual( [], ); });