import { test, expect } from '@playwright/test'; import fs from 'fs'; import path from 'path'; test.describe('Chat Roleplay Simulation & Supervision Suite', () => { test.beforeEach(async ({ page }) => { await page.addInitScript(() => { window.localStorage.clear(); window.localStorage.setItem('cognitive-clarity-settings', JSON.stringify({ voiceName: 'Zephyr', vocalStyle: 'Helpful', genderPreference: 'Neutral', openRouterApiKey: 'sk-or-v1-playwright-test-key', roleplayModel: 'google/gemini-3.8-flash', supervisorModel: 'google/gemini-3.8-flash' })); }); // Mock OpenRouter API requests deterministically await page.route('https://openrouter.ai/api/v1/chat/completions', async (route) => { const request = route.request(); const postData = JSON.parse(request.postData() || '{}'); // 1. Streaming Roleplay Chat if (postData.stream) { const sseBody = [ 'data: {"choices":[{"delta":{"content":"Hey, sorry I didn\'t "}}]}\n\n', 'data: {"choices":[{"delta":{"content":"get back to you right away. Work was totally overwhelming yesterday."}}]}\n\n', 'data: [DONE]\n\n' ].join(''); await route.fulfill({ status: 200, contentType: 'text/event-stream', body: sseBody }); return; } // 2. Turn Supervisor or Session Report Analysis const isSessionReport = postData.messages?.some((m: any) => typeof m.content === 'string' && m.content.includes('SESSION EVALUATION PROMPT') ); if (isSessionReport) { const mockSummaryReport = { analysis: { distortions: ['Mind Reading'], isAdaptive: true, evidence: 'User clearly asked for context before jumping to catastrophic conclusions.' }, rating: { score: 4, reason: 'Demonstrated measured emotional self-regulation and clear communication.' }, suggestions: { alternativeThought: 'A delayed message is not proof of abandonment or malice.', behavioralStep: 'Practice pausing for 2 minutes before assuming negative intentions.' } }; await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ choices: [{ message: { content: JSON.stringify(mockSummaryReport) } }] }) }); return; } // Turn supervisor analysis const mockTurnInsight = { analysis: { distortions: [], isAdaptive: true, evidence: 'Checked in calmly without accusation.' }, rating: { score: 5, reason: 'Balanced and open inquiry.' }, suggestions: { alternativeThought: 'Waiting for factual data is adaptive.', behavioralStep: 'Continue listening to the friend\'s explanation.' } }; await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ choices: [{ message: { content: JSON.stringify(mockTurnInsight) } }] }) }); }); }); test('01 - Launch Text Chat, Stream Response, Live Insights, and Export Report', async ({ page }, testInfo) => { await page.goto('/'); await page.waitForLoadState('networkidle'); // Click 'Chat' on the first scenario (The Silent Friend) const chatBtn = page.getByRole('button', { name: 'Chat' }).first(); await chatBtn.click(); // Verify initializing transition screen await expect(page.getByText('Initializing Session')).toBeVisible(); // Wait for Chat Session view await expect(page.getByText('The Silent Friend')).toBeVisible({ timeout: 5000 }); await expect(page.getByText('Complete Interaction')).toBeVisible(); const shotDir = path.join(process.cwd(), 'docs/screenshots', testInfo.project.name); fs.mkdirSync(shotDir, { recursive: true }); await page.screenshot({ path: path.join(shotDir, '10-chat-session-initial.png'), fullPage: true }); // Send a message const chatInput = page.getByPlaceholder('Type your response in character...'); await chatInput.fill('Hey Sam, no worries at all! Just wanted to check if you were doing okay.'); await page.keyboard.press('Enter'); // Verify bot streamed message appears await expect( page.getByText('Work was totally overwhelming yesterday') ).toBeVisible({ timeout: 5000 }); // Verify Live Insight Panel updates await expect(page.getByText('Live Clinical Insight')).toBeVisible(); await expect(page.getByText('Waiting for factual data is adaptive')).toBeVisible(); await page.screenshot({ path: path.join(shotDir, '11-chat-interaction-streamed.png'), fullPage: true }); // Complete the interaction await page.getByRole('button', { name: 'Complete Interaction' }).click(); // Verify Session Summary Report renders await expect(page.getByRole('heading', { name: 'Session Summary Report' })).toBeVisible({ timeout: 6000 }); await expect(page.getByText('Adaptive Growth Observed')).toBeVisible(); await expect(page.getByText('Master Reframe')).toBeVisible(); await expect(page.getByText('Waiting for factual data is adaptive')).toBeVisible(); // Verify Export actions are present await expect(page.getByTitle('Download Markdown Report')).toBeVisible(); await expect(page.getByTitle('Download JSON Report')).toBeVisible(); await page.screenshot({ path: path.join(shotDir, '12-session-report-summary.png'), fullPage: true }); // Close Report and return to home await page.getByRole('button', { name: 'Close Report & Return' }).click(); await expect(page.getByRole('heading', { name: 'Training Scenarios' })).toBeVisible(); }); });