- Increase logo size (48x48 desktop, 56x56 mobile) for better visibility - Add logo as favicon - Add logo to mobile header - Move user menu to navigation bars (sidebar on desktop, bottom bar on mobile) - Fix desktop chat layout - container structure prevents voice controls cutoff - Fix mobile bottom bar - use icon-only ActionIcons instead of truncated text buttons - Hide Create Node/New Conversation buttons on mobile to save header space - Make fixed header and voice controls work properly with containers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
144 lines
5.4 KiB
TypeScript
144 lines
5.4 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
test.describe('Voice Mode', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
// Navigate to chat page (should be authenticated via setup)
|
|
await page.goto('/chat');
|
|
await expect(page.getByText('Ponderants Interview')).toBeVisible();
|
|
});
|
|
|
|
test('should start voice conversation and display correct button text', async ({ page }) => {
|
|
// Initial state - button should show "Start Voice Conversation"
|
|
const voiceButton = page.getByRole('button', { name: /Start Voice Conversation/i });
|
|
await expect(voiceButton).toBeVisible();
|
|
|
|
// Click to start voice mode
|
|
await voiceButton.click();
|
|
|
|
// Button should transition to one of the active states
|
|
// Could be "Generating speech..." if there's a greeting, or "Listening..." if no greeting
|
|
await expect(page.getByRole('button', { name: /Generating speech|Listening|Checking for greeting/i })).toBeVisible({
|
|
timeout: 5000,
|
|
});
|
|
});
|
|
|
|
test('should skip audio during generation and transition to listening', async ({ page }) => {
|
|
// Start voice mode
|
|
const voiceButton = page.getByRole('button', { name: /Start Voice Conversation/i });
|
|
await voiceButton.click();
|
|
|
|
// Wait for generation or playing state
|
|
await expect(page.getByRole('button', { name: /Generating speech|AI is speaking/i })).toBeVisible({
|
|
timeout: 5000,
|
|
});
|
|
|
|
// Skip button should be visible
|
|
const skipButton = page.getByRole('button', { name: /Skip/i });
|
|
await expect(skipButton).toBeVisible();
|
|
|
|
// Click skip
|
|
await skipButton.click();
|
|
|
|
// Should transition to listening state
|
|
await expect(page.getByRole('button', { name: /Listening/i })).toBeVisible({ timeout: 3000 });
|
|
});
|
|
|
|
test('should use test buttons to simulate full conversation flow', async ({ page }) => {
|
|
// Start voice mode
|
|
await page.getByRole('button', { name: /Start Voice Conversation/i }).click();
|
|
|
|
// Wait for initial state (could be checking, generating, or listening)
|
|
await page.waitForTimeout(1000);
|
|
|
|
// If there's a skip button (greeting is playing), click it
|
|
const skipButton = page.getByRole('button', { name: /Skip/i });
|
|
if (await skipButton.isVisible()) {
|
|
await skipButton.click();
|
|
}
|
|
|
|
// Should eventually reach listening state
|
|
await expect(page.getByRole('button', { name: /Listening/i })).toBeVisible({ timeout: 5000 });
|
|
|
|
// In development mode, test buttons should be visible
|
|
const isDevelopment = process.env.NODE_ENV !== 'production';
|
|
if (isDevelopment) {
|
|
// Click "Simulate User Speech" test button
|
|
const simulateSpeechButton = page.getByRole('button', { name: /Simulate Speech/i });
|
|
await expect(simulateSpeechButton).toBeVisible();
|
|
await simulateSpeechButton.click();
|
|
|
|
// Should transition to userSpeaking state
|
|
await expect(page.getByRole('button', { name: /Speaking/i })).toBeVisible({ timeout: 2000 });
|
|
|
|
// Add a phrase using test button
|
|
const addPhraseButton = page.getByRole('button', { name: /Add Phrase/i });
|
|
await addPhraseButton.click();
|
|
|
|
// Should be in timingOut state
|
|
await expect(page.getByRole('button', { name: /auto-submit/i })).toBeVisible({ timeout: 2000 });
|
|
|
|
// Trigger timeout using test button
|
|
const triggerTimeoutButton = page.getByRole('button', { name: /Trigger Timeout/i });
|
|
await triggerTimeoutButton.click();
|
|
|
|
// Should submit and wait for AI
|
|
await expect(page.getByRole('button', { name: /Submitting|Waiting for AI/i })).toBeVisible({
|
|
timeout: 2000,
|
|
});
|
|
|
|
// Wait for AI response (this will take a few seconds)
|
|
await expect(page.getByRole('button', { name: /Generating speech|AI is speaking/i })).toBeVisible({
|
|
timeout: 15000,
|
|
});
|
|
|
|
// Skip the AI audio
|
|
const skipAudioButton = page.getByRole('button', { name: /Skip/i });
|
|
if (await skipAudioButton.isVisible()) {
|
|
await skipAudioButton.click();
|
|
}
|
|
|
|
// Should return to listening
|
|
await expect(page.getByRole('button', { name: /Listening/i })).toBeVisible({ timeout: 3000 });
|
|
}
|
|
});
|
|
|
|
test('should stop voice mode and return to idle', async ({ page }) => {
|
|
// Start voice mode
|
|
const voiceButton = page.getByRole('button', { name: /Start Voice Conversation/i });
|
|
await voiceButton.click();
|
|
|
|
// Wait for active state
|
|
await page.waitForTimeout(1000);
|
|
|
|
// Click the button again to stop
|
|
await page.getByRole('button', { name: /Listening|Speaking|Generating|AI is speaking/i }).click();
|
|
|
|
// Should return to idle state
|
|
await expect(page.getByRole('button', { name: /Start Voice Conversation/i })).toBeVisible({
|
|
timeout: 2000,
|
|
});
|
|
});
|
|
|
|
test('should disable text input while voice mode is active', async ({ page }) => {
|
|
const textInput = page.getByPlaceholder(/type your thoughts here/i);
|
|
|
|
// Text input should be enabled initially
|
|
await expect(textInput).toBeEnabled();
|
|
|
|
// Start voice mode
|
|
await page.getByRole('button', { name: /Start Voice Conversation/i }).click();
|
|
|
|
// Wait for voice mode to activate
|
|
await page.waitForTimeout(1000);
|
|
|
|
// Text input should be disabled
|
|
await expect(textInput).toBeDisabled();
|
|
|
|
// Stop voice mode
|
|
await page.getByRole('button', { name: /Listening|Speaking|Generating|AI is speaking/i }).click();
|
|
|
|
// Text input should be enabled again
|
|
await expect(textInput).toBeEnabled();
|
|
});
|
|
});
|