dev1/tests/e2e/27-chat-support-stream-chunking.spec.mjs

64 lines
2.6 KiB
JavaScript

// @ts-check
import { test, expect } from '@playwright/test';
import { loadTestUser } from '../utils/testUser.js';
test.describe('@p0 Chat drawer — stream chunking', () => {
test.setTimeout(20000);
test('assistant reply is assembled from multiple chunks/lines', async ({ page }) => {
const user = loadTestUser();
// Stub threads list/create -> empty -> create {id}
const threadId = 'thread-chunks';
await page.route('**/api/chat/threads', async route => {
if (route.request().method() === 'GET') {
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ threads: [] }) });
}
if (route.request().method() === 'POST') {
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ id: threadId }) });
}
return route.fallback();
});
await page.route(`**/api/chat/threads/${threadId}`, async route => {
if (route.request().method() === 'GET') {
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ messages: [] }) });
}
return route.fallback();
});
// Stub stream with multiple line fragments (simulate chunked SSE)
await page.route('**/api/chat/threads/*/stream', async route => {
const body = [
'This is line 1.',
'This is line 2.',
'Final line.',
].map(l => l + '\n').join('');
await route.fulfill({ status: 200, headers: { 'Content-Type': 'text/event-stream' }, body });
});
// 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
await page.getByRole('button', { name: /^Open chat$/i }).click();
// Send prompt
const input = page.getByPlaceholder('Ask me anything…');
const send = page.getByRole('button', { name: /^Send$/i });
await input.fill('test chunked stream');
await send.click();
// Expect all lines to appear merged in the **same** assistant message
const assistantBubble = page.locator('div.text-left.text-gray-800').last();
await expect(assistantBubble).toBeVisible({ timeout: 8000 });
await expect(assistantBubble).toContainText('This is line 1.');
await expect(assistantBubble).toContainText('This is line 2.');
await expect(assistantBubble).toContainText('Final line.');
});
});