proteinea / tests /chat-e2e.spec.ts
Mahmoud Eljendy
feat: Antibody Studio — AI-native antibody design workspace by Proteinea
30cc31a
import { test, expect } from "@playwright/test";
/**
* E2E test for the real-backend SSE chat path.
*
* Stubs the actual endpoints the chat page uses:
* - POST /api/projects → ensures a project exists
* - POST /api/projects/proj-test/tasks → creates a task (conversation_id)
* - POST ${PHYLO_BACKEND}/api/tasks/{id}/messages/stream → SSE stream
*
* The page calls createConversation() which calls ensureDefaultProject() +
* createTask(), then getStreamUrl() which posts to /api/tasks/{id}/messages/stream.
*/
test("SSE chat path renders streamed assistant response", async ({ page }) => {
const taskId = "task-e2e-test";
// Stub project creation/lookup
await page.route("**/api/projects", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ id: "proj-test", name: "Quick Tasks" }),
});
});
// Stub task creation (createConversation → createTask)
await page.route("**/api/projects/proj-test/tasks", async (route) => {
if (route.request().method() === "POST") {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ id: taskId, projectId: "proj-test", title: "(new conversation)", createdAt: Date.now(), updatedAt: Date.now(), messages: [], artifacts: [] }),
});
} else {
await route.fallback();
}
});
// Stub the SSE stream endpoint (where sendReal posts the message)
await page.route(`**/api/tasks/${taskId}/messages/stream`, async (route) => {
const sseBody = [
'data: {"type":"text_delta","text":"Hello "}',
'data: {"type":"text_delta","text":"world"}',
'data: {"type":"done"}',
"",
].join("\n");
await route.fulfill({
status: 200,
contentType: "text/event-stream",
body: sseBody,
});
});
// Stub dataset sync status (called on mount for greeting runtime spec)
await page.route("**/api/datasets/sync/status", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify([]),
});
});
// Stub task PATCH (persistence after assistant response)
await page.route(`**/api/tasks/${taskId}`, async (route) => {
if (route.request().method() === "PATCH") {
await route.fulfill({ status: 200, contentType: "application/json", body: "{}" });
} else {
await route.fallback();
}
});
// Stub message append
await page.route(`**/api/tasks/${taskId}/messages`, async (route) => {
await route.fulfill({ status: 200, contentType: "application/json", body: "{}" });
});
await page.goto("/chat");
// Wait for the page to be ready (conversation created, input available)
const textarea = page.locator("textarea");
await expect(textarea).toBeVisible({ timeout: 10_000 });
// Type a message and send
await textarea.fill("Test message");
await textarea.press("Enter");
// Assert the assistant message contains the streamed text
await expect(page.locator("text=Hello world")).toBeVisible({ timeout: 10_000 });
// Assert no error banners
await expect(page.locator("text=Connection error")).not.toBeVisible();
});