Such structure is given
<div class="user-number">123</div>
<div class="user-state">
<span class="u-state-icon icon icon-1"></span>
<span> User1</span>
</div>
I've tried such (incorrect) xpath for locating User1 by user-number and do not understand where is the problem..
xpath=//*[#class='user-number' and text() = '123']/following-sibling::*[contains(#class,'user-state')]/descendant::*[contains(#text,'User1')]
What is the best way to debug it?
For example, if
xpath=//*[#class='user-number' and text() = '123']/following-sibling::*[contains(#class,'user-state')]
locates some element - how to print out its text property - to check which element is actually located?
Your xpath expression is, surely, incorrect - #text should be replaced with text() (or just .):
//*[#class='user-number' and . = '123']/following-sibling::*[contains(#class,'user-state')]/descendant::*[contains(.,'User1')]
Debugging xpath expressions is usually done using the browser developer tools: in the firebug, or inside a browser console. For instance, in the google-chrome console, you can execute the following:
$x("//*[#class='user-number' and . = '123']/following-sibling::*[contains(#class,'user-state')")
And see if there is a match.
Or, you can also debug it inside your code. For example (using python), find the first div element and print out it's text:
element = driver.find_element_by_xpath("//*[#class='user-number' and . = '123']")
print(element.text)
The meta-question is, how to debug XPath expressions?
Well, for simple ones like these, it's really best to just stare at them till you see the problem. Check the spelling of names, check namespaces, check whitespace issues. At least it's easier than debugging regular expressions.
For more complex XPaths, try breaking them up. Remove a predicate and see if that makes a difference. Or work in reverse, build up the path expression by adding conditions, checking at each stage that it still finds something.
If you're really seriously into XPath, consider schema-aware processing: this will match your XPath expression against a schema to make sure it makes sense.
Consider using a visual XPath processor for debugging. There are a number around. I use the XPath processor in oXygen (though not really for debugging the XPath, more for discovering the content of the document, but those tasks often need to be done together.)
Related
I am getting below error while executing below capybara command,
The interesting thing is the same XPath is not giving any error in I am expecting that XPath to be present.
But when I am trying to perform click on that XPath, it's throwing below error.
--------------code----------------
Then(/^I click on "([^"])" on left tree child of "([^"])"$/) do |child, parent|
within(:xpath, ".//div/span[#class='folder-nav-tree-fileroom' and text()='DND-IndexTwistyExpClps']/../../../../..", wait:5) do
find(:xpath, ".//span[contains(text(), '1 IndexTwistyLevel1')]/../../../span[#class='ui-tree-toggler fa fa-fw fa-caret-right']", wait:5).click
end
end
Error : Capybara::ElementNotFound: Unable to find visible xpath "//div[.//span[contains(text(), '1 IndexTwistyLevel1')]]/span[#class='ui-tree-toggler fa fa-fw fa-caret-right']"
Your code has a number of issues, which indicate it can't actually be working like you claim. If you fix the code and provide the HTML fragment it should be matching against we can narrow done to the issue, but for now the errors are:
Firstly, you have mismatched/non-escaped
's and )s in your XPath expressions (can't have inside a string surrounded bys so it's obvious you haven't copy/pasted your actual code)
Secondly, ::after is not valid XPath - ::after pseudo elements are purely CSS and can't be accessed from XPath, so including that in your selector isn't going to give the expected results. This should result in an invalid selector error being raised by Chrome.
Thirdly, by not starting your selectors with . you're completely defeating the within scoping block - see https://github.com/teamcapybara/capybara#beware-the-xpath--trap
Finally, using visible: false on an element you want to click makes no sense, since you can't click on an element that isn't displayed on the page.
Unfortunately its tough to tell which of these may be causing your actual issue (if any) since the code you have provided isn't valid.
within(:xpath, config['documents_obj']['FRChildTreeXpath'].sub('TEXT', parent), wait:5) do
elem = find(:xpath, config['documents_obj']['childTwistyXpath'].sub('TEXT', child), visible:false, wait:5).native
page.driver.browser.action.click(elem).perform
To avoid the error which iwas gettign what i simply did, is I used capybara action builder,
Take the native element then perform the action.
It worked perfectly in my case.
Reference : https://seleniumhq.github.io/selenium/docs/api/rb/Selenium/WebDriver/ActionBuilder.html
If you're visually looking at a webpage and there is something clickable and unique on the page, you'll just click it. Without thinking about the page structure.
I'm interested to see what the most concise xpath is that could be constructed to simulate this in a versatile manner.
For example, target the "I'm feeling Lucky" button on the Google homepage:
//*[contains(#*, 'Lucky')]
The above works. But would fail in the element contained Lucky as inner text, or if the wrong case was specified. As such, our xpath needs to cater for any sensitivity and also look for the given string matching inner-text as well.
How could the above xpath be expressed in the most concise yet encompassing structure?
There is nothing thats very generic and executing such xpaths could be costly also at times.
"//*[contains(#*, 'Lucky')] | //*[contains(text(), 'Lucky')]"
Above is one xpath you can combine to get some results. You start specifying which nodes you don't to examine or ones which you want to examine
"//*[contains(#*, 'Lucky')] | //*[contains(text(), 'Lucky')][not(self::script|self::td)]"
And you can keep improving it
It's not possible to create a versatile XPath to accurately/reliability locate an element by text.
Why?
Because the text evaluated by an XPath is not necessary rendered in the page.
Because there's a hight chance to end-up with multiple matches since each ancestor also contains the expected text.
But mainly because there's too many rules/specific cases to consider.
But if I had to create one, then I'd start with this one:
"(html/body//*[not(self::script or self::style)][contains(concat(#value, normalize-space()), 'MyText')])[last()]"
Get all the descendants of the <body>
html/body//*
except <script> and <style>
[not(self::script or self::style)]
where the value attribute or normalize html contains 'MyText'
[contains(concat(#value, normalize-space()), 'MyText')]
then returns the last and deepest match
[last()]
I have recently started with Selenium, and I've decided to use only Selenium 2 / WebDriver.
In my test code, I often arrive at a WebElement without knowing where it is in the page.
I'd like to have code that, given an WebElement, constructs an XPath expression to uniquely select it.
FireFox recorder plugins for Selenium do this; what I want is code to do it in Selenium 2.
I can write such code myself by using WebElement's findElement to walk up the tree and findElements to find the child we came from, but it's nontrivial to come up with something fast (repeatedly calling By.xpath seems bad) and complete (e.g. due to namespaces).
(A related question suggests using CSS selectors instead - that's fine with me.)
Has anyone done this for me? What is the best approach?
Maybe this will help: I am testing a website where the id's are dynamically generated, so they change all the time. In order to get their xpath and work with it I use this function:
/**
* Gets the absolute xPath for elements with dynamic ids.
*
* #param driver - the current WebDriver instance
* #param element - the element for which the xPath will be found
* #return the absolute xPath for this element
*/
public static String getElementXPath(WebDriver driver, WebElement element) {
return (String)((JavascriptExecutor)driver).executeScript(
"gPt=function(c)" +
"{" +
"if(c.id!=='')" +
"{return c.tagName + '[#id=\"'+c.id+'\"]'}" +
"if(c===document.body)" +
"{return c.tagName}" +
"var a=0;" +
"var e=c.parentNode.childNodes;" +
"for(var b=0;b<e.length;b++)" +
"{var d=e[b];" +
"if(d===c)" +
"{return gPt(c.parentNode)+'/'+c.tagName+'['+(a+1)+']'}" +
"if(d.nodeType===1&&d.tagName===c.tagName)" +
"{a++}" +
"}" +
"};" +
"return gPt(arguments[0]);", element);
}
It's pretty straight forward: and btw yes css is the way to go; xpath should be only used as a measure of last resort. http://sauceio.com/index.php/2010/01/selenium-totw-css-selectors-in-selenium-demystified/ explains css locators in much more depth than I can in the space provided here.
Best approach: If you're using firefox download firebug, that will let you look at your html. Pres cmd+Shift+c and it'll open for you with an element highlighter. Find your html element, maybe it'll look something like this
<input type="submit" tabindex="110" value="Post Your Answer" id="submit-button">
Then you can find your element pretty simply
WebElement element = driver.findElement(By.cssSelector("input[id='submit-button']"))
Notice that we put the tagname first "input" followed by some kind of unique identifier in the brackets "input[id='submit-button']." For the most part this will cover 75% of all css locators you use. The other 25% require a little bit more tricky stuff covered in the link I placed at the top of the page.
You may ask "What kind of unique identifiers can I use besides id" well that is covered here: http://release.seleniumhq.org/selenium-remote-control/0.9.2/doc/dotnet/Selenium.html
Good luck starting out
EDIT
Well good luck finding your elements in the first place...If you need you can search elements by partial locator text like input[id*='submit']. Using that is helpful for dynamically generated elements, when you use the partial text as the part of the locator that doesn't vary from element to element.
You mentioned walking up the html tree perhaps I didn't see that when I first read the question. I think you hit the on issue at hand. Walking up the html tree isn't suggested as it makes your tests more fragile to html changes. It will also make your code unreadable in the long run as well. In general if your id's are missing or unpredictable I would suggest talking to proj. management about getting the developers to make code that can actually be automated (eg: getting identifiers implemented on critical elements). This will actually save both you and the developers alot of effort in the long run, and it will also increase the speed and reliability of your tests.
We can find the Submit Button using ID:
1.driver.findElement(By.id("submit-button"))
ID > NAME > CSS > XPATH
How can I check whether a given text string is present on the current page using Selenium?
The code is this:
def elem = driver.findElement(By.xpath("//*[contains(.,'search_text')]"));
if (elem == null) println("The text is not found on the page!");
If your searching the whole page for some text , then providing an xpath or selector to find an element is not necessary. The following code might help..
Assert.assertEquals(driver.getPageSource().contains("text_to_search"), true);
For some reason, certain elements don't seem to respond to the "generic" search listed in the other answer. At least not in Selenium2library under Robot Framework which is where I needed this incantation to find the particular element:
xpath=//script[contains(#src, 'super-sekret-url.example.com')]
A simpler (but probably less efficient) alternative to XPaths is to just get all the visible text in the page body like so:
def pageText = browser.findElement(By.tagName("body")).getText();
Then if you're using JUnit or something, you can use an assertion to check that the string you are searching for is contained in it.
assertThat("Text not found on page", pageText, containsString(searchText));
Using an XPath is perhaps more efficient, but this way is simpler to understand for those unfamiliar with it. Also, an AssertionError generated by assertThat will include the text that does exist on the page, which may be desirable for debugging as anybody looking at the logs can clearly see what text is on the page if what we are looking for isn't.
HI there
selenium.getXpathCount does not find element, any one hoas any idea ? Here is my code:
if (existArtist){
int result = selenium.getXpathCount("//*[#id='chugger-results']/div[1]/ul/li").intValue();
if (result>0){
//DO THIS
Either you have a broken DOM (Do a W3C Validation and see if you have any unclosed tags) or your XPath is looking for an element that doesn't exist.
We would need to see the entire HTML of the page to be able to answer your question (more visibility of your test code would be useful too)