Skip to content

TE-15304: re-roll dom-serializer bundle (fix page.evaluate "Unexpected token 'function'" regression)#523

Merged
sushobhit-lt merged 1 commit into
LambdaTest:stagefrom
shrinishLT:TE-15304
May 30, 2026
Merged

TE-15304: re-roll dom-serializer bundle (fix page.evaluate "Unexpected token 'function'" regression)#523
sushobhit-lt merged 1 commit into
LambdaTest:stagefrom
shrinishLT:TE-15304

Conversation

@shrinishLT
Copy link
Copy Markdown
Contributor

@shrinishLT shrinishLT commented May 30, 2026

TL;DR

PR #522 shipped a dom-serializer bundle that breaks every SDK injecting via page.evaluate(bundle) (playwright, puppeteer, webdriverio) with:

SyntaxError: Unexpected token 'function'

This follow-up replaces the broken bundle with a re-rolled one that starts with (function(...) — a valid expression-context IIFE that all SDK injection patterns accept.

JIRA: TE-15304

Cause

The bundle at src/dom/dom-serializer.js is a pre-built artifact generated by webpack + webpack-obfuscator in smartui-cli-dom-serializer, then committed verbatim here. webpack-obfuscator's output is non-deterministic — for the same source, builds randomly produce one of:

Form Looks like % of builds
A. IIFE-wrapped (function(_0x...){...})() ~20%
B. Hoisted helper first function a0_0xNNNN(...){...} ... ~80%

The stringArray: true and selfDefending: true features in the obfuscator config cause helper function declarations to be hoisted to top level. Their hoisting is randomized between runs.

PR #522's bundle was form B — a hoisted helper at the top. Empirically verified with a 10-run experiment (5 baseline + 5 with TE-15304); both setups produced 60–80% bad rolls.

Why it's an SDK-side bug only some of them hit

page.evaluate(str) evaluates str as a JavaScript expression. A leading function declaration (form B) is a statement and throws SyntaxError. Other injection patterns are unaffected:

SDK Injection Form B bundle
@lambdatest/cypress-driver eval(bundle) (evaluates as program) ✓ works
@lambdatest/selenium-driver executeScript(bundle) (script-tag-style) ✓ works
@lambdatest/playwright-driver page.evaluate(bundle) ✗ throws SyntaxError
@lambdatest/puppeteer-driver page.evaluate(bundle) ✗ throws SyntaxError
@lambdatest/webdriverio-driver browser.execute(bundle) ✗ throws SyntaxError

This is why the regression slipped past review — most internal flows use selenium/cypress, where the broken bundle still worked.

Fix in this PR

Single file changed: src/dom/dom-serializer.js. No source code or build pipeline changes here.

Re-ran npm run build:prod in the serializer repo until the obfuscator landed a form-A roll, then committed that artifact. Verified locally:

  • Bundle now starts with (function(_0x40c4a2,_0x2284c6){...
  • make use-cli-branch BRANCH=TE-15304 followed by make upd-cli TEST=test-playwright.js runs the playwright SDK end-to-end without Unexpected token errors ✓
  • Snapshot processed successfully on the cloud ✓

Follow-up (separate PR, NOT in this one)

The underlying obfuscator non-determinism remains — the next maintainer who rebuilds and commits a new bundle has the same 80% chance of regressing this. A proper fix is to disable stringArray, selfDefending, and splitStrings in the obfuscator config so output is always IIFE-wrapped (and ~27% smaller). That change reduces obfuscation strength slightly and warrants a separate discussion + PR against smartui-cli-dom-serializer. Until then, anyone rebuilding the bundle should:

# verifies bundle starts with `(`
head -c 40 src/dom/dom-serializer.js

Test plan

  • Local end-to-end: playwright SDK injects, snapshot captured, no error
  • Selenium SDK still works (unchanged bundle injection path)
  • Reviewer runs the same playwright-driver test against a stage deploy carrying this commit
  • Confirm make use-cli-branch BRANCH=stage (after merge) shows ✓ GOOD ROLL — IIFE-wrapped

🤖 Generated with Claude Code

## Cause

The dom-serializer bundle is generated by webpack + webpack-obfuscator
and committed to this repo as a pre-built artifact (src/dom/dom-
serializer.js). webpack-obfuscator's output is **non-deterministic** —
for the same source, builds randomly produce either:

  (A) an IIFE-wrapped bundle: `(function(...){...})()`            ~20%
  (B) a bundle starting with a hoisted helper function declaration:
      `function a0_0xNNNN(...){...}`                             ~80%

The bundle that landed on this branch (and was merged via PR LambdaTest#522 to
stage) happened to be form (B). Any SDK consumer that injects the
bundle via `page.evaluate(str)` then breaks with:

    SyntaxError: Unexpected token 'function'

…because page.evaluate parses its input as an expression, and a leading
function declaration is a statement, not an expression. eval() and
script-tag injection are unaffected, so:

  ✓ @lambdatest/cypress-driver    (uses eval())
  ✓ @lambdatest/selenium-driver   (executeScript as script tag)
  ✗ @lambdatest/playwright-driver (page.evaluate)
  ✗ @lambdatest/puppeteer-driver  (page.evaluate)
  ✗ @lambdatest/webdriverio-driver (browser.execute)

This masking is why the regression wasn't caught by CI — most flows
use selenium/cypress.

## Fix in this commit

Re-runs `npm run build:prod` until the obfuscator lands an IIFE-wrapped
roll, then ships that bundle. No source/code change — only the pre-
built artifact at src/dom/dom-serializer.js is replaced.

Verified empirically: 10-run experiment (5 baseline + 5 TE-15304),
both setups produced ~80% bad rolls. After this commit, the bundle
starts with `(function(_0x40c4a2,_0x2284c6){...` — page.evaluate
consumers work, snapshot is captured end-to-end.

## Follow-up (not in this PR)

webpack-obfuscator's `stringArray: true` + `selfDefending: true`
features are what cause the random helper hoisting. A future PR
against smartui-cli-dom-serializer should disable those (and
`splitStrings`) so future bundles are deterministic and never
require a manual re-roll. That change is non-trivial — it reduces
obfuscation strength somewhat — and is left for a separate PR/
discussion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sushobhit-lt sushobhit-lt merged commit aaac54e into LambdaTest:stage May 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants