Skip to content

fix(screenDom): prioritize known app roots and skip empty containers#223

Merged
kevinccbsg merged 1 commit into
mainfrom
feat/screendom-root-detection
Apr 21, 2026
Merged

fix(screenDom): prioritize known app roots and skip empty containers#223
kevinccbsg merged 1 commit into
mainfrom
feat/screendom-root-detection

Conversation

@kevinccbsg

Copy link
Copy Markdown
Member

Summary

  • Make screenDom query scoping robust against injected body siblings (sandbox overlays, browser extensions) that currently silently hijack queries by landing before the app root in DOM order.
  • Resolve the container in priority order: user-configured rootSelector#root / #app / app-root → first non-empty direct body child → document.body.
  • Add rootSelector?: string option on InitTWDOptions, wired through initTWD to a package-internal setter (no new public exports from twd-js).
  • Emit a one-time-per-session console.warn when the heuristic fallback fires without a configured rootSelector, pointing users to the new option.

Motivation

Reproduced on CodeSandbox Devbox: CodeSandbox injects <div id=\"highlighter\"> before <div id=\"root\"> for its click-to-inspect overlay, and every screenDom.getByText(...) silently fails with "element not found" because the (empty) highlighter became the scoped container. Any browser extension or framework overlay that injects a body sibling has the same effect. First-install experience on a sandbox is a silent breakage.

What changes

  • src/proxies/screenDom.ts — priority list + skip-empty heuristic + one-time warn + module-state reset for tests.
  • src/bundled.tsxrootSelector?: string on InitTWDOptions; initTWD forwards to the internal setter before initTests / initRequestMocking.
  • Docs: docs/testing-library.md (rewritten "How screenDom Works" + troubleshooting); docs/getting-started.md (new commented option in the initTWD example).
  • CHANGELOG: additional bullet under the existing unreleased 1.7.2 entry — no version bump.

Non-goals

  • No public re-export of setRootSelector or resetScreenDomState — those are package-internal.
  • No signature change to initTests (React-path power users who need a custom root use initTWD).
  • No change to screenDomGlobal.

Test plan

  • npm run test:ci — 391/391 passing across 54 files
  • npm run docs:build — VitePress build clean
  • npm run build — succeeds; the TS errors in src/plugin/* are pre-existing and unrelated
  • New unit tests cover: priority order (#root > decoy, #app fallback, app-root fallback), skip-empty heuristic, configured selector wins, configured-but-missing falls through, warn fires exactly once per session
  • Manual verification on CodeSandbox (run an example app and confirm the #highlighter regression no longer manifests)

🤖 Generated with Claude Code

Resolve the screenDom container in priority order: user-configured
rootSelector → #root / #app / app-root → first non-empty body child →
document.body. Emit a one-time console warning when falling back to the
heuristic so users discover the new rootSelector option.

Unblocks sandbox environments (CodeSandbox, extensions) that inject
overlay siblings before the app root and silently hijack screenDom
queries.

Adds rootSelector?: string to InitTWDOptions. No new public exports,
no version bump — ships under the existing 1.7.2 entry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kevinccbsg kevinccbsg merged commit e968418 into main Apr 21, 2026
8 checks passed
@kevinccbsg kevinccbsg deleted the feat/screendom-root-detection branch April 21, 2026 09:57
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.

1 participant