import { test, expect } from '@playwright/test'; import fs from 'fs'; import path from 'path'; test.describe('Voice Roleplay Simulation & Visualizer Suite', () => { test.beforeEach(async ({ page }) => { // Stub getUserMedia and AudioContext before loading page await page.addInitScript(() => { window.localStorage.clear(); window.localStorage.setItem('cognitive-clarity-settings', JSON.stringify({ voiceName: 'Kore', vocalStyle: 'Calm', genderPreference: 'Female', openRouterApiKey: 'sk-or-v1-playwright-test-key', roleplayModel: 'google/gemini-3.8-flash', supervisorModel: 'google/gemini-3.8-flash' })); // Mock MediaDevices with real native MediaStream from AudioContext if (navigator.mediaDevices) { navigator.mediaDevices.getUserMedia = async () => { try { const AudioCtx = window.AudioContext || (window as any).webkitAudioContext; const ctx = new AudioCtx(); const dest = ctx.createMediaStreamDestination(); return dest.stream; } catch (e) { return new MediaStream(); } }; navigator.mediaDevices.enumerateDevices = async () => [ { deviceId: 'default', kind: 'audioinput', label: 'Studio Microphone Pro', groupId: 'group-1', toJSON: () => {} } as MediaDeviceInfo ]; } }); // Mock OpenRouter Speech synthesis API await page.route('https://openrouter.ai/api/v1/audio/speech', async (route) => { // Return empty audio buffer const dummyPcm = new Uint8Array(2048); await route.fulfill({ status: 200, contentType: 'audio/mpeg', body: Buffer.from(dummyPcm) }); }); }); test('01 - Launch Voice Session, Visualizer Orb, and Transcript Drawer', async ({ page }, testInfo) => { await page.goto('/'); await page.waitForLoadState('networkidle'); // Click 'Voice' on 'Critical Feedback' const voiceBtn = page.getByRole('button', { name: 'Voice' }).first(); await voiceBtn.click(); // Verify initializing transition screen await expect(page.getByText('Initializing Session')).toBeVisible(); // Wait for Voice Session cockpit await expect(page.getByText(/Active Roleplay Session/)).toBeVisible({ timeout: 5000 }); await expect(page.getByText('Begin Voice Simulation')).toBeVisible(); await expect(page.getByText('Kore Vocal Persona Active')).toBeVisible(); const shotDir = path.join(process.cwd(), 'docs/screenshots', testInfo.project.name); fs.mkdirSync(shotDir, { recursive: true }); await page.screenshot({ path: path.join(shotDir, '13-voice-cockpit-initial.png'), fullPage: true }); // Click 'Begin Voice Simulation' await page.getByRole('button', { name: 'Begin Voice Simulation' }).click(); // Toggle Transcript Drawer const transcriptToggleBtn = page.getByTitle('Toggle Transcript Drawer'); await transcriptToggleBtn.click(); // Verify Transcript Drawer opens await expect(page.getByText('Live Conversation')).toBeVisible(); await page.screenshot({ path: path.join(shotDir, '14-voice-transcript-drawer.png'), fullPage: true }); // Close Transcript Drawer by toggling it back off await transcriptToggleBtn.click(); await expect(page.getByText('Live Conversation')).not.toBeVisible(); // Toggle Mute const muteBtn = page.getByTitle('Mute Microphone'); await muteBtn.click(); await expect(page.getByTitle('Unmute Microphone')).toBeVisible(); // Open Audio Hardware Settings const audioSettingsBtn = page.getByTitle('Audio Settings'); await audioSettingsBtn.click(); await expect(page.getByText('Select Audio Input Device')).toBeVisible(); await page.screenshot({ path: path.join(shotDir, '15-voice-audio-settings-modal.png'), fullPage: true }); }); });