Visibility of element- selenium webdriver - selenium

My script creates a new article: fills few fields and click "Submit button" at end of page.
I have written Click() function in util class like :
public void click(String xpathKey)
{
WebElement myDynamicElement = (new WebDriverWait(driver, 60))
.until(ExpectedConditions.visibilityOfElementLocated(
By.cssSelector(prop.getProperty(xpathKey))));
try
{
myDynamicElement.click();
}
catch (Exception e)
{
e.printStackTrace();
throw e;
}
}
Waiting for visibility of element means it will wait until element will be visible on the page or on screen? My script clicks on submit button while it's not exactly visible on the page.
I am running this script since months and it's running perfectly fine. Suddenly it started giving error element is not clickable at point(213, 415). It never appeared before. Anyone has an idea, why it could have happened?
I have done many cases, where the element is not exactly visible, generally button at end of page. selenium does not scroll itself, it finds the element and performs operation.

Try this.
public void click(String xpathKey)
{
WebElement myDynamicElement = (new WebDriverWait(driver, 60))
.until(ExpectedConditions.visibilityOfElementLocated(
By.cssSelector(prop.getProperty(xpathKey))));
try
{
Actions act = new Actions(driver);
act.moveToElement(myDynamicElement);
act.click();
act.build().perform();
}
catch (Exception e)
{
e.printStackTrace();
throw e;
}
}

The error message you are getting indicates that there is an element covering the element you are trying to click. If you read the error message carefully, it will tell you the HTML of the blocking element and that will help you find it on the page. Without more info, it's hard to tell exactly what the situation is but there are a few common causes.
You may have just closed a dialog/popup and it's not quite completely gone before you try to click. In this case, wait for some element that's part of the dialog to be invisible generally solves this problem.
There may be some wait/loading/spinner control that appears and disappears but you are clicking before it's completely gone. The solution is the same as #1, wait for some element that's part of the spinner to be invisible.
There may be some UI element like a header, footer, sidebar that is floating that covers the element you are trying to click if it's at the very bottom/top/etc of the page. These can be a real pain because you never know when the elements are going to align and be covered. One solution is to use JS to scroll the page a little more. For example, if you script is at the top of the page and you want to click something at the bottom. Doing a click will scroll the page to show that element but that puts the element at the very bottom of the page and under a floating footer. You try to click but catch the exception. Since you know you're at the bottom of the page, you scroll the page downwards by X pixels. This brings your desired element out from behind the floating footer and now you can click it.
NOTE: If you are going to click an element right after waiting for it, you should use .elementToBeClickable(locator) instead of .visibilityOfElementLocated(). It won't solve your current problem but it's a more complete and proper wait for what you are wanting to do.

Related

How to validate the accuracy of touch actions for scrolling on a mobile device?

My scenario is to scroll to somewhere in the middle of the page, to an element which is dynamic.
Now when I use touchAction using :-
TouchAction tc2=touchAction.press(PointOption.point(startX, startY)).waitAction().moveTo(PointOption.point(endX, endY)).release().perform();
The amount of scrolling is inconsistent, sometimes it over scrolls and sometime it underscrolls.
Also we do not have a boolean return for touch action to know wheather it has actually worked or not.
Q1.How do we validate wheather or not TouchAction is working correctly or not?
Q2.Which is the best way to implement scroll for mobile devices using appium?
This is good approach I have used. You can do scrolling to look a specific element with UiAutomator2 OR scrolling till the element is visible on page.
Add in desired capability UiAutomator2 if you are using appium as automation engine.
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "UiAutomator2");
Now use below functions if you have element's id, and index as 0 for there is one element on page.
public void scrollByID(String Id, int index) {
try {
driver.findElement(MobileBy.AndroidUIAutomator("new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().resourceId(\""+Id+"\").instance("+index+"));"));
} catch (Exception e) {
e.printStackTrace();
}
}
There is more ways to do scrolling. You can find them here

In the Navigator.click() method where exactly in the stack does the scrollIntoView() occur?

