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.
Related
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.
I would want to select the first instance of an element in a page where many number of such elements are present with 'ID' which will not be same always.
for example, visit, http://www.sbobet.com/euro which lists lot of sports and odds, where I want to click on the first odds.
and the html structure would be like this,
I want to click on this first span value and proceed with some test case.
Any help on how to achieve this ?
There could be two approaches two the problem:
1. If you are sure you will always need only the first instance:
driver.FindElementsByClassName("OddsR")[0];
If not, then you have collection of elemets and you can access an of those
2. Also, you can first identify any closest enclosing div and then you can use the same snippet as above:
driver.FindElementsByClassName("OddsR")[0];
This one is a better approach if page is a bit dynamic in nature
Use #class attribute. If OddsR class you are intrested in is the 1st one on the page then just use Driver.FindElement(By.ClassName("OddsR")). Webdriver will pick the 1st occurence (no matter if there are more)
Have checked your link and I agree with alecxe, you should probably start with div. But i would suggest a simpler selector :
css = "div.MarketBd span.OddsR"
The above selector will always point to the first span of "OddsR" class within div of "MarketBd" class.
Thanks for the response.
I am finally able to click on the element, by this XPATH,
"//span[#class='OddsR']"
This clicks on the first occurrence of 'OddsR' values, without giving any index.
How to count the number of elements are matching with for the given xpath expression
xpath: driver.findElement(By.xpath("//div[contains(#id,'richedittext_instance')]"))
all i need is the count.
Try this code:
//Assume driver is intialized properly.
int iCount = 0;
iCount = driver.findElements(By.xpath("Xpath Value")).size());
The iCount has the number of elements having the same xpath value.
Another option
If you are basing your requirements strictly on the need to use Selenium, you might be able to do something like this using WebElements and getting the size of the returned list:
List<WebElement> myListToCheck=currentDriver.findElements(By.xpath("somePath"));
if(myListToCheck.size()>0){
//do this
}else{
//do something else
}
Or just simply returning the size of the returned list; if that's all you really want to get from it...
int mySize=myListToCheck.size()
I believe once you have an established WebElements list, you can also use iterators to go over that list.
Helpful, I dunno... just providing another way to get to the same end-game.
Not working in Selenium, which only allows to return nodes from XPath, not primitives like the number returned by count(...). Kept for reference and is valid for most other tools offering a more complete XPath API.
You should only return least possible amount of data from the query. count(//div[contains(#id,'richedittext_instance')]) counts the number of results within XPath and thus is faster as all the elements do not have to be passed from the XPath engine to Selenium.
I can't help you with how to fetch this as n int out of selenium, but this should be easy stuff.
Do the following:
from selenium.webdriver.common.by import By
elements = driver.find_elements(By.XPATH, "Your_XPath")
This outputs a list of selenium.webdriver.firefox.webelement.FirefoxWebElements (in my Firefox browser).
Finally, find out the length of the list:
len(elements)
NB.: Please note that I have written find_elements() (plural) and NOT find_element(). Both of them are different. find_element() only returns the first matched web element, but to find the list of all the matched web elements, we have to use find_elements().
In String Template one can easily get an element of a Java Map within the template.
Is it possible to get the n-th element of an array in a similar way?
According to the String Template Cheat Sheet you can easily get the first or second element:
You can combine operations to say things like first(rest(names)) to get second element.
but it doesn't seem possible to get the n-th element easily. I usually transform my list into a map with list indexes as keys and do something like
map.("25")
Is there some easier/more straightforward way?
Sorry, there is no mechanism to get a[i].
There is no easy way getting n-th element of the list.
In my opinion this indicates that your view and business logic are not separated enough: knowledge of what magic number 25 means is spread in both tiers.
One possible solution might be converting list of values to object which provides meaning to the elements. For example, lets say list of String represents address lines, in which case instead of map.("3") you would write address.street.
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]