fix(browse): clear refs when iframe auto-detaches in getActiveFrameOrPage#1311
Open
yashkot007 wants to merge 1 commit intogarrytan:mainfrom
Open
fix(browse): clear refs when iframe auto-detaches in getActiveFrameOrPage#1311yashkot007 wants to merge 1 commit intogarrytan:mainfrom
yashkot007 wants to merge 1 commit intogarrytan:mainfrom
Conversation
…Page
Asymmetric cleanup between two equivalent staleness conditions:
onMainFrameNavigated() → clearRefs() + activeFrame = null ✓
getActiveFrameOrPage() → activeFrame = null (refs NOT cleared) ✗
Both paths see the same staleness condition — refs were captured
against a frame that no longer exists. The main-frame path correctly
clears both pieces of state. The iframe-detach path nulls the frame
but leaves the refMap intact.
The lazy click-time check in `resolveRef` (tab-session.ts:97) partially
saves us — `entry.locator.count()` on a detached-frame locator throws
or returns 0, so the click errors out as "Ref X is stale". But the
user has no signal that frame context silently changed underfoot: the
next `snapshot` runs against `this.page` (main) while old iframe refs
still litter `refMap` with the same role+name keys. New refs collide
with stale ones, the resolver picks one at random, the user clicks
the wrong element.
TODOS.md line 816-820 documents "Detached frame auto-recovery" as a
shipped iframe-support feature in v0.12.1.0. This restores the
documented intent — the recovery should leave the session in a clean
state, not a half-cleared one.
Fix: 1 line — add `this.clearRefs()` next to `this.activeFrame = null`
inside the if-branch.
Test plan:
- [x] New regression test: 4/4 pass
- refs cleared when getActiveFrameOrPage detects detached iframe
- refs preserved when active frame is still attached (no regression)
- refs preserved when no frame set (page-level path untouched)
- matches onMainFrameNavigated symmetry — both paths reach the
same clean end state
- [x] `bun run build` clean
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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
TabSession.getActiveFrameOrPage()(tab-session.ts:151) auto-recovers from detached iframes by settingactiveFrame = nulland silently falling back to the main page. The matchingclearRefs()call is missing.Asymmetric handling of two equivalent staleness conditions:
Both paths see the same staleness condition — refs were captured against a frame that no longer exists. The main-frame path correctly clears both pieces of state; the iframe-detach path leaves
refMapintact.Why this matters
The lazy click-time check in
resolveRef(tab-session.ts:97) partially saves us —entry.locator.count()on a detached-frame locator throws or returns 0, so a click against a stale ref errors out cleanly withRef X is stale.But the user has no signal that frame context silently changed underfoot:
frame foo→snapshot→ got@e1, @e2, @e3(refs against the iframe)getActiveFrameOrPage()silently nullsactiveFrame, falls back tothis.pagesnapshotruns against the main page, generates new refsrefMapwith the same role+name keysclick @e1may target the wrong element on the main pageTODOS.mdline 816-820 documents this region:The fix restores the documented intent — auto-recovery should leave the session in a clean state, not a half-cleared one.
Fix
getActiveFrameOrPage(): Page | Frame { if (this.activeFrame?.isDetached()) { this.activeFrame = null; + this.clearRefs(); } return this.activeFrame ?? this.page; }One line. Same symmetry as the main-frame nav path right below it.
Regression test
browse/test/tab-session-frame-detach.test.ts— pure-logic tests againstTabSessiondirectly, no browser launch (same pattern astab-isolation.test.ts).Four cases:
getActiveFrameOrPagedetects detached iframe (fails onmain, passes with the fix)onMainFrameNavigated()and the iframe-detach path reach the same clean end state — locks the symmetry so a future refactor splitting the two paths fails before mergeTest plan
bun run buildcleanRelated
Independent of #1309 (
lastConsoleFlushedundeclared) and #1310 (concurrent state-write ENOENT). All three from the same stress-test session, but each touches a different file / subsystem and can land in any order.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmithwith what you need.