fix(browser): avoid esbuild __name helper in evaluateViaPlaywright

When tsx/esbuild compiles arrow functions, it adds a __name helper
for debugging. This helper doesn't exist in the browser context,
causing 'ReferenceError: __name is not defined' when using
page.evaluate() with inline functions.

The fix uses new Function() constructed at runtime, which esbuild
doesn't transform, avoiding the __name injection.
This commit is contained in:
Azade
2026-01-03 20:54:11 +00:00
committed by Peter Steinberger
parent 934f891932
commit 18a89a31af

View File

@@ -211,49 +211,38 @@ export async function evaluateViaPlaywright(opts: {
ensurePageState(page); ensurePageState(page);
if (opts.ref) { if (opts.ref) {
const locator = refLocator(page, opts.ref); const locator = refLocator(page, opts.ref);
return await locator.evaluate((el, fnBody) => { // Use Function constructor at runtime to avoid esbuild adding __name helper
const compileRunner = (body: string) => { // which doesn't exist in the browser context
const inner = `"use strict"; const candidate = ${body}; return typeof candidate === "function" ? candidate(element) : candidate;`; const elementEvaluator = new Function(
// This intentionally evaluates user-supplied code in the browser context. "el",
// oxlint-disable-next-line typescript-eslint/no-implied-eval "fnBody",
return new Function("element", inner) as (element: Element) => unknown; `
}; "use strict";
let compiled: unknown;
try { try {
compiled = compileRunner(fnBody); var candidate = eval("(" + fnBody + ")");
return typeof candidate === "function" ? candidate(el) : candidate;
} catch (err) { } catch (err) {
const message = throw new Error("Invalid evaluate function: " + (err && err.message ? err.message : String(err)));
err instanceof Error
? err.message
: typeof err === "string"
? err
: "invalid expression";
throw new Error(`Invalid evaluate function: ${message}`);
} }
return (compiled as (element: Element) => unknown)(el as Element); `,
}, fnText); ) as (el: Element, fnBody: string) => unknown;
return await locator.evaluate(elementEvaluator, fnText);
} }
return await page.evaluate((fnBody) => { // Use Function constructor at runtime to avoid esbuild adding __name helper
const compileRunner = (body: string) => { // which doesn't exist in the browser context
const inner = `"use strict"; const candidate = ${body}; return typeof candidate === "function" ? candidate() : candidate;`; const browserEvaluator = new Function(
// This intentionally evaluates user-supplied code in the browser context. "fnBody",
// oxlint-disable-next-line typescript-eslint/no-implied-eval `
return new Function(inner) as () => unknown; "use strict";
};
let compiled: unknown;
try { try {
compiled = compileRunner(fnBody); var candidate = eval("(" + fnBody + ")");
return typeof candidate === "function" ? candidate() : candidate;
} catch (err) { } catch (err) {
const message = throw new Error("Invalid evaluate function: " + (err && err.message ? err.message : String(err)));
err instanceof Error
? err.message
: typeof err === "string"
? err
: "invalid expression";
throw new Error(`Invalid evaluate function: ${message}`);
} }
return (compiled as () => unknown)(); `,
}, fnText); ) as (fnBody: string) => unknown;
return await page.evaluate(browserEvaluator, fnText);
} }
export async function armFileUploadViaPlaywright(opts: { export async function armFileUploadViaPlaywright(opts: {