- devtools protocol kills Electrobun's CEF browser on attach (navigates) - ChromeDriver with debuggerAddress connects WITHOUT navigating - Added Vite dev server auto-start (Electrobun dev mode requires it) - Fixed this.skip() → test.pending for cross-protocol compat - chromedriver@145 matches CEF Chrome 145
179 lines
6.1 KiB
JavaScript
179 lines
6.1 KiB
JavaScript
/**
|
|
* WebDriverIO config for Electrobun stack E2E tests.
|
|
*
|
|
* Uses CDP (Chrome DevTools Protocol) via CEF mode for reliable E2E automation.
|
|
* Electrobun must be built/run with AGOR_CEF=1 to bundle CEF and expose
|
|
* --remote-debugging-port=9222 (configured in electrobun.config.ts).
|
|
*
|
|
* Port conventions:
|
|
* 9222 — CDP debugging port (CEF)
|
|
* 9760 — Vite dev server (HMR)
|
|
* 9761 — (reserved, was WebKitWebDriver)
|
|
*/
|
|
|
|
import { execSync, spawn } from 'node:child_process';
|
|
import { resolve, dirname } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { existsSync, rmSync } from 'node:fs';
|
|
import { sharedConfig } from './wdio.shared.conf.js';
|
|
import { waitForPort } from './helpers/actions.ts';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const projectRoot = resolve(__dirname, '../..');
|
|
const electrobunRoot = resolve(projectRoot, 'ui-electrobun');
|
|
|
|
const CDP_PORT = 9222;
|
|
|
|
// Use the Electrobun fixture generator (different groups.json format)
|
|
let fixture;
|
|
try {
|
|
const { createTestFixture } = await import('../../ui-electrobun/tests/e2e/fixtures.ts');
|
|
fixture = createTestFixture('agor-ebun-cdp');
|
|
} catch {
|
|
const { createTestFixture } = await import('./infra/fixtures.ts');
|
|
fixture = createTestFixture('agor-ebun-cdp');
|
|
}
|
|
|
|
process.env.AGOR_TEST = '1';
|
|
process.env.AGOR_CEF = '1';
|
|
process.env.AGOR_TEST_DATA_DIR = fixture.dataDir;
|
|
process.env.AGOR_TEST_CONFIG_DIR = fixture.configDir;
|
|
|
|
let viteProcess;
|
|
|
|
console.log(`[electrobun-cdp] Test fixture at ${fixture.rootDir ?? fixture.configDir}`);
|
|
|
|
let appProcess;
|
|
|
|
export const config = {
|
|
...sharedConfig,
|
|
|
|
// Use ChromeDriver to attach to existing CEF via debuggerAddress
|
|
// ChromeDriver connects to the existing CDP port WITHOUT navigating/destroying the page
|
|
automationProtocol: 'webdriver',
|
|
|
|
services: [['chromedriver', { args: ['--verbose'] }]],
|
|
|
|
capabilities: [{
|
|
browserName: 'chrome',
|
|
'goog:chromeOptions': {
|
|
debuggerAddress: `localhost:${CDP_PORT}`,
|
|
},
|
|
}],
|
|
|
|
async onPrepare() {
|
|
// Find existing binary or build
|
|
const candidates = [
|
|
resolve(electrobunRoot, 'build/dev-linux-x64/AgentOrchestrator-dev/AgentOrchestrator-dev'),
|
|
resolve(electrobunRoot, 'build/Agent Orchestrator'),
|
|
resolve(electrobunRoot, 'build/AgentOrchestrator'),
|
|
];
|
|
let electrobunBinary = candidates.find(p => existsSync(p));
|
|
|
|
if (!electrobunBinary && !process.env.SKIP_BUILD) {
|
|
console.log('[electrobun-cdp] Building with CEF...');
|
|
try {
|
|
execSync('npx vite build', { cwd: electrobunRoot, stdio: 'inherit' });
|
|
execSync('npx electrobun build --env=dev', { cwd: electrobunRoot, stdio: 'inherit' });
|
|
} catch (e) {
|
|
console.warn('[electrobun-cdp] Build failed:', e.message);
|
|
}
|
|
electrobunBinary = candidates.find(p => existsSync(p));
|
|
}
|
|
|
|
if (!electrobunBinary) {
|
|
// Kill any stale process on CDP port before launching
|
|
try { execSync(`fuser -k ${CDP_PORT}/tcp 2>/dev/null || true`); } catch {}
|
|
|
|
// Start Vite dev server first (Electrobun dev mode loads JS from it)
|
|
console.log('[electrobun-cdp] Starting Vite dev server on port 9760...');
|
|
viteProcess = spawn('npx', ['vite', 'dev', '--port', '9760', '--host', 'localhost'], {
|
|
cwd: electrobunRoot,
|
|
env: { ...process.env },
|
|
stdio: 'pipe',
|
|
});
|
|
viteProcess.stdout?.on('data', (d) => {
|
|
const msg = d.toString();
|
|
if (msg.includes('ready') || msg.includes('Local:')) console.log(`[vite] ${msg.trim()}`);
|
|
});
|
|
viteProcess.stderr?.on('data', (d) => process.stderr.write(`[vite] ${d}`));
|
|
|
|
// Wait for Vite to be ready
|
|
const viteStart = Date.now();
|
|
while (Date.now() - viteStart < 15000) {
|
|
try { const r = await fetch('http://localhost:9760/'); if (r.ok) break; } catch {}
|
|
await new Promise(r => setTimeout(r, 500));
|
|
}
|
|
console.log('[electrobun-cdp] Vite dev server ready.');
|
|
|
|
// Launch Electrobun with CEF
|
|
console.log('[electrobun-cdp] Launching via electrobun dev...');
|
|
appProcess = spawn('npx', ['electrobun', 'dev'], {
|
|
cwd: electrobunRoot,
|
|
env: {
|
|
...process.env,
|
|
AGOR_CEF: '1',
|
|
AGOR_TEST: '1',
|
|
AGOR_TEST_DATA_DIR: fixture.dataDir,
|
|
AGOR_TEST_CONFIG_DIR: fixture.configDir,
|
|
},
|
|
stdio: 'pipe',
|
|
});
|
|
} else {
|
|
console.log(`[electrobun-cdp] Launching binary: ${electrobunBinary}`);
|
|
appProcess = spawn(electrobunBinary, [], {
|
|
env: {
|
|
...process.env,
|
|
AGOR_CEF: '1',
|
|
AGOR_TEST: '1',
|
|
AGOR_TEST_DATA_DIR: fixture.dataDir,
|
|
AGOR_TEST_CONFIG_DIR: fixture.configDir,
|
|
},
|
|
stdio: 'pipe',
|
|
});
|
|
}
|
|
|
|
appProcess.stdout?.on('data', (d) => process.stdout.write(`[app] ${d}`));
|
|
appProcess.stderr?.on('data', (d) => process.stderr.write(`[app] ${d}`));
|
|
appProcess.on('exit', (code) => console.log(`[electrobun-cdp] App exited with code ${code}`));
|
|
|
|
// Wait for CDP port to become available
|
|
return waitForPort(CDP_PORT, 30_000);
|
|
},
|
|
|
|
async before() {
|
|
// Wait for Electrobun app to render — use string script for CDP compatibility
|
|
await browser.waitUntil(
|
|
async () => {
|
|
const hasEl = await browser.execute(
|
|
'return document.querySelector(".app-shell") !== null' +
|
|
' || document.querySelector(".project-grid") !== null' +
|
|
' || document.querySelector(".status-bar") !== null'
|
|
);
|
|
return hasEl;
|
|
},
|
|
{ timeout: 20_000, interval: 500, timeoutMsg: 'Electrobun app did not load in 20s' },
|
|
);
|
|
console.log('[electrobun-cdp] App loaded.');
|
|
},
|
|
|
|
onComplete() {
|
|
if (appProcess) {
|
|
console.log('[electrobun-cdp] Stopping app...');
|
|
appProcess.kill('SIGTERM');
|
|
appProcess = undefined;
|
|
}
|
|
if (viteProcess) {
|
|
console.log('[electrobun-cdp] Stopping Vite dev server...');
|
|
viteProcess.kill('SIGTERM');
|
|
viteProcess = undefined;
|
|
}
|
|
|
|
const cleanup = fixture.cleanup ?? (() => {
|
|
try {
|
|
if (fixture.rootDir) rmSync(fixture.rootDir, { recursive: true, force: true });
|
|
} catch { /* best-effort */ }
|
|
});
|
|
cleanup();
|
|
},
|
|
};
|