top of page

Selenium C# Tutorial: Handling Frames & iFrames

One of the main challenges you might have while developing your Selenium test automation scripts is handling Iframes or frames. HTML frames allow developers to split-screen horizontally or vertically, independent window or sub-window. This method allows developers to keep specific data visible to users while other views are scrolled or replaced. For example, a developer can add a frame to display a navigation menu or a second frame used to display a static banner within the same window.


An Iframes is an HTML document embedded inside another HTML document on a website, such as ads. A page with frames is created by using the <frameset> tag or the <iframe> tag. All frame tags are nested with a <frameset> tag.


In the following example, a page will display an iframe with a link to my blog:

While writing your selenium test automation scripts, you will need to know how to work and use frames and iframes. Frames can be identified by an ID or through the name attribute while the driver.switchTo().frame() command is used to change the driver focus to the relevant frame.


Switch Window Commands For Frames & iFrames

The first thing that we need to do when working with frames and iFrames is to access them in our code. This is done by using the driver.switchTo() as I mentioned above.frame() command. This method is used to access frames or iFrames by their handle (A unique ID). This window handle remains unchanged throughout the test scenario execution (will be changed when we re-run the tests). It is used by the switch command to identify and access specific frames or iFrames.

Here are the Switch Window commands you’ll require for switching frame or iFrame:



SwitchTo Frame

Using three options, we can switch over the elements and handle frames/Iframes with selenium API.


Option 1: By Frame Index

The frame/iFrame index is another attribute to direct driver focus to a specific frame/iFrame. In a giver website, each frame will have its unique index that starts with ‘0’, so if we have two frames in a website, the switch command will be as follow:

 [TestMethod]
        public void switchExample()
        {         
            driver.SwitchTo().Frame(0);
            driver.SwitchTo().Frame(1);
        }

To identify the number of frames/iframes in a given site, we can use the below code snippet:

int numberOfFrames = driver.FindElements(By.TagName("iframe")).Count;

Option 2: By Id or Name

ID and Name are fundamental and straightforward attributes for handling frames in Selenium through which we can switch to the frame/iFrames.

 [TestMethod]
        public void switchExample()
        {         
            driver.SwitchTo().Frame("Add Frame ID here");
            driver.SwitchTo().Frame("Add Frame Name here");
        }

Option 3: By Web Element

we can also identify frames with the same Selenium locators (XPath, CssSelector, etc.) we use to locate other web elements.

driver.SwitchTo().Frame(driver.FindElement(By.weblocator("locator")));

SwitchTo DefaultContent

This SwitchTo DefaultContent command selects either the first frame on the site or the main document (< main >); the ht page contains iFrames.

driver.SwitchTo().DefaultContent();

SwitchTo ParentFrame

This method is used to select the parent frame of the currently selected frame.

driver.SwitchTo().ParentFrame();



Handling iFrames In Selenium Using SwitchTo() Method

now that we know the basic commands we will need for working with frames and iFrames, it is time to review some examples based on Selenium.dev as a test URL. The site contains three different iFrames:

1. packageListFrame

2. package frame

3. classFrame

Example 1: Using Frame Name

[TestMethod]
public void Example_1_FrameByName()
{            
/*
Frames on site: 
(1) Frame Name: packageListFrame
(2) Frame Name: packageFrame
(3) Frame Name: classFrame              
*/

//Validate the number of frames on site:             
            Assert.AreEqual(3,driver.FindElements(By.TagName("iframe")).Count);
IJavaScriptExecutor jsExecutor = (IJavaScriptExecutor)driver;

try
{   
//Switch and Validate frame(1)           
driver.SwitchTo().Frame("packageListFrame");
Console.WriteLine("Frame name is: " + jsExecutor.ExecuteScript("return self.name") + " as expected");
Assert.AreEqual("packageListFrame", jsExecutor.ExecuteScript("return self.name"));

//Get an element from the frame and click on it
IWebElement packageList = driver.FindElement(By.PartialLinkText("org.openqa.selenium.chrome"));
packageList.Click();                              
                
//Switch to the Parent frame before switching to any other frame
driver.SwitchTo().ParentFrame();

//Switch and Validate frame(2)
driver.SwitchTo().Frame("packageFrame");
Console.WriteLine("Frame name is: " + jsExecutor.ExecuteScript("return self.name") + " as expected");
Assert.AreEqual("packageFrame", jsExecutor.ExecuteScript("return self.name"));

                
//Switch to the Parent frame before switching to any other frame
driver.SwitchTo().ParentFrame();

//Switch and Validate frame (3)
driver.SwitchTo().Frame("classFrame");
Assert.AreEqual("classFrame", jsExecutor.ExecuteScript("return self.name"));
Console.WriteLine("Frame name is: " + jsExecutor.ExecuteScript("return self.name") + " as expected");                   
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}                       
}

