// @ts-check import { test, expect } from '@playwright/test'; import { loadTestUser } from '../utils/testUser.js'; test.describe('@p0 Chat drawer — stream throttling (429) + recovery', () => { test.setTimeout(20000); test('second prompt hits 429 → shows fallback; third succeeds', async ({ page }) => { const user = loadTestUser(); // Stub threads (list/create + preload) const threadId = 'thread-throttle'; 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(); }); // Stream endpoint: 1st -> 200, 2nd -> 429, 3rd -> 200 let callCount = 0; await page.route('**/api/chat/threads/*/stream', async route => { callCount += 1; if (callCount === 2) { return route.fulfill({ status: 429, contentType: 'text/event-stream', body: '' }); } const text = callCount === 1 ? 'First OK reply.' : 'Recovered OK reply.'; return route.fulfill({ status: 200, headers: { 'Content-Type': 'text/event-stream' }, body: text + '\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 await page.getByRole('button', { name: /^Open chat$/i }).click(); // 1) First send → success const input = page.getByPlaceholder('Ask me anything…'); const send = page.getByRole('button', { name: /^Send$/i }); await input.fill('hello 1'); await send.click(); await expect(page.getByText(/^First OK reply\./)).toBeVisible({ timeout: 8000 }); // 2) Second send → 429 throttled → fallback error appears await input.fill('hello 2'); await send.click(); await expect( page.getByText(/Sorry — something went wrong\. Please try again later\./i) ).toBeVisible({ timeout: 8000 }); // 3) Third send → recovery success await input.fill('hello 3'); await send.click(); await expect(page.getByText(/^Recovered OK reply\./)).toBeVisible({ timeout: 8000 }); }); });