Automated Testing Frames in Selenium WebDriver

How to test content inside Frames and iFrames in Selenium WebDriver

Courtney Zhan
5 min readMay 8, 2022

Frames (and iFrames) are widely considered to be bad practice. To the point where frames have been deprecated in HTML5. iFrames themselves still are supported but they carry some performance and accessibility concerns. Despite this, iFrames are still widely used, especially in enterprise apps. For example, Microsoft dynamic 365 uses iFrames heavily.

This tutorial will show you multiple ways to get past these frames and test the content inside them in Selenium WebDriver.

iFrames vs Frames — What’s the Difference?

Frames (<frame>) are used in conjunction with Framesets, so I’ll explain framesets first to understand frames. A frameset splits the view of a browser into sections (frames). And each frame contains an independent page.

Frameset with 3 frames.

HTML Source:

<frameset rows="100,*" frameborder="0" border="0" framespacing="0">
<frame name="topNav" id="topNavId" src="top_nav.html">
<frameset cols="200,*" frameborder="0" border="0" framespacing="0">
<frame name="menu" id="menu_frame" src="menu_1.html" scrolling="auto" noresize>
<frame name="content" src="content.html">
</frameset>
</frameset>

iFrame stands for ‘inline frame’. iFrames are used to embed a document within the current HTML document (hence ‘inline’ in the name). iFrames do not have to be in a frameset. In short, it’s like another page inside the current page.

In the context of automated testing, Frames and iFrames are the same. In this article, I’ll refer to both as ‘frames’’.

Steps to Automated Testing page operations in a Frame

Selenium Driver only can find elements in the current page or frame. To interact with elements inside a frame, the driver must first focus on that frame.

1. Identify a frame

2. Switch to a frame

3. Drive the elements inside the frame

4. Switch back the main page

How to Switch to a Frame?

In Selenium WebDriver, we use the switch_to command to focus on a specific frame. There are multiple ways to identify a frame (then we can switch to it). Here are some common methods:

  • Frame by ‘ID’
  • Frame by Selenium WebElement
  • Frame by index

Identify Frame by ‘ID’

This is the most intuitive method but only works if the ID attribute is present.

Example website where the iFrame has an id of “Frame1” to use as an identifier.

The HTML fragment:

<iframe frameborder="1" id="Frame1" name="first-frame">
...
</iframe>

The test step below switches the focus to it.

driver.switch_to.frame("Frame1")

After this line, you can start interacting with the contents inside the frame, Frame1. In the above example, that is the Username and Password form.

Below is the complete testcase:

  it "Testing iFrame by ID" do
driver.navigate.to(site_url + "/iframe.html")
driver.find_element(:name, "user").send_keys("agileway")
# switch to the sign in frame
driver.switch_to.frame("Frame1")
driver.find_element(:name, "username").send_keys("tester")
driver.find_element(:name, "password").send_keys("TestWise")
driver.find_element(:id, "loginBtn").click
sleep 0.5
expect(driver.page_source).to include("Signed in")
# return to main document
driver.switch_to.default_content()
driver.find_element(:id, "accept_terms").click
end

Note: If there are multiple frames that share the same ID, then the driver will switch to the first frame that matches the ID.

Can you identify a frame directly by Name?

According to the Selenium Documentation, you should be able to use the name attribute directly. i.e. driver.switch_to.frame(“first-frame”) However, I could not get this to work in Selenium 4.1.0 — if you could, please let me know how! 😁

Besides directly calling ID, there are slightly more complex but more powerful ways of identifying frames.

Identify Frame by finding the WebElement first/by Source

We can use Selenium’s find_element feature to get a WebElement, then use this element for identifying the frame to switch to. This is very flexible, as it means you can find the frame using your preferred method, including:

  • name
  • xpath
  • css_selector
  • and more!

I prefer to use XPath on the frame’s source (src) attribute. The frame’s source must be present, even if an ID or name is not. The source is often unique on a page, but this is not guaranteed.

Example website where the iFrame has a src of “login_iframe.html” to use as an identifier.

The HTML fragment:

<iframe frameborder="1" src="login_iframe.html">
...
</iframe>

The test step below switches the focus to the frame using the source:

elem_frame = driver.find_element(:xpath, "//iframe[@src='login_iframe.html']")driver.switch_to.frame(elem_frame)

By passing in the WebElement, the focus is switching to the frame, and you can start interacting with the elements inside it.

Below is the complete testcase:

it "Testing iFrames by element" do
driver.navigate.to(site_url + "/iframe.html")
driver.find_element(:name, "user").send_keys("agileway")
# switch to the sign in frame
elem_frame = driver.find_element(:xpath, "//iframe[@src='login_iframe.html']")
driver.switch_to.frame(elem_frame)
driver.find_element(:name, "username").send_keys("tester")
driver.find_element(:name, "password").send_keys("TestWise")
driver.find_element(:id, "loginBtn").click
sleep 0.5
expect(driver.page_source).to include("Signed in")

# return to main document
driver.switch_to.default_content()
driver.find_element(:id, "accept_terms").click
end

Frame by Index

We can also use the index of the frames to identify specific frames. A webpage can contain multiple frames.

To list all the frames, run window.frames in your browser’s console. This will list all the frames on the current page. See the below screenshot for example output and where to find the frames’ indices.

Example website with two frames. `window.frames` was executed on the browser console and listed two frames.

You can copy the index from the console (the purple number at the start of the line) to get the index value.

The HTML fragment for the above screencap:

<iframe src="login_iframe.html">
...
</iframe>
<iframe src="account_details_iframe.html">
...
</iframe>

The test step below switches the focus to the first frame:

driver.switch_to.frame(0)

The full testcase to interact with elements from both frames is below:

it "Testing iFrames by index" do
driver.navigate.to(site_url + "/iframes.html")

# switch to first frame
driver.switch_to.frame(0)

driver.find_element(:name, "username").send_keys("agileway")
# return to main document
driver.switch_to.default_content()
# switch to second frame
driver.switch_to.frame(1)
driver.find_element(:id, "radio_male").click
end

How to Leave a Frame

In the above test cases, you may notice that after completing operations inside the frames, there is another switch_to but to the default_content() rather than a specific frame.

default_content returns the driver to the main page before we start any switching. It is good practice to do this after the end of each test case. This can help the driver avoid getting stuck in a frame across test cases.

In the case of the index example with multiple frames, you should be returning to the main (or parent) content before entering another frame at the same level.

--

--