Skip to content

fix(Playwright): switchTo resolves nested iframes relative to current frame - #5717

Open
DavertMik wants to merge 1 commit into
4.xfrom
fix/playwright-nested-switchto-5688
Open

fix(Playwright): switchTo resolves nested iframes relative to current frame#5717
DavertMik wants to merge 1 commit into
4.xfrom
fix/playwright-nested-switchto-5688

Conversation

@DavertMik

@DavertMik DavertMik commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Fixes #5688

Problem

On Playwright, switching into an iframe that is nested inside the current frame left the helper pointing at nothing:

I.amOnPage('/iframe_nested')
I.switchTo('[name=wrapper]')
I.see('Iframe test')         // ok
I.switchTo('[name=content]') // reported as passed
I.see('Information')         // times out

After the second switchTo nothing was reachable any more — not the nested frame, not the parent frame, not the top level. Puppeteer and WebDriver were unaffected, and within({ frame: [...] }) worked, which is why this read as a Playwright-only regression.

Cause

switchTo() built the frame locator from this.page unconditionally:

this.frame = await Promise.race([this.page.frameLocator(locator), ...])

So '[name=content]' was looked up on the top-level document, where it does not exist, and the resulting FrameLocator resolved to nothing.

The failure was silent because the existence check immediately above it goes through _locateElement(), which does honour the current frame. The frame was found, then discarded.

Introduced in cb7efd6 (while removing TestCafe); 3.x chained the locator correctly.

Fix

Chain from the current frame when there is one, as 3.x did:

this.frame = this.frame ? this.frame.frameLocator(locator) : this.page.frameLocator(locator)

The Promise.race wrapper goes away with it: frameLocator() is synchronous, so it never raced anything and left an uncleared 5s timer behind on every switchTo call.

Tests

Three cases added to the shared web API spec, since the behaviour is cross-helper:

  • switching into nested iframes one level at a time — fails on 4.x
  • switchTo(null) returning to the top level from a nested frame — fails on 4.x
  • a nested iframe not being reachable from the top-level context, i.e. switchTo resolves the frame against the current context rather than the page (passes either way; guards the fix from being "fixed" by widening the lookup to the whole document)

Verified locally against Playwright and Puppeteer (#switchTo, plus the full within/iframe/frame set in Playwright_test.js — 43 passing) and against the acceptance within suite (8 passing). WebDriver runs in CI.

🤖 Generated with Claude Code

https://claude.ai/code/session_01M93h8jjpyUt1A7Px3kwpxC

… frame

switchTo() always built the frame locator from the page, so switching into
an iframe nested inside the current frame silently resolved to nothing:
the step passed, but every following action timed out and no element on
any level was reachable.

The existence check ahead of it runs against the current frame, which is
why the bad switch was never reported. Chain the frame locator from the
current frame when there is one, as 3.x did.

frameLocator() is synchronous, so the Promise.race wrapper never raced
anything and left a dangling 5s timer behind on every switchTo call.

Fixes #5688

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M93h8jjpyUt1A7Px3kwpxC
@DavertMik
DavertMik force-pushed the fix/playwright-nested-switchto-5688 branch from ff337cf to 54dd76d Compare September 13, 2026 22:31
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.

Playwright 4.x bug: switchTo doesn't handle nested frames properly

1 participant