1

I'm trying to click on element using the structure:

parentElement.findElement(XPath of Child Element);

However, this throws org.openqa.selenium.NoSuchElementException.

I'm currently scraping list of (parent) elements using XPath: .//*[@id='savedCartViewForm']/div/div. This identifies the correct list of elements (works as expected). Once I have list I apply the function:

parentElement.findElement(By.xpath(XPath));

Using the XPath:

.//input[contains(@aria-label,'Delete')]

and

.//input[contains(@value,'Delete')]

However this triggers org.openqa.selenium.NoSuchElementException.

I've researched this on SO for a couple of hours and based on several posts I added the '.' before two slashes which means relative to parent (instead of relative to entire DOM).

If I remove the dot I always get the first element on page - not the child of each parent element in list.

The HTML has the following structure:

<form id="savedCartViewForm" action="/gp/cart/view.html/ref=ord_cart_shr?app-nav-type=none&dc=df" method="post">
  <input type="hidden" value="1" name="fromAUI" />
  <input type="hidden" value="4CPM1MKXXXXXZ" name="requestID" />
  <input type="hidden" value="15XXXXXX0" name="timeStamp" />
  <input type="hidden" value="gkAVhUvXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAFx2yhxAAA" name="token" />
  <div class="a-divider a-divider-section">
    <div class="a-row sc-list-head sc-java-remote-feature">
      <div class="a-row sc-list-body sc-java-remote-feature">
        <div class="a-row sc-list-item sc-list-item-border sc-java-remote-feature" data-quantity="4" data-price="8.99" data-previous-offer-id="ekOCOsC%2Bl7B8l5MNqXXXXXXXXXXXXXXXXXXXXXXXXXXbBFS5rQm%2BDi9cGGpFufHEITXWAr6tAjIiPTFbZiXjZyIce7Y" data-outofstock="0"
          data-minquantity="1" data-itemtype="saved" data-itemislastpantryitem="0" data-itemid="S2e1cb5b5-ebb5-4e70-8474-c596d80bd99a" data-itemcategory="normal" data-item-count="1" data-isprimeasin="0" data-giftwrapped="0" data-giftable="0" data-encoded-offering="erF6bSsUaPN0XP13xfXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXYvWwmsZJ2HZwKuDJbLvjiR%2BI2CQAPyug7sPmmGV7DdJ"
          data-best-offer-id="erF6bSsUaPN0XP13xfsXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXwmsZJ2HZwKuDJbLvjiR%2OezFaQg7sPmmGV7DdJ" data-asin="B0742J1KYD">
          <div class="sc-list-item-spinner" style="display:none;">
            <div class="sc-list-item-overwrap" style="display:none;" />
            <div class="sc-list-item-removed-msg a-padding-medium" style="display:none;">
              <div class="sc-list-item-content">
                <div class="a-row a-spacing-base a-spacing-top-base">
                  <div class="a-column a-span10">
                    <div class="a-fixed-left-grid">
                      <div class="a-fixed-left-grid-inner" style="padding-left:115px">
                        <div class="a-fixed-left-grid-col a-float-left a-col-left" style="width:115px;margin-left:-115px;float:left;">
                          <div class="a-fixed-left-grid-col a-col-right" style="padding-left:0%;float:left;">
                            <ul class="a-unordered-list a-nostyle a-vertical a-spacing-mini">
                              <div class="a-row sc-action-links">
                                <span class="a-size-small sc-action-delete">
<span class="a-declarative" data-sc-item-action="{"itemID":"S2e1cbXXXXXXXXXXXXXXXXXXXXXXXXXXd80b9a","itemType":"saved","isWishListItem":0,"action":"delete","isFresh":0}" data-action="sc-item-action">
<input type="submit" aria-label="Delete MENSI Outdoor Patio Heater M6*0.75 Head Thread With M8X1 End Connection Nuts Thermocouple 410mm" value="Delete" name="submit.delete.S2XXXXXXXXXXXXXXXXXXXXXXXXXX0bd99a"/>
</span>
                                </span>
                                <i class="a-icon a-icon-text-separator" aria-label="|" role="img" />
                                <span class="a-size-small sc-action-add-best-offer sc-invisible-when-no-js">
