how to locate dynamic element using xpath(ends-with function not working) - selenium

I have used ends-with function as
(By.xpath("//input[ends-with(#id,'_PHONE$']"));
But it didnot work

The ends-with function is part of XPath 2.0 but browsers generally only support 1.0.
So, if you strictly want to fetch all elements that ends with a specific pattern, you can either fetch all elements that contain that pattern (using the contains() function) and then strictly check the suffix of the id (fetch the attribute value by .getAttribute("id")) using Java's .endsWith() method.
Or
You can use string-length function, substring function and equals to get this XPath:
"//input[substring(#id, string-length(#id) - string-length('_PHONE$1') +1) = '_PHONE$1']"

driver.findElement(By.xpath("//id[contains(text(),'PHONE$')]"));

You can use below XPath as well:-
//input[contains(#id,'PHONE$1')]
Hope it will help you :)

Your id is ending with _PHONE$1 and not _PHONE$. Notice that there is a 1 at the end.
(By.xpath("//input[ends-with(#id,'_PHONE$1']"));
If you still don't want to match that 1 use contains.
By.xpath("//input[contains(#id,'_PHONE$1']"));

Use contains Method
By.xpath("//input[contains(text(), '_PHONE$']");
Or use wait explicit method

Related

How can I find element by non-unique resousre-id?

I test an application which use non-unique resourse-id for elements.
Is there any way to find such elements by xpath like
//*[#resourse-id='non-unique-id'][2]
I mean the second element with same resourse-id.
I'd recommend avoiding xpath in mobile automation since this is the most time-consuming strategy to find elements.
If you don't have any other anchors for your elements but you confident in its order, you can stick to the following approach: Appium driver can return a list of elements with the same locator, in case of Page Object model you can either do this way:
#AndroidFindBy(uiAutomator = "resourceIdMatches(\".*whatever\")")
private List<MobileElement> elements;
so, once your page is initialized, you can access an element by index:
elements.get(1).click();
or, in case of manual managenemt, you can do this way:
List<MobileElement> elements = driver.findElements(MobileBy.AndroidUIAutomator("resoureceIdMatches(\".*whatever\")"));
elements.get(3).click();
Hope this helps.
As far as my understanding goes, you need to select the second element with the path as mentioned: //*[#resourse-id='non-unique-id']
To do that, you need to first grab all the elements with the same non-unique resource ID and then get() them. So, your code should be:
driver.findElements(By.xpath("//*[#resourse-id='non-unique-id']")).get(1).click();
The index for any list starts at 0. So, the second element can be accessed through the value of 1.
Hope this helps.
Try following approach:
(//*[#resourse-id='non-unique-id'])[2]
HTML with non-unique ids is not a valid HTML document.
So, for the sake of future testability, ask the developers to fix the ids.

Build XPath using wildcard for changing strings

I am trying to build an XPath for a property that is constantly changing. The number prefix is bound to change sometimes.
Original:
//*[#id="MainContent_DXEditor3_I"]
which I can query using
$x('//*[#id="MainContent_DXEditor3_I"]
Intended use: I would like to build the string to handle any number in the sub-string. Example: if the property changes to 'MainContent_DXEditor33_I' or 'MainContent_DXEditor8_IXYZ' - I still want to be able to find the element without having to rebuild
You can try to relax the predicate by using starts-with() :
//*[#starts-with(#id, "MainContent_DXEditor")]
You should try to identify a unique parent of the element or save xpath as a string that contains a variable.
These are the 2 possible solutions.
A general selector will return multiple elements, if you identify a unique parent then you are closer and after that you can select any first, second.. last if you have a list.

Using "not" in selenium xpath [duplicate]

I want to write something of the sort:
//a[not contains(#id, 'xx')]
(meaning all the links that there 'id' attribute doesn't contain the string 'xx')
I can't find the right syntax.
not() is a function in XPath (as opposed to an operator), so
//a[not(contains(#id, 'xx'))]
you can use not(expression) function
or
expression != true()
None of these answers worked for me for python. I solved by this
a[not(#id='XX')]
Also you can use or condition in your xpath by | operator. Such as
a[not(#id='XX')]|a[not(#class='YY')]
Sometimes we want element which has no class. So you can do like
a[not(#class)]
Use boolean function like below:
//a[(contains(#id, 'xx'))=false]

xPath last select element

Can someone help me to bring this code working? I have several select fields and I only want the last one in my variable.
variable = browser.elements_by_xpath('//div[#class="nested-field"]//select[last()]
Thanks!
This is a FAQ: The [] operator in XPath has higher precedence (priority) than the // pseudo-operator. This is why brackets must be used to change the default operator priorities. There are at least several similar questions with good explanations -- search for them and read and understand.
Instead of:
//div[#class="nested-field"]//select[last()]
Use:
(//div[#class="nested-field"]//select)[last()]
is the class attribute an exact match?
if the mark up is like this
<div class="nested-field other">
...
then you'll have to either match by the exact class or use xpath contains.

Get the last element of the list in Django

I have a model:
class List:
data = ...
previous = models.ForeignKey('List', related_name='r1')
obj = models.ForeignKey('Obj', related_name='nodes')
This is one direction list containing reference to some obj of Obj class. I can reverse relation and get some list's all elements refering to obj by:
obj.nodes
But how Can I get the very last node? Without using raw sql, genering as little SQL queries by django as can.
obj.nodes is a RelatedManager, not a list. As with any manager, you can get the last queried element by
obj.nodes.all().reverse()[0]
This makes sense anyway only if there is any default order defined on the Node's Meta class, because otherwise the semantic of 'reverse' don't make any sense. If you don't have any specified order, set it explicitly:
obj.nodes.order_by('-pk')[0]
len(obj.nodes)-1
should give you the index of the last element (counting from 0) of your list
so something like
obj.nodes[len(obj.nodes)-1]
should give the last element of the list
i'm not sure it's good for your case, just give it a try :)
I see this question is quite old, but in newer versions of Django there are first() and last() methods on querysets now.
Well, you just can use [-1] index and it will return last element from the list. Maybe this question are close to yours:
Getting the last element of a list in Python
for further reading, Django does not support negative indexing and using something like
obj.nodes.all()[-1]
will raise an error.
in newer versions of Django you can use last() function on queryset to get the last item of your list.
obj.nodes.last()
another approach is to use len() function to get the index of last item of a list
obj.nodes[len(obj.nodes)-1]