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
117 lines
4 KiB
JavaScript
117 lines
4 KiB
JavaScript
/**
|
|
* Shared WebDriverIO configuration — common settings for both Tauri and Electrobun.
|
|
*
|
|
* Stack-specific configs (wdio.tauri.conf.js, wdio.electrobun.conf.js)
|
|
* import and extend this with their own lifecycle hooks and capabilities.
|
|
*/
|
|
|
|
import { resolve, dirname } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { getResultsDb } from './infra/results-db.ts';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const projectRoot = resolve(__dirname, '../..');
|
|
|
|
export const sharedConfig = {
|
|
// ── Runner ──
|
|
runner: 'local',
|
|
maxInstances: 1,
|
|
|
|
// ── Connection defaults (overridden per-stack) ──
|
|
hostname: 'localhost',
|
|
path: '/',
|
|
|
|
// ── Specs — unified set, all shared ──
|
|
specs: [
|
|
resolve(projectRoot, 'tests/e2e/specs/splash.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/smoke.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/groups.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/settings.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/theme.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/terminal.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/agent.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/keyboard.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/search.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/notifications.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/files.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/comms.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/tasks.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/status-bar.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/context.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/diagnostics.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/worktree.test.ts'),
|
|
resolve(projectRoot, 'tests/e2e/specs/llm-judged.test.ts'),
|
|
],
|
|
|
|
// ── Framework ──
|
|
framework: 'mocha',
|
|
mochaOpts: {
|
|
ui: 'bdd',
|
|
timeout: 180_000,
|
|
},
|
|
|
|
// ── Reporter ──
|
|
reporters: ['spec'],
|
|
|
|
// ── Logging ──
|
|
logLevel: 'warn',
|
|
|
|
// ── Timeouts ──
|
|
waitforTimeout: 10_000,
|
|
connectionRetryTimeout: 30_000,
|
|
connectionRetryCount: 3,
|
|
|
|
// ── Hooks ──
|
|
|
|
/** Smart test caching: skip tests with 3+ consecutive passes */
|
|
beforeTest(test) {
|
|
browser.__expectedErrors = [];
|
|
|
|
if (process.env.FULL_RESCAN) return;
|
|
|
|
const db = getResultsDb();
|
|
const specFile = test.file?.replace(/.*specs\//, '') ?? '';
|
|
if (db.shouldSkip(specFile, test.title)) {
|
|
const stats = db.getCacheStats();
|
|
console.log(`Skipping (3+ consecutive passes): ${test.title} [${stats.skippable}/${stats.total} skippable]`);
|
|
// this.skip() works in Mocha non-arrow context — safe for both protocols
|
|
this.skip();
|
|
}
|
|
},
|
|
|
|
/** After each test: check for error toasts, record in pass cache */
|
|
async afterTest(test, _context, { passed }) {
|
|
let unexpected = [];
|
|
try {
|
|
// Use string script for cross-protocol compatibility (devtools + webdriver)
|
|
const errors = await browser.execute(
|
|
'return (function() {' +
|
|
' var toasts = Array.from(document.querySelectorAll(".toast-error, .load-error"));' +
|
|
' return toasts.map(function(t) { return (t.textContent || "").trim(); }).filter(Boolean);' +
|
|
'})()'
|
|
);
|
|
|
|
const expected = browser.__expectedErrors || [];
|
|
unexpected = errors.filter(e => !expected.some(exp => e.includes(exp)));
|
|
|
|
if (unexpected.length > 0 && passed) {
|
|
throw new Error(
|
|
`Unexpected error toast(s) during "${test.title}": ${unexpected.join('; ')}`
|
|
);
|
|
}
|
|
} catch (e) {
|
|
if (e.message?.includes('Unexpected error toast')) throw e;
|
|
}
|
|
|
|
const db = getResultsDb();
|
|
const specFile = test.file?.replace(/.*specs\//, '') ?? '';
|
|
db.recordTestResult(specFile, test.title, passed && unexpected.length === 0);
|
|
},
|
|
|
|
// ── TypeScript ──
|
|
autoCompileOpts: {
|
|
tsNodeOpts: {
|
|
project: resolve(projectRoot, 'tests/e2e/tsconfig.json'),
|
|
},
|
|
},
|
|
};
|