import { test, expect, _electron as electron } from '@playwright/test'; test.describe('Settings Modal E2E', () => { test.describe.configure({ mode: 'serial' }); let electronApp: any; let window: any; test.beforeAll(async () => { electronApp = await electron.launch({ // We assume this is run from apps/desktop or from root with appropriate context. // Adjust this path if your build output is located elsewhere. args: ['apps/desktop/out/main/index.js'], env: { ...process.env, NODE_ENV: 'test', }, }); let found = false; for (const w of electronApp.windows()) { await w.waitForLoadState('domcontentloaded'); const t = await w.title(); if (t === 'D3RO Voice' || t === 'd3ro-voice') { window = w; found = true; break; } } if (!found) { window = await electronApp.waitForEvent('window', { predicate: async (page: any) => { await page.waitForLoadState('domcontentloaded'); const t = await page.title(); return t === 'D3RO Voice' || t === 'd3ro-voice'; } }); } // Bypass onboarding for these tests await window.evaluate(() => { window.electronAPI.config.set({ key: 'onboardingCompleted', value: true }); }); // Reload window to apply bypassed onboarding await window.reload(); await window.waitForLoadState('domcontentloaded'); }); test.afterAll(async () => { if (electronApp) { await electronApp.close(); } }); test('should open Settings Modal and navigate through tabs', async () => { // Open Settings Modal using IPC await window.evaluate(() => { window.dispatchEvent(new CustomEvent('d3ro:open-settings')); }); // Wait for the Settings modal to appear by checking for a known tab or title const tabs = window.locator('.MuiTab-root'); await expect(tabs.first()).toBeVisible({ timeout: 5000 }); // 1. General Tab (index 0) await tabs.nth(0).click(); // Wait for something in General Tab to be visible // "테마" or "언어" select boxes should be present. We'll check for switch inputs await expect(window.locator('input[type="checkbox"]').first()).toBeVisible(); // 2. LLM Tab (index 3) await tabs.nth(3).click(); // "D3RO API 서버 설정" is hardcoded in SettingsModal.tsx await expect(window.locator('text="D3RO API 서버 설정"').first()).toBeVisible(); // 3. Cloud Sync Tab (index 5) await tabs.nth(5).click(); // Cloud Sync tab might be empty or take time to render, give it a small wait await window.waitForTimeout(500); // 4. System / About Tab (index 6) await tabs.nth(6).click(); // "D3RO-VOICE" is hardcoded in the About tab await expect(window.locator('text="D3RO-VOICE"').first()).toBeVisible(); // Close the Settings Modal // The close button has an X icon from lucide-react. Or we can just press Escape await window.keyboard.press('Escape'); // Ensure the modal is closed await expect(tabs.first()).toBeHidden({ timeout: 2000 }); }); });