Skip to content

feat(injected-helpers): extra fiber roots for portal modal support (closes #126 Gap B)#181

Merged
Lykhoyda merged 11 commits into
mainfrom
feat/gh-126-gap-b-extra-roots
May 27, 2026
Merged

feat(injected-helpers): extra fiber roots for portal modal support (closes #126 Gap B)#181
Lykhoyda merged 11 commits into
mainfrom
feat/gh-126-gap-b-extra-roots

Conversation

@Lykhoyda

Copy link
Copy Markdown
Owner

Summary

Closes Gap B of #126cdp_interact press testID="..." failing on fields inside react-native-actions-sheet modals (and other portal-mounted React subtrees) because their fiber roots are not in React DevTools' getFiberRoots() registry.

Gap A (TextField wrapper / RHF Controller) was shipped in #179 via cdp_interact action="setFieldValue".

What changed

  1. Extracted private iterateAllRoots(cb) primitive in injected-helpers.ts. Owns the renderer-iteration logic that forEachRootFiber and findAllRootFibers were duplicating, plus the new extra-roots step.
  2. Both public helpers became thin wrappers — same return shapes as before, zero caller changes.
  3. New extractFiberFromInstance(inst) helper turns user-provided component instances into fibers via three accepted shapes: _reactInternals (modern React), _reactInternalFiber (legacy React), or already-a-fiber duck-type (escape hatch).
  4. globalThis.__RN_AGENT_EXTRA_ROOTS__ is the user-facing opt-in: set it to a function returning component instances. Called fresh on every fiber-root scan.
  5. Tool description + template snippet for discoverability.

Architecture

  • One extension point for extra-roots (inside iterateAllRoots) — DRY across both wrappers.
  • Per-resolver try/catch isolates user-side bugs from native renderer iteration.
  • Synthetic rendererId: -1 marks extra-roots in the collector path.
  • Failure modes match the silent convention of __NAV_REF__ and __ZUSTAND_STORES__ (no console warnings on misconfig).

Test plan

  • 1527 / 1527 cdp-bridge unit tests passing (+12 net new in gh-126-extra-roots.test.js and +1 drift-guard in find-active-renderer-migration.test.js)
  • extractFiberFromInstance covers all 3 input shapes + rejection cases (including dual-key duck-type rejecting generator-like objects with only .return)
  • iterateAllRoots extra-roots step covers partial-failure, null-mixing, throwing resolver, non-array return, undefined resolver, sparse-array holes, non-function resolver (typeof guard discrimination)
  • forEachRootFiber delegation preserves short-circuit through to extra-roots
  • End-to-end: cdp_interact press testID against a component reachable ONLY via extra-roots fires its onPress (the user-visible fix)
  • Pure refactor in Task 3 (extract iterateAllRoots) verified by full existing-suite pass with NO behavior change before Task 4 wired extra-roots
  • CI green
  • Deferred: Manual rehearsal on a real RN app with react-native-actions-sheet modal — not blocking merge per spec §11

Out of scope

  • Auto-discovery via React DevTools onCommitFiberRoot (rejected in brainstorm — too deep into internals; opt-in is enough)
  • getTree() default path (no filter) does NOT see extra-roots — deliberate, see spec §5
  • /doctor probe for portal-library deps — rejected in brainstorm
  • docs-site portal-roots page — rejected in brainstorm

Refs

🤖 Generated with Claude Code

Lykhoyda and others added 11 commits May 27, 2026 14:30
…akeSandbox

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…als / fiber duck-type support

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nts per review

- Restore B143 LogBox historical rationale to findAllRootFibers (lost
  in the original refactor)
- Restore Gemini A3 try/catch teardown rationale to iterateAllRoots
- Defer the negative-rendererId claim to Task 4 (avoid forward-leaning
  doc that contradicts the code at this SHA)
- Grammar nit: 'Calling cb returning truthy' → 'A truthy return from cb'

No behavior change — comments only. 1518/1518 passing.
@Lykhoyda Lykhoyda merged commit 6e05a7a into main May 27, 2026
7 checks passed
@Lykhoyda Lykhoyda deleted the feat/gh-126-gap-b-extra-roots branch May 27, 2026 15:07
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