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 frame, which I want to switch to. In order to avoid any explicit waits, I tried the following code snippet:
self.driver.switch_to_default_content()
WebDriverWait(self.driver, 300).
until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'frame1')))
WebDriverWait(self.driver, 300).
until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'frame2')))
However, this snippet always fails and results in the following error:
...
File "/home/adietz/Projects/Venv/nosetests/local/lib/python2.7/site-packages/selenium/webdriver/support/wait.py", line 71, in until
value = method(self._driver)
File "/home/adietz/Projects/Venv/nosetests/local/lib/python2.7/site-packages/selenium/webdriver/support/expected_conditions.py", line 247, in __call__
self.frame_locator))
File "/home/adietz/Projects/Venv/nosetests/local/lib/python2.7/site-packages/selenium/webdriver/support/expected_conditions.py", line 402, in _find_element
raise e
WebDriverException: Message: TypeError: can't access dead object
However, if I use a sleep in addition:
time.sleep(30)
self.driver.switch_to_default_content()
WebDriverWait(self.driver, 300).
until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'frame1')))
WebDriverWait(self.driver, 300).
until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'frame2')))
selenium is able to find the frame inside the frame and switch to it. It looks like in the error case selenium switches to 'frame1' while 'frame2' is not yet loaded, but 'frame2' gets loaded in some other instance of 'frame1', or not recognized by selenium (maybe a bug?). So now selenium is inside some 'frame1' and for some reasons does not realize that the 'frame2' has been loaded.
The only way I can fix this (without using a long sleep) is by using this ugly piece of code:
mustend = time.time() + 300
while time.time() < mustend:
try:
self.driver.switch_to_default_content()
self.driver.switch_to.frame(self.driver.find_element_by_id("frame1"))
self.driver.switch_to.frame(self.driver.find_element_by_id("frame2"))
break
except WebDriverException as e:
self.log("Sleeping 1 sec")
time.sleep(1)
if time.time() > mustend:
raise TimeoutException
So whenever I get a WebDriverException
(dead object), I go to the top-level frame and try to switch to the inner frame - frame by frame.
Is there any other approach I can try?
Additional information
- The iframes are nested, i.e. 'frame2' is inside 'frame1'.
See Question&Answers more detail:
os