import { browser, expect } from '@wdio/globals'; // Phase D — Error Handling UI Tests (D4–D5) // Tests toast notifications, notification center, and error state handling. // ─── Helpers ────────────────────────────────────────────────────────── /** Close any open overlays/panels to reset UI state. */ async function resetToHomeState(): Promise { // Close settings panel if open const panel = await browser.$('.sidebar-panel'); if (await panel.isDisplayed().catch(() => false)) { await browser.execute(() => { const btn = document.querySelector('.settings-close') || document.querySelector('.panel-close'); if (btn) (btn as HTMLElement).click(); }); await browser.pause(300); } // Close notification panel if open await browser.execute(() => { const panel = document.querySelector('[data-testid="notification-panel"]'); if (panel) { const backdrop = document.querySelector('.notification-center .backdrop'); if (backdrop) (backdrop as HTMLElement).click(); } }); await browser.pause(200); // Dismiss search overlay const overlay = await browser.$('.search-overlay'); if (await overlay.isExisting()) await browser.keys('Escape'); await browser.pause(200); } // ─── Scenario D4: Toast Notifications ──────────────────────────────── describe('Scenario D4 — Toast Notifications', () => { before(async () => { await resetToHomeState(); }); it('should render ToastContainer in the app', async () => { const container = await browser.$('.toast-container'); await expect(container).toBeExisting(); }); it('should display notification center bell icon', async () => { const bell = await browser.$('[data-testid="notification-bell"]'); await expect(bell).toBeDisplayed(); }); it('should show notification dropdown when bell clicked', async () => { // Click bell via JS for reliability await browser.execute(() => { const bell = document.querySelector('[data-testid="notification-bell"]'); if (bell) (bell as HTMLElement).click(); }); await browser.pause(500); const panel = await browser.$('[data-testid="notification-panel"]'); await expect(panel).toBeDisplayed(); // Verify panel has a title const title = await browser.execute(() => { const el = document.querySelector('[data-testid="notification-panel"] .panel-title'); return el?.textContent?.trim() ?? ''; }); expect(title).toBe('Notifications'); }); it('should show panel actions area in notification center', async () => { // Panel should still be open from previous test const panelExists = await browser.execute(() => { return document.querySelector('[data-testid="notification-panel"]') !== null; }); if (!panelExists) { await browser.execute(() => { const bell = document.querySelector('[data-testid="notification-bell"]'); if (bell) (bell as HTMLElement).click(); }); await browser.pause(500); } // Verify panel-actions div exists (buttons may be conditional on having notifications) const actionsDiv = await browser.$('[data-testid="notification-panel"] .panel-actions'); await expect(actionsDiv).toBeExisting(); // Verify the panel list area exists (may show empty state) const list = await browser.$('[data-testid="notification-panel"] .panel-list'); await expect(list).toBeExisting(); // Close panel await browser.execute(() => { const backdrop = document.querySelector('.notification-center .backdrop'); if (backdrop) (backdrop as HTMLElement).click(); }); await browser.pause(300); }); it('should close notification panel on Escape', async () => { // Open panel await browser.execute(() => { const bell = document.querySelector('[data-testid="notification-bell"]'); if (bell) (bell as HTMLElement).click(); }); await browser.pause(400); const panelBefore = await browser.$('[data-testid="notification-panel"]'); await expect(panelBefore).toBeDisplayed(); // Press Escape await browser.keys('Escape'); await browser.pause(400); // Panel should be gone const panelAfter = await browser.execute(() => { return document.querySelector('[data-testid="notification-panel"]') !== null; }); expect(panelAfter).toBe(false); }); }); // ─── Scenario D5: Error States ─────────────────────────────────────── describe('Scenario D5 — Error States', () => { before(async () => { await resetToHomeState(); }); it('should not show any loadError warnings on fresh launch', async () => { // Check that no .load-error elements are visible const loadErrors = await browser.$$('.load-error'); let visibleCount = 0; for (const el of loadErrors) { if (await el.isDisplayed().catch(() => false)) { visibleCount++; } } expect(visibleCount).toBe(0); }); it('should show status bar with agent state indicators', async () => { const statusBar = await browser.$('[data-testid="status-bar"]'); await expect(statusBar).toBeDisplayed(); // Verify status bar contains project count text const text = await statusBar.getText(); expect(text).toContain('projects'); }); it('should show notification center in a functional state', async () => { const center = await browser.$('[data-testid="notification-center"]'); await expect(center).toBeDisplayed(); // Bell should be clickable without errors await browser.execute(() => { const bell = document.querySelector('[data-testid="notification-bell"]'); if (bell) (bell as HTMLElement).click(); }); await browser.pause(400); // Verify panel rendered without crash const panel = await browser.$('[data-testid="notification-panel"]'); await expect(panel).toBeDisplayed(); // Close await browser.execute(() => { const backdrop = document.querySelector('.notification-center .backdrop'); if (backdrop) (backdrop as HTMLElement).click(); }); await browser.pause(200); }); it('should render project boxes without error indicators', async () => { const boxes = await browser.$$('[data-testid="project-box"]'); expect(boxes.length).toBeGreaterThanOrEqual(1); // Verify no project box has an error overlay or error class const errorBoxes = await browser.execute(() => { const boxes = document.querySelectorAll('[data-testid="project-box"]'); let errorCount = 0; for (const box of boxes) { if (box.querySelector('.project-error') || box.classList.contains('error')) { errorCount++; } } return errorCount; }); expect(errorBoxes).toBe(0); }); });