3

I'm new to Selenium and have searched for a solution for this, but cannot find one.

I am trying to drill down into a nav containing a collapsable directory tree. The folder nodes' content starts as an empty div that is populated when their "+" icon is clicked. The problem is that I cannot find anything within the newly populated div. I am using find_element_by_link_text() and have tried find_element_by_partial_link_text() with a fragment. I've even done a find_elements_by_tag_name() and the new elements (anchors) are not listed with those that exist outside of the new div.

The entire nav is contained within an iframe - is there a switch_to method that would apply?

Here is a sanitized example of what the HTML looks like:

<iframe id="KnownID" ...>
  <html ...>
   <body ...>
    <div id="unknown_id_first_subtree"> ... </div>

    <div id="unknown_id_nth_subtree">
      <div id="unknown_a">
       <table> <tbody> <tr> <td width="however wide the indent"></td>
         <td>
           <!-- Child nodes begin here -->
           <div>
             <table> <tbody> <tr>
               <td class="treeCell">
                 <a id="unknown_id"> this toggles the tree node display </a>
                 <a id="unknown_id">This is the text I know</a>
               </td> </tr> </tbody>
             </table>
           </div>
           <div id="subtreeContainer_unknown_id">
               <!-- Empty place holder to hold expanded content -->
           </div>
           <!-- Repeat above pattern for each tree entry -->
         </td>
       </tr> </tbody> </table>
      </div>
    </div>   ... closes out the nth_subtree
    repeats

The empty place holder is populated when the node is expanded. I do not know any of the ID's when my script runs, all that I know is the text of the link ("This is the text I know").

The IDs of the elements are, of course, available at run time, and I can construct the ID of the various elements I need to use by replacing the prefix.

I was able to find_element_by_xpath the first entry:

//a[contains(text(),'A')]

with both FirePath and Seleninum. I can find "B" in "A/B" using FirePath with:

//a[contains(text(),'A')]/../../../../../..//div[@id='subtreeContainer_$div$fileFolder_div_ff8']//a[contains(text(),'B')]

However, that string does not work when I issue it from Selenium using find_elements_by_xpath(). (I use the plural version because several entries match ("A", "A1", "A2") a single left fragment, just look for the one that I want in that list.)

The code that I wrote is basically:

xpath = "//"
segments = [ "A", "B", "C", ...]
for segment in segments:
  xpath += "a[contains(text(),'%s')]" % segment
  anchors = driver.find_elements_by_xpath(xpath)
  subTreeId = None
  for anchor in anchors:
    if anchor.text == segment:
      id = anchor.get_attribute("id")
      openId = "open" + id
      find_element_by_id(openId).click()
      subTreeId = "subTreeId" + id
      WebDriverWait(driver, 60).until(EC.presence_of_element_located((By.ID, subTreeId)))
      xpath += "/../../../../../..//div[@id='%s']//" % subTreeId
      break
  if subTreeId is None:
     fail()

The first iteration works and opens the first level of sub-tree, however, the second pass fails with this string:

//a[contains(text(),'A')]/../../../../../..//div[@id='subtreeContainer_$div$fileFolder_div_ff8']//a[contains(text(),'B')]

which is the same as the one above and I can cut-n-paste this string into FirePath and it finds the node (nodes, actually, "B", "B1", "B2", ...) - sorry to repeat myself.

My thinking is that when I "click" the "openId" element, Selenium's concept of the "current node" changes and so should the xpath, however, I was not able to get that concept to work by not carrying the prior xpath forward (I changed the "+=" to just "=" for the xpath assignment just before the "break".

Thanks (again), I appreciate the help

2
  • 2
    Please edit your question to include an HTML fragment to show the structure of the page you are trying to manipulate.
    – user246
    Commented Apr 21, 2015 at 1:48
  • Hi account4327, and welcome to sqa.stackexchange. Have you looked into the webdriver's switchTo() method? There are already plenty of answers here, and on stackoverflow, discussing it. Commented Apr 21, 2015 at 8:32

1 Answer 1

1

Refresh the browser AFTER clicking the '+' icon and then use find_element or find_elements functions. Something like this.

driver.find_element_by_id("+").click()
driver.refresh()
elements = driver.find_elements_by_tag_name("a")
    for element in elements:
        if "your_link" in element.get_attribute('href'):
            element.click()

I faced a similar problem in finding the dynamically generated/displayed menu item and the above solution worked for me. This solution may not work if the menu collapses again after refreshing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.