TE-15304: ship updated dom-serializer bundle with scroll capture#522
Merged
Conversation
Re-embeds the prod (obfuscated) bundle from smartui-cli-dom-serializer PR LambdaTest#11 into src/dom/dom-serializer.js. The new bundle stamps page- and per-element scroll-state data attributes during DOM serialization so the rendering service can reproduce the user's scroll position before screenshotting (fixes blank screenshots on virtualized scrollers like the Vault PDF viewer). No TypeScript source code changes — src/lib/server.ts already reads this file and ships its contents to SDKs over HTTP at the existing /domserializer route. Older SDKs and older dotui ignore the new attributes (forward/backward compatible). Bundle size: 62 266 -> 63 700 bytes (the new serialize-scroll module). Depends on: https://github.com/LambdatestIncPrivate/smartui-cli-dom-serializer/pull/11 RFC: https://github.com/LambdatestIncPrivate/internal-docs/pull/1991 JIRA: https://lambdatest.atlassian.net/browse/TE-15304 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wires the two new opt-in flags through the CLI so they reach both the serializer (running in the SDK's browser process) and dotui (in the snapshot payload on Kafka). - src/types.ts: declare both flags on the Snapshot.options interface. - src/lib/schemaValidation.ts: extend snapshot.options schema so the flags pass validation. Without this, the existing additionalProperties:false would reject snapshots that set them. - src/lib/processSnapshot.ts: forward both flags into processedOptions so they are carried through to the Kafka payload that dotui consumes. Mirrors the existing useExtendedViewport plumbing. - src/dom/dom-serializer.js: refresh the obfuscated bundle from the updated serializer (now gates capture by these same flags). 62 266 -> 64 765 bytes (the new gating + early-exit logic). Both flags default false: when a snapshot doesn't set them, the new code paths are no-ops at every layer. Depends on: https://github.com/LambdatestIncPrivate/smartui-cli-dom-serializer/pull/11 RFC: https://github.com/LambdatestIncPrivate/internal-docs/pull/1991 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pixel scroll values are captured from the test's browser/viewport. If the snapshot fans out to other browsers/viewports/devices via web or mobile config, only the matching combo reproduces correctly; others drift. Surface this as a one-line warn so users see it during the run. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
processSnapshot.ts has two parallel functions that each process options into processedOptions: prepareSnapshot (line 44, used for the LSRS-cap path) and processSnapshot (line 290, the default export used for the local-discovery path). The earlier commit only added forwarding to the first one — local-discovery flows (the common case) dropped the new flags silently. Add forwarding + warning to processSnapshot too. Also refreshes the obfuscated dom-serializer bundle to match the latest serializer build (capture is now unconditional at the serializer layer — see smartui-cli-dom-serializer commit). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
sushobhit-lt
approved these changes
May 29, 2026
shrinishLT
pushed a commit
to shrinishLT/smartui-cli
that referenced
this pull request
May 30, 2026
## 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>
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Re-embeds the prod (obfuscated) DOM-serializer bundle. The new bundle stamps:
data-smartui-page-scroll-x/yon<html>(window-level scroll)data-smartui-scroll-top/lefton every scrollable element (inner-container scroll)…so the rendering service can reproduce the user's actual scroll position before taking the screenshot. Fixes blank/wrong-page screenshots on UIs that use virtualized scrolling (Vault PDF viewer, react-window, react-virtualized, etc.).
What changed in this PR
One file only:
src/dom/dom-serializer.js— replaced with the rebuilt obfuscated bundle from the serializer repo. No TypeScript source code changes.src/lib/server.ts:63already reads this file and ships its bytes to SDKs over the existing/domserializerroute.Bundle size: 62 266 → 63 700 bytes (the new
serialize-scrollmodule).Backward compatibility
SmartUIDOM.serialize(...)the same way.data-smartui-*attributes on the HTML — silent no-op until dotui is also updated.Dependencies
Test plan
npm run build:prod.~/Documents/scripts/sdk-playwright/sdk/Makefileupdtarget locally to repack with this bundle and run against the test URL list.🤖 Generated with Claude Code