agent-orchestrator/tests/e2e/specs/phase-d-errors.test.ts
Hibryda 56971c3f27 test(e2e): add Phase D/E/F specs covering new architecture (54 tests)
Phase D — Settings & Error Handling:
- D1: Settings panel 6-category tabs, search, active highlighting
- D2: Appearance settings (themes, fonts, cursor, scrollback)
- D3: Theme Editor (color pickers, groups, save/cancel)
- D4: Toast notifications, notification center bell/dropdown
- D5: Error states (no loadError warnings, status bar)

Phase E — Agents & Health:
- E1: ProjectBox tab bar (7+ tabs, PERSISTED-LAZY switching)
- E2: Agent session UI (prompt input, context meter, cost)
- E3: Provider configuration (panels, capabilities, toggles)
- E4: Status bar fleet state (counts, cost, attention queue)
- E5: Project health indicators (status dot, CWD, pressure, burn rate)
- E6: Metrics tab (fleet aggregates, health cards, Live/History)
- E7: Conflict detection (no false badges on fresh launch)
- E8: Audit log (manager-only tab, toolbar, entries)

Phase F — Search & LLM Quality:
- F1: Search overlay (Ctrl+Shift+F, input, empty state, close)
- F2: Context tab & anchors (visualization, budget scale)
- F3: SSH tab (connection list, add button)
- F4-F7: LLM-judged quality (settings completeness, theme editor,
  error messages, overall UI consistency)
2026-03-18 03:20:37 +01:00

190 lines
6.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { browser, expect } from '@wdio/globals';
// Phase D — Error Handling UI Tests (D4D5)
// Tests toast notifications, notification center, and error state handling.
// ─── Helpers ──────────────────────────────────────────────────────────
/** Close any open overlays/panels to reset UI state. */
async function resetToHomeState(): Promise<void> {
// 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);
});
});