How to find element in nested Frame (not iframe) with #document wrapping frame content

451 views
Skip to first unread message

Geist SCM

unread,
Jan 24, 2020, 1:07:31 AM1/24/20
to Selenium Users
9:10 PM (16 minutes ago)
I searched for a few hours and only found one solution for this issue and requires using jQuery within selenium web driver.  Which seems to imply the web page must be using jQuery.

I suspect the html that is causing the failure of the web driver is very old and might be why I cannot find solid info on it.

Synopsis:  
find_element_by_id fails after switching to a nested frame (NOT iframe) where the frame content is wrapped in a #document 'element'
  1. Is this a known limitation?
  2. Is there a solution for working with this 'OMG' html?
Details:

I have tried below with both Chrome and Firefox web drivers; both fail the same.

Web page snippet:

<head>...</head>
<body>
   <frameset id="mainFrameSet">
      ...

      <frameset id="main" ...>
       ...

         <frame id="navigationFrame" src="navigationMonitor.htm?devId=4"...>
         #document
         <html>
            <head>...</head>
            <body>
               <div id="navigationTree">...</div>
            </body>
         </html>
         </frame>

      </frameset>
   </frameset>
</body>
</html>

Selenium python that fails:
    # just logged in so...
    # wait until main frame set is visible
    wait.until(EC.visibility_of_element_located((By.ID, 'mainFrameSet')))

    # list all the frames in DOM
    # this works as expected and lists all frames in DOM
    for frame in driver.find_elements_by_tag_name('frame'):
        log_msg('f name: {}'.format(frame.get_attribute('name')))

    # get nested div element but if fails due to #document 'element'
    wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID,'navigationFrame')))
    driver.find_element_by_id('navigationTree')


Output:
It shows:
  • All frames are seen by web driver
  • wait.util and switch gives no error
  • driver.find_element_by_id('navigationTree') fails with: Unable to locate element
    • I have switched to the nested frame a number of ways without issue except the find_element always fails the same way
1579834426.5536537 f name: tabArea
1579834426.5623124 f name: sensorInfo
1579834426.569566 f name: monitorInfo
1579834426.57814 f name: deviceStatus
1579834426.588289 f name: navigationFrame
1579834426.5970855 f name: detailArea
1579834426.6044142 f name: activeEventsArea
1579834426.6769533 driver failed
Traceback (most recent call last):
  File "./test_unity_navigation_with_chrome.py", line 291, in <module>
    test_login()
  File "./test_unity_navigation_with_chrome.py", line 279, in test_login
    login_unity()
  File "./test_unity_navigation_with_chrome.py", line 74, in login_unity
    driver.find_element_by_id('navigationTree')
  File "/home/phawkins/devel/work/rf/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 360, in find_element_by_id
    return self.find_element(by=By.ID, value=id_)
  File "/home/phawkins/devel/work/rf/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 978, in find_element
    'value': value})['value']
  File "/home/phawkins/devel/work/rf/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
    self.error_handler.check_response(response)
  File "/home/phawkins/devel/work/rf/lib/python3.6/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="navigationTree"]"}
  (Session info: chrome=79.0.3945.130)


My environment:

        Tool |      Version       | Path
-------------+--------------------+-------------------------------------
  Linux Dist | Ubuntu 18.04.3 LTS | NA
Linux Kernel | 4.15.0-58-generic  | NA
  Git commit | 2173279a           | NA
      Python | 3.6.8              | /home/phawkins/devel/work/rf/bin/python
          RF | 3.2b1              | /home/phawkins/devel/work/rf/bin/robot
 RF Selenium | 4.1.0              | /home/phawkins/devel/work/rf/lib/python3.6/site-packages
 RF Requests | 0.6.3              | /home/phawkins/devel/work/rf/lib/python3.6/site-packages
    Selenium | 3.141.0            | /home/phawkins/devel/work/rf/lib/python3.6/site-packages
    Requests | 2.22.0             | /home/phawkins/devel/work/rf/lib/python3.6/site-packages
    Net-SNMP | 5.7.3              | /usr/bin/snmpget
    Easysnmp | 0.2.5              | /home/phawkins/devel/work/rf/lib/python3.6/site-packages
      Poster | 0.8.1              | /home/phawkins/devel/work/rf/lib/python3.6/site-packages
      Chrome | 79.0.3945.130      | /usr/bin/google-chrome
chromedriver | 79.0.3945.36       | /home/phawkins/devel/work/rf/bin/chromedriver
     Firefox | 72.0.1             | /usr/bin/firefox
 Geckodriver | 0.26.0             | /home/phawkins/devel/work/rf/bin/geckodriver
------------------------------------------------------------------------



Geist SCM

unread,
Jan 24, 2020, 12:35:10 PM1/24/20
to Selenium Users

Turns out it was not the #document virtual element at all.  This morning I set that idea aside and started looking at the issue of not finding an element when it is clearly there.  I was thinking it might be a timing issue but using a pause after switching to the inner frame did not seem to help.  Turns out my pause was not long enough.

Then a clue came along to a page uses a Wait with a search for the element in it.   While I was using something similar to wait for the page to load I had never done this on finding an element.  But that was what worked.

# driver, wait, and EC are global and set in another method

def login_unity():
    # find login fields and input credentials
    log_msg('wait for login box, enter creds, login')
    log_in_btn = wait.until(EC.element_to_be_clickable((By.ID, 'login')))
    user = driver.find_element_by_id('username')
    pw = driver.find_element_by_id('password')
    user.send_keys(g_user)
    pw.send_keys(g_pw)
    log_in_btn.click()

    log_msg('wait until top frameset is visible')
    wait.until(EC.visibility_of_element_located((By.ID, 'mainFrameSet')))
    driver.switch_to_default_content()

    log_msg('switch to nested frame')
    wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID,'navigationFrame')))

    log_msg('find element in frame content')
    link_element = wait.until(EC.presence_of_element_located((By.ID, 'report164160')))
    # above was change that made it work instead of just a find_element_by_id()

    log_msg('click link')
    link_element.click()


Reply all
Reply to author
Forward
0 new messages