On occasion, you’ll run into a relic of the front-end world — frames. And when writing a test against them, you can easily get tripped if you’re not paying attention.
Rather than gnash your teeth when authoring your tests, you can easily work with the elements in a frame by telling Selenium to switch to that frame first. Then the rest of your test should be business as usual.
Sometimes you might be getting a NoSuchElementException even though you have written the correct XPath or any other locators(id, name, CSS selector). In such cases, you need to check whether elements are there inside the iframe or not. if is there in the iframe you need to switch to frame(driver.switchTo().frame(“frame-top”);) and then you need to interact to that element
Also, don’t forget to switch to default content(driver.switchTo().defaultContent();) after interacting with iframe elements
Let’s check the examples.

Sample Code
Java
// filename: Frames.java
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
public class Frames {
WebDriver driver;
@Before
public void setUp() throws Exception {
driver = new FirefoxDriver();
}
@After
public void tearDown() throws Exception {
driver.quit();
}
@Test
public void nestedFrames() throws Exception {
driver.get("http://the-internet.herokuapp.com/nested_frames");
driver.switchTo().frame("frame-top");
driver.switchTo().frame("frame-middle");
assertThat(driver.findElement(By.id("content")).getText(), is(equalTo("MIDDLE")));
driver.switchTo().defaultContent();
}
@Test
public void iFrames() throws Exception {
driver.get("http://the-internet.herokuapp.com/tinymce");
driver.switchTo().frame("mce_0_ifr");
WebElement editor = driver.findElement(By.id("tinymce"));
String beforeText = editor.getText();
editor.clear();
editor.sendKeys("Hello World!");
String afterText = editor.getText();
assertThat(afterText, not(equalTo((beforeText))));
driver.switchTo().defaultContent();
assertThat(driver.findElement(By.cssSelector("u")).getText(),
is("An iFrame containing the TinyMCE WYSIWYG Editor"));
}
}
Python
# filename: frames.py
import unittest
from selenium import webdriver
class Frames(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
def tearDown(self):
self.driver.quit()
def test_example_1(self):
driver = self.driver
driver.get('http://the-internet.herokuapp.com/nested_frames')
driver.switch_to.frame('frame-top')
driver.switch_to.frame('frame-middle')
assert driver.find_element_by_id('content').text == "MIDDLE", "content should be MIDDLE"
driver.switch_to.default_content()
def test_example_2(self):
driver = self.driver
driver.get('http://the-internet.herokuapp.com/tinymce')
driver.switch_to.frame('mce_0_ifr')
editor = driver.find_element_by_id('tinymce')
before_text = editor.text
editor.clear()
editor.send_keys('Hello World!')
after_text = editor.text
assert after_text != before_text, "%s equals %s" % (before_text, after_text)
driver.switch_to.default_content()
assert driver.find_element_by_css_selector('u').text != "", "element should not be empty"
if __name__ == "__main__":
unittest.main()
Ruby
# filename: frames.rb
require 'selenium-webdriver'
require 'rspec/expectations'
include RSpec::Matchers
def setup
@driver = Selenium::WebDriver.for :firefox
end
def teardown
@driver.quit
end
def run
setup
yield
teardown
end
#Test 1
run do
@driver.get 'http://the-internet.herokuapp.com/nested_frames'
@driver.switch_to.frame('frame-top')
@driver.switch_to.frame('frame-middle')
expect(@driver.find_element(id: 'content').text).to eql 'MIDDLE'
@driver.switch_to.default_content
end
#Test 2
run do
@driver.get 'http://the-internet.herokuapp.com/tinymce'
@driver.switch_to.frame('mce_0_ifr')
editor = @driver.find_element(id: 'tinymce')
before_text = editor.text
editor.clear
editor.send_keys 'Hello World!'
after_text = editor.text
expect(after_text).not_to eql before_text
@driver.switch_to.default_content
expect(@driver.find_element(css: 'h3').text).not_to be_empty
end
C#
// filename: Frames.cs
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
public class Frames
{
IWebDriver Driver;
[SetUp]
public void SetUp()
{
Driver = new FirefoxDriver();
}
[TearDown]
public void TearDown()
{
Driver.Quit();
}
[Test]
public void NestedFrames()
{
Driver.Navigate().GoToUrl("http://the-internet.herokuapp.com/nested_frames");
Driver.SwitchTo().Frame("frame-top");
Driver.SwitchTo().Frame("frame-middle");
Assert.That(Driver.FindElement(By.Id("content")).Text.Equals("MIDDLE"));
}
[Test]
public void Iframes()
{
Driver.Navigate().GoToUrl("http://the-internet.herokuapp.com/tinymce");
Driver.SwitchTo().Frame("mce_0_ifr");
IWebElement Editor = Driver.FindElement(By.Id("tinymce"));
string StartText = Editor.Text;
Editor.Clear();
Editor.SendKeys("Hello World!");
string EndText = Editor.Text;
Assert.AreNotEqual(EndText, StartText);
Driver.SwitchTo().DefaultContent();
string HeaderText = Driver.FindElement(By.CssSelector("u")).Text;
Assert.That(HeaderText.Equals("An iFrame containing the TinyMCE WYSIWYG Editor"));
}
}
When you save this file and run it here is what will happen:
Test 1
- Open the browser
- Visit the page
- Switch to the nested frame
- Grab the text from the frame and assert that Selenium is in the correct place
- Close the browser
Test 2
- Open the browser
- Visit the page
- Switch to the frame that contains the TinyMCE editor
- Find and store the text in the editor
- Clear the text in the editor
- Input new text in the editor
- Find and store the new text in the editor
- Assert that the original and new text entries don’t match
- Switch to the top level of the page
- Grab the text from the top of the page and assert it’s what we expect
- Close the browser