// ============================================================ // SETTINGS (React port) — Voice + Content sub-sections. // // Commit 3 of the Settings port. Covers the eight remaining // sub-sections so the React Settings page matches settings.html // feature-for-feature: // • Voice Preferences (STT / TTS selectors + Save + Preview) // • Browser Whisper (WASM stub — localStorage-only) // • Web Speech Recognition (localStorage-only + privacy modal) // • My Templates (Memories CRUD) // • AI Corrections (read-only list) // • Audio Backups (list + delete) // • Saved Encounters (list + delete) // • Compliance (static info card) // ============================================================ const { test, expect, E2E_BASE } = require('../fixtures'); async function openReactSettings(page) { await page.goto(E2E_BASE + '/app/settings'); await page.waitForSelector( '[data-testid="voice-preferences-section"], [data-testid="templates-section"], [data-testid="compliance-section"]', { timeout: 15000 } ); } test.describe('React Settings — Voice + Content sections render', () => { test('Voice Preferences: STT / TTS selectors + Save + Preview', async ({ authedPage: _, page }) => { await openReactSettings(page); await expect(page.locator('[data-testid="stt-model-select"]')).toBeVisible(); await expect(page.locator('[data-testid="tts-voice-select"]')).toBeVisible(); await expect(page.locator('[data-testid="btn-save-voice-prefs"]')).toBeVisible(); await expect(page.locator('[data-testid="btn-preview-voice"]')).toBeVisible(); }); test('Browser Whisper card: enable toggle + model select', async ({ authedPage: _, page }) => { await openReactSettings(page); await expect(page.locator('[data-testid="browser-whisper-enabled"]')).toBeVisible(); await expect(page.locator('[data-testid="browser-whisper-model"]')).toBeVisible(); await expect(page.locator('[data-testid="browser-whisper-status"]')).toBeVisible(); }); test('Web Speech: checkbox shows privacy confirm modal before enabling', async ({ authedPage: _, page }) => { let nativeDialogFired = false; page.on('dialog', async (d) => { nativeDialogFired = true; await d.dismiss(); }); await openReactSettings(page); const checkbox = page.locator('[data-testid="web-speech-enabled"]'); await expect(checkbox).toBeVisible(); const isDisabled = await checkbox.isDisabled(); if (!isDisabled) { await checkbox.check(); await expect(page.locator('[data-testid="confirm-modal-cancel"]')).toBeVisible(); await page.click('[data-testid="confirm-modal-cancel"]'); } expect(nativeDialogFired).toBe(false); }); test('Templates: inputs + save button present', async ({ authedPage: _, page }) => { await openReactSettings(page); await expect(page.locator('[data-testid="mem-category"]')).toBeVisible(); await expect(page.locator('[data-testid="mem-name"]')).toBeVisible(); await expect(page.locator('[data-testid="mem-content"]')).toBeVisible(); await expect(page.locator('[data-testid="btn-mem-save"]')).toBeVisible(); }); test('Templates: saving without name shows inline error', async ({ authedPage: _, page }) => { await openReactSettings(page); await page.click('[data-testid="btn-mem-save"]'); await expect(page.getByText('Enter a template name')).toBeVisible(); }); test('Corrections card renders (list may be empty)', async ({ authedPage: _, page }) => { await openReactSettings(page); await expect(page.locator('[data-testid="corrections-section"]')).toBeVisible(); }); test('Audio Backups + Saved Encounters + Compliance render', async ({ authedPage: _, page }) => { await openReactSettings(page); await expect(page.locator('[data-testid="audio-backups-section"]')).toBeVisible(); await expect(page.locator('[data-testid="saved-encounters-section"]')).toBeVisible(); await expect(page.locator('[data-testid="compliance-section"]')).toBeVisible(); }); });