Unable to locate child elements using uiautomator (java) - java

#AndroidFindBy (uiAutomator = "new UiSelector().className(\"android.support.v7.widget.RecyclerView\").childSelector(new UiSelector().className(\"android.widget.RelativeLayout\"))")
public List<MobileElement> listOfElements;
System.out.print(listOfElements.size());
This returns 1.
So there is an element "android.support.v7.widget.RecyclerView" which contains 9 elements "android.widget.RelativeLayout". Those I want to get a list of, but I get only 1 element with the aforementioned locator. What am I doing wrong here?
If I add .index() at the end of locator, then it will give me an element according to specified index number, but I need a list of all child elements.
And does appium support all UiSelector commands? Because some of them do not seem to be working (like classNameMatches where you can type a regex, or fromParent, scrollable, ...)

you can use parent , child class strategy as below,
WebElement l1 = driver.findElementByClassName("android.support.v7.widget.RecyclerView\");
//All elements in big container L1
List<WebElement> l2 = l1.findElements(By.className("android.widget.RelativeLayout\));
System.out.println("size of L2= " + l2.size());
for(int i = 0 ; i<l2.size();i++){
System.out.println("\n Index is : " + i + "Content-desc is : " + l2.get(i).getAttribute("name"));
}
Modify the loop as per your needs

Related

How do I select a specific element from a set with similar XPath paths?

There are 2 drop-down lists. Each has a similar meaning, for example, "Jorge". Lists in different modules. When I need to fill in, for example, a list that is lower in the tree, then the first match is taken along the XPath path, on an undisclosed list.
Not lists, but values in drop-down lists!
There are 2 drop-down lists. Each has a similar meaning, for example, "Jorge". Lists in different modules. When I need to fill in, for example, a list that is lower in the tree, then the first match is taken along the XPath path, on an undisclosed list.
Not lists, but values in drop-down lists!
I wanted to implement it in Java this way:
Example:
if (findElement(By.xpath("(//example//example)")).isDisplayed()) {
findElement(By.xpath("(//example//example)")).click();
}
But in this case, the element is not displayed.
How to implement a search of all values similar to the XPath path in order to get the one that is displayed?
I tried to do something like this: (//example//example)1 (//example//example)[2] (//example//example)[3]
In my case, we have that 1 - the element does not exist [2] - exists, but is not displayed (isDisplayed = false) [3] - exists, is displayed (isDisplayed = true)
iterating through the values in the loop for [n] cannot be implemented, because, for example, the value 1 is not.
Described as difficult as possible :D. Excuse me.
If someone understands my nonsense, please help me. How to implement my requirement?
enter image description here
UPD:
The problem was solved (for me) by substituting the first value into the expression ()"{1}" immediately.
Now I'm interested in why I get an exception after the first iteration:
Method threw 'org.openqa.selenium.ElementNotInteractableException' exception.
Code:
int number = 1;
String option = "(//ul[contains(#style, 'display: block')]//li//span[contains(text(),'" + valueField + "') or strong[contains(text(),'" + valueField.toUpperCase() + "')]])";
findElement(By.xpath(option+"["+number+"]"));
String[] words = valueField.split(" ");
StringBuilder builder = new StringBuilder();
for (int i = 0; i < words.length; i++) {
builder.append(words[i]);
setFieldByLabel(nameModule, nameLabel, builder.toString());
fastWaitLoading();
for (int y = 0; y < 10; y++) {
if (findElement(By.xpath(option+"["+number+"]")).isDisplayed()) {
new Actions(browser.getWebDriver())
.moveToElement(findElement(option))
.click()
.build()
.perform();
break;
}
number++;
}
}
So I am trying to fully understand your question, and I don't. What I would recommend for a situation like this is, iterate through all elements by creating a list with: findElements(By.xpath ... )
This way you will get a list of webelements and you can iterate through them. Then apply a foreach, assert if element is displayed (it exists as it has been found with findElements) and you should be able to interact with it.
Yeah, everything is in a prominent place)
Missed it
new actions(browser.getWebDriver()) .moveToElement(findElement(**option**)) .click() .build() .perform(); break;
Here
new actions(browser.getWebDriver())
.moveToElement(findElement(**option + "[" + number+"]"**))
.click()
.build()
.perform();
break;

How to add a web elements to an ArrayList?

I have a method in which I am trying to add 12 web elements:
private List<WebElement> iphoneSnippetList = new ArrayList<>();
#Test
public void test(){
chromeDriver.get("https://market.yandex.ru/catalog--smartfony/54726/list?hid=91491&glfilter=7893318%3A153043&onstock=1&local-offers-first=0");
new WebDriverWait(chromeDriver, 15).until(ExpectedConditions.elementToBeClickable(By.xpath("//article[#data-autotest-id='product-snippet'][1]")));
for (int i = 0; i <= 12; i++) {
iphoneSnippetList.add((WebElement) By.xpath("//article[#data-autotest-id='product-snippet'][" + i + "]"));
}
System.out.println(iphoneSnippetList);
}
Simplified DOM elements in which I only need to get the text :
<article class="_2vCnw cia-vs cia-cs" data-autotest-id="product-snippet"</article>
<article class="_2vCnw cia-vs cia-cs" data-autotest-id="product-snippet"</article>
<article class="_2vCnw cia-vs cia-cs" data-autotest-id="product-snippet"</article>
I need to add all 12 web elements to my array and then make sure that the received elements contain the name "Iphone", but when adding elements, there is exception:
java.lang.ClassCastException: class org.openqa.selenium.By$ByXPath cannot be cast to class org.openqa.selenium.WebElement (org.openqa.selenium.By$ByXPath and org.openqa.selenium.WebElement are in unnamed module of loader 'app')
iphoneSnippetList is a List of WebElement in Java-Selenium bindings.
I am not sure why you want to add 12 web elements using the loop, instead a findElements with right xpath would have been a good choice. Anyway, there's a problem with you code related to casting.
See below, driver.findElement will return the web element, and we are storing that into a variable called Webelement e, and adding the same into iphoneSnippetList
for (int i = 0; i <= 12; i++) {
WebElement e = driver.findElement(By.xpath("//article[#data-autotest-id='product-snippet'][" + i + "]"));
iphoneSnippetList.add(e);
}
System.out.println(iphoneSnippetList);
Also, this loop will run for 13 times not 12 times. In case you want this to run for 12 times, initialize i = 1 not i = 0
I think you will have issue with xpath also, cause you are not using xpath indexing correctly.
try this instead :
for (int i = 1; i <= 12; i++) {
WebElement e = driver.findElement(By.xpath("(//article[#data-autotest-id='product-snippet'])['" +i+ "']"));
iphoneSnippetList.add(e);
}
System.out.println(iphoneSnippetList);

How to loop on the if statement if it is a WebElement?

I am trying to manipulate this blocks of codes:
List<WebElement> more = driver.findElements(By.xpath("/html/body/div[1]/div/div[3]/div/div/div[1]/div/div[2]/div[2]/div/div[4]/button"));
if(more.size()!=0){
driver.findElement(By.xpath("/html/body/div[1]/div/div[3]/div/div/div[1]/div/div[2]/div[2]/div/div[4]/button")).click();
}else {
WebElement present = driver.findElement(By.xpath("/html/body/div[1]/div/div[3]/div/div/div[1]/div/div[2]/div[2]/div/div[3]/div/table/tbody"));
List<WebElement> list = present.findElements(By.xpath("/html/body/div[1]/div/div[3]/div/div/div[1]/div/div[2]/div[2]/div/div[3]/div/table/tbody/tr"));
System.out.println("Total Number of TR: " + list.size());
}
What Im trying to do hopefully is that before I execute what is in the IF statement I want to loop that everytime it sees the element /html/body/div[1]/div/div[3]/div/div/div[1]/div/div[2]/div[2]/div/div[4]/button it will be click and if it is not available then ill execute this:
WebElement present = driver.findElement(By.xpath("/html/body/div[1]/div/div[3]/div/div/div[1]/div/div[2]/div[2]/div/div[3]/div/table/tbody"));
List<WebElement> list = present.findElements(By.xpath("/html/body/div[1]/div/div[3]/div/div/div[1]/div/div[2]/div[2]/div/div[3]/div/table/tbody/tr"));
System.out.println("Total Number of TR: " + list.size());
For further info what I am trying to do here is this.
I am on a listview for a specific module, and then at the button there is a "Click here for more records" -> its XPath is /html/body/div[1]/div/div[3]/div/div/div[1]/div/div[2]/div[2]/div/div[4]/button
I want that if i am in the listview and that button is present as mentioned above -I want to click it. And if in the listview there is no button "Click here for more records" (for example the records is composed of 5records only so there is no pagination clearly) I want to execute a blocks of code.
What I understood from your query is that you want to loop your IF condition statement multiple times until your else condition satisfies. For this, you can try following code:
(1) try{
(2) String xpathVAL="/html/body/div[1]/div/div[3]/div/div/div[1]/div/div[2]/div[2]/div/div[4]/button";
(3) int i=1;
(4) while(i!=0){
(5) if(driver.findElements(By.xpath(xpathVAL)).size() != 0)
(6) {
(7) driver.findElement(By.xpath(xpathVAL).click();
(8) Thread.sleep(2000);
(9) }
(10) else{
(11) Thread.sleep(2000);
(12) WebElement present = driver.findElement(By.xpath("/html/body/div[1]/div/div[3]/div/div/div[1]/div/div[2]/div[2]/div/div[3]/div/table/tbody"));
(13) List<WebElement> list = present.findElements(By.xpath("/html/body/div[1]/div/div[3]/div/div/div[1]/div/div[2]/div[2]/div/div[3]/div/table/tbody/tr"));
(14) LOGGER.debug("Total Number of TR: " + list.size());
(15) i=0;
(16) }
(17) }
(18) }catch(Exception e){
(19) LOGGER.debug("Exception Caught");
(20) WebElement present = driver.findElement(By.xpath("/html/body/div[1]/div/div[3]/div/div/div[1]/div/div[2]/div[2]/div/div[3]/div/table/tbody"));
List<WebElement> list = present.findElements(By.xpath("/html/body/div[1]/div/div[3]/div/div/div[1]/div/div[2]/div[2]/div/div[3]/div/table/tbody/tr"));
}
I think your requirement would be to keep click a button until some window appears and the button disappears. What I suggest for this is, apply "Thread.sleep(//some 3-4 seconds//)". However, it is poor style of coding and using forceful thread is not suggested by many standards. You can put some other implicit wait there. Also, if your element is not found after certain period of time, you can apply break condition after certain time interval, else it will go to infinite loop. If you are having trouble writing the code, let me know and I will help you in that.
EDIT
Try following points to remove element not present in cache:-
Use Explicit wait(Thread.sleep) at line 8 and line 11
Change your xpath from position based to some id/name/class type. Changing it to NAME based gets more clearer picture of the element even if its position is changed.
Again re-initialize the element if exception is caught at line 20.

Appium findElement used twice in one row not working

I am trying to find an element by its full path (wholeElement) and by first finding the higher level element and then finding the lower level element within that element (modularElement). Here is my code:
WebElement modularElement = appDriver.findElement(By.xpath("//UIATableCell[2]")).findElement(By.xpath("//UIAStaticText[4]"));
WebElement wholeElement = appDriver.findElement(By.xpath("//UIATableCell[2]/UIAStaticText[4]"));
Logger.LogMessage("modularElement attribute1: " + modularElement.getLocation(), Priority.High);
Logger.LogMessage("wholeElement attribute1: " + wholeElement.getLocation(), Priority.High);
The really strange issue I am experiencing is the two elements (modular and whole) are different elements and not the same one (shown by the different locations printed in the code above). Can anyone explain why this is the case?
Thanks.
UPDATE:
I have also tried using .// but that is providing the same issue still:
WebElement modularElement = appDriver.findElement(By.xpath("//UIATableCell[2]")).findElement(By.xpath(".//UIAStaticText[4]"));
They are not the same.
appDriver.findElement(By.xpath("//UIATableCell[2]")).findElement(By.xpath("//UIAStaticText[4]"));
Here, you are searching for //UIAStaticText[4] anywhere, at any level in the entire DOM tree:
When using xpath be aware that webdriver follows standard conventions:
a search prefixed with "//" will search the entire document, not just
the children of this current node. Use ".//" to limit your search to
the children of this WebElement.
While //UIATableCell[2]/UIAStaticText[4] would search among the direct children of //UIATableCell[2] only.
I would do it like so instead:
By locator = new ByChained(By.xpath("//UIATableCell[2]"),By.xpath(".//UIAStaticText[4]"));
WebElement modularElement = appDriver.findElement(locator);
Or perhaps this:
public WebElement getCellTextElement(int cell, String varText) {
By locator = new ByChained(By.xpath("//UIATableCell[" + cell + "]"),
By.xpath(".//UIAStaticText[contains(text(),'" + varText + "')]"));
WebElement modularElement = appDriver.findElement(locator);
return modularElement;
}

How to get only second li element using Jsoup?

I have three li elements in ul, as shown in the image http://i.imgur.com/vfZ15Gw.jpg I want to retrieve every li element separately specially the second one.
please give me suggestions
you can use
Elements e = doc.select("ul.about-stats>li");
if(e.size() > 2){
Element firstLi = e.get(0); //to get first
Element secondLi = e.get(1); //to get second
Element thirdLi = e.get(2); //to get third
}
or you can use
e.listIterator();

Categories