<input class="wl-refdata" type="hidden" value="true" name="isSelectedForCheckout"/>
<i class="a-icon a-icon-text-separator" aria-label="|" role="img"/>
<span class="a-size-small sc-action-move-to-wishlist sc-invisible-when-no-js">
</div>
</div>
</div>
</div>
</div>
<div class="a-column a-span2 a-text-left a-span-last">
</div>
</div>
</div>
<div class="a-row sc-list-item sc-list-item-border sc-java-remote-feature" data-quantity="8" data-price="7.37" data-outofstock="0" data-minquantity="1" data-itemtype="saved" data-itemislastpantryitem="0" data-itemid="See02cb-XXXXXXXXXXXXXXXXXXXXXXXXXXc5" data-itemcategory="normal" data-item-count="2" data-isprimeasin="0" data-giftwrapped="0" data-giftable="0" data-encoded-offering="MzgFwAMDc3XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX4bqRzg7IzfFp%2B%2BDg%2BAYyl4X" data-asin="B004DYKIH4">
<div class="sc-list-item-spinner" style="display:none;">
<div class="sc-list-item-overwrap" style="display:none;"/>
<div class="sc-list-item-removed-msg a-padding-medium" style="display:none;">
<div class="sc-list-item-content">
<div class="a-row a-spacing-base a-spacing-top-base">
<div class="a-column a-span10">
<div class="a-fixed-left-grid">
<div class="a-fixed-left-grid-inner" style="padding-left:115px">
<div class="a-fixed-left-grid-col a-float-left a-col-left" style="width:115px;margin-left:-115px;float:left;">
<div class="a-fixed-left-grid-col a-col-right" style="padding-left:0%;float:left;">
<ul class="a-unordered-list a-nostyle a-vertical a-spacing-mini">
<div class="a-row sc-action-links">
<span class="a-size-small sc-action-delete">
<span class="a-declarative" data-sc-item-action="{"itemID":"SeccXXXXXXXXXXXXXXXXXXXXXXXXXXd441c5","itemType":"saved","isWishListItem":0,"action":"delete","isFresh":0}" data-action="sc-item-action">
<input type="submit" aria-label="Delete Bit Adapter - 1/4" to 1/4" - Turn Any Ratchet Into a Driver! Now with Quick-Change By Pro Tools" value="Delete" name="submit.delete.SeccXXXXXXXXXXXXXXXXXXXXXXXXXX5"/>
</span>
                                </span>
                                <i class="a-icon a-icon-text-separator" aria-label="|" role="img" />
                                <span class="a-size-small sc-action-move-to-cart">
<input class="wl-refdata" type="hidden" value="B003IXYJYO" name="creativeAsin"/>
<input class="wl-refdata" type="hidden" value="5BD74XXXXXXXXXXXXXXXXXXXXXXXXXX68" name="assocToken"/>
<input class="wl-refdata" type="hidden" value="xsc" name="linkCode"/>
<input class="wl-refdata" type="hidden" value="true" name="isSelectedForCheckout"/>
<i class="a-icon a-icon-text-separator" aria-label="|" role="img"/>
<span class="a-size-small sc-action-move-to-wishlist sc-invisible-when-no-js">
<i class="a-icon a-icon-text-separator" aria-label="|" role="img"/>
<span id="comparison-lite-modal-B004DYKIH4" class="a-declarative" data-a-modal="{"cache":"0","hideHeader":"true","width":"80%","ajaxFailMsg":"We\u2019re sorry, an error has occurred. Please try again.","url":"/compare/product/B004DYKIH4/ref=psdc_sXXXXB004DYKIH4?viewType=sfl","height":"570"}" data-action="a-modal">
</div>
</div>
</div>
</div>
</div>
<div class="a-column a-span2 a-text-left a-span-last">
</div>
</div>
</div>

