Skip to content

How to Handle iFrames in Selenium and Playwright

Practice iframe automation — switching into frames by testid, name, and title; interacting with nested iframes; waiting for dynamic iframe content; and handling form validation inside frames in Playwright, Selenium & Cypress.

Intermediate15 min6 scenarios14 test cases

Interactive Scenarios

S01Scenario 1: Basic iframe — Fill and Submit (Beginner)
data-testidiframe: [data-testid="iframe-basic"]
data-testidinput: [data-testid="iframe-name-input"]
data-testidbutton: [data-testid="iframe-submit-btn"]
/practice-frames/iframe-basic.html
data-testid="iframe-basic"name="basic-frame"title="Basic Iframe"
Not submitted yet
S02Scenario 2: iframe with Checkbox & Select (Beginner)
titleiframe: iframe[title="Form Iframe"]
data-testidselect: [data-testid="iframe-lang-select"]
getByLabelcheckbox: getByLabel("I agree to the terms")
/practice-frames/iframe-form.html
data-testid="iframe-form"name="form-frame"title="Form Iframe"
Preferences not saved
S03Scenario 3: Multiple iFrames — Locate by Attribute (Medium)

Each iframe must be located differently. Frame 1 has a testid; Frame 2 has only a name; Frame 3 has only a title.

data-testidiframe: [data-testid="iframe-frame-1"]
data-testidbutton: [data-testid="iframe-f1-action-btn"]
/practice-frames/iframe-multi-1.html
data-testid="iframe-frame-1"name="frame-one"title="Frame One"
nameiframe: iframe[name="frame-two"]
aria-labelbutton: getByRole("button", { name: "Activate Frame Two" })
/practice-frames/iframe-multi-2.html
name="frame-two"title="Frame Two"
titleiframe: iframe[title="Frame Three"]
text onlybutton: getByRole("button", { name: "Confirm Action" })
/practice-frames/iframe-multi-3.html
title="Frame Three"
No frame interacted with
S04Scenario 4: Nested iFrames — 2 Levels Deep (Medium)
data-testidouter: [data-testid="iframe-outer"]
titleinner: frameLocator('iframe[title="Inner Frame"]')
data-testidinput: [data-testid="iframe-inner-input"]
/practice-frames/iframe-nested-outer.html
data-testid="iframe-outer"title="Outer Frame"
Inner frame inside: iframe[title="Inner Frame"]2 levels deep
Inner frame not interacted with
S05Scenario 5: Dynamic Content in iframe — Wait for Load (Hard)HARD
data-testidiframe: [data-testid="iframe-dynamic"]
rolebutton: getByRole("button", { name: "Reveal Secret" }) — no testid
aria-labelinput: getByRole("textbox", { name: "Reveal code input" }) — no testid

Content loads after 1.5 s. Use expect(frame.getByRole('button')).toBeVisible({ timeout: 5000 }) — don't use fixed waits.

/practice-frames/iframe-dynamic.html
data-testid="iframe-dynamic"title="Dynamic Frame"
Dynamic content not interacted with
S06Scenario 6: Form Validation Inside iframe (Challenge)CHALLENGE
data-testidiframe: [data-testid="iframe-validation"]
role=alerterrors: getByRole("alert") — NO data-testid on error spans
getByLabelcompany field: getByLabel("Company") — no testid

Submit with empty fields to trigger errors. Error messages use role="alert" — locate without testid via role, XPath following-sibling, or partial text.

/practice-frames/iframe-validation.html
data-testid="iframe-validation"name="validation-frame"title="Validation Frame"
Form not submitted