Files
WealthySmart/frontend/e2e/asistente.spec.ts
Carlos Escalante fbc0816be6
Some checks failed
Deploy to VPS / test (push) Failing after 1m37s
Deploy to VPS / deploy (push) Has been skipped
Add Playwright assistant regression coverage
2026-07-14 21:48:59 -06:00

114 lines
4.3 KiB
TypeScript

import { expect, test, type Page } from "@playwright/test";
test.setTimeout(150_000);
async function startFreshAssistant(page: Page) {
await page.goto("/login");
await page.getByLabel("Username").fill(process.env.ADMIN_USERNAME!);
await page.getByLabel("Password").fill(process.env.ADMIN_PASSWORD!);
await page.getByRole("button", { name: /sign in/i }).click();
await page.waitForURL("/");
const initialConnect = page.waitForResponse((response) => {
if (!response.url().includes("/api/copilotkit") || response.request().method() !== "POST") {
return false;
}
try {
return JSON.parse(response.request().postData() ?? "{}").method === "agent/connect";
} catch {
return false;
}
});
await page.goto("/asistente");
await expect(page.getByRole("heading", { name: "Asistente" })).toBeVisible();
await (await initialConnect).finished();
const newConversation = page.getByRole("button", { name: "Nueva conversación" });
if (await newConversation.isEnabled()) {
await newConversation.click();
const reconnect = page.waitForResponse((response) => {
if (!response.url().includes("/api/copilotkit") || response.request().method() !== "POST") {
return false;
}
try {
return JSON.parse(response.request().postData() ?? "{}").method === "agent/connect";
} catch {
return false;
}
});
await page.getByRole("button", { name: "Borrar historial" }).click();
await (await reconnect).finished();
await expect(
page.getByRole("textbox", { name: "Escribe tu pregunta…" }),
).toBeEnabled({ timeout: 30_000 });
}
}
async function ask(page: Page, question: string, expectedTool: string) {
// The BFF response is the exact CopilotKit stream consumed by the browser.
// Checking it catches server-side RUN_ERROR events even if the UI changes.
const stream = page.waitForResponse(
(response) => {
if (
!response.url().includes("/api/copilotkit") ||
response.request().method() !== "POST"
) {
return false;
}
try {
return JSON.parse(response.request().postData() ?? "{}").method === "agent/run";
} catch {
return false;
}
},
);
const composer = page.getByRole("textbox", { name: "Escribe tu pregunta…" });
await expect(composer).toBeEnabled({ timeout: 30_000 });
await composer.fill(question);
const sendButton = page.getByTestId("copilot-send-button");
await expect(sendButton).toBeEnabled({ timeout: 30_000 });
await sendButton.click();
await expect(page.getByText(question, { exact: true }).last()).toBeVisible();
const response = await stream;
await response.finished();
const events = await response.text();
expect(events).not.toContain("RUN_ERROR");
expect(events).toContain(expectedTool);
// The HTTP stream may finish before CopilotKit has committed the tool run
// and released its client-side running state. Waiting for the page action
// avoids losing the next Enter keypress during that short interval.
await expect(page.getByRole("button", { name: "Nueva conversación" })).toBeEnabled({
timeout: 30_000,
});
}
test("Asistente completes Luna's read-only tool flows", async ({ page }) => {
const consoleErrors: string[] = [];
page.on("console", (message) => {
if (message.type() === "error") consoleErrors.push(message.text());
});
await startFreshAssistant(page);
await ask(page, "What date is it today?", "get_current_date");
await ask(page, "List my last 10 transactions.", "get_recent_transactions");
await ask(page, "What is my net worth?", "get_net_worth");
await ask(page, "How much did I spend today?", "get_daily_spending");
await ask(page, "Show my spending by category this month.", "render_spending_summary");
const spendingCard = page.getByTestId("spending-summary-card");
await expect(spendingCard).toBeVisible({ timeout: 30_000 });
await expect(page.getByRole("textbox", { name: "Escribe tu pregunta…" })).toBeEnabled({
timeout: 30_000,
});
await page.reload();
await expect(page.getByRole("heading", { name: "Asistente" })).toBeVisible();
await expect(page.getByText("Show my spending by category this month.", { exact: true })).toBeVisible();
await expect(page.getByTestId("spending-summary-card")).toBeVisible();
expect(consoleErrors.join("\n")).not.toContain("ChatClientException");
});