How to print all the elements shown over the mobile screen in appium with java, actually i have written a code as:-
List<WebElement> orderidList=driver.findElementsByXPath("//android.widget.TextView[contains(#resource-id,'view_shipments_OrderNo_TextView')]")
for (int i = 0; i < orderidList.size(); i++) {
System.out.println(orderidList.get(i).getText());
}
But it prints name of orderids that are visible to mobile phone view. But i want distinct list of all the orderids, all orderids are visible after scrolling, i can implement the scrolling but i don't know how much i need to scroll. Please suggest!!
here is the screenshot of UI automator and i want to get list of all the orderids:-
This is expected behavior. UiAutomator can detect only the visible elements on Android device's screen. You can get the list of elements are visible. If you want to get the list of all the elements then you need to scroll and get the list, scroll and get the list and so on till the ends. There is not way to get the list of in-visible elements for Android using Appium Inspector/ UiAutomator
Like Vinod already told it will only print visible elements on the screen. So you need to make your code do the steps we would do if we were to scroll manually, scroll until you dont see any new elements. Have a look at the code below. I have used linked hashset to maintain order of elements and not capture any duplicates.
Set<String> appList = new LinkedHashSet<String>();
By by = By.xpath("//android.widget.TextView[contains(#resource-id,'view_shipments_OrderNo_TextView')]");
String currentOrder, newOrder;
do {
currentOrder = driver.findElements(by).get(0).getText();
int count = driver.findElements(by).size();
for (int i = 0; i < count; i++) {
String appName = driver.findElements(by).get(i).getText();
appList.add(appName);
}
driver.swipe(400, 400, 400, 74, 2000);
newOrder = driver.findElements(by).get(0).getText();
} while (!currentOrder.equals(newOrder));
Related
I am working on a messaging application. The GUI is written in Java Swing. When the client starts, it asks my server for the chats a specific user is involved in. The server will send these in the form of an string array eg: {CHAT_PATH,CHAT_PATH}.
Once the client receives this it feeds it to my GUI class, which is supposed to display each chat name in the list (I will filter out the rest of the path) on screen listed downward. This is where my problem lies. I start by creating a JButton list:
JButton[] chat_names = {};
and then I loop through the list of chats (chat_data) and add to my chat_names list a new JButton for each chat name. Like this:
for (int x=0; x<chat_data.length-1; x++){
chat_names[x] = new JButton(chat_data[x]);
chat_names[x].setBounds(100,100,100,100);
}
for (int x=0; x<chat_names.length; x++){
frame.add(chat_names[x]);
}
When I do this I get the following syntax error:
Exception in thread "main"
java.lang.ArrayIndexOutOfBoundsException: Index 0 out of
bounds for length 0
at gui_main.menu_screen(gui_main.java:16)
at Main.main(Main.java:89)
Does anyone know if this is fixable or another way I could display a list of buttons each with a chat_name on them.
Here you created an array of JButtons with length 0
JButton[] chat_names = {};
You can either call
chat_names = new JButton[chat_data.length];
before the for-loops or create a
List<JButton> chatNames = new ArrayList<>();
to have a variable length list of buttons
As a tip use camelCase rather than snake_case for your variables and methods, as that's the convention.
And one more thing don't manually specify the bounds of each JButton, instead use a proper Layout Manager for example GridLayout or BoxLayout may work. If you insist on using setBounds and (more than surely) null-layout you may find yourself in a problem similar to this one when trying to run it on a different computer or a different monitor.
You can also merge these 2 loops:
for (int x=0; x<chat_data.length-1; x++){
chat_names[x] = new JButton(chat_data[x]);
chat_names[x].setBounds(100,100,100,100);
}
for (int x=0; x<chat_names.length; x++){
frame.add(chat_names[x]);
}
Into one, reducing one iteration over all the chats and thus improving performance:
for (int x=0; x<chat_data.length-1; x++){
chat_names[x] = new JButton(chat_data[x]);
chat_names[x].setBounds(100,100,100,100); //Use a layout manager!
frame.add(chat_names[x]);
}
I wrote following piece of code to move a draggable object on
https://jqueryui.com/draggable/
driver.get("https://jqueryui.com/draggable/");
WebElement eleFrame=driver.findElement(By.className("demo-frame"));
driver.switchTo().frame(eleFrame);
WebElement ele=driver.findElement(By.xpath("//*[#id='draggable']"));
Actions move=new Actions(driver);
move.dragAndDropBy(ele, 180, 300).release().build().perform();
This code does not move the object.
when i tried
move.clickAndHold(ele).moveByOffset(300, 100).release().build().perform();
it is working fine.I read the documnets it is saying dragAndropBy have internally same functionality as clickAndHold and then moving by some offset.
I have tested it before for both vertical/horizontal slider and it used to work fine.
Please suggest what is the problem with dragAndDropBy code. or some other functionality is actually expected out of it.
Any help will be much appreciated.
Actually it's pretty weird that move.clickAndHold(ele).moveByOffset(300, 100).release().build().perform(); is working for you... I've tried them both and they throw the same exception:
org.openqa.selenium.UnsupportedCommandException: moveto did not match a known command
However, there are open bugs in Selelnium and in geckodriver on this issue.
BTW, the only difference between the two is that you don't have the ButtonReleaseAction in your custom action.
You can use dragAndDrop() method.
Actions action = new Actions(driver);
action.dragAndDrop(sourceElement, destinationElement).build().perform();
Refere tutorial http://www.seleniumeasy.com/selenium-tutorials/drag-and-drop-using-webdriver-action-class
No need to release() When "dragAndDropBy" is used.
Try this:
move.dragAndDropBy(ele, 180, 300).build().perform();
Multiple Controls Drag and Drop to the Same Destination.
WebElement element_1 = driver.findElement(By.xpath("//li[#data-lobid='12']")); //source element 1
WebElement element_2 = driver.findElement(By.xpath("//li[#data-lobid='21']")); //source element 2
WebElement destination = driver.findElement(By.xpath(".//*[#id='lobModalPopUp']/div")); //destination path
int[] array_source = new int[]{12,21}; // create fixed array for id number of source element 1 and 2
for(int i = 0; i<array_source.length; i++) //Passing id number of source element 1 and 2 inside the for loop.
{
WebElement all_source_element = driver.findElement(By.xpath("//li[#data-lobid='"+arraylobs[i]+"']")); // getting all source element with the help of fixed array.
Actions drag = new Actions(driver);
drag.clickAndHold(all_source_element).build().perform();
Thread.sleep(3500);
drag.clickAndHold().moveToElement(destination).release(destination).build().perform();
Thread.sleep(3500);
}
driver.get("https://jqueryui.com/draggable/");
driver.switchTo().frame(0);
WebElement dragMe = driver.findElement(By.cssSelector(".ui-draggable-handle"));
new Actions(driver).dragAndDropBy(dragMe, dragMe.getLocation().getX()+100, dragMe.getLocation().getY()+100).perform();
This is how to use the dragAndDropBy(WebElement source, int xOffset, int yOffset) method provided in Actions class to perform drag and drop operations.
WebElement source: web-element that you want to drag around.
int xOffset and int yOffset are future x-axis and y-axis coordinate positions. Basically, the code gets the current x-axis and y-axis coordinate positions and adds int number to move the draggable element.
Please make sure to set up your driver properly before using this block of code.
Let's suppose I've a list of String like this
List<String> button_names={"Button1","Button2","Button3","Button4"};
I've to insert JButtons with those texts in a JPanel so I do
for (int i=0; i<button_names.length; i++)
myJPanel.add(new JButton(button_name[i]));
My question is... If my model (in this case, my List button_names) changes for any reasons, how can I refresh my JPanel in order to show that change?
Should I do
myJPanel.removeAll()
and insert again my JButtons()? Thank you in adance
Yes removeAll and then reinserting new buttons is the easiest and generally the best way to go. Otherwise, you have to start figuring out which buttons have been removed, which have been added, and where in the list these new buttons are. Also, buttons in the list should change position I guess, so you'd have to cover that case to.
You can write a method like this that you could use in initial creation, and when you want to reload the list
void addButtonsToPanel(JPanel p) {
p.removeAll();
for (int i=0; i<button_names.length; i++)
myJPanel.add(new JButton(button_name[i]));
validate();
repaint();
}
I'm looking for a way to populate a gridview from the bottom left going across and up rather than the top left going across and down, but also still be able to use pointToPosition(x, y) to get the correct element in the array (so bottom left would be 0).
I'm not entirely sure if this is possible or not but I guess it must be, however I can't think of any way to do it without messing up the ability to find the array indices properly. Any help would be appreciated.
here is the code to get the string array used to fill the grid:
int num = 0;
//populates a standard array from the grid in the JSONObject
for (int vertical = 0; vertical < puzzleArray.size(); vertical++) //rows
{
for (int horizontal = 0; horizontal < puzzleArray.get(0).length(); horizontal++) //columns
{
//adds each letter of each row stored in puzzleArray to puzzleInputArray
puzzleInputArray[num] = puzzleArray.get(vertical).charAt(horizontal) + "";
num++;
}
}
The puzzleArray comes in as 9 strings of 9 letters which are then separated into a seperate array with the code above.
I fill the GridView with a standard ArrayAdapter:
//fill GridView with the puzzle input array from the puzzle class
ArrayAdapter<String> gridAdapter = new ArrayAdapter<String>(c, R.layout.cell_layout, todaysPuzzle.puzzleInputArray);
wordsearchGrid.setAdapter(gridAdapter);
And I need to be able to call the equivalent of this on the grid:
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
startPosition = wordsearchGrid.pointToPosition((int)downX, (int)downY);
letterDown = (String) wordsearchGrid.getItemAtPosition(startPosition);
Thanks.
to solve your problem, you simply have to use more advances techniques to create your adapter.
Writing an adapter in one line of code is great, but to get a more customized experience of adapting your array to a gridView, you will have to write a BaseAdapter yourself.
From there, it will be quite simple, you can for example have two arrays as its member variables, one to store the "real" indexes, and one to the "displaying" indexes.
Hope I helped you :) !
When I use the method WebElement#findElement(By) with By.cssSelector, it searches for the element through the whole page. But I want to restrict the selection by current-view-only. I don't want to allow Selenium to "use scrollbar". How can I achieve this?
The way to go for this could be in the way of getting all the elements on the page and then filtering out those out of viewport.
WebElement.getLocation() is a ground tool for this.
If you're in the left-top corner of the page (default after the load), you can use window.innerHeight and window.innerWidth (most browsers, but IE9+).
// assuming JS is enabled for this instance of driver
JavascriptExecutor js = (JavascriptExecutor)driver;
int viewportWidth = (Integer)js.executeScript("return window.innerWidth;");
int viewportHeight = (Integer)js.executeScript("return window.innerHeight;");
List<WebElement> list = driver.findElements(By.cssSelector("whatever"));
for (Iterator<WebElement> iter = list.iterator(); iter.hasNext(); ) {
WebElement elem = iter.next();
Point p = elem.getLocation();
if ((p.getX() > viewportWidth) || (p.getY() > viewportHeight)) {
iter.remove();
}
}
If you cannot say for sure that the viewport will be in its default position (at coordinates [0, 0]), you can add window.mozInnerScreenX and window.mozInnerScreenY (Firefox 3.6+ required) to the condition. Or, possibly better, window.scrollX and window.scrollY.
You also have to define whether to include partially shown elements or not and adjust the algorithm accordingly (WebElement.getSize() to the rescue!).
If you'll have trouble that after the search, the viewport changed, try to scrool back to the original position via window.scroll().