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
52
tests/e2e/helpers/execute.ts
Normal file
52
tests/e2e/helpers/execute.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* Cross-protocol browser.execute() wrapper.
|
||||
*
|
||||
* WebDriverIO's devtools protocol (CDP via puppeteer-core) breaks when
|
||||
* browser.execute() receives a function argument because:
|
||||
* 1. WebDriverIO prepends a polyfill before `return (fn).apply(null, arguments)`
|
||||
* 2. The devtools executeScript trims the script, finds no leading `return`,
|
||||
* and passes it directly to eval()
|
||||
* 3. eval() fails with "Illegal return statement" because `return` is outside
|
||||
* a function body (the polyfill lines precede it)
|
||||
*
|
||||
* Fix: always pass a string expression to browser.execute(). Arguments are
|
||||
* JSON-serialized and inlined into the script — no reliance on the `arguments`
|
||||
* object which is protocol-dependent.
|
||||
*
|
||||
* Works identically with:
|
||||
* - WebDriver protocol (Tauri via tauri-driver)
|
||||
* - devtools/CDP protocol (Electrobun via CEF)
|
||||
*/
|
||||
|
||||
import { browser } from '@wdio/globals';
|
||||
|
||||
/**
|
||||
* Execute a function in the browser, cross-protocol safe.
|
||||
*
|
||||
* Usage mirrors browser.execute():
|
||||
* exec(() => document.title)
|
||||
* exec((sel) => document.querySelector(sel) !== null, '.my-class')
|
||||
* exec((a, b) => a + b, 1, 2)
|
||||
*/
|
||||
export async function exec<R>(fn: (...args: any[]) => R, ...args: any[]): Promise<R> {
|
||||
const fnStr = fn.toString();
|
||||
const serializedArgs = args.map(a => JSON.stringify(a)).join(', ');
|
||||
// Wrap as an IIFE expression — no `return` at the top level
|
||||
const script = `return (${fnStr})(${serializedArgs})`;
|
||||
return browser.execute(script) as Promise<R>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip a test programmatically — works with both protocols.
|
||||
*
|
||||
* Mocha's this.skip() requires a non-arrow `function()` context. In
|
||||
* WebDriverIO hooks (beforeTest), `this` may not carry the Mocha context
|
||||
* with devtools protocol. This helper uses the same mechanism but is
|
||||
* callable from any context that has the Mocha `this`.
|
||||
*
|
||||
* Usage inside `it('...', async function () { ... })`:
|
||||
* if (condition) { skipTest(this); return; }
|
||||
*/
|
||||
export function skipTest(ctx: Mocha.Context): void {
|
||||
ctx.skip();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue