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().
Related
I'm Trying to capture the Co-ordinates of Maps to do some action on Maps.
wait = new WebDriverWait(driver, 15);
wait.until(ExpectedConditions.elementToBeClickable(By.`path`("//button[contains(text(),'Add Tract')]"))).click();
Utils.scrollUp();
Thread.sleep(10000);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("TimeZoneId")));
//Timezone is the area which I'm trying to capture the Co-Ordinates
Point point1 = timezone.getLocation();
SOP("Element's Position from left side is: "+point1.getX()+" pixels.");
SOP("Element's Position from top is: "+point1.getY()+" pixels.");
}
if your map has <canvas> tag, then try
To perform using Actions chains, below is an example C# code similar to Java
IWebElement canvas = driver.FindElement(By.Id("TimeZoneId"));
int xCo = canvas.Location.X;
int yCo = canvas.Location.Y;Actions action = new Actions(driver);
action.MoveToElement(canvas, 1 + xCo, 2 + yCo).Click().Build().Perform();
Try OpenCV
If you are testing overlays on map. use JavaScriptExecutor and by adding hooks to your code in order to perform actions in your Map.
Try with Sikuli (personally, I have not used this. Needs some research)
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));
below mentioned is my code, which is not sending the keys to the textbox, however it finds the correct element as the cursor keeps blinking in the textbox.
public class cl01 {
public static void main(String[] args) {
System.setProperty("webdriver.gecko.driver","C:\\Program Files\\Java\\geckodriver-v0.14.0-win32\\geckodriver.exe");
WebDriver driver = new FirefoxDriver();
driver.get("http://www.rediff.com/");
String P1 = driver.getWindowHandle();
System.out.println(P1);
Set<String> windows = driver.getWindowHandles();
Iterator<String> W = windows.iterator();
while(W.hasNext())
{
String C1 = W.next();
System.out.println(C1);
if(!P1.equalsIgnoreCase(C1))
{
driver.switchTo().window(C1).close();
}
}
driver.switchTo().window(P1);
System.out.println("web page opened");
//Browser's position is set
driver.manage().window().setPosition(new Point(30, 40));
int height = driver.manage().window().getSize().getHeight();
System.out.println( "height of the browser is " +height);
int width = driver.manage().window().getSize().getWidth();
System.out.println("width of the browser is " +width);
driver.manage().window().maximize();
driver.findElement(By.linkText("Create a Rediffmail account")).click();
System.out.println("sign up link opened");
driver.findElement(By.xpath(".//*[#id='wrapper']/table[2]/tbody/tr[3]/td[3]/input")).sendKeys("ABC");
The code looks fine to me. Maybe it's slow to load and you need to add a wait for the first element.
I would avoid using XPath in cases like this, especially when the nested layers are so deep and you are relying on indexes. It makes for a very brittle locator. I would use a CSS selector like the below.
By.cssSelector("input[name^='name']")
I tested this and it worked for me. It's basically looking for an INPUT tag that has a name that starts with "name". The name ends with what looks like an automatically generated string but this part is unique on the page.
Here are some references to learn CSS selectors. CSS selectors are really powerful and it's time well spent to learn them.
CSS Selectors Reference
CSS Selectors Tips
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.
I can switch between two tabs/windows but my requirement is to know or get active window between them.
In my project, on a click of a webElement of a page a random pop(tab/window) gets opened and I would like to know whether that(new) window has focus or my original page.
I tried to use JNA Api to get the active window and its title but my web page is
remotely located.
Perfect solution is greatly appreciated.
Thanks
driver.getTitle() will give you the title of the page that you can use to determine which page you are on or if you are on the page where you want to be and then use the logic to switch window if required. getTitle() returns a String and you can use one of the string methods to compare the title, for example:
String title = getDriver().getTitle();
if(!title.equals("Expected Title")) {
//may be you would like to switch window here
}
String title = driver.getTitle()
This will give you the title of the page which you can refer to using Selenium to figure out which page the driver is currently on.
I wrote my own method to switch to a window if the window title is known, maybe some of this would be helpful. I used Selenide (Java) methods for this, but if you've got Vanilla WebDriver, you can achieve the same thing
/** Switches user to window of user's choice */
public static void switchToWindow(String windowTitle) {
WebDriver driver = getWebDriver();
// Get list of all open tabs - note behaviour may be different between FireFox and Chrome.
ArrayList<String> tabs = new ArrayList<>(driver.getWindowHandles());
// iterate through open tabs. If the title of the page is contained in the tab, switch to it.
for (String windowHandle : driver.getWindowHandles()) {
String title = getWebDriver().getTitle();
driver.switchTo().window(windowHandle);
if (title.equalsIgnoreCase(windowTitle)) {
break;
}
}
}
This method might not be lightening fast, but it will iterate through current open windows and check the title matches the one you've specified.
If you want to assert the title, you could use the xpath selector:
String pageTitle = driver.findElement(By.xpath("//title[text() = 'Title you looking for']"));
This is a dumb example with you can surround with try/catch, implement assertions or other technique to have the result you need.
In JavaScript, for me this worked. After clicking on the first link of bing search results in edge, my link opened in a new tab. I explicitly mentioned to stay in the same tab.
async function switchTab() {
await driver.getAllWindowHandles().then(async function (handles) {
await driver.switchTo().window(handles[1]);
});
}
//get initial window handles
Set<String> prevWindowHandles = driver.getWindowHandles();
while(true){
//get current window handles
Set<String> currWindowHandles = driver.getWindowHandles();
//if one of the current window handles not equals to
//any of the previous window handles,switch to this window
//and prevWindowHandles = currWindowHandles
for(String prevHandle : prevWindowHandles){
int noEqualNum = 0;
for(String currHandle : currWindowHandles){
if(!currHandle.equals(prevHandle))
noEqualNum++
}
if(noEqualNum == currWindowHandles.size()){
driver.switchTo().window(currWindow);
prevWindowHandles = currWindowHandles;
break;
}
}
}