Output:







Example 2: Using Frame ID

[TestMethod]
public void Example_2_FrameByID()
{
IJavaScriptExecutor jsExecutor = (IJavaScriptExecutor)driver;

/*
Frames on site: 
(1) Frame Name: packageListFrame
(2) Frame Name: packageFrame
(3) Frame Name: classFrame              
*/

//Validate the number of frames on site:             
Assert.AreEqual(3, driver.FindElements(By.TagName("iframe")).Count);

try
{
//Switch and Validate frame(1)           
driver.SwitchTo().Frame(0);                
Console.WriteLine("The name of Frame ID 0 is: " + jsExecutor.ExecuteScript("return self.name") + " as expected");
Assert.AreEqual("packageListFrame", jsExecutor.ExecuteScript("return self.name"));

//Get an element from the frame and click on it
IWebElement packageList = driver.FindElement(By.PartialLinkText("org.openqa.selenium.chrome"));
packageList.Click();

//Switch to the Parent frame before switching to any other frame
driver.SwitchTo().ParentFrame();
                
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);                
}
}

Output:





Example 3: Using Frame Locator

[TestMethod]
public void Example_3_FrameByLocator()
{
IJavaScriptExecutor jsExecutor = (IJavaScriptExecutor)driver;

try
{
//Switch and Validate frame(1)     
                driver.SwitchTo().Frame(driver.FindElement(By.XPath("/html/body/main/div/div[2]/iframe")));                                              
Assert.AreEqual("classFrame", jsExecutor.ExecuteScript("return self.name"));

//Switch to the Parent frame before switching to any other frame
driver.SwitchTo().ParentFrame();
                
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);                
}                           
}

Output:








Identifying and handling frames by their content

While working with frames, you will find that the frame name or id attributes are not defined, and the use of 'Index' to fund them is less reliable. To handle this scenario, we can identify frames by the content of the document loaded in these frames

to make tests more reliable.


In selenium WebDriver, we can get elements of the same criteria in a list. So, why not use the same logic for frames using the tagname() method. In the test below, we will iterate through each frame element in the collection, passing this element to the switchTo().frame() method and checking its content. If the frame has a matching condition, we will check its content, and if not, we will return to the parent frame.


Code:

[TestMethod]
public void LocateFramesByContent()
{
            driver.Navigate().GoToUrl("https://www.selenium.dev/selenium/docs/api/java/index.html?overview-summary.html");
driver.Manage().Window.Maximize();
IJavaScriptExecutor jsExecutor = (IJavaScriptExecutor)driver;

//Get all frames on the Page, created with <Iframe> tag
IList<IWebElement> framesOnPage = driver.FindElements(By.TagName("iframe"));

//Option 1: Using FOR loop
for (int i = 0; i < framesOnPage.Count; i++)
{
driver.SwitchTo().Frame(framesOnPage[i]);

if (driver.PageSource.Contains("GeckoDriverService"))
{
Assert.AreEqual("packageFrame", jsExecutor.ExecuteScript("return self.name"));
Console.WriteLine(jsExecutor.ExecuteScript("return self.name"));
break;
}
else
{
driver.SwitchTo().ParentFrame();
}                                
}

driver.SwitchTo().ParentFrame();

//Option 2: Using Foreach loop
foreach (var frame in framesOnPage)
{
driver.SwitchTo().Frame(frame);
if (driver.PageSource.Contains("GeckoDriverService"))
{
Assert.AreEqual("packageFrame", jsExecutor.ExecuteScript("return self.name"));
Console.WriteLine(jsExecutor.ExecuteScript("return self.name"));
break;
}
else
{
driver.SwitchTo().ParentFrame();
}
}
}



Handling Nested Frames Using SwitchTo() Method

A nested frame is a frameset that contains a collection of frames (or sub-frames). So, to access a nested frame, we first need to switch driver focus to ParentFrameset and only then use the SwitchTo() command to switch to the Child frame.


Let us see a basic example that demonstrates this flow:


<iframe " frameborder="0" scrolling="no"

src="http://Any Reference name="IframeExample" style="width:100px; height:200px;"></iframe>


Code:

[TestMethod]
publicvoid WorkingWithIFrames()
{
IWebDriver FireFox = new FirefoxDriver();

//Locate the frame that contains the nested iframe
FireFox.SwitchTo().Frame("Containing Frame");

//locate the Iframe element via name
IWebElement iframeElement = FireFox.FindElement(By.Name("IframeExample"));

//Accessing the Iframe
FireFox.SwitchTo().Frame(iframeElement);

//Return to main page
FireFox.SwitchTo().ParentContent();


146 views0 comments
bottom of page