I have a rather complex webpage setup I need to test, containing nested frames.
In the actual problem the selenium code is loading new webpage contents containing a
Better approach is to make your own expected_condition. For example:
class nested_frames_to_be_available_and_switch:
def __init__(self, *args):
"""
:param args: locators tuple of nested frames (BY.ID, "ID1"), (BY.ID, "ID2"), ...
"""
self.locators = args
def __call__(self, driver):
try:
for locator in self.locators:
driver.switch_to.frame(driver.find_element(*locator))
except WebDriverException:
driver.switch_to_default_content()
return False
return True
WebDriverWait(driver, 300).until(nested_frames_to_be_available_and_switch((By.ID, 'frame1'), (By.ID, 'frame1')))
But maybe there is no need for that.. To tell so I need to see your html DOM.
This error message...
WebDriverException: Message: TypeError: can't access dead object
...implies that there was an error while switching between <iframes>
.
Some more information in terms of:
<iframe>
tagswould have helped us to analyze the issue in a better way. However, at this point it is worth to mention that initially Selenium always gets the focus on the default_content. Here are a few approaches to work with nested <frames>
and <framesets>
:
If both frame1 and frame2 are at same level i.e. under the Top Level Browsing Context you need to:
self.driver.switch_to.frame(self.driver.find_element_by_id("frame1"))
self.driver.switch_to_default_content()
self.driver.switch_to.frame(self.driver.find_element_by_id("frame2"))
If frame2 is nested within frame1, to switch from frame1 to frame2 you need to:
self.driver.switch_to_default_content()
self.driver.switch_to.frame(self.driver.find_element_by_id("frame1"))
//code
self.driver.switch_to.frame(self.driver.find_element_by_id("frame2"))
If frame2 and frame3 is within frame1 then, to switch from frame2 to frame3 you need to:
self.driver.switch_to.frame(self.driver.find_element_by_id("frame2"))
self.driver.switch_to.frame(self.driver.find_element_by_id("frame1"))
self.driver.switch_to.frame(self.driver.find_element_by_id("frame3"))
If frame2 and frame3 is within a frameset23 which is within frame1 then, to switch from frame2 to frame3 you need to:
self.driver.switch_to.frame(self.driver.find_element_by_id("frame2"))
#ignore presence of frameset23
self.driver.switch_to.frame(self.driver.find_element_by_id("frame1"))
#ignore presence of frameset23
self.driver.switch_to.frame(self.driver.find_element_by_id("frame3"))
While dealing with iframe and frameset you need to induce WebDriverWait inconjunction with expected_conditions:
frame_to_be_available_and_switch_to_it()
As an example to switch from Top Level Browsing Context to an <iframe>
an effective line of code will be:
Using frame ID:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.ID,"frameID")))
Using frame NAME:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.NAME,"frameNAME")))
Using frame CLASS_NAME:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.frame_CLASS_NAME,"u_0_f")))
Using frame CSS_SELECTOR:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"frame_CSS_SELECTOR")))
Using frame XPATH:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"frame_XPATH")))
Ways to deal with #document under iframe