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