2:I[7012,["4765","static/chunks/4765-f5afdf8061f456f3.js","9856","static/chunks/9856-3b185291364d9bef.js","6687","static/chunks/app/docs/%5B...slug%5D/page-e07536548216bee4.js"],"MarkdownRenderer"] 4:I[9856,["4765","static/chunks/4765-f5afdf8061f456f3.js","9856","static/chunks/9856-3b185291364d9bef.js","6687","static/chunks/app/docs/%5B...slug%5D/page-e07536548216bee4.js"],""] 5:I[4126,[],""] 7:I[9630,[],""] 8:I[4278,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"HeadingProvider"] 9:I[1476,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"Header"] a:I[3167,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"Sidebar"] b:I[7409,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"PageFrame"] 3:T5cd3, # 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 ```bash # 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: ```bash # 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 ```typescript 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`: | Setting | Value | Description | | ------------ | ----------------------- | ----------------------------------------- | | `testDir` | `./e2e` | Directory containing test files | | `baseURL` | `http://localhost:5173` | Default app URL (or E2E_BASE_URL env var) | | `trace` | `on-first-retry` | Collect trace on first retry | | `screenshot` | `only-on-failure` | Screenshot on failure | | `video` | `retain-on-failure` | Record video on failure | | `timeout` | `30000` | Test timeout (30s) | | `retries` | `2` (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 ```typescript 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 ```typescript // 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 ```typescript // 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 ```typescript test("should show validation errors", async ({ page }) => { await page.getByRole("button", { name: /submit/i }).click(); await expect(page.locator('[role="alert"]')).toBeVisible(); }); ``` #### Navigation ```typescript 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 | File | Status | Description | | --------------------------------- | -------- | ---------------------------------------- | | `quick-consult.spec.ts` | ACTIVE | Fully implemented - tests chat flow | | `clinical-context.spec.ts` | ACTIVE | Fully implemented - clinical context UI | | `pdf-upload.spec.ts` | ACTIVE | Fully implemented - document upload flow | | `voice-mode.spec.ts` | ACTIVE | Fully implemented - voice UI elements | | `accessibility.spec.ts` | TEMPLATE | Skipped - keyboard navigation | | `conversation-management.spec.ts` | TEMPLATE | Skipped - conversation CRUD | | `export-conversation.spec.ts` | TEMPLATE | Skipped - export functionality | | `profile-settings.spec.ts` | TEMPLATE | Skipped - profile management | | `register-user.spec.ts` | TEMPLATE | Skipped - 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.skip` → `test.describe` 5. **Update the file header** from `STATUS: TEMPLATE` to `STATUS: IMPLEMENTED` 6. **Run locally** to verify: `pnpm test:e2e --project=chromium e2e/ai/.spec.ts` Example promotion (see `quick-consult.spec.ts` for reference): ```typescript // 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 | File | Status | Description | | ------------------------------------------- | ------ | --------------------------------------------- | | `voice-mode-navigation.spec.ts` | ACTIVE | Tests Voice Mode tile → /chat navigation | | `voice-mode-session-smoke.spec.ts` | ACTIVE | Tests "Start Voice Session" button behavior | | `voice-mode-voice-chat-integration.spec.ts` | ACTIVE | Tests voice panel + chat timeline integration | | `ai/voice-mode.spec.ts` | ACTIVE | Legacy 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**: ```bash # 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**: ```bash # 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: ```bash # 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_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: | Feature | Navigation Test | Session Test | | ------------- | ------------------------ | ------------------------------------- | | Voice Mode | `voice-mode-navigation` | `voice-mode-session-smoke` (tolerant) | | Quick Consult | `quick-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:** ```typescript // BAD: Always passes expect(condition || true).toBe(true); // BAD: Empty assertion test("should work", async ({ page }) => { await page.goto("/"); // No assertions! }); ``` **Use real assertions:** ```typescript // 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 ```typescript // 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: ```bash export OPENAI_API_KEY="sk-..." ``` 2. Run the generator: ```bash 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: ```javascript 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: ```bash pnpm generate:e2e ``` ### Auto Playwright Usage in Tests ```typescript 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 ```bash # 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): | Secret | Purpose | | ---------------- | ------------------------------------------------ | | `E2E_EMAIL` | Test user email for login tests (required) | | `E2E_PASSWORD` | Test user password for login tests (required) | | `OPENAI_API_KEY` | AI test generation (optional, needs var enabled) | | Variable | Purpose | | ---------------------- | ------------------------------------------ | | `CI_GENERATE_AI_TESTS` | Set to `true` to enable AI test generation | ### Test Reports After running tests: ```bash # 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: ```bash pnpm exec playwright show-trace test-results//trace.zip ``` ### Debug Mode ```bash # 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//screenshot.png` - Videos: `test-results//video.webm` ## Environment Variables | Variable | Description | Default | | ---------------- | -------------------------------- | ----------------------- | | `E2E_BASE_URL` | Base URL for tests | `http://localhost:5173` | | `E2E_EMAIL` | Test user email address | `test@example.com` | | `E2E_PASSWORD` | Test user password | `TestPassword123!` | | `OPENAI_API_KEY` | OpenAI API key for AI generation | - | | `CI` | Set 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`: ```typescript export default defineConfig({ timeout: 60 * 1000, // 60 seconds }); ``` ### Browser not installed ```bash 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 - [Playwright Documentation](https://playwright.dev/docs/intro) - [Auto Playwright](https://github.com/lucgagan/auto-playwright) - [VoiceAssist Development Workflow](./client-implementation/DEVELOPMENT_WORKFLOW.md) - [WEB_APP_SPECS](./WEB_APP_SPECS.md) ## 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 6:["slug","TESTING_GUIDE","c"] 0:["X7oMT3VrOffzp0qvbeOas",[[["",{"children":["docs",{"children":[["slug","TESTING_GUIDE","c"],{"children":["__PAGE__?{\"slug\":[\"TESTING_GUIDE\"]}",{}]}]}]},"$undefined","$undefined",true],["",{"children":["docs",{"children":[["slug","TESTING_GUIDE","c"],{"children":["__PAGE__",{},[["$L1",["$","div",null,{"children":[["$","div",null,{"className":"mb-6 flex items-center justify-between gap-4","children":[["$","div",null,{"children":[["$","p",null,{"className":"text-sm text-gray-500 dark:text-gray-400","children":"Docs / Raw"}],["$","h1",null,{"className":"text-3xl font-bold text-gray-900 dark:text-white","children":"Testing Guide"}],["$","p",null,{"className":"text-sm text-gray-600 dark:text-gray-400","children":["Sourced from"," ",["$","code",null,{"className":"font-mono text-xs","children":["docs/","TESTING_GUIDE.md"]}]]}]]}],["$","a",null,{"href":"https://github.com/mohammednazmy/VoiceAssist/edit/main/docs/TESTING_GUIDE.md","target":"_blank","rel":"noreferrer","className":"inline-flex items-center gap-2 rounded-md border border-gray-200 dark:border-gray-700 px-3 py-1.5 text-sm text-gray-700 dark:text-gray-200 hover:border-primary-500 dark:hover:border-primary-400 hover:text-primary-700 dark:hover:text-primary-300","children":"Edit on GitHub"}]]}],["$","div",null,{"className":"rounded-lg border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 p-6","children":["$","$L2",null,{"content":"$3"}]}],["$","div",null,{"className":"mt-6 flex flex-wrap gap-2 text-sm","children":[["$","$L4",null,{"href":"/reference/all-docs","className":"inline-flex items-center gap-1 rounded-md bg-gray-100 px-3 py-1 text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700","children":"← All documentation"}],["$","$L4",null,{"href":"/","className":"inline-flex items-center gap-1 rounded-md bg-gray-100 px-3 py-1 text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700","children":"Home"}]]}]]}],null],null],null]},[null,["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children","docs","children","$6","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[null,["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children","docs","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/7f586cdbbaa33ff7.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","className":"h-full","children":["$","body",null,{"className":"__className_f367f3 h-full bg-white dark:bg-gray-900","children":[["$","a",null,{"href":"#main-content","className":"skip-to-content","children":"Skip to main content"}],["$","$L8",null,{"children":[["$","$L9",null,{}],["$","$La",null,{}],["$","main",null,{"id":"main-content","className":"lg:pl-64","role":"main","aria-label":"Documentation content","children":["$","$Lb",null,{"children":["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]]}]]}]}]],null],null],["$Lc",null]]]] c:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Testing Guide | Docs | VoiceAssist Docs"}],["$","meta","3",{"name":"description","content":"This guide describes how to run, write, and generate end-to-end (E2E) tests for the VoiceAssist web application using Playwright and Auto Playwright (..."}],["$","meta","4",{"name":"keywords","content":"VoiceAssist,documentation,medical AI,voice assistant,healthcare,HIPAA,API"}],["$","meta","5",{"name":"robots","content":"index, follow"}],["$","meta","6",{"name":"googlebot","content":"index, follow"}],["$","link","7",{"rel":"canonical","href":"https://assistdocs.asimo.io"}],["$","meta","8",{"property":"og:title","content":"VoiceAssist Documentation"}],["$","meta","9",{"property":"og:description","content":"Comprehensive documentation for VoiceAssist - Enterprise Medical AI Assistant"}],["$","meta","10",{"property":"og:url","content":"https://assistdocs.asimo.io"}],["$","meta","11",{"property":"og:site_name","content":"VoiceAssist Docs"}],["$","meta","12",{"property":"og:type","content":"website"}],["$","meta","13",{"name":"twitter:card","content":"summary"}],["$","meta","14",{"name":"twitter:title","content":"VoiceAssist Documentation"}],["$","meta","15",{"name":"twitter:description","content":"Comprehensive documentation for VoiceAssist - Enterprise Medical AI Assistant"}],["$","meta","16",{"name":"next-size-adjust"}]] 1:null