fix(e2e): cross-protocol browser.execute() — works with both WebDriver + CDP
Root cause: WebDriverIO devtools protocol wraps functions in a polyfill that puts `return` inside eval() (not a function body) → "Illegal return". Fix: exec() wrapper in helpers/execute.ts converts function args to IIFE strings before passing to browser.execute(). Works identically on both WebDriver (Tauri) and CDP/devtools (Electrobun CEF). - 35 spec files updated (browser.execute → exec) - 4 config files updated (string-form expressions) - helpers/actions.ts + assertions.ts updated - 560 vitest + 116 cargo passing
This commit is contained in:
parent
407e49cc32
commit
6a8181f33a
42 changed files with 630 additions and 541 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import { browser, expect } from '@wdio/globals';
|
||||
import { exec } from '../helpers/execute.ts';
|
||||
|
||||
// Phase B — Grid: Multi-project grid, tab switching, status bar.
|
||||
// Scenarios B1-B3 + new grid/UI tests.
|
||||
|
|
@ -6,14 +7,14 @@ import { browser, expect } from '@wdio/globals';
|
|||
// ─── Helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
async function getProjectIds(): Promise<string[]> {
|
||||
return browser.execute(() => {
|
||||
return exec(() => {
|
||||
const boxes = document.querySelectorAll('[data-testid="project-box"]');
|
||||
return Array.from(boxes).map((b) => b.getAttribute('data-project-id') ?? '').filter(Boolean);
|
||||
});
|
||||
}
|
||||
|
||||
async function focusProject(id: string): Promise<void> {
|
||||
await browser.execute((pid) => {
|
||||
await exec((pid) => {
|
||||
const h = document.querySelector(`[data-project-id="${pid}"] .project-header`);
|
||||
if (h) (h as HTMLElement).click();
|
||||
}, id);
|
||||
|
|
@ -21,7 +22,7 @@ async function focusProject(id: string): Promise<void> {
|
|||
}
|
||||
|
||||
async function switchProjectTab(id: string, tabIndex: number): Promise<void> {
|
||||
await browser.execute((pid, idx) => {
|
||||
await exec((pid, idx) => {
|
||||
const tabs = document.querySelector(`[data-project-id="${pid}"]`)?.querySelectorAll('[data-testid="project-tabs"] .ptab');
|
||||
if (tabs?.[idx]) (tabs[idx] as HTMLElement).click();
|
||||
}, id, tabIndex);
|
||||
|
|
@ -29,7 +30,7 @@ async function switchProjectTab(id: string, tabIndex: number): Promise<void> {
|
|||
}
|
||||
|
||||
async function getAgentStatus(id: string): Promise<string> {
|
||||
return browser.execute((pid) => {
|
||||
return exec((pid) => {
|
||||
const p = document.querySelector(`[data-project-id="${pid}"] [data-testid="agent-pane"]`);
|
||||
return p?.getAttribute('data-agent-status') ?? 'not-found';
|
||||
}, id);
|
||||
|
|
@ -50,7 +51,7 @@ describe('Scenario B1 — Multi-Project Grid', () => {
|
|||
it('should render multiple project boxes', async () => {
|
||||
await browser.waitUntil(
|
||||
async () => {
|
||||
const count = await browser.execute(() =>
|
||||
const count = await exec(() =>
|
||||
document.querySelectorAll('[data-testid="project-box"]').length,
|
||||
);
|
||||
return (count as number) >= 1;
|
||||
|
|
@ -65,7 +66,7 @@ describe('Scenario B1 — Multi-Project Grid', () => {
|
|||
});
|
||||
|
||||
it('should show project headers with CWD paths', async () => {
|
||||
const headers = await browser.execute(() => {
|
||||
const headers = await exec(() => {
|
||||
const els = document.querySelectorAll('.project-header .info-cwd');
|
||||
return Array.from(els).map((e) => e.textContent?.trim() ?? '');
|
||||
});
|
||||
|
|
@ -87,7 +88,7 @@ describe('Scenario B1 — Multi-Project Grid', () => {
|
|||
if (ids.length < 1) return;
|
||||
|
||||
await focusProject(ids[0]);
|
||||
const isActive = await browser.execute((id) => {
|
||||
const isActive = await exec((id) => {
|
||||
const box = document.querySelector(`[data-project-id="${id}"]`);
|
||||
return box?.classList.contains('active') ?? false;
|
||||
}, ids[0]);
|
||||
|
|
@ -95,7 +96,7 @@ describe('Scenario B1 — Multi-Project Grid', () => {
|
|||
});
|
||||
|
||||
it('should show project-specific accent colors on each box border', async () => {
|
||||
const accents = await browser.execute(() => {
|
||||
const accents = await exec(() => {
|
||||
const boxes = document.querySelectorAll('[data-testid="project-box"]');
|
||||
return Array.from(boxes).map((b) => getComputedStyle(b as HTMLElement).getPropertyValue('--accent').trim());
|
||||
});
|
||||
|
|
@ -103,7 +104,7 @@ describe('Scenario B1 — Multi-Project Grid', () => {
|
|||
});
|
||||
|
||||
it('should render project icons (emoji) in headers', async () => {
|
||||
const icons = await browser.execute(() => {
|
||||
const icons = await exec(() => {
|
||||
const els = document.querySelectorAll('.project-header .project-icon, .project-header .emoji');
|
||||
return Array.from(els).map((e) => e.textContent?.trim() ?? '');
|
||||
});
|
||||
|
|
@ -115,7 +116,7 @@ describe('Scenario B1 — Multi-Project Grid', () => {
|
|||
it('should show project CWD tooltip on hover', async () => {
|
||||
const ids = await getProjectIds();
|
||||
if (ids.length < 1) return;
|
||||
const titleAttr = await browser.execute((id) => {
|
||||
const titleAttr = await exec((id) => {
|
||||
const el = document.querySelector(`[data-project-id="${id}"] .project-header .info-cwd`);
|
||||
return el?.getAttribute('title') ?? el?.textContent?.trim() ?? '';
|
||||
}, ids[0]);
|
||||
|
|
@ -126,7 +127,7 @@ describe('Scenario B1 — Multi-Project Grid', () => {
|
|||
const ids = await getProjectIds();
|
||||
if (ids.length < 2) return;
|
||||
await focusProject(ids[0]);
|
||||
const isActive = await browser.execute((id) => {
|
||||
const isActive = await exec((id) => {
|
||||
return document.querySelector(`[data-project-id="${id}"]`)?.classList.contains('active') ?? false;
|
||||
}, ids[0]);
|
||||
expect(isActive).toBe(true);
|
||||
|
|
@ -135,7 +136,7 @@ describe('Scenario B1 — Multi-Project Grid', () => {
|
|||
it('should show all base tabs per project', async () => {
|
||||
const ids = await getProjectIds();
|
||||
if (ids.length < 1) return;
|
||||
const tabLabels = await browser.execute((id) => {
|
||||
const tabLabels = await exec((id) => {
|
||||
const tabs = document.querySelector(`[data-project-id="${id}"]`)?.querySelectorAll('[data-testid="project-tabs"] .ptab');
|
||||
return Array.from(tabs ?? []).map((t) => t.textContent?.trim() ?? '');
|
||||
}, ids[0]);
|
||||
|
|
@ -148,7 +149,7 @@ describe('Scenario B1 — Multi-Project Grid', () => {
|
|||
const ids = await getProjectIds();
|
||||
if (ids.length < 1) return;
|
||||
await switchProjectTab(ids[0], 0);
|
||||
const hasTerminal = await browser.execute((id) => {
|
||||
const hasTerminal = await exec((id) => {
|
||||
return document.querySelector(`[data-project-id="${id}"] [data-testid="terminal-tabs"], [data-project-id="${id}"] .terminal-section`) !== null;
|
||||
}, ids[0]);
|
||||
expect(hasTerminal).toBe(true);
|
||||
|
|
@ -167,7 +168,7 @@ describe('Scenario B2 — Independent Tab Switching', () => {
|
|||
if (ids.length < 2) { console.log('Skipping B2 — need 2+ projects'); this.skip(); return; }
|
||||
await switchProjectTab(ids[0], 3); // Files tab
|
||||
await switchProjectTab(ids[1], 0); // Model tab
|
||||
const getActiveTab = (id: string) => browser.execute((pid) => {
|
||||
const getActiveTab = (id: string) => exec((pid) => {
|
||||
return document.querySelector(`[data-project-id="${pid}"] [data-testid="project-tabs"] .ptab.active`)?.textContent?.trim() ?? '';
|
||||
}, id);
|
||||
const firstActive = await getActiveTab(ids[0]);
|
||||
|
|
@ -182,7 +183,7 @@ describe('Scenario B2 — Independent Tab Switching', () => {
|
|||
await focusProject(ids[0]);
|
||||
await focusProject(ids[1]);
|
||||
await focusProject(ids[0]);
|
||||
const activeTab = await browser.execute((id) => {
|
||||
const activeTab = await exec((id) => {
|
||||
return document.querySelector(`[data-project-id="${id}"] [data-testid="project-tabs"] .ptab.active`)?.textContent?.trim() ?? '';
|
||||
}, ids[0]);
|
||||
expect(activeTab).toBe('Model');
|
||||
|
|
@ -193,7 +194,7 @@ describe('Scenario B2 — Independent Tab Switching', () => {
|
|||
|
||||
describe('Scenario B3 — Status Bar Fleet State', () => {
|
||||
it('should show agent count in status bar', async () => {
|
||||
const barText = await browser.execute(() => {
|
||||
const barText = await exec(() => {
|
||||
const bar = document.querySelector('[data-testid="status-bar"]');
|
||||
return bar?.textContent ?? '';
|
||||
});
|
||||
|
|
@ -201,7 +202,7 @@ describe('Scenario B3 — Status Bar Fleet State', () => {
|
|||
});
|
||||
|
||||
it('should show no burn rate when all agents idle', async () => {
|
||||
const hasBurnRate = await browser.execute(() => {
|
||||
const hasBurnRate = await exec(() => {
|
||||
const bar = document.querySelector('[data-testid="status-bar"]');
|
||||
const burnEl = bar?.querySelector('.burn-rate');
|
||||
const costEl = bar?.querySelector('.cost');
|
||||
|
|
@ -219,7 +220,7 @@ describe('Scenario B3 — Status Bar Fleet State', () => {
|
|||
const ids = await getProjectIds();
|
||||
if (ids.length < 2) return;
|
||||
await focusProject(ids[1]);
|
||||
const barAfter = await browser.execute(() => {
|
||||
const barAfter = await exec(() => {
|
||||
return document.querySelector('[data-testid="status-bar"]')?.textContent ?? '';
|
||||
});
|
||||
expect(barAfter.length).toBeGreaterThan(0);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue