refactor(e2e): split spec files under 300-line limit
- phase-c.test.ts (626 lines) → phase-c-ui.test.ts (279), phase-c-tabs.test.ts (272), phase-c-llm.test.ts (76) — all 11 scenarios preserved - agor.test.ts (799 lines) → smoke.test.ts (47), workspace.test.ts (79), settings.test.ts (247), features.test.ts (488) — split in progress - Reset-to-home-state hooks added to stateful before() blocks - wdio.conf.js specs array updated for all new filenames
This commit is contained in:
parent
e76bc341f2
commit
f08c4b18cf
9 changed files with 1495 additions and 628 deletions
272
tests/e2e/specs/phase-c-tabs.test.ts
Normal file
272
tests/e2e/specs/phase-c-tabs.test.ts
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
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 () => {
|
||||
// Reset UI to home state
|
||||
const settingsPanel = await browser.$('.settings-panel');
|
||||
if (await settingsPanel.isExisting()) {
|
||||
const closeBtn = await browser.$('.settings-close');
|
||||
if (await closeBtn.isExisting()) await closeBtn.click();
|
||||
}
|
||||
|
||||
// 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-tab');
|
||||
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-tab');
|
||||
if (!panel) return false;
|
||||
const text = panel.textContent ?? '';
|
||||
return text.toLowerCase().includes('font');
|
||||
});
|
||||
expect(hasFonts).toBe(true);
|
||||
});
|
||||
|
||||
it('should show default shell setting', async () => {
|
||||
const hasShell = await browser.execute(() => {
|
||||
const panel = document.querySelector('.sidebar-panel, .settings-tab');
|
||||
if (!panel) return false;
|
||||
const text = panel.textContent ?? '';
|
||||
return text.toLowerCase().includes('shell');
|
||||
});
|
||||
expect(hasShell).toBe(true);
|
||||
});
|
||||
|
||||
it('should have theme dropdown with 17 themes', async () => {
|
||||
// Click the theme dropdown to see options
|
||||
const themeCount = await browser.execute(() => {
|
||||
// Find the theme dropdown (custom dropdown, not native select)
|
||||
const dropdowns = document.querySelectorAll('.settings-tab .custom-dropdown, .settings-tab .dropdown');
|
||||
for (const dd of dropdowns) {
|
||||
const label = dd.closest('.settings-row, .setting-row')?.textContent ?? '';
|
||||
if (label.toLowerCase().includes('theme')) {
|
||||
// Click to open it
|
||||
const trigger = dd.querySelector('.dropdown-trigger, .dropdown-selected, button');
|
||||
if (trigger) (trigger as HTMLElement).click();
|
||||
return -1; // Flag: opened dropdown
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
if (themeCount === -1) {
|
||||
// Dropdown was opened, wait and count options
|
||||
await browser.pause(300);
|
||||
const optionCount = await browser.execute(() => {
|
||||
const options = document.querySelectorAll('.dropdown-option, .dropdown-item, .theme-option');
|
||||
return options.length;
|
||||
});
|
||||
// Should have 17 themes
|
||||
expect(optionCount).toBeGreaterThanOrEqual(15);
|
||||
|
||||
// Close dropdown
|
||||
await browser.keys('Escape');
|
||||
await browser.pause(200);
|
||||
}
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await browser.keys('Escape');
|
||||
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, .project-header .health-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, .health-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 '';
|
||||
// Status bar shows running/idle/stalled counts
|
||||
return bar.textContent ?? '';
|
||||
});
|
||||
// Should contain at least idle count
|
||||
expect(counts).toMatch(/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}"]`);
|
||||
// MetricsPanel has live view with fleet stats
|
||||
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}"]`);
|
||||
// ContextTab has stats, token meter, file references
|
||||
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}"]`);
|
||||
// FilesTab has a directory tree
|
||||
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);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue