7

I have an arbitrary number of tiles that have a unique class name. One of them has a unique title so I'm trying to grab that one specifically. Once I've done that, I want a reference to child element rather deep in its structure.

Does the "tile." part of tile.findElement() do anything for me here? I want to be specifically using an xpath relative to tile.

public WebElement getArticleTileByTitle(String title){
        By xpath = By.xpath(".//div[contains(., '" + title + "') or @title='" + title +  "']");
        List<WebElement> tiles = findPresentElements(By.className("articleTile"));
        for(WebElement tile : tiles){
            if(isElementPresent(tile, xpath))
                return tile;
        }
        return null;
    }

public boolean articleTileImageIsVisible(WebElement tile){
    WebElement background = tile.findElement(By.xpath("/*[2]/*[2]/*[1]/*[3]")); //This throws NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"/*[2]/*[2]/*[1]/*[3]"}
    //figure out stuff about background
}

I know that background is of type img so I've tried

tile.findElement(By.xpath("./img/*[2]/*[2]/*[1]/*[3]"));
tile.findElement(By.xpath("./*/*[2]/*[2]/*[1]/*[3]"));
tile.findElement(By.xpath(".//*/*[2]/*[2]/*[1]/*[3]"));
tile.findElement(By.xpath("./*/*[2]/*[2]/*[1]/*[3]"));

Never the less, I keep getting variations on NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"/[2]/[2]/[1]/[3]"} and That's not a valid xpath.

This question is very similar to Selenium 2 - Can findElement(By.xpath) be scoped to a particular element? but people seem to have either misinterpreted it or my use case is different.

Glen Pierce
  • 4,401
  • 5
  • 31
  • 50
  • 1
    Do you use "tiles" for anything else or are you just using it as a stepping stone to getting the child element? The xpaths you are trying to use to get the child elements are horrendous btw. That style is guaranteed to break and be really difficult to debug. If you post an example of the html I'm sure we'll be able to come up with something better for you. – NotInventedHere Jul 18 '17 at 21:35
  • What's the URL for the site? – JeffC Jul 19 '17 at 01:52

2 Answers2

22

The API documentation for findElements() says:

When using xpath be aware that webdriver follows standard conventions: a search prefixed with "//" will search the entire document, not just the children of this current node. Use ".//" to limit your search to the children of this WebElement.

So you should be able to do something like:

WebElement foo = driver.findElement(By.xpath("//*[@title='" + title + "']"));
WebElement bar = foo.findElement(By.xpath(".//img"));

The leading dot in the second xpath makes all the difference, as it will search only for child elements of foo.

SiKing
  • 10,003
  • 10
  • 39
  • 90
2

Topic with similar question! - XPath to get all child nodes (elements, comments, and text) without parent

this part from that topic can interest you.

child::* selects all element children of the context node

child::text() selects all text node children of the context node

child::node() selects all the children of the context node, whatever their node type

We can identify the child nodes from the parent, by localizing it with the parent and then passing ( ./child::*) as a parameter to the findElements(By.xpath(""))

var childs = parent.findElements(By.xpath("./child::*"));

then in your code filter/process them...

STG
  • 93
  • 5