From 18a89a31aff2bffac4996d376012d03f91bfa261 Mon Sep 17 00:00:00 2001 From: Azade Date: Sat, 3 Jan 2026 20:54:11 +0000 Subject: [PATCH] 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. --- src/browser/pw-tools-core.ts | 61 +++++++++++++++--------------------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/src/browser/pw-tools-core.ts b/src/browser/pw-tools-core.ts index d9fc5e30e..9d6be2520 100644 --- a/src/browser/pw-tools-core.ts +++ b/src/browser/pw-tools-core.ts @@ -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: {