dev1/tests/e2e/24-chat-support-drawer.spec.mjs

93 lines
3.2 KiB
JavaScript

// @ts-check
import { test, expect } from '@playwright/test';
import { loadTestUser } from '../utils/testUser.js';
test.describe('@p0 Chat drawer — Support stream', () => {
test.setTimeout(20000);
test('FAB opens Support → create/load thread → send prompt → assistant reply appears', async ({ page }) => {
const user = loadTestUser();
// ---- Stub chat API before the app mounts (ensureSupportThread runs on mount) ----
let createdId = 'thread-e2e';
// list existing -> none
await page.route('**/api/chat/threads', async (route) => {
if (route.request().method() === 'GET') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ threads: [] }),
});
return;
}
// create new
if (route.request().method() === 'POST') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ id: createdId }),
});
return;
}
await route.fallback();
});
// preload thread messages -> empty
await page.route(`**/api/chat/threads/${createdId}`, async (route) => {
if (route.request().method() === 'GET') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ messages: [] }),
});
return;
}
await route.fallback();
});
// streaming endpoint -> return simple line chunks as text/event-stream
await page.route('**/api/chat/threads/*/stream', async (route) => {
const reply = 'E2E assistant reply.';
await route.fulfill({
status: 200,
headers: { 'Content-Type': 'text/event-stream' },
body: `${reply}\n`,
});
});
// ---- Sign in ----
await page.context().clearCookies();
await page.goto('/signin', { waitUntil: 'networkidle' });
await page.getByPlaceholder('Username', { exact: true }).fill(user.username);
await page.getByPlaceholder('Password', { exact: true }).fill(user.password);
await page.getByRole('button', { name: /^Sign In$/ }).click();
await page.waitForURL('**/signin-landing**', { timeout: 15000 });
// ---- Open chat via FAB (forces Support pane) ----
const fab = page.getByRole('button', { name: /^Open chat$/i });
await expect(fab).toBeVisible({ timeout: 5000 });
await fab.click();
// Drawer visible; Support tab selected
const supportTab = page.getByRole('button', { name: /^Aptiva\s*Support$/i });
await expect(supportTab).toBeVisible({ timeout: 5000 });
// Input and Send present
const input = page.getByPlaceholder('Ask me anything…');
const send = page.getByRole('button', { name: /^Send$/i });
await expect(input).toBeVisible();
await expect(send).toBeDisabled(); // empty prompt
// Send a message -> should render user bubble + streamed assistant reply
await input.fill('Hi from E2E');
await expect(send).toBeEnabled();
await send.click();
// User bubble
await expect(page.getByText(/^Hi from E2E$/)).toBeVisible({ timeout: 5000 });
// Assistant reply (from our stream stub)
await expect(page.getByText(/^E2E assistant reply\./)).toBeVisible({ timeout: 8000 });
});
});