With Geb and WebElement, before a click is performed the webelement is first scrolled into view. I run into a problem here because there is a 'menu' bar at the top of screen that the webdriver doesn't see. this cause chrome to throw a webdriver exception stating that the element is not clickable at point x,y since the webDriver scrolls the element under the menu banner.
If I look at the implementation of the NonEmptyNavigator and subsequently remote webElement, I can't find where the scrollIntoView() occurs in the code. I want to put some code in between the scrollIntoView() and the actual click action so that I can offset the ScrollIntoView() slightly so the click can be performed. where exactly in stack for Navigator.click() does the scrolling into view happen?
Scrolling elements into view before clicking when calling WebElement.click() happens inside of the implementation of the method on the browser side so you won't find any reference to scrolling anything into view in Geb or RemoteWebElement. Here's a link to an example of the scrolling happening on the browser side from Marionette's (Firefox WebDriver implementation) code base: https://searchfox.org/mozilla-central/source/testing/marionette/interaction.js#148.
If you wish to manually scroll the element into view before clicking on it you might want to write a Geb module and overwrite click() in it:
class ViewPortOffsetModule extends Module {
Navigator click() {
//put your implementation of scrolling the element to view here, most probably using the js executor
super.click()
}
}
and then in your content definition:
static content = {
elementNeedingOffsetWhenScrollingIntoView { $("#my-element").module(ViewPortOffsetModule) }
}
Now, if you correctly implemented scrolling into view in ViewPortOffsetModule, calling elementNeedingOffsetWhenScrollingIntoView.click() will scroll the element into view with offset before clicking it.

How to validate the user has been scroll to top when he click on "back to top" button in selenium

I came across one of the scenario where I need to validate the user is scroll to top of the page when clicked on the "back to top" button on the bottom of the screen.
I tried with the following way but that didn't work.
I tried to validate the element present on the top of the page using
isDisplayed method
I have attached the image for clear description.
Solved it using the javascript concept used pageYOffset method.
Complete code
JavascriptExecutor executor = (JavascriptExecutor) driver;
Long value = (Long) executor.executeScript("return window.pageYOffset;");
pageYOffset method will return the vertical pixels, so as soon I logged in got the vertical pixels and then scrolled to the back to top button and after performing the action on back to top button, again got the vertical pixels and validated it.
isDisplayed() checks if the element is actually present in the viewport so it should work. May be put some wait in between clicking and checking isDisplayed for debugging puropose .
if (element.isDisplayed()) {
doSomething();
}
else {
doSomethingElse();
}

Unable to get Xpath for an input tag on a form

I am not able to get the Xpath for an input file with Selenium.
Here is a screenshot (of the mark-up).
Since the element you want is inside an iframe, you will have to switch selenium's focus to the iframe and then use the xpath to fetch the element.
JAVA:
To switch to the iframe, use
driver.switchTo().frame("uploadFile"); // used iframe's id as locator inside frame()
then, to fetch the input element, use the xpath //input[#name='file']
Do not forget to navigate away from the iframe after you are done interacting with this iframe. To navigate to default frame, use driver.switchTo().defaultContent();
There is a frame in your html code, first you have to switch to that frame.
WebDriver's driver.switchTo().frame() method takes one of the three possible arguments:
A number.
Select a frame by its (zero-based) index. That is, if a page has three
frames, the first frame would be at index 0, the second at index 1 and
the third at index 2. Once the frame has been selected, all subsequent
calls on the WebDriver interface are made to that frame.
A name or ID.
Select a frame by its name or ID. Frames located by matching name
attributes are always given precedence over those matched by ID.
A previously found WebElement.
Select a frame using its previously located WebElement.
Get the frame by it's id/name or locate it by driver.findElement() and you'll be good.
Then you can perform any action on input tag using below cssSelector :
driver.findElement(By.cssSelector("input[name=file]"));
And after performing your action don't forget to swith it to default frame :
driver.switchTo().defaultContent();
Exception Handling
You can wait for the alert to come for 30 seconds using below code , once the alert is present you can easily accept it.
try {
WebDriverWait waitAlert = new WebDriverWait(wb, 30);
waitAlert.until(ExpectedConditions.alertIsPresent());
wb.switchTo().alert().accept();
} catch (Exception e) {
logger.info("Alert Didn't Come");
}
Let me know if it helps.
Try below code.
//Going inside of the iframe
driver.switchTo().frame("uploadFile");
//Getting file input webelement
WebElement input=driver.findElement(By.xpath("//form[#name='fileUploadFrm']//input[#name='file']"));
//Sending file path using sendkeys method
input.sendKeys("filepath");
//Switch back to default
driver.switchTo().defaultContent();
Exception handling: Modal dialog present exception will be thrown when an alert appeared and we are not handling it. If the alert doesn't appear every time place below after your operations.
try {
Alert alert = driver.switchTo().alert();
alert.accept();
//if alert present, accept and move on.
}
catch (NoAlertPresentException e) {
//do what you normally would if you didn't have the alert.
}
Let me know if it works for you

