OS: Windows 7
Selenium Version: 3.0.1.0
Browser: Chrome
When calling WebElement.FindElement(By.XPath('//element') getting wrong results.
the result is same as Driver.FindElement(By.XPath('//element') - instead of the element inside that parent.
I have a workaround:
WebElement.FindElement(By.XPath('.//element') (add '.')
But I think this is unnecessary because I try to find element inside its parent
Page for example:
<html>
<body>
<div id="first">
<button onclick="alert('first Btn clicked');">firstBtn</button>
</div>
<div id="second">
<button onclick="alert('second Btn clicked');">secondBtn</button>
</div>
</body>
</html>
Code:
C#
// wrongly clicks first button
Driver.FindElement(By.Id("second")).FindElement(By.XPath("//button")).Click();
// works correct
Driver.FindElement(By.Id("second")).FindElement(By.XPath(".//button")).Click();
I believe this is working as expected.
In your first example, you are saying "//button". You are telling it to start at the root (html node) and find the first button it finds, which is firstBtn. The second example states to search for the first button it finds from the current location by using the (.). This is the appropriate usage.
This is how xpath works and not a Selenium thing to fix if it were an issue.
This is working as expected. If you specify a selector that is relative to the document root, it will search from the document root. You should consider using CSS, where the search context _will_ be context element.
the '//' not always meant to say relative to document root / anywhere in the document
as the selector './/button' means any descendant of current element.
I'm writing locators for 3 years and never imagine that when I search for an element in context of another element than the search will be from the root. just because I had a bug in my test result then after debugging it I realize this. I'm sure that most of the people do not know about this behavior.
I still think that like in any language when you query XML with XPath, and you search for nodes inside other nodes the result will be relative to node not the document
the '/' in the beginning always means the document root. Read the XPath specification:
https://www.w3.org/TR/xpath/#location-paths
start from the sentence
"There are two kinds of location path: relative location paths and absolute location paths."
@barancev
I'm sorry but I think that you didn't understand the issue.
You said that '/' means document root
I opened this issue about '//' in the beginning
'//' can be anywhere in the doc
but also can be any descendant (not only direct child)
See in the same link that you gave:
"chapter//para
selects the para element descendants of the chapter element children of the context node"
Please read again
@LirazShay Maybe this can help you: http://stackoverflow.com/questions/35606708/what-is-the-difference-between-and-in-xpath
@LingSpb
In the link you share:
descendant-or-self axis (//*)
//ename selects all ename elements in a document.
.//ename selects all ename elements at or beneath the context node.
I still think that when searching WebWlement.findElement(by.XPath) your context is the web element NOT the document, so the '.' in the beginning had to be implemented under the hood.
I'm sure that most of the users are not aware of this behavior
Selenium doesn't invent xpath, so if anyone wants to use by.XPath, they need to learn how xpath works first.
Getting element outside of the current context can be seen when you use functions, for example:
void deleteItem(WebElement element){
// click on the delete button
element.FindElement(By.XPath(".//button")).Click();
// click on the confirmation dialog
element.FindElement(By.XPath("//dialog")).Click();
}
Note: the dialog is not beneath the given element
If it would help more easily identify that you are searching by direct parent context like in your example, using ( ./ ) is also valid instead of ( .// ).
// is short for /descendant-or-self::node()/
so having // in the beginning implies having / in the beginning
we follow xpath specification, and we're not going to break it, despite it might seem illogical
please send bug reports to the xpath specifiation :)
Thanks for sharing the answer (".//"), this "bug" was killing me :)
Thank you so much!!! I have had a trouble with it. You very helped me.
same here, i missunterstand that for xpath the webelement is not the root ...
i think the call driver.findelement is search on root and webelement.findelement is search in the dom of this element (for xpath the root).
this was wrong :D
Please make this expected behavior more clear in the docs.
This issue saved my day! I would even suggest to output a warning that a absolute selector is used in a relative findElement Function of a SearchContext, what makes no sense and will always confuse all code readers.
Most helpful comment
the '//' not always meant to say relative to document root / anywhere in the document
as the selector './/button' means any descendant of current element.
I'm writing locators for 3 years and never imagine that when I search for an element in context of another element than the search will be from the root. just because I had a bug in my test result then after debugging it I realize this. I'm sure that most of the people do not know about this behavior.
I still think that like in any language when you query XML with XPath, and you search for nodes inside other nodes the result will be relative to node not the document