Testing Guide

Comprehensive testing strategies including unit tests, integration tests, and end-to-end testing with Playwright.

Unit Tests

Component and function-level testing with Vitest

pnpm test

Integration

API and service integration testing

pytest tests/

E2E Tests

Full user flow testing with Playwright

pnpm test:e2e

Test Coverage Areas

Frontend

  • • React component rendering
  • • Hook behavior (useAuth, useChat)
  • • State management
  • • User interactions

Backend

  • • API endpoint responses
  • • Authentication flows
  • • Knowledge base queries
  • • WebSocket connections

VoiceAssist E2E Testing Guide

This guide describes how to run, write, and generate end-to-end (E2E) tests for the VoiceAssist web application using Playwright and Auto Playwright (AI-powered test generation).

Overview

VoiceAssist uses a multi-layered testing approach:

  • Unit Tests: Component-level tests using Vitest (in apps/web-app/src/__tests__/)
  • Integration Tests: API and service integration tests
  • E2E Tests: Full user journey tests using Playwright (in e2e/)

Prerequisites

  • Node.js 18+ installed
  • pnpm 8+ installed
  • Playwright browsers installed

Quick Start

# Install dependencies pnpm install # Install Playwright browsers (first time only) pnpm exec playwright install --with-deps # Run all E2E tests pnpm test:e2e # Run tests with UI (interactive mode) pnpm test:e2e:ui # Run tests in debug mode pnpm test:e2e:debug # View HTML report after tests pnpm test:e2e:report # Run fast Vitest tests (for development) cd apps/web-app && pnpm test:fast

Project Structure

VoiceAssist/
├── e2e/                          # E2E test directory
│   ├── fixtures/                 # Test fixtures and helpers
│   │   ├── auth.ts               # Authentication helpers and mock state
│   │   └── files/                # Test fixture files
│   │       └── sample-document.txt  # Sample document for upload tests
│   ├── login.spec.ts             # Manual login tests
│   ├── voice-mode-navigation.spec.ts  # [ACTIVE] Voice Mode tile → /chat flow
│   ├── voice-mode-session-smoke.spec.ts # [ACTIVE] Voice session smoke test
│   └── ai/                       # AI-generated and implemented tests
│       ├── quick-consult.spec.ts    # [ACTIVE] Chat flow tests
│       ├── clinical-context.spec.ts # [ACTIVE] Clinical context UI tests
│       ├── pdf-upload.spec.ts       # [ACTIVE] Document upload tests
│       ├── voice-mode.spec.ts       # [ACTIVE] Voice mode UI tests (legacy)
│       ├── register-user.spec.ts    # [TEMPLATE] User registration
│       ├── conversation-management.spec.ts # [TEMPLATE] Conversation CRUD
│       ├── profile-settings.spec.ts # [TEMPLATE] Profile management
│       ├── export-conversation.spec.ts # [TEMPLATE] Export functionality
│       └── accessibility.spec.ts    # [TEMPLATE] Keyboard navigation
├── playwright.config.ts          # Playwright configuration
├── scripts/
│   └── generate-e2e-tests.js     # AI test generator script
├── playwright-report/            # HTML test reports (generated)
└── test-results/                 # Test artifacts (generated)

Test Credentials Setup

E2E tests require test credentials. Set these in your .env file:

# E2E Test Credentials (do not commit real credentials) E2E_BASE_URL=http://localhost:5173 E2E_EMAIL=test@example.com E2E_PASSWORD=TestPassword123!

The auth fixtures in e2e/fixtures/auth.ts provide helpers for:

  • Mock authentication: Set localStorage state to bypass login
  • UI-based login: Actually fill and submit the login form
  • Clearing auth state: Reset authentication between tests

Using Auth Fixtures

