How to write valid XPath expression using AND condition - selenium

On multiple environments of the app which we are testing, the ID of one element is different. I have this div ID
CoredataForm:sec2_natural:grid1:left_section_natural:profession:selectProfession_auto_complete_force:ajax
Bold marked parts of the id, is the part which is same for all the environments.
How should I write xpath expression which would fit to all of them?
I used this
xpath="//div[starts-with(#id,'CoredataForm:sec2_natural:grid1:left_section_natural:profession:selectProfession') and ends-with(#id,'ajax')]"
but it doesn't work. Maybe another question: how can I use contains() function with multiple wildcards?

Your XPath might not work if your tool supports XPath1.0 only cause fn:ends-with is not available in XPath1.0
You can try to replace ends-with with contains in your XPath as
"//div[starts-with(#id,'CoredataForm:sec2_natural:grid1:left_section_natural:profession:selectProfession') and contains(#id,'ajax')]"

Selenium supports only XPath 1, but as JaSON says, ends-with is only available in XPath 2 and later versions.
However, it's possible to check that a string ends with another string using just the XPath 1 functions substring and string-length. The substring function returns a substring starting at a particular character location. The first character in the string has position 0, so substring('abc', 1)='bc'
If a string $s1 ends with another string$s2, then the following is true:
substring($s1, string-length($s1) - string-length($s2)) = $s2
So this expression should work for you (broken into multiple lines, for readability):
//div[
starts-with(
#id,
'CoredataForm:sec2_natural:grid1:left_section_natural:profession:selectProfession'
)
and
substring(
#id,
string-length(#id) - string-length('ajax')
) = 'ajax'
]

Related

Regex in Selenium Xpath Not Working //*[contains(#content-desc,"Resend in .*?[0-9a-zA-Z]*[0-9][0-9a-zA-Z].* sec")]

My Text in UI is "Resend in 48 sec" in which "48" is a timer which is dynamic so I want to crate an Xpath using the contains and Inside Contains I am using Regex but still unable to find the Element
//*[contains(#content-desc,"Resend in .*?[0-9a-zA-Z]*[0-9][0-9a-zA-Z].* sec")]
Selenium is still using XPath 1.0, which was defined over 20 years ago and has no support for regular expressions.
You can use this XPath instead:
//*[contains(#content-desc,"Resend in") and(contains(#content-desc,"sec"))]
Now you can get this element, get it's content-desc attribute value and then validate the content of that attribute
You may wanna do this instead :
String regEx = ".*?[0-9a-zA-Z]*[0-9][0-9a-zA-Z].*";
driver.findElement(By.xpath("//*[contains(#content-desc,'Resend in') + '"+regEx+"' + and(contains(#content-desc, 'sec')) ]"));

extracting part of success text using selenium webdriver

I have the following text appearing on the success page of my application.
This is to confirm that your application has been received. Your Order Number is “#00007942”. If further instructions or any clarification is needed regarding your application, a representative will contact you.
Complete text having same property.
Please help me in extracting the value 00007942 and store it in variable.
First, get your text in your way.
String successMessage = driver.findElement(By.cssSelector("your selector")).getText(); // use locator of your wish
Now, use replace all non-digit from your string as follows-
String orderNumber = successMessage.replaceAll("\\D+", ""); // this replaces all non-digits from your previous string
there is no way to retrieve partial text in selenium webdriver.
Instead, you access the complete text of an Web Element using element.getText() in Java or element.text in python and store it as a String variable.
Then you process the string to retrieve the substring you want.
In all programming languages, there are many ways to achieve it. some of them are substring method, regular expression.

WebDriver not identifying WebElement

I using xpath="//div[#class='localityKewordDropDown']/descendant::div[#class='over']/span[text()='Dwarka, New']
but the element is not getting recognized. NosuchElementException is getting encountered.
Could anyone help me out here.I want to click the drop down value highlighted in the image.
It's failing beacuse there is a space after the word 'New'. The following should work.
//div[#class='localityKewordDropDown']/div/div[text()='Dwarka, New ']
Or consider serarching for the element containing the text rather than matching the entire text.
//div[#class='localityKewordDropDown']/div/div[contains(.,'Dwarka, New')]
And as cathal mentioned, you are searching for a div and not a span.
EDIT:As you request (although I don't believe there is a difference between "descendent" and "//".
//div[#class='localityKewordDropDown']/descendant::div[text()='Dwarka, New ']
//div[#class='localityKewordDropDown']/descendant::div[contains(text(),'Dwarka, New')]
Contains is an xpath function that allows you to query on something containing a value. It can be used with attributes, nodes but it's generally most useful for finding elements containg text. The reason this is working where as your query for the exact string fails is because the element you seek is padded with a trailing space. The contains query will find the element you are seeking as it's ignoring this trailing space.
i dont see anyw spans around your element, try the following:
WebElement name = driver.findElement(By.xpath("//div[#id='keyword_suggest']//div[text()='Dwarka, New']"));
Try this:
WebElement name = driver.findElement(By.xpath("//*[contains(text()='Dwarka, New')]"));

How do I select an empty element in XPath?

We select elements with Django 1.4 tests and Selenium like this:
self.assertEqual(1, len(self.selenium.find_elements_by_xpath("//a[#href='#'][#class='button save-as'][#title='Save As...'][text()='Save As']")))
(The class inherits from LiveServerTestCase).
The problem is that sometimes there are elements without text, and if we select with [text()=''] it fails (the len is 0). How can I select elements without text?
Update: Because [text()=''] didn't work, I had to assert two lines to assert no text:
self.assertEqual(1, len(self.selenium.find_elements_by_xpath("//a[#href='#'][#class='button properties'][#title='Properties']")))
self.assertEqual("", self.selenium.find_element_by_xpath("//a[#href='#'][#class='button properties'][#title='Properties']").text)
Now I can assert the same with one line:
self.assertEqual(1, len(self.selenium.find_elements_by_xpath("//a[#href='#'][#class='button properties'][#title='Properties'][not(text())]")))
You could use XPath's not() function.
//a[#href='#'][#class='button save-as'][#title='Save As...'][not(text())]

Selenium target has random numbers

I've been trying to test a web application that generates html id's with a random value in the middle. For instance: attribute_new_12493044135_name
The attribute defines the class of object that I want to find and the "name" is the unique part of this string. The problem is that I don't have Xpath 2.0 and thus can't use ends-with on the script.
Can anyone help? I've tried to use Selenium Webdriver and IDE, and couldn't find an answer.
You are indeed correct you can not use the ends-with function if you do not have access to the Xpath 2.0 library. But you do have access to all the Xpath 1.0 functions. http://www.edankert.com/xpathfunctions.html
You have two functions you can use to xpath to your element.
contains(): //*[contains(#id, 'name')]
substring(): //*[substring(#id, string-length(#id)-3)="name"]
The 3 in string-length is the number of characters of your locator minus 1. ie 'name' has 4 characters so 4 - 1 = 3
Good Luck!
Also using a combination of css locators instead of the XPath will work:
[id*=attribute_new_][id*=_name]
OR:
[id^=attribute_new_][id$=_name]
Here's what the signs mean:
"^" - prefixes / starts with
"$" - suffixes / ends with
"*" - substrings / contains