How to work best with iframes


#1

Handling IFrames

An iframe is an HTML element that allows an external webpage to be embedded in an HTML document using the iframe tag, as shown in the example below:

<iframe src="http://sampleurl.com/example.php" width="700" height="90"></iframe>

Iframes are frequently used as a part of e-commerce solutions, to isolate third-party forms from the rest of the website. They are also used for displaying different types of media within a webpage. For example, YouTube videos and Google Maps windows are often embedded in webpages using iframes.

Unfortunately, elements contained within iframes can not be accessed directly. Instead, to test elements contained within iframes, you will first need to switch the WebDriver execution context to the iframe. Then you can continue to perform your test actions on the elements inside as you normally would.

This sounds complicated, but after finishing this tutorial, you will see that it is a lot easier in practice, and that the Page Object pattern is a big help in keeping iframe-laden tests maintainable.

In the following example we will use this demo website. The text editor you see there is placed inside an iframe. If you would try to access the editor without switching to the iframe’s execution context first, you would get a NoSuchElementException.

In order to test the editor and write something in it, we need to switch to the iframe first. To do so, follow these steps:

  1. Create two Page Object files, one for the top frame (containing the iframe) and one for the iframe that contains the code editor. Let’s call them TopPO and IframePO, respectively. You can create the Page Object files from within the application, or you can create them directly from our Ranorex Selocity extension:

  2. Build the selector for the iframe element, and add it to TopPO. Build the selector for the editor element (which is inside the iframe) and add it to IframePO. Here is how to do it with Ranorex Selocity:

  3. Create a new Action in the TopPO, let’s call it switchToIframe. It consists of an “Assign to variable” step, followed by the switchTo() method. As this method switches the context to the iframe, we want to return an IframePO instance.

    Here is what this would look like in a Java project:

    public IframePO switchToIframe() {
        WebElement iframeElement = this.wait.until(ExpectedConditions.visibilityOfElementLocated(this.iframe));
         
        driver.switchTo().frame(iframeElement);
         
        return new IframePO(driver);
    }
    

    … or in a TypeScript (Protractor) project:

    public async switchToIframe(): Promise<IframePO> {
      await browser.wait(ExpectedConditions.visibilityOf(element(this.iframe)), browser.allScriptsTimeout, this.iframe.toString());
      const iframeElement = element(this.iframe);
    
      await browser.switchTo().frame(iframeElement.getWebElement()); 
    
      return new IframePO();
    }
    
  4. In the IframePO, create an Action as you normally would, e.g. one that uses sendKeys to type “Hello World” into the editor, and call it writeHelloWorld().

  5. That’s it! Let’s use this setup in a test:
    Java:

    @Test
    public void IframeTest() {
        WebDriver driver = getDriver();
    
        TopPO topPo = new TopPO(driver);
        topPo.open("https://the-internet.herokuapp.com/iframe"); 
    
        IframePO iframePO = topPo.switchToIframe();
        iframePO.writeHelloWorld();
    }
    

    TypeScript (Protractor):

    it('should write "Hello World" into the editor', async () => {
      const topPo = new TopPO();
      await topPo.open('https://the-internet.herokuapp.com/iframe');
      
      const iframePo = await topPo.switchToIframe();
      await iframePo.writeHelloWorld();
    });
    

Nested iframes

If your web page has multiple iframes, nested one inside another, the workflow will be:
Locate the parent iframe, and use switchTo() to get to the outer iframe. After that, you need to use switchTo() again to get to the inner iframe from there.

For example on this webpage, you first need to locate the parent frame, and inside it the child frame. After that we will perform the actions, in this case, getting and asserting the “Inner Frame Checkbox” text.

@Test
public void NestedIframetest() {
    WebDriver driver = getDriver();

    // Instantiate the PO file
    IframeTestPo iframe = new IframeTestPo(driver);
    iframe.open("https://chercher.tech/practice/frames-example-selenium-webdriver");

    // Switch to parent iframe first, then to the child iframe, and then get the text 
    iframe.switchToOuterIframe().switchToInnerIframe().getTextFromChildFrame();
}

If you want to get back to the original position outside both iframes, and continue with your other test scenarios you can use driver.switchTo().defaultContent(). This method takes you outside both iframes, right to the top frame.

Conclusion:
Iframes are a little more complicated to work with, but you can use the switchTo() method to deal with them. With this tutorial you have learned how you can use Ranorex Selocity to generate the necessary selectors with ease and how to work with them using the Page Object pattern. Don’t forget to return to the top frame with switchTo().defaultContent() when you’re done with the iframe.


Release notes v1.0.0