1

I am trying to traverse to the ancestor node from a child node using xpath, but it does not want to work.

WebElement menuItemText = driver.findElement(By.xpath("//span[contains( text(), '" + itemTitle + "')]"));
menuItemText = menuItemText.findElement(By.xpath(".//parent::*[@attribute='onclick']"));
menuItemText.click();

The nodes is:

<div onclick="something()">
  <div onclick="myFunction()">
    <div>
      <div>
        <span>Text!</span>
      </div>
    </div>
  </div>
</div>

However, the function name is very complex and each node has strange unique IDs. Not that it should matter too much but I want to traverse up the DOM from the child node to the parent / ancestor node that includes an onclick attribute. I want to get the first onclick when traversing up the DOM. So, the onclick=myFunction() is what I want to get.

Is that possible? I tried doing a while() loop and it worked for once but not anymore.

Guy
  • 34,831
  • 9
  • 31
  • 66
hozzaye07
  • 11
  • 2

3 Answers3

0

You can directly access the ancestor element from child node by using ancestor keyword as follows:

//span[contains(text(),\"Text\")]/ancestor::div[@onclick]
Guy
  • 34,831
  • 9
  • 31
  • 66
  • It worked, but I don't know if it actually traversed from child to parent. I had to edit the question because I noticed something in the DOM. There are two ancestors with the onclick function but it is the first onclick function I want to get from traversing from child. So, the myFunction is what I want. (these functions name will vary) – hozzaye07 Feb 19 '20 at 06:40
  • You can analyze what is the different between the two ancestors. Is there any attribute with different value, or you can go further to its greater ancestor then go down to its child (expected node). For Example: //span[contains(text(),\"Text\")]/ancestor::div[@firstIndex]/div[@onclick] I suggest you pass here the complete DOM tree, so I can help furthermore. – Thodo Timoteus Sinaga Feb 20 '20 at 07:34
  • Based on my experience, what @Riswan chatoli suggest by using index is not the best solution. – Thodo Timoteus Sinaga Feb 20 '20 at 07:43
0

I hope any of the following will solve the issue. ie) it will select the first ancestor div that contains attribute on click.

1: //span[contains(text(),\"Text\")]/ancestor::div[@onclick][1]
2: (//span[contains(text(),\"Text\")]/ancestor::div[@onclick])[1]
0

To search for the element with text as Text! and referencing it to locate the <div> tag with onclick attribute as myFunction(), you have to induce WebDriverWait for the elementToBeClickable and you can use the following based Locator Strategy:

  • xpath:

    new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//span[contains(., '" + itemTitle + "')]//preceding::div[starts-with(@onclick, 'myFunction')]"))).click();
    
DebanjanB
  • 118,661
  • 30
  • 168
  • 217