top of page

Welcome
to NumpyNinja Blogs

NumpyNinja: Blogs. Demystifying Tech,

One Blog at a Time.
Millions of views. 

“Conquering Hidden Elements: Your Third Step into Advanced Playwright Automation”

Building on your element interaction skills from our previous journey, it’s time to tackle one of web automation’s trickiest challenges: working with hidden and nested content. As you advance in your Playwright expertise, you’ll inevitably encounter iframes and complex document structures that can make even seasoned automation engineers scratch their heads. These nested contexts are everywhere in modern web applications — from embedded payment forms to third-party widgets — and knowing how to handle them separates beginners from automation pros.


Understanding Frames vs IFrames


Frames represent an outdated method for creating site layouts using multiple documents from the same domain. Though you’ll rarely encounter them in modern applications, they still appear in legacy systems built before HTML5 standards took hold. On the other hand, iframes remain a cornerstone of contemporary web development, enabling developers to seamlessly embed content from entirely different domains within their applications.

Whether you’re automating tests for a cutting-edge React application or maintaining scripts for legacy enterprise systems, both Selenium and Playwright provide robust capabilities for interacting with these structures. The key lies in understanding how to identify and work with these different contexts effectively.


ree

The IFrame

Let’s start with a common scenario. When you need to interact with elements inside iframes — such as clicking a button embedded within an iframe — you’ll encounter HTML structure like this:

html

<div id=”modal”>

<iframe id=”buttonframe” name=”myframe” src=”https://seleniumhq.github.io">

<button>Click here</button>

</iframe>

</div>

Your first instinct might be to write straightforward code:

Selenium:

await driver.findElement(By.css(‘button’)).click();

Playwright:

await page.locator(‘button’).click();

But here’s the frustrating reality: you write a perfectly good script to click that button, but instead of working, you get hit with a dreaded “no such element” error. Everything looks right in your code, so what’s going wrong?

The culprit is the iframe itself. When Selenium runs your script, it can only “see” elements that exist in the main document. If your target button lives inside an iframe, Selenium has no idea it exists — it’s like trying to find something in a house when you’re only looking through the front window.

This is where the fundamental difference between Selenium and Playwright becomes apparent.


Selenium’s Approach: Frame Switching

Just like switching between browser windows, you need to tell Selenium WebDriver to switch its focus to the iframe first. Think of it as walking through the front door and then entering the specific room where your button is located.


Method 1: Using Element Reference

// Store the web element

const iframe = driver.findElement(By.css(‘#modal > iframe’));

// Switch to the frame

await driver.switchTo().frame(iframe);

// Now we can click the button

await driver.findElement(By.css(‘button’)).click();

Method 2: Using Name or ID

// Using the ID

await driver.switchTo().frame(“buttonframe”);

// Or using the name instead

await driver.switchTo().frame(“myframe”);

// Now we can click the button

await driver.findElement(By.css(“button”)).click();

Method 3: Using Index

// Switches to the second frame (index 1)

await driver.switchTo().frame(1);



Playwright’s Smarter Approach: Direct Frame References

Unlike Selenium’s “switching” approach, Playwright takes a more intuitive path — instead of jumping in and out of frames, you simply grab a reference to the frame you need and work with it directly.


Method 1: Element Handle to Frame

// Get the iframe element handle

const iframeElementHandle = await page.locator(‘#modal > iframe’).elementHandle();

// Get the frame from the iframe element

const frame = await iframeElementHandle.contentFrame();

// Now interact with elements inside the iframe

await frame.locator(‘button’).click();

Method 2: Direct Frame Access by Name/ID

// Switch to iframe by ID or name

const frame = page.frame({ name: ‘buttonframe’ }) || page.frame({ name: ‘myframe’ });

// Always check if frame exists

if (frame) {

await frame.locator(‘button’).click();

} else {

throw new Error(‘Frame not found’);

}

Method 3: Using Frame Index

const allFrames = page.frames();

const frame = allFrames[1]; // Index 1 = second iframe

if (frame) {

await frame.locator(‘button’).click();

} else {

throw new Error(‘Frame at index 1 not found’);

}

Key Differences and Best Practices

Playwright Advantages:

  • No Context Switching: You get a reference to the frame and act within it directly

Best Practices:

  • Always check if the frame is null to avoid runtime errors

  • Use descriptive names or IDs when possible rather than relying on indexes

  • Remember that frame indexes can change if the page structure updates

  • Test your frame interactions across different browsers and page states


Take away

While both tools handle iframes effectively, Playwright’s direct reference model feels more intuitive than Selenium’s context switching, eliminating the mental overhead of tracking frame states. Mastering these iframe techniques — regardless of your chosen tool — will save you countless debugging hours when those frustrating “element not found” errors strike.



“Everything you’ll ever need to know is within you; the secrets of the universe are imprinted on the cells of your body.”


 
 

+1 (302) 200-8320

NumPy_Ninja_Logo (1).png

Numpy Ninja Inc. 8 The Grn Ste A Dover, DE 19901

© Copyright 2025 by Numpy Ninja Inc.

  • Twitter
  • LinkedIn
bottom of page