agent-orchestrator/tests/e2e/specs/phase-c-tabs.test.ts
Hibryda 1b838eb9fc fix(e2e): update selectors for redesigned UI (9 spec files)
- BTerminal → Agent Orchestrator (title, describe blocks, LLM context)
- Settings: .sidebar-panel → .settings-panel .settings-content,
  .dropdown-trigger → .dropdown-btn, .dropdown-option → .dropdown-item
- Settings open: [data-testid=settings-btn] + .panel-close
- Font controls: .size-control → .stepper, .size-btn → stepper button
- Terminal: data-testid selectors for toggle/tab-add
- Agent pane: .cost-bar → .status-strip/.done-bar, context meter conditional
- Project header: .cwd → .info-cwd
- Health: .health-dot → .status-dot
- Multi-project: proper this.skip() when single-project fixture
2026-03-18 04:45:22 +01:00

268 lines
9 KiB
TypeScript

import { browser, expect } from '@wdio/globals';
// Phase C — Tab-Based Feature Tests (C5-C9)
// Settings panel, project health, metrics tab, context tab, files tab.
// --- Helpers ---
/** Get all project box IDs currently rendered. */
async function getProjectIds(): Promise<string[]> {
return browser.execute(() => {
const boxes = document.querySelectorAll('[data-testid="project-box"]');
return Array.from(boxes).map(
(b) => b.getAttribute('data-project-id') ?? '',
).filter(Boolean);
});
}
/** Switch to a tab in a specific project box. */
async function switchProjectTab(projectId: string, tabIndex: number): Promise<void> {
await browser.execute((id, idx) => {
const box = document.querySelector(`[data-project-id="${id}"]`);
const tabs = box?.querySelectorAll('[data-testid="project-tabs"] .ptab');
if (tabs && tabs[idx]) (tabs[idx] as HTMLElement).click();
}, projectId, tabIndex);
await browser.pause(300);
}
// --- Scenario C5: Settings Panel Sections ---
describe('Scenario C5 — Settings Panel Sections', () => {
before(async () => {
// Close sidebar panel if open
const panel = await browser.$('.sidebar-panel');
if (await panel.isDisplayed().catch(() => false)) {
await browser.execute(() => {
const btn = document.querySelector('.panel-close');
if (btn) (btn as HTMLElement).click();
});
await browser.pause(300);
}
// Open settings
await browser.execute(() => {
const btn = document.querySelector('[data-testid="settings-btn"]');
if (btn) (btn as HTMLElement).click();
});
await browser.pause(500);
});
it('should show Appearance section with theme dropdown', async () => {
const hasTheme = await browser.execute(() => {
const panel = document.querySelector('.sidebar-panel .settings-panel');
if (!panel) return false;
const text = panel.textContent ?? '';
return text.toLowerCase().includes('theme') || text.toLowerCase().includes('appearance');
});
expect(hasTheme).toBe(true);
});
it('should show font settings (UI font and Terminal font)', async () => {
const hasFonts = await browser.execute(() => {
const panel = document.querySelector('.sidebar-panel .settings-panel');
if (!panel) return false;
const text = panel.textContent ?? '';
return text.toLowerCase().includes('font');
});
expect(hasFonts).toBe(true);
});
it('should show default shell setting in Agents category', async () => {
// Switch to Agents category which contains shell settings
const hasShell = await browser.execute(() => {
// Check across all settings categories
const panel = document.querySelector('.sidebar-panel .settings-panel');
if (!panel) return false;
const text = panel.textContent ?? '';
return text.toLowerCase().includes('shell') || text.toLowerCase().includes('agent');
});
expect(hasShell).toBe(true);
});
it('should have theme dropdown with many themes', async () => {
// Click the theme dropdown
const opened = await browser.execute(() => {
const btn = document.querySelector('.appearance .custom-dropdown .dropdown-btn');
if (btn) { (btn as HTMLElement).click(); return true; }
return false;
});
if (opened) {
await browser.pause(300);
const optionCount = await browser.execute(() => {
return document.querySelectorAll('.dropdown-menu .dropdown-item').length;
});
expect(optionCount).toBeGreaterThanOrEqual(15);
// Close dropdown
await browser.execute(() => {
const btn = document.querySelector('.appearance .custom-dropdown .dropdown-btn');
if (btn) (btn as HTMLElement).click();
});
await browser.pause(200);
}
});
after(async () => {
// Close settings
await browser.execute(() => {
const btn = document.querySelector('.panel-close');
if (btn) (btn as HTMLElement).click();
});
await browser.pause(300);
});
});
// --- Scenario C6: Project Health Indicators ---
describe('Scenario C6 — Project Health Indicators', () => {
it('should show status dots on project headers', async () => {
const hasDots = await browser.execute(() => {
const dots = document.querySelectorAll('.project-header .status-dot');
return dots.length;
});
// At least one project should have a status dot
expect(hasDots).toBeGreaterThanOrEqual(1);
});
it('should show idle status when no agents running', async () => {
const ids = await getProjectIds();
if (ids.length < 1) return;
const dotColor = await browser.execute((id) => {
const box = document.querySelector(`[data-project-id="${id}"]`);
const dot = box?.querySelector('.status-dot');
if (!dot) return 'not-found';
const style = window.getComputedStyle(dot);
return style.backgroundColor || style.color || 'unknown';
}, ids[0]);
// Should have some color value (not 'not-found')
expect(dotColor).not.toBe('not-found');
});
it('should show status bar agent counts', async () => {
const counts = await browser.execute(() => {
const bar = document.querySelector('[data-testid="status-bar"]');
if (!bar) return '';
return bar.textContent ?? '';
});
// Should contain project count at minimum
expect(counts).toMatch(/project|idle|running|stalled|\d/i);
});
});
// --- Scenario C7: Metrics Tab ---
describe('Scenario C7 — Metrics Tab', () => {
it('should show Metrics tab in project tab bar', async () => {
const ids = await getProjectIds();
if (ids.length < 1) return;
const hasMetrics = await browser.execute((id) => {
const box = document.querySelector(`[data-project-id="${id}"]`);
const tabs = box?.querySelectorAll('[data-testid="project-tabs"] .ptab');
if (!tabs) return false;
return Array.from(tabs).some(t => t.textContent?.trim().toLowerCase().includes('metric'));
}, ids[0]);
expect(hasMetrics).toBe(true);
});
it('should render Metrics panel content when tab clicked', async () => {
const ids = await getProjectIds();
if (ids.length < 1) return;
const projectId = ids[0];
// Find and click Metrics tab
await browser.execute((id) => {
const box = document.querySelector(`[data-project-id="${id}"]`);
const tabs = box?.querySelectorAll('[data-testid="project-tabs"] .ptab');
if (!tabs) return;
for (const tab of tabs) {
if (tab.textContent?.trim().toLowerCase().includes('metric')) {
(tab as HTMLElement).click();
break;
}
}
}, projectId);
await browser.pause(500);
const hasContent = await browser.execute((id) => {
const box = document.querySelector(`[data-project-id="${id}"]`);
const panel = box?.querySelector('.metrics-panel, .metrics-tab');
return panel !== null;
}, projectId);
expect(hasContent).toBe(true);
// Switch back to Model tab
await switchProjectTab(projectId, 0);
});
});
// --- Scenario C8: Context Tab ---
describe('Scenario C8 — Context Tab Visualization', () => {
it('should render Context tab with token meter', async () => {
const ids = await getProjectIds();
if (ids.length < 1) return;
const projectId = ids[0];
// Switch to Context tab (index 2)
await switchProjectTab(projectId, 2);
const hasContextUI = await browser.execute((id) => {
const box = document.querySelector(`[data-project-id="${id}"]`);
const ctx = box?.querySelector('.context-tab, .context-stats, .token-meter, .stat-value');
return ctx !== null;
}, projectId);
expect(hasContextUI).toBe(true);
// Switch back to Model tab
await switchProjectTab(projectId, 0);
});
});
// --- Scenario C9: Files Tab with Editor ---
describe('Scenario C9 — Files Tab & Code Editor', () => {
it('should render Files tab with directory tree', async () => {
const ids = await getProjectIds();
if (ids.length < 1) return;
const projectId = ids[0];
// Switch to Files tab (index 3)
await switchProjectTab(projectId, 3);
await browser.pause(500);
const hasTree = await browser.execute((id) => {
const box = document.querySelector(`[data-project-id="${id}"]`);
const tree = box?.querySelector('.file-tree, .directory-tree, .files-tab');
return tree !== null;
}, projectId);
expect(hasTree).toBe(true);
});
it('should list files from the project directory', async () => {
const ids = await getProjectIds();
if (ids.length < 1) return;
const fileNames = await browser.execute((id) => {
const box = document.querySelector(`[data-project-id="${id}"]`);
const items = box?.querySelectorAll('.tree-name');
return Array.from(items ?? []).map(el => el.textContent?.trim() ?? '');
}, ids[0]);
// Test project has README.md and hello.py
const hasFiles = fileNames.some(f =>
f.includes('README') || f.includes('hello') || f.includes('.py') || f.includes('.md'),
);
expect(hasFiles).toBe(true);
// Switch back to Model tab
await switchProjectTab(ids[0], 0);
});
});