Frames

Introduction

A page has one main frame. Page-level interactions (such as click, type, locator) run in the main frame by default.

A page can also have additional frames created with the <iframe> element. To interact with elements inside an iframe, you get a browser scoped to that frame using frame(iframeSelector). The returned object has the same API as the page (e.g. locator, click, type), but all actions run inside that frame.

To go back to the main page, use the original browser reference for main-page actions. You do not need to "switch back"; you keep two references: one for the main page and one for the frame.

Locating elements inside a frame

Call browser.frame(iframe_selector) to get a FrameHandle (cstesting/browser.py). Use await on actions. Then use the main browser again for the top document.

await browser.goto("https://example.com/page-with-iframe")
await browser.wait_for_selector("iframe", {"timeout": 10000})

frame = browser.frame("iframe")
await frame.type("#username-input", "John")
await frame.click('button[type="submit"]')

await browser.locator("body").click()

Selector formats inside the frame are the same as on the main page: CSS, XPath (//input[@name='user']), id=, name=, or any attr=value.

Frame access

CSTesting provides frame(String iframeSelector): you pass a selector that matches the iframe element in the main page (or in the current frame for nested frames). The selector targets the <iframe> DOM node, not the document inside it.

Approach CSTesting
By tagbrowser.frame("iframe")
By idbrowser.frame("iframe#my-frame") or browser.frame("#my-frame")
By name attributebrowser.frame("iframe[name='frame-login']")
By URL (src)browser.frame("iframe[src*='domain']") or browser.frame("iframe[src^='https://auth.']")

Get frame by the iframe's name attribute:

frame = browser.frame("iframe[name='frame-login']")
await frame.type("#username-input", "John")

Get frame by the iframe's URL (e.g. contains "domain"):

frame = browser.frame("iframe[src*='domain']")
await frame.type("#username-input", "John")

There is no separate frameByName(String) or frameByUrl(Pattern) API; use the same frame(iframeSelector) with an attribute selector (e.g. iframe[name='...'], iframe[src*='...']).

Interacting with the frame

FrameHandle supports click, type, locator, check, select, wait_for_selector, evaluate, content, nested frame(...), etc. (see browser.py). There is no assertThat—use expect on values you read from the frame.

Example:

frame = browser.frame("iframe#login")
await frame.type("name=user", "John")
await frame.type("name=pass", "secret")
await frame.click('button[type="submit"]')

Nested frames

An iframe can contain another iframe. To interact with a nested frame, call frame(iframeSelector) on the parent frame reference (not on the main browser). That returns a new browser scoped to the inner iframe.

outer = browser.frame("iframe#outer")
inner = outer.frame("iframe#inner")
await inner.click("button")
await inner.type("#input", "hello")

h1 = await outer.locator("h1").first().text_content()

await browser.locator("body").click()

Selector for the inner iframe is evaluated in the context of the outer frame's document. So "iframe#inner" means an iframe with id="inner" inside the outer frame.

Summary

Topic CSTesting
Main frameDefault. Use the browser reference.
Single iframeframe = browser.frame("iframeSelector") then await frame.click(...), await frame.type(...), frame.locator(...), etc.
By namebrowser.frame("iframe[name='frame-login']")
By URLbrowser.frame("iframe[src*='domain']")
Nested frameouter = browser.frame("iframe#outer"); then inner = outer.frame("iframe#inner");
Back to mainUse the original browser reference; no explicit "switch back".

Note: The iframe should be in the DOM (and ideally loaded) before frame(). Use await browser.wait_for_selector("iframe", {"timeout": 10000}) and optionally await browser.wait_for_load() or await browser.sleep(500) for slow embeds.