import { TEST_USER, setupAuthenticatedState, clearAuthState, loginViaUI } from "./fixtures/auth"; test.beforeEach(async ({ page }) => { // Option 1: Mock authentication (faster, no API needed) await setupAuthenticatedState(page); await page.goto("/"); // Option 2: Login via UI (tests actual login flow) await loginViaUI(page); });

Configuration

The Playwright configuration is in playwright.config.ts:

SettingValueDescription
testDir./e2eDirectory containing test files
baseURLhttp://localhost:5173Default app URL (or E2E_BASE_URL env var)
traceon-first-retryCollect trace on first retry
screenshotonly-on-failureScreenshot on failure
videoretain-on-failureRecord video on failure
timeout30000Test timeout (30s)
retries2 (CI) / 0 (local)Retry count

Browser Projects

Tests run on multiple browsers and devices:

  • Chromium (Desktop Chrome)
  • Firefox
  • WebKit (Safari)
  • Mobile Chrome (Pixel 5)
  • Mobile Safari (iPhone 12)

Writing E2E Tests

Basic Test Structure

import { test, expect } from "@playwright/test"; test.describe("Feature Name", () => { test.beforeEach(async ({ page }) => { // Setup: Navigate to starting page await page.goto("/login"); }); test("should do something", async ({ page }) => { // Interact with the page await page.getByLabel(/email/i).fill("user@example.com"); await page.getByLabel(/password/i).fill("password"); await page.getByRole("button", { name: /sign in/i }).click(); // Assert expectations await expect(page).toHaveURL("/"); await expect(page.getByText("Welcome")).toBeVisible(); }); });

Best Practices

  1. Use semantic locators: Prefer getByRole(), getByLabel(), getByText() over CSS selectors
  2. Wait for elements: Use await expect(element).toBeVisible() before interacting
  3. Test user flows: Focus on real user journeys, not implementation details
  4. Keep tests independent: Each test should be able to run in isolation
  5. Use meaningful descriptions: Test names should describe the expected behavior

Common Patterns

Authentication

// Login helper - note: use #password for password field // (getByLabel matches multiple elements due to "Show password" button) async function login(page: Page, email: string, password: string) { await page.goto("/login"); await page.getByLabel(/email/i).fill(email); await page.locator("#password").fill(password); // Use ID selector for password await page.getByRole("button", { name: /sign in/i }).click(); await expect(page).toHaveURL("/"); }

Common Selectors for VoiceAssist

// Form fields page.getByLabel(/email/i); // Email input page.locator("#password"); // Password input (use ID) page.getByRole("button", { name: /sign in/i }); // Sign in button page.getByRole("button", { name: /sign up/i }); // Sign up button // Navigation page.getByRole("link", { name: /sign up/i }); // Registration link page.getByRole("link", { name: /forgot/i }); // Forgot password link // OAuth buttons page.getByRole("button", { name: /google/i }); // Google OAuth page.getByRole("button", { name: /microsoft/i }); // Microsoft OAuth // Validation errors page.locator('[role="alert"]'); // Error alert messages page.getByText(/required/i); // Required field errors

Form Validation

test("should show validation errors", async ({ page }) => { await page.getByRole("button", { name: /submit/i }).click(); await expect(page.locator('[role="alert"]')).toBeVisible(); });
test("should navigate to profile", async ({ page }) => { await page.goto("/profile"); await expect(page).toHaveURL("/profile"); await expect(page.getByRole("heading", { name: /profile/i })).toBeVisible(); });

AI Template Tests

The e2e/ai/ directory contains AI-generated test templates. These are skipped by default to prevent false positives in CI.

Template Status

FileStatusDescription
quick-consult.spec.tsACTIVEFully implemented - tests chat flow
clinical-context.spec.tsACTIVEFully implemented - clinical context UI
pdf-upload.spec.tsACTIVEFully implemented - document upload flow
voice-mode.spec.tsACTIVEFully implemented - voice UI elements
accessibility.spec.tsTEMPLATESkipped - keyboard navigation
conversation-management.spec.tsTEMPLATESkipped - conversation CRUD
export-conversation.spec.tsTEMPLATESkipped - export functionality
profile-settings.spec.tsTEMPLATESkipped - profile management
register-user.spec.tsTEMPLATESkipped - user registration

Promoting a Template to a Real Test

To convert a template into a fully functional test:

  1. Implement all TODO steps with actual Playwright code
  2. Add meaningful assertions that validate expected behavior
  3. Handle edge cases (backend unavailable, auth failures)
  4. Remove .skip from test.describe.skiptest.describe
  5. Update the file header from STATUS: TEMPLATE to STATUS: IMPLEMENTED
  6. Run locally to verify: pnpm test:e2e --project=chromium e2e/ai/<file>.spec.ts

Example promotion (see quick-consult.spec.ts for reference):

// Before (template) test.describe.skip("Feature Name (template)", () => { test("description", async ({ page }) => { // TODO: Step 1: Navigate... }); }); // After (implemented) test.describe("Feature Name", () => { test("description", async ({ page }) => { await page.goto("/feature"); await expect(page.getByRole("heading")).toBeVisible(); // ... real implementation }); });

Voice Mode E2E Tests

VoiceAssist includes dedicated E2E tests for the Voice Mode feature. These tests verify the user journey from the Home page Voice Mode tile to the Chat page with voice capabilities.

Voice Mode Test Files

FileStatusDescription
voice-mode-navigation.spec.tsACTIVETests Voice Mode tile → /chat navigation
voice-mode-session-smoke.spec.tsACTIVETests "Start Voice Session" button behavior
voice-mode-voice-chat-integration.spec.tsACTIVETests voice panel + chat timeline integration
ai/voice-mode.spec.tsACTIVELegacy voice UI tests (for migration)

Voice Mode Navigation Test

File: e2e/voice-mode-navigation.spec.ts

Purpose: Tests the complete Voice Mode navigation flow from Home to Chat.

Test Cases:

  1. Main Navigation Flow:

    • User clicks Voice Mode tile on Home page
    • User is navigated to /chat with voice state
    • Voice Mode panel auto-opens
    • "Start Voice Session" button is visible and enabled
  2. Voice Mode Tile Branding:

    • Verify Voice Mode tile has correct heading
    • Verify description mentions voice/hands-free
    • Check for NEW badge (optional)
  3. Keyboard Accessibility:

    • Voice Mode tile is keyboard focusable
    • Can be activated with Enter/Space
  4. Home Page Layout:

    • Both Voice Mode and Quick Consult tiles visible

Run Locally:

# Run all Voice Mode navigation tests pnpm test:e2e voice-mode-navigation.spec.ts # Run specific test pnpm test:e2e voice-mode-navigation.spec.ts -g "should navigate" # Debug mode pnpm test:e2e voice-mode-navigation.spec.ts --debug

Voice Mode Session Smoke Test

File: e2e/voice-mode-session-smoke.spec.ts

Purpose: Tests "Start Voice Session" button behavior without requiring live backend.

Design Philosophy:

This test is tolerant of backend configuration and only fails if the UI is completely unresponsive. It succeeds if ANY of these occur:

  • Connection state indicator appears (Connecting/Connected/Error)
  • Error banner/toast appears (backend unavailable)
  • Voice visualizer appears
  • Button changes state (disabled, loading, text change)
  • Stop/Cancel button appears
  • Permission dialog appears

Backend Architecture:

Voice Mode now uses OpenAI Realtime API ephemeral sessions for secure authentication:

  • Backend calls /v1/realtime/sessions to create short-lived session tokens
  • Frontend receives ephemeral token (e.g., ek_...) with expiration timestamp
  • WebSocket connects using openai-insecure-api-key.{ephemeral_token} protocol
  • No raw OpenAI API keys exposed to the client
  • Automatic session refresh before expiry (monitored at hook level)

Test Cases:

  1. Response Validation (always runs):

    • Clicks "Start Voice Session"
    • Verifies SOME UI response occurs within 10 seconds
    • Logs which response was detected
    • Fails ONLY if no UI change occurs (indicates broken button)
  2. Connection Status Visibility (always runs):

    • Clicks "Start Voice Session"
    • Verifies connection status text is displayed
    • Status should be one of: connecting, connected, reconnecting, error, failed, expired, or disconnected
    • Tests that ephemeral session states are surfaced in the UI
  3. Live Backend Test (gated by LIVE_REALTIME_E2E=1):

    • Connects to actual OpenAI Realtime API
    • Verifies either connected state or error message
    • Skipped by default to avoid API costs
    • Uses ephemeral session tokens (backend must have valid OPENAI_API_KEY)

Run Locally:

# Run smoke test (tolerant, no backend required) pnpm test:e2e voice-mode-session-smoke.spec.ts # Run with live backend (requires OPENAI_API_KEY) LIVE_REALTIME_E2E=1 pnpm test:e2e voice-mode-session-smoke.spec.ts # Debug mode pnpm test:e2e voice-mode-session-smoke.spec.ts --debug

Environment Variables:

  • LIVE_REALTIME_E2E=1: Enable live backend testing (costs money, requires valid OpenAI key)

Voice Pipeline Smoke Suite

For comprehensive voice pipeline validation, use the Voice Pipeline Smoke Suite which covers backend, frontend unit, and E2E tests:

# Quick validation (backend + frontend + E2E) # See docs/VOICE_MODE_PIPELINE.md for full commands # Backend (mocked) cd services/api-gateway && source venv/bin/activate python -m pytest tests/integration/test_openai_config.py tests/integration/test_voice_metrics.py -v # Frontend unit (run individually to avoid OOM) cd apps/web-app && export NODE_OPTIONS="--max-old-space-size=768" npx vitest run src/hooks/__tests__/useRealtimeVoiceSession.test.ts --reporter=dot # E2E npx playwright test e2e/voice-mode-*.spec.ts --project=chromium --reporter=list

For detailed pipeline architecture, metrics tracking, and complete test commands, see VOICE_MODE_PIPELINE.md.

Voice Mode Test Strategy

Deterministic Tests (run in CI):

  • ✅ Navigation flow (Voice Mode tile → /chat)
  • ✅ UI element presence (panel, buttons, tiles)
  • ✅ Button responsiveness (some UI change occurs)
  • ✅ Connection status visibility (ephemeral session states)
  • ✅ Keyboard accessibility

Optional Live Tests (gated by env flag):

  • ⏭️ Actual WebSocket connection (requires backend)
  • ⏭️ Audio capture/playback (requires permissions)
  • ⏭️ OpenAI Realtime API integration (costs money)

Not Tested (too flaky/expensive for E2E):

  • ❌ Actual voice recognition accuracy
  • ❌ Real-time latency measurements
  • ❌ Audio quality assessment
  • ❌ Cross-browser WebRTC compatibility

Voice Mode vs Quick Consult

Both features are tested with similar patterns:

FeatureNavigation TestSession Test
Voice Modevoice-mode-navigationvoice-mode-session-smoke (tolerant)
Quick Consultquick-consult (in ai/)Covered by chat flow tests

Troubleshooting Voice Mode Tests

Voice Mode panel not found:

  • Check that data-testid="voice-mode-card" exists on Home page
  • Verify ChatPage passes autoOpenRealtimeVoice prop
  • Check browser console for React errors

Start button not responding:

  • Check if button is actually enabled (isEnabled check)
  • Verify WebSocket connection handler exists
  • Check for JavaScript errors in console

Live tests timing out:

  • Ensure OPENAI_API_KEY is set and valid
  • Check that backend /voice/realtime-session endpoint is accessible
  • Verify network connectivity (no firewall blocking WebSockets)

Permission dialogs blocking tests:

  • Tests should handle permission prompts gracefully
  • Smoke test considers permission dialog as a valid response
  • Use browser flags to auto-grant permissions if needed

Writing Robust Assertions

Avoid Always-Passing Tests

Never use patterns like:

// BAD: Always passes expect(condition || true).toBe(true); // BAD: Empty assertion test("should work", async ({ page }) => { await page.goto("/"); // No assertions! });

Use real assertions:

// GOOD: Real validation expect(stateChanged, `Expected state change but got: ${debugInfo}`).toBe(true); // GOOD: Verify actual behavior await expect(page.getByText("Success")).toBeVisible();

Login Test Pattern

The login test (e2e/login.spec.ts) validates form submission by checking for ANY of:

  • Navigation away from /login
  • Error alert or toast appears
  • Button changes to loading state
  • Network request was made to auth endpoint
// Real assertion with network tracking page.on("request", (req) => { if (req.url().includes("/auth")) loginRequestMade = true; }); const stateChanged = !isStillOnLogin || hasAlert || hasToast || isButtonDisabled || loginRequestMade; expect(stateChanged, "Form submission must trigger some response").toBe(true);

AI-Powered Test Generation

VoiceAssist includes Auto Playwright for AI-powered test generation.

Setup

  1. Set your OpenAI API key:

    export OPENAI_API_KEY="sk-..."
  2. Run the generator:

    pnpm generate:e2e # Skip existing files (default) pnpm generate:e2e --force # Overwrite all files

How It Works

The generator script (scripts/generate-e2e-tests.js) creates test files from natural language descriptions. When OPENAI_API_KEY is set, it generates tests using the auto() function from auto-playwright, which interprets plain-text instructions at runtime.

Important: By default, the generator skips existing files to preserve manually edited tests. Use --force to regenerate all files.

Adding New AI-Generated Tests

Edit scripts/generate-e2e-tests.js to add new scenarios:

const testScenarios = [ // ... existing scenarios { name: "My New Feature", filename: "my-feature.spec.ts", description: "User performs action X and sees result Y", steps: [ "Navigate to the feature page", "Click the start button", "Fill in the form with test data", "Submit the form", "Verify the success message appears", ], }, ];

Then regenerate tests:

pnpm generate:e2e

Auto Playwright Usage in Tests

import { test } from "@playwright/test"; import { auto } from "auto-playwright"; test("AI-powered test", async ({ page }) => { // Navigate manually or let auto handle it await page.goto("/"); // Use natural language instructions await auto("Click the login button", { page, test }); await auto("Enter email address testuser@example.com", { page, test }); await auto("Click submit", { page, test }); await auto("Verify the dashboard loads", { page, test }); });

Running Tests

Local Development

# Run all tests pnpm test:e2e # Run specific test file pnpm exec playwright test e2e/login.spec.ts # Run tests matching a pattern pnpm exec playwright test -g "login" # Run only on Chrome pnpm exec playwright test --project=chromium # Run in headed mode (see browser) pnpm exec playwright test --headed # Run in debug mode pnpm test:e2e:debug

CI/CD Integration

The GitHub Actions workflow (.github/workflows/frontend-ci.yml) automatically:

  1. Installs dependencies and Playwright browsers
  2. Runs all E2E tests (templates are skipped)
  3. Uploads test reports as artifacts

Note: AI test generation is disabled by default in CI to avoid OpenAI API costs. To enable it, set the repository variable CI_GENERATE_AI_TESTS=true in Settings > Secrets and variables > Actions > Variables.

Add the following secrets in your repository settings (Settings > Secrets and variables > Actions):

SecretPurpose
E2E_EMAILTest user email for login tests (required)
E2E_PASSWORDTest user password for login tests (required)
OPENAI_API_KEYAI test generation (optional, needs var enabled)
VariablePurpose
CI_GENERATE_AI_TESTSSet to true to enable AI test generation

Test Reports

After running tests:

# Open HTML report pnpm test:e2e:report # Reports are also saved to: # - playwright-report/ (HTML) # - test-results/results.json (JSON) # - test-results/junit.xml (JUnit)

Debugging Failed Tests

Using Traces

When a test fails on retry, Playwright records a trace. View it:

pnpm exec playwright show-trace test-results/<test-name>/trace.zip

Debug Mode

# Run specific test in debug mode pnpm exec playwright test e2e/login.spec.ts --debug

Screenshots and Videos

Failed tests automatically capture:

  • Screenshots: test-results/<test-name>/screenshot.png
  • Videos: test-results/<test-name>/video.webm

Environment Variables

VariableDescriptionDefault
E2E_BASE_URLBase URL for testshttp://localhost:5173
E2E_EMAILTest user email addresstest@example.com
E2E_PASSWORDTest user passwordTestPassword123!
OPENAI_API_KEYOpenAI API key for AI generation-
CISet to true in CI environments-

Security Note: Never commit real credentials. Use .env files (gitignored) for local development and GitHub Secrets for CI.

Troubleshooting

Tests timing out

Increase timeout in playwright.config.ts:

export default defineConfig({ timeout: 60 * 1000, // 60 seconds });

Browser not installed

pnpm exec playwright install --with-deps

Tests flaky in CI

  • Add retries: retries: 2 in config
  • Use proper waits: await expect(element).toBeVisible()
  • Check for race conditions in your app

Auto Playwright not working

  • Ensure OPENAI_API_KEY is set
  • Check OpenAI API quota
  • Review generated test code for correct selectors

Resources

Contact

For issues with E2E tests:

  1. Check the test output and logs
  2. Review screenshots/videos/traces
  3. Consult this guide
  4. Open an issue in the repository

Latest Test Results

Testing Results & Manual Test Guide

Date: 2025-11-22 Branch: fix/system-review-and-testing Tester: Claude (AI Assistant) Status: Code Review Complete, Manual Testing Required


Summary

This document outlines the testing that has been performed and provides a manual testing checklist for validating the WebSocket protocol fixes and conversation management features.

Changes Made

  1. ✅ Fixed WebSocket protocol mismatch between frontend and backend
  2. ✅ Updated message types (chunk, message.done)
  3. ✅ Changed field names to camelCase (messageId)
  4. ✅ Fixed client message sending format
  5. ✅ Added environment configuration for WebSocket URL
  6. ✅ Created comprehensive documentation

Code Review Results

Files Changed

FileLines ChangedStatusDescription
services/api-gateway/app/api/realtime.py~50✅ ModifiedUpdated WebSocket protocol to match frontend
apps/web-app/src/hooks/useChatSession.ts~15✅ ModifiedFixed message sending and WebSocket URL
apps/web-app/.env.example-✅ CreatedEnvironment configuration template
apps/web-app/.env.development-✅ CreatedDevelopment environment config
docs/SYSTEM_REVIEW_2025-11-22.md-✅ CreatedComprehensive system review
docs/WEBSOCKET_PROTOCOL.md-✅ CreatedWebSocket protocol specification
docs/TESTING_RESULTS_2025-11-22.md-✅ CreatedThis file

Issues Fixed

  1. WebSocket Protocol Mismatch (P0 - CRITICAL)

    • Status: ✅ Fixed
    • Backend now sends chunk instead of message_chunk
    • Backend now sends message.done instead of message_complete
    • All field names are now camelCase
  2. Client Message Type (P0 - CRITICAL)

    • Status: ✅ Fixed
    • Client now sends type: "message" instead of type: "message.send"
    • Message content sent directly, not nested in object
  3. Hardcoded WebSocket URL (P1 - HIGH)

    • Status: ✅ Fixed
    • URL now configurable via environment variables
    • Development default: ws://localhost:8000/api/realtime/ws
    • Production default: wss://assist.asimo.io/api/realtime/ws

Issues Identified (Not Fixed Yet)

  1. WebSocket Authentication (P0 - CRITICAL)

    • Status: ⚠️ Not Fixed
    • Backend doesn't validate JWT token
    • Recommendation: Add token validation in backend
  2. Last Message Preview (P1 - HIGH)

    • Status: ⚠️ Needs Investigation
    • Backend may not populate lastMessagePreview field
    • Recommendation: Verify backend implementation
  3. Optimistic Updates (P2 - MEDIUM)

    • Status: ⚠️ Not Implemented
    • Conversation operations wait for server response
    • Recommendation: Add optimistic UI updates
  4. Error Notifications (P2 - MEDIUM)

    • Status: ⚠️ Not Implemented
    • Errors only logged to console
    • Recommendation: Add toast notifications

Manual Testing Checklist

Prerequisites

  1. Backend Running:

    cd ~/VoiceAssist docker-compose ps # Should show: voiceassist-server (healthy)
  2. Frontend Setup:

    cd ~/VoiceAssist/apps/web-app cp .env.example .env pnpm install pnpm dev
  3. Browser: Chrome, Firefox, or Safari (latest version)


Test Suite 1: WebSocket Connection

Test 1.1: Initial Connection

Steps:

  1. Open browser to http://localhost:5173 (or configured port)
  2. Login with test account
  3. Navigate to /chat
  4. Observe browser console for WebSocket messages

Expected Results:

  • ✅ WebSocket connects to ws://localhost:8000/api/realtime/ws
  • ✅ Receives connected event with client_id
  • ✅ Connection status shows "connected" in UI
  • ✅ No console errors

Actual Results:

  • Pass
  • Fail (describe issue):

Test 1.2: Heartbeat (Ping/Pong)

Steps:

  1. With chat open, wait 30 seconds
  2. Observe browser console for ping/pong messages

Expected Results:

  • ✅ Client sends { type: "ping" } every 30 seconds
  • ✅ Server responds with { type: "pong", timestamp: "..." }
  • ✅ Connection stays alive

Actual Results:

  • Pass
  • Fail (describe issue):

Test 1.3: Reconnection

Steps:

  1. Open browser DevTools → Network tab
  2. Right-click on WS connection → "Close connection"
  3. Observe reconnection behavior

Expected Results:

  • ✅ Connection status shows "reconnecting"
  • ✅ Client attempts to reconnect with exponential backoff
  • ✅ Connection re-established within 5 seconds
  • ✅ Connection status shows "connected" again

Actual Results:

  • Pass
  • Fail (describe issue):

Test Suite 2: Message Streaming

Test 2.1: Send Message

Steps:

  1. Type "What are the symptoms of diabetes?" in message input
  2. Press Enter or click Send
  3. Observe message flow in browser console

Expected Results:

  • ✅ User message appears in chat immediately
  • ✅ Client sends:
    { "type": "message", "content": "What are the symptoms of diabetes?", "session_id": "conversation-uuid" }
  • ✅ Server responds with chunk events
  • ✅ Server sends message.done with complete message

Actual Results:

  • Pass
  • Fail (describe issue):

Test 2.2: Streaming Response

Steps:

  1. Send a message
  2. Observe assistant response appearing

Expected Results:

  • ✅ Response appears incrementally (streaming)
  • ✅ Typing indicator shows during streaming
  • ✅ Each chunk is appended correctly
  • ✅ Final message is complete and readable

Actual Results:

  • Pass
  • Fail (describe issue):

Test 2.3: Citations

Steps:

  1. Send a message that triggers KB search
  2. Observe citations in response

Expected Results:

  • ✅ Citations appear at bottom of message
  • ✅ Citation count is shown
  • ✅ Clicking citation expands details

Actual Results:

  • Pass
  • Fail (describe issue):

Test Suite 3: Conversation Management

Test 3.1: Create Conversation

Steps:

  1. Click "New Conversation" button
  2. Observe URL and UI changes

Expected Results:

  • ✅ New conversation created
  • ✅ URL updates to /chat/{new-conversation-id}
  • ✅ Chat interface loads
  • ✅ No error messages

Actual Results:

  • Pass
  • Fail (describe issue):

Test 3.2: Rename Conversation

Steps:

  1. Hover over conversation in sidebar
  2. Click three-dot menu
  3. Click "Rename"
  4. Type new name and press Enter

Expected Results:

  • ✅ Inline input appears
  • ✅ Name updates after pressing Enter
  • ✅ Sidebar shows new name
  • ✅ No errors in console

Actual Results:

  • Pass
  • Fail (describe issue):

Test 3.3: Archive Conversation

Steps:

  1. Hover over conversation in sidebar
  2. Click three-dot menu
  3. Click "Archive"

Expected Results:

  • ✅ Conversation removed from active list
  • ✅ If active conversation, redirects to /chat
  • ✅ No errors

Actual Results:

  • Pass
  • Fail (describe issue):

Test 3.4: Delete Conversation

Steps:

  1. Hover over conversation in sidebar
  2. Click three-dot menu
  3. Click "Delete"
  4. Confirm deletion in dialog

Expected Results:

  • ✅ Confirmation dialog appears
  • ✅ After confirming, conversation deleted
  • ✅ Removed from sidebar
  • ✅ If active conversation, redirects to /chat

Actual Results:

  • Pass
  • Fail (describe issue):

Test 3.5: Last Message Preview

Steps:

  1. Send a message in a conversation
  2. Create a new conversation
  3. Look at previous conversation in sidebar

Expected Results:

  • ✅ Sidebar shows preview of last message
  • ✅ Preview is truncated to ~60 characters
  • ✅ Shows "No messages yet" for empty conversations

Actual Results:

  • Pass
  • Fail (describe issue):

Test Suite 4: Error Handling

Test 4.1: Network Error

Steps:

  1. Send a message
  2. Stop the backend server: docker-compose stop voiceassist-server
  3. Observe error handling

Expected Results:

  • ✅ Connection status shows "disconnected"
  • ✅ Reconnection attempts visible
  • ✅ Error message shown to user
  • ✅ After restarting server, reconnects automatically

Actual Results:

  • Pass
  • Fail (describe issue):

Test 4.2: Invalid Conversation

Steps:

  1. Navigate to /chat/invalid-uuid

Expected Results:

  • ✅ Error page shown: "Conversation Not Found"
  • ✅ "Back to Conversations" button works
  • ✅ No crash or console errors

Actual Results:

  • Pass
  • Fail (describe issue):

Test 4.3: Server Error

Steps:

  1. Send a malformed message (modify code temporarily)
  2. Observe error handling

Expected Results:

  • ✅ Error message received from server
  • ✅ Error displayed to user
  • ✅ Can send new messages after error

Actual Results:

  • Pass
  • Fail (describe issue):

Test Suite 5: Browser Compatibility

Test 5.1: Chrome

Browser: Chrome (version: ___) Status:

  • All tests pass
  • Some tests fail (list):

Test 5.2: Firefox

Browser: Firefox (version: ___) Status:

  • All tests pass
  • Some tests fail (list):

Test 5.3: Safari

Browser: Safari (version: ___) Status:

  • All tests pass
  • Some tests fail (list):

Test Suite 6: Accessibility

Test 6.1: Keyboard Navigation

Steps:

  1. Use Tab key to navigate through conversations
  2. Use Enter to select conversation
  3. Use Tab to navigate to message input
  4. Type message and press Enter

Expected Results:

  • ✅ All interactive elements are keyboard accessible
  • ✅ Focus indicators visible
  • ✅ Can complete full chat flow with keyboard only

Actual Results:

  • Pass
  • Fail (describe issue):

Test 6.2: Screen Reader

Tool: NVDA / JAWS / VoiceOver

Steps:

  1. Navigate conversation list with screen reader
  2. Send a message
  3. Listen to assistant response

Expected Results:

  • ✅ Conversations announced correctly
  • ✅ New messages announced
  • ✅ Status changes announced

Actual Results:

  • Pass
  • Fail (describe issue):

Performance Testing

Test 7.1: Message List Performance

Steps:

  1. Create conversation with 100+ messages
  2. Scroll through message list
  3. Monitor performance metrics

Expected Results:

  • ✅ Smooth scrolling (60 FPS)
  • ✅ No memory leaks
  • ✅ Messages virtualized correctly

Actual Results:

  • Pass
  • Fail (describe issue):

Test 7.2: Multiple Conversations

Steps:

  1. Create 50+ conversations
  2. Navigate between them
  3. Monitor performance

Expected Results:

  • ✅ List renders quickly
  • ✅ Navigation is instant
  • ✅ No lag when switching

Actual Results:

  • Pass
  • Fail (describe issue):

Known Issues

Critical (Requires Fix)

  1. WebSocket Authentication Not Implemented
    • Backend doesn't validate JWT tokens
    • Security risk in production
    • Action: Implement token validation before production deployment

High Priority

  1. Last Message Preview May Not Work
    • Backend field population not verified
    • Action: Test manually and fix if needed

Medium Priority

  1. No Error Notifications

    • Errors only logged to console
    • Action: Add toast notification system
  2. No Optimistic Updates

    • UI waits for server responses
    • Action: Implement optimistic updates for better UX

Test Summary

Total Tests: 24 Passed: _ / 24 Failed: _ / 24 Not Tested: ___ / 24

Overall Status: ⏳ Awaiting Manual Testing


Recommendations

Before Production Deployment

  1. Implement WebSocket Authentication (P0)

    • Validate JWT tokens on connection
    • Reject unauthorized connections
    • Estimated effort: 1 hour
  2. Verify Last Message Preview (P1)

    • Test backend field population
    • Fix if not working
    • Estimated effort: 2 hours
  3. Add Error Notifications (P1)

    • Implement toast notification system
    • Show user-friendly errors
    • Estimated effort: 2 hours

For Better UX

  1. Add Optimistic Updates (P2)

    • Update UI before server responds
    • Revert on error
    • Estimated effort: 3 hours
  2. Add Loading Skeletons (P2)

    • Show loading states for conversations
    • Improve perceived performance
    • Estimated effort: 2 hours

For Production Monitoring

  1. Add Analytics (P3)

    • Track WebSocket connection success rate
    • Monitor message latency
    • Track error rates
    • Estimated effort: 4 hours
  2. Add Error Tracking (P3)

    • Integrate Sentry or similar
    • Track client-side errors
    • Estimated effort: 2 hours

Next Steps

  1. ✅ Code review complete
  2. ⏳ Manual testing (use this checklist)
  3. ⏳ Fix any issues found during testing
  4. ⏳ Run automated test suite
  5. ⏳ Update this document with results
  6. ⏳ Create pull request

Testing Started: 2025-11-22 Testing Completed: **____** Tester Signature: **____**

Beginning of guide
End of guide