103 lines
3.3 KiB
TypeScript
103 lines
3.3 KiB
TypeScript
import type { Page, Route } from '@playwright/test';
|
|
|
|
export const E2E_SESSION_ID = 'e2e-session-abc123';
|
|
|
|
/**
|
|
* Build an SSE body string from a list of segment texts.
|
|
* Produces the format the companion SSE parser expects.
|
|
*/
|
|
function buildSseBody(segments: Array<{ text: string; emotion?: string }>): string {
|
|
const events = segments
|
|
.map(
|
|
(seg, i) =>
|
|
`event: segment\ndata: ${JSON.stringify({ part_index: i, text: seg.text, emotion: seg.emotion ?? 'neutral' })}\n`,
|
|
)
|
|
.join('\n');
|
|
return `${events}\ndata: [DONE]\n\n`;
|
|
}
|
|
|
|
async function fulfillOrContinue(route: Route, status: number, body?: { contentType: string; body: string }): Promise<void> {
|
|
try {
|
|
if (body) {
|
|
await route.fulfill({ status, contentType: body.contentType, body: body.body });
|
|
} else {
|
|
await route.fulfill({ status });
|
|
}
|
|
} catch {
|
|
// Route may already be handled (navigation cancelled)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mock the companion API for a clean test session.
|
|
*
|
|
* Sets up:
|
|
* - POST /api/session → { session_id: E2E_SESSION_ID }
|
|
* - POST /api/chat → SSE segments from the provided response text
|
|
* - GET /socket.io/** → 404 (voice WebSocket disabled; app shows 'disconnected')
|
|
*/
|
|
export async function setupApiMocks(
|
|
page: Page,
|
|
opts: { chatSegments?: Array<{ text: string; emotion?: string }> } = {},
|
|
): Promise<void> {
|
|
const segments = opts.chatSegments ?? [
|
|
{ text: 'Hello! How can I help you today?', emotion: 'friendly' },
|
|
];
|
|
|
|
await page.route('**/api/session', async (route) => {
|
|
if (route.request().method() !== 'POST') { await route.continue(); return; }
|
|
await fulfillOrContinue(route, 200, {
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({ session_id: E2E_SESSION_ID }),
|
|
});
|
|
});
|
|
|
|
await page.route('**/api/chat', async (route) => {
|
|
if (route.request().method() !== 'POST') { await route.continue(); return; }
|
|
await fulfillOrContinue(route, 200, {
|
|
contentType: 'text/event-stream',
|
|
body: buildSseBody(segments),
|
|
});
|
|
});
|
|
|
|
// Block Socket.IO — voice WebSocket is not under test here
|
|
await page.route('**/socket.io/**', async (route) => {
|
|
await fulfillOrContinue(route, 404);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Mock a session creation failure (500 from server).
|
|
*/
|
|
export async function setupSessionErrorMock(page: Page): Promise<void> {
|
|
await page.route('**/api/session', async (route) => {
|
|
if (route.request().method() !== 'POST') { await route.continue(); return; }
|
|
await fulfillOrContinue(route, 500);
|
|
});
|
|
|
|
await page.route('**/socket.io/**', async (route) => {
|
|
await fulfillOrContinue(route, 404);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Mock a chat request that returns a server error.
|
|
*/
|
|
export async function setupChatErrorMock(page: Page): Promise<void> {
|
|
await page.route('**/api/session', async (route) => {
|
|
if (route.request().method() !== 'POST') { await route.continue(); return; }
|
|
await fulfillOrContinue(route, 200, {
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({ session_id: E2E_SESSION_ID }),
|
|
});
|
|
});
|
|
|
|
await page.route('**/api/chat', async (route) => {
|
|
if (route.request().method() !== 'POST') { await route.continue(); return; }
|
|
await fulfillOrContinue(route, 500);
|
|
});
|
|
|
|
await page.route('**/socket.io/**', async (route) => {
|
|
await fulfillOrContinue(route, 404);
|
|
});
|
|
}
|