Based on everything I read on SO, the XPath above should work. What is causing this exception?

Thanks

Update: Here are a couple of references I relied on:

Locating child nodes of WebElements in selenium

WebElement.FindElement(By.XPath) returns element not relative to parent but to the document

How to get all descendants of an element using webdriver?

S.O.S
  • 848
  • 10
  • 30
  • 1
    The HTML sample you provided does not contain `@id='savedCartViewForm'`. But the rest of your reasoning is correct. – SiKing Feb 27 '19 at 17:19
  • @SiKing I did not include it bec this part was used to identify the original list and it works as expected (I verified it as it matches exactly the number of elements on page). I only included the part that is not working. Should I update my post? – S.O.S Feb 27 '19 at 17:22
  • @SiKing please update HTML with `savedCartViewForm` – Sers Feb 27 '19 at 17:33
  • @Sers SiKing: Updated – S.O.S Feb 27 '19 at 17:41

3 Answers3

1

I fixed the problem by updating my XPath to:

/descendant::input[@value = 'Delete']

I'm now able to identify the correct element. However, it is still unclear to me why the original XPath did not work and this one does - since according to several posts I read '//' is shorthand for descendant or self and . is added so that search begins relative to parent element. So the reason still does not make sense to me.

If someone can provide an updated answer with an explanation I will select that answer as answer to question instead of my own.

S.O.S
  • 848
  • 10
  • 30
0

Try code below with css selectors instead of xpath.

List<WebElement> rows = driver.findElements(By.cssSelector("#savedCartViewForm .a-row"));
rows.forEach(row -> {
    WebElement deleteButton = row.findElement(By.cssSelector("input[value = 'Delete']"));
    System.out.println(deleteButton.getAttribute("aria-label"));
});

With xpath:

List<WebElement> rows = driver.findElements(By.xpath("//form[@id = 'savedCartViewForm']//div[contains(@class, 'a-row')]"));
rows.forEach(row -> {
    WebElement deleteButton = row.findElement(By.xpath(".//input[@value = 'Delete']"));
    System.out.println(deleteButton.getAttribute("aria-label"));
});
Sers
  • 12,047
  • 2
  • 12
  • 31
  • Thanks. Is it possible to update this code with XPath? My program was built using XPath. Also do you mind explaining why my previous code is not working? This way I understand how to fix my XPath in the future. Thanks a lot.. – S.O.S Feb 27 '19 at 17:51
  • @S.O.S added with xpath selectors – Sers Feb 27 '19 at 17:54
0

This is one of this places where Selenium gets complicated. The Xpath functionality depends upon a couple of things.

  1. Some browsers have native Xpath support and some don't (Assume this is always subject to change).
  2. Some drivers use the native browser implementation and some don't (Assume this is always subject to change).
  3. If for whatever reason native is not supported Selenium will fall back to the Wicked Good Xpath support.

You now have potentially different functionality for different browsers and different driver binary versions. Let's assume all the native implementations are 100% spec compliant for the purposes of this answer.

If you come across a driver binary/browser version that falls back to Wicked Good Xpath it is not totally 100% spec compliant, you are probably seeing this error:

https://github.com/google/wicked-good-xpath/issues/43

Now bear in mind Selenium used a forked version of Wicked good Xpath, so it may differ a little bit more than the above. Historically // didn't mean descendant-or-self in Selenium world, it meant search the entire DOM. The current Selenium implementation of Wicked Good Xpath is available at:

https://github.com/SeleniumHQ/selenium/tree/07a18746ff756e90fd79ef253a328bd7dfa9e6dc/third_party/js/wgxpath

As you have already worked out the solution to your problem is descendant-or-self, but since the shorthand version "//" means something else in Wicked Good XPath, you were not getting the expected result.

TL;DR;

Don't use Xpath shorthand when building Xpaths for Selenium tests.

Ardesco
  • 7,281
  • 26
  • 49