How to make Selenium WebDriver wait for page to load when new page is loaded via JS event

I'm working on automating a site which has a number of links which load new pages via a JS event. Basically, there are elements which are clickable, clicking on one causes some JavaScript to run and this leads to a form being submitted and routing to a new page.
Now if these were just standard HTML links there would be no problem as Selenium is smart enough to tell that there's a new page coming and to wait to do things. But as good as it is, Selenium can't tell that the clicks in this instance are leading to new pages to load so it doesn't wait and just keeps going. As such it doesn't wait for the new page, tries to find elements which aren't there and my tests all fail. Bummer.
As a temporary solution I'm just pausing the program for three seconds like so:
oldPageDriver.clickThatButton();
try {
Thread.sleep(3000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
newPageDriver = new NewPageDriver(driver);
newPageDriver.doStuffOnNewPage();
And this works, sort of. I don't like it because it's "hacky," and just interrupting the program instead of doing something smarter. Because the delay is hard coded at three seconds I get failures if the link is working but just slow. I've considered something like an implicit wait but that accomplishes the same thing and I've not found a solid, workable answer in Java anywhere after a considerable amount of looking.
So, can anyone suggest a way around this? Specifically, how to make Selenium know that a new page is expected and to wait until it's available?
The wait for the document.ready event is not the entire fix to this problem, because this code is still in a race condition: Sometimes this code is fired before the click event is processed so this directly returns, since the browser hasn't started loading the new page yet.
After some searching I found a post on Obay the testing goat, which has a solution for this problem. The c# code for that solution is something like this:
IWebElement page = null;
...
public void WaitForPageLoad()
{
if (page != null)
{
var waitForCurrentPageToStale = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
waitForCurrentPageToStale.Until(ExpectedConditions.StalenessOf(page));
}
var waitForDocumentReady = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
waitForDocumentReady.Until((wdriver) => (driver as IJavaScriptExecutor).ExecuteScript("return document.readyState").Equals("complete"));
page = driver.FindElement(By.TagName("html"));
}
`
I fire this method directly after the driver.navigate.gotourl, so that it gets a reference of the page as soon as possible. Have fun with it!
Explicit waits are what you need;
http://docs.seleniumhq.org/docs/04_webdriver_advanced.jsp
You can directly add this to your test or you may want to DRY it up, especially if there is a common wait expectation such as the disappearance of a spinning icon.
You could extend the click method to always wait after clicking or if following page objects, add a wait_until_loaded method to a base page class. There many other valid approaches but dependent on how the AUT is implemented
Simple ready2use snippet, working perfectly for me
static void waitForPageLoad(WebDriver wdriver) {
WebDriverWait wait = new WebDriverWait(wdriver, 60);
Predicate<WebDriver> pageLoaded = new Predicate<WebDriver>() {
#Override
public boolean apply(WebDriver input) {
return ((JavascriptExecutor) input).executeScript("return document.readyState").equals("complete");
}
};
wait.until(pageLoaded);
}