HTML frames allow developers to present documents in multiple views, which may be in a separate child window or sub-window. Multiple views offer developers a way to keep certain information visible while other views are scrolled or replaced. For example, within the same window, one frame might display a static banner, the second a navigation menu, and the third the main document that can be scrolled through or replaced by navigating in the second frame.
A page with frames is created 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 three frames, each loading different HTML pages:
<html> <frameset cols="25%,*,25%" frameborder="NO" framespacing="0" border="0"> <frame id="left" src="frame_a.htm" /> <frame src="frame_b.htm" /> <frame name="right" src="frame_c.htm" /> </frameset> </html>
Frames can be identified by an ID or through the name
attribute. In this recipe, we will identify and work with frames using the driver.switchTo().frame()
method of the WebDriver.TargetLocator
interface, which is used to locate a given frame or window using the id
, name
, instance of WebElement
, and the index.
Let's create a test on a simple page that has three frames. We will use id
, name
and index to identify these frames and interact with contents of these frames, as shown in the following examples:
testFrameWithIdOrName
test, we will use the name
and id
attributes to identify frames, as shown in the following code:package com.secookbook.examples.chapter06; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; public class FramesTest { public static WebDriver driver; @BeforeClass public static void setUp() { driver = new FirefoxDriver(); driver.get("http://cookbook.seleniumacademy.com/Frames.html"); driver.manage().window().maximize(); } @Test public void testFrameWithIdOrName() { try { // Activate the frame on left side using it's id attribute driver.switchTo().frame("left"); // Get an element from the frame on left side and verify it's // contents WebElement msg = driver.findElement(By.tagName("p")); assertEquals("This is Left Frame", msg.getText()); } finally { // Activate the Page, this will move context from frame back to the // Page driver.switchTo().defaultContent(); } try { // Activate the frame on right side using it's name attribute driver.switchTo().frame("right"); // Get an element from the frame on right side and verify it's // contents WebElement msg = driver.findElement(By.tagName("p")); assertEquals("This is Right Frame", msg.getText()); } finally { // Activate the Page, this will move context from frame back to the // Page driver.switchTo().defaultContent(); } } @AfterClass public static void tearDown() { // Close the Parent Popup Window driver.close(); driver.quit(); } }
testFrameByIndex
, we will use index for identifying the frame, as shown in the following code:@Test public void testFrameByIndex() { try { // Activate the frame in middle using it's index. Index starts at 0 driver.switchTo().frame(1); // Get an element from the frame in the middle and verify it's // contents WebElement msg = driver.findElement(By.tagName("p")); assertEquals("This Frame doesn't have id or name", msg.getText()); } finally { // Activate the Page, this will move context from frame back to the // Page driver.switchTo().defaultContent(); } }
The Selenium WebDriver's WebDriver.TargetLocator
interface provides the driver.switchTo().frame()
method to activate a frame on a page and perform operations. This method takes the id
or name
attribute value or instance of a WebElement
(the <frame>
element can be located using the driver.findElement()
method).
In the following example, the id
attribute is used to identify a frame:
//Activate the frame on left side using it's id attribute driver.switchTo().frame("left");
When frames do not have the id
or name
attributes defined, index can be used to identify a frame. In the preceding example, the frame in the middle does not have the id
or name
attributes. The middle frame's index will be 1
, as it has a frame on the left-hand side with the index as 0, and on the right-hand side with the index 2
:
//Activate the frame in middle using it's index. Index starts at 0 driver.switchTo().frame(1);
Once a frame is activated, we can leave the driver instance to interact with the page loaded in the frame. To return to the main page, use the driver.switchTo().defaultContent()
method.
Warning: While working with multiple frames, when an operation is completed on a frame and a test flow needs to move to another frame, calling the driver.switchTo().frame()
method will not move the context to the desired frame. The test will first need to activate the main page by calling the driver.switchTo().defaultContent()
method and then later activating the desired frame.
While working with frames, you will find that the id
or name
attributes are not defined. Still, frames can be identified using their index. This may not be a reliable way when applications are dynamic and there is a need to ensure that the correct frame is activated.
Let's look at an example in which we will identify frames by the contents of the page loaded in these frames to make tests more reliable, as shown in following code example:
@Test public void testFrameByContents() { // Get all frames on the Page, created with <frame> tag List<WebElement> frames = driver.findElements(By.tagName("frame")); // In this example frame in the middle is activated by checking the // contents // Activate frame and check if it has the desired content. If found // perform the operations // if not, then switch back to the Page and continue checking next frame try { for (WebElement frame : frames) { // switchTo().frame() also accepts frame elements apart from id, // name or index driver.switchTo().frame(frame); String title = driver.getTitle(); if (title.equals("Frame B")) { WebElement msg = driver.findElement(By.tagName("p")); assertEquals("This is Left Frame", msg.getText()); break; } else driver.switchTo().defaultContent(); } } finally { // Activate the Page, this will move context from frame back to the // Page driver.switchTo().defaultContent(); } }
In Selenium WebDriver, we can get multiple elements matching the same criteria in a list. Here we will get all frame elements from the page using the tagName()
method, as shown in following code example:
//Get all frames on the Page, created with <frame> tag List<WebElement> frames = driver.findElements(By.tagName("frame"));
The test will iterate through each frame element, passing this element to the driver.switchTo().frame()
method and checking its content. If the frame has matching content, then we can continue operations on the frame and later switch back to the main page, as shown in the following code example:
for (WebElement frame : frames) { // switchTo().frame() also accepts frame elements apart from id, // name or index driver.switchTo().frame(frame); String title = driver.getTitle(); if (title.equals("Frame B")) { WebElement msg = driver.findElement(By.tagName("p")); assertEquals("This is Left Frame", msg.getText()); break; } else driver.switchTo().defaultContent(); }
3.16.66.156