Dynamic waiting for element to become clickable not working - java

I have written a function as following
public static WebElement waitForElementToBeClickable(WebDriver driver, WebElement webElement, int seconds) {
WebDriverWait wait = new WebDriverWait(driver, seconds);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(webElement));
element.click();
return element;
}
Now i am importing this function and using it as following
private String loginButton = "btnActive";
private String home = "//a[#id='pt1:_UIShome']";
WebElement login = driver.findElement(By.id(loginButton));
libraryUtils.waitForElements.waitForElementToBeClickable(driver, login, 20).click();
WebElement homeButton = driver.findElement(By.xpath(home));
libraryUtils.waitForElements.waitForElementToBeClickable(driver, homeButton, 20).click();
The login button is clicked but then after going to the next page i get the following error -
org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document
The Xpath is right, I have checked that. And when I use element.click(), that also works but then that would require me to manually enter the sleep time, which is what I'm doing. I would like this to be dynamic. Appreciate any help or suggestions.

Sometimes JS had not been finished running, and if you try to interact with the web element or web elements you would see staleElemenent exception.
However the below solution may work for you :
new WebDriverWait(driver, 10).ignoring(StaleElementReferenceException.class).until(ExpectedConditions.elementToBeClickable(By.xpath("//a[#id='pt1:_UIShome']")));
driver.findElement(By.xpath("//a[#id='pt1:_UIShome']")).click();

Possibly it will be not a nice, but I see no stable solution other that adding some sleep there.
So, please try this:
private String loginButton = "btnActive";
private String home = "//a[#id='pt1:_UIShome']";
WebElement login = driver.findElement(By.id(loginButton));
libraryUtils.waitForElements.waitForElementToBeClickable(driver, login, 20).click();
driver.findElement(By.xpath(home));
libraryUtils.waitForElements.waitForElementToBeClickable(driver, homeButton, 20);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.findElement(By.xpath(home)).click();

Problem here is that you are already doing element.click() in the waitForElementToBeClickable function and calling click again while calling this function.
libraryUtils.waitForElements.waitForElementToBeClickable(driver, login, 20).click();
Since you have already clicked while waiting for the element to be clickable, you shouldn't be clicking it again. I hope you got the answer for StaleElementException

Related

Selenium Webdriver: How to wait untill progressbar vanishes and click on the button [duplicate]

I used explicit waits and I have the warning:
org.openqa.selenium.WebDriverException:
Element is not clickable at point (36, 72). Other element would receive
the click: ...
Command duration or timeout: 393 milliseconds
If I use Thread.sleep(2000) I don't receive any warnings.
#Test(dataProvider = "menuData")
public void Main(String btnMenu, String TitleResultPage, String Text) throws InterruptedException {
WebDriverWait wait = new WebDriverWait(driver, 10);
driver.findElement(By.id("navigationPageButton")).click();
try {
wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector(btnMenu)));
} catch (Exception e) {
System.out.println("Oh");
}
driver.findElement(By.cssSelector(btnMenu)).click();
Assert.assertEquals(driver.findElement(By.cssSelector(TitleResultPage)).getText(), Text);
}
WebDriverException: Element is not clickable at point (x, y)
This is a typical org.openqa.selenium.WebDriverException which extends java.lang.RuntimeException.
The fields of this exception are :
BASE_SUPPORT_URL : protected static final java.lang.String BASE_SUPPORT_URL
DRIVER_INFO : public static final java.lang.String DRIVER_INFO
SESSION_ID : public static final java.lang.String SESSION_ID
About your individual usecase, the error tells it all :
WebDriverException: Element is not clickable at point (x, y). Other element would receive the click
It is clear from your code block that you have defined the wait as WebDriverWait wait = new WebDriverWait(driver, 10); but you are calling the click() method on the element before the ExplicitWait comes into play as in until(ExpectedConditions.elementToBeClickable).
Solution
The error Element is not clickable at point (x, y) can arise from different factors. You can address them by either of the following procedures:
1. Element not getting clicked due to JavaScript or AJAX calls present
Try to use Actions Class:
WebElement element = driver.findElement(By.id("navigationPageButton"));
Actions actions = new Actions(driver);
actions.moveToElement(element).click().build().perform();
2. Element not getting clicked as it is not within Viewport
Try to use JavascriptExecutor to bring the element within the Viewport:
WebElement myelement = driver.findElement(By.id("navigationPageButton"));
JavascriptExecutor jse2 = (JavascriptExecutor)driver;
jse2.executeScript("arguments[0].scrollIntoView()", myelement);
3. The page is getting refreshed before the element gets clickable.
In this case induce ExplicitWait i.e WebDriverWait as mentioned in point 4.
4. Element is present in the DOM but not clickable.
In this case induce ExplicitWait with ExpectedConditions set to elementToBeClickable for the element to be clickable:
WebDriverWait wait2 = new WebDriverWait(driver, 10);
wait2.until(ExpectedConditions.elementToBeClickable(By.id("navigationPageButton")));
5. Element is present but having temporary Overlay.
In this case, induce ExplicitWait with ExpectedConditions set to invisibilityOfElementLocated for the Overlay to be invisible.
WebDriverWait wait3 = new WebDriverWait(driver, 10);
wait3.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("ele_to_inv")));
6. Element is present but having permanent Overlay.
Use JavascriptExecutor to send the click directly on the element.
WebElement ele = driver.findElement(By.xpath("element_xpath"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", ele);
In case you need to use it with Javascript
We can use arguments[0].click() to simulate click operation.
var element = element(by.linkText('webdriverjs'));
browser.executeScript("arguments[0].click()",element);
I ran into this error while trying to click some element (or its overlay, I didn't care), and the other answers didn't work for me. I fixed it by using the elementFromPoint DOM API to find the element that Selenium wanted me to click on instead:
element_i_care_about = something()
loc = element_i_care_about.location
element_to_click = driver.execute_script(
"return document.elementFromPoint(arguments[0], arguments[1]);",
loc['x'],
loc['y'])
element_to_click.click()
I've also had situations where an element was moving, for example because an element above it on the page was doing an animated expand or collapse. In that case, this Expected Condition class helped. You give it the elements that are animated, not the ones you want to click. This version only works for jQuery animations.
class elements_not_to_be_animated(object):
def __init__(self, locator):
self.locator = locator
def __call__(self, driver):
try:
elements = EC._find_elements(driver, self.locator)
# :animated is an artificial jQuery selector for things that are
# currently animated by jQuery.
return driver.execute_script(
'return !jQuery(arguments[0]).filter(":animated").length;',
elements)
except StaleElementReferenceException:
return False
You can try
WebElement navigationPageButton = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.presenceOfElementLocated(By.id("navigationPageButton")));
navigationPageButton.click();
Scrolling the page to the near by point mentioned in the exception did the trick for me. Below is code snippet:
$wd_host = 'http://localhost:4444/wd/hub';
$capabilities =
[
\WebDriverCapabilityType::BROWSER_NAME => 'chrome',
\WebDriverCapabilityType::PROXY => [
'proxyType' => 'manual',
'httpProxy' => PROXY_DOMAIN.':'.PROXY_PORT,
'sslProxy' => PROXY_DOMAIN.':'.PROXY_PORT,
'noProxy' => PROXY_EXCEPTION // to run locally
],
];
$webDriver = \RemoteWebDriver::create($wd_host, $capabilities, 250000, 250000);
...........
...........
// Wait for 3 seconds
$webDriver->wait(3);
// Scrolls the page vertically by 70 pixels
$webDriver->executeScript("window.scrollTo(0, 70);");
NOTE: I use Facebook php webdriver
If element is not clickable and overlay issue is ocuring we use arguments[0].click().
WebElement ele = driver.findElement(By.xpath("//div[#class='input-group-btn']/input"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", ele);
The best solution is to override the click functionality:
public void _click(WebElement element){
boolean flag = false;
while(true) {
try{
element.click();
flag=true;
}
catch (Exception e){
flag = false;
}
if(flag)
{
try{
element.click();
}
catch (Exception e){
System.out.printf("Element: " +element+ " has beed clicked, Selenium exception triggered: " + e.getMessage());
}
break;
}
}
}
In C#, I had problem with checking RadioButton,
and this worked for me:
driver.ExecuteJavaScript("arguments[0].checked=true", radio);
Can try with below code
WebDriverWait wait = new WebDriverWait(driver, 30);
Pass other element would receive the click:<a class="navbar-brand" href="#"></a>
boolean invisiable = wait.until(ExpectedConditions
.invisibilityOfElementLocated(By.xpath("//div[#class='navbar-brand']")));
Pass clickable button id as shown below
if (invisiable) {
WebElement ele = driver.findElement(By.xpath("//div[#id='button']");
ele.click();
}

Element not visible exception - even if different Selenium waits are used

I am trying to automate functional testing of a web application using Selenium and Java. In my application there are several menus. When clicked on a particular menu, a drop down of sub menus appear
click to view screenshot of menu
I use below code to click sub menu
driver.findElement(By.xpath("id=menu")).click();
driver.findElement(By.xpath("id=sub_menu_a")).click();
but the issue is that it throws a 'ElementNotVisibleException' at the second line. The same happens even if I use implicit wait
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
explicit wait
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("id=sub_menu_a")));
and fluent wait.
Wait<WebDriver> fluentWait=new FluentWait<WebDriver>(driver)
.withTimeout(60, TimeUnit.SECONDS)
.pollingEvery(2, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class,ElementNotVisibleException.class);
WebElement element=fluentWait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver){
driver.findElement(By.xpath("id=menu"));
return driver.findElement(By.xpath("id=sub_menu_a"));
}
});
element.click();
but no luck. But the code works fine if add sleep time using
Thread.sleep(sleeptime);
before and after the first line of code. But it is not a permanent solution since the page load time may vary depend on the network speed and the data in the page. Is there any other solution?
Try this
WebElement menu=driver.findElement(By.xpath("id=menu"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", menu);
WebElement subMenu=driver.findElement(By.xpath("id=sub_menu_a"));
executor.executeScript("arguments[0].click();", subMenu);
Hope this work
Try to use Actions class and see if it works or not ...
driver.findElement(By.xpath("id=menu")).click();
WebElement subMenu=driver.findElement(By.xpath("id=sub_menu_a"));
Actions myaction = new Actions(driver);
myaction.moveToElement(subMenu);
WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(ExpectedConditions.elementToBeClickable(subMenu));
myaction.click().perform();
Fluent waits should work fine.
Try using something like this:
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver).withTimeout(10, TimeUnit.SECONDS).ignoring(NoSuchElementException.class);
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("id=sub_menu_a")));
but I would go for css Selectors they are perfect for html pages.
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver).withTimeout(10, TimeUnit.SECONDS).ignoring(NoSuchElementException.class);
wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#sub_menu_a")));
Or if your sub_menu_a is a child of menu I would go for
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver).withTimeout(10, TimeUnit.SECONDS).ignoring(NoSuchElementException.class);
wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#menu #sub_menu_a")));
Could you try
WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("id=sub_menu_a")));
Also it would be better if you can give html to find the right xpath as I think better XPATH will yield the result of click on the submenu.
Long time ago I have the similar issue (don't remember the exact case so indeed your HTML page snipped would be helpful) so I was forced to use Thread.sleep()
To avoid long waits will propose something like this method:
static void waitAndClick(WebDriver driver, By by, int attempts, int sleep) throws InterruptedException {
for (int i = 0; i < attempts; i++) {
WebElement element = null;
try {
element = driver.findElement(by);
} catch (NoSuchElementException e) {
// Do nothing
}
if (element == null) {
int time = sleep * (i + 1);
Thread.sleep(time);
} else {
element.click();
break;
}
}
throw new NoSuchElementException("Error");
}
It's not a 100% complete solution but just an idea.

Element not found in cache - perhaps the page has changed since it has looked up

I'm testing a web app, in which after opening a page I need to select a radio button after that a pop-up will appear. In that pop-up I'm selecting an ID. Once selected, it will come to main window, in which I'm trying to select a text field with ID. But I receive the following error:
Element not found in the cache - perhaps the page has changed since it was looked up
Command duration or timeout: 50.14 seconds
driver.findElement(By.xpath("html/body/section/div/div[2]/div[3]/div/div/div/div/ul/li[1]/a")).click();
driver.findElement(By.xpath("html/body/section/div/div[12]/div[1]/div/div[2]/div[3]/div/div/div/div/button[1]")).click();
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
String mainWindowHandle=driver.getWindowHandle();
driver.findElement(By.xpath("html/body/div[3]/div/div")).click();
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
Set s = driver.getWindowHandles();
Iterator ite = s.iterator();
while(ite.hasNext())
{
String popupHandle=ite.next().toString();
if(!popupHandle.contains(mainWindowHandle))
{
driver.switchTo().window(popupHandle);
}
}
driver.findElement(By.xpath("html/body/div[3]/div/div/div[3]/div/div/div[1]/div[2]/div[4]/div[2]/a")).click();
driver.manage().timeouts().implicitlyWait(50, TimeUnit.SECONDS);
driver.switchTo().window( mainWindowHandle );
driver.findElement(By.id("Title")).sendKeys("auto title");
Problem is I cannot find the textfield with ID: Title" for inserting "auto title.
Thanks in Advance.
Instead of using sleep() with hardcoded time intervals, use an explicit wait:
WebDriverWait wait = new WebDriverWait(driver, 30);
WebElement title = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("Title")));
title.sendKeys("auto title");
Finally found a solution by adding
Thread.sleep(5000);
before finding the element and it solved.

Unable to Handle Ajax Pop up in Selenium WebDriver

I'm new in Selenium. I'm trying to make Script in selenium of MacDonald's login and Order.But After login I'm unable to click Continue and any other option please help me.
my code is:--
WebDriver selenium= new FirefoxDriver();
selenium.manage().window().maximize();
String baseurl = "http://www.mcdelivery.co.in/";
selenium.get(baseurl);
Thread.sleep(2000);
Thread.sleep(5000);
WebElement loginbtn = selenium.findElement(By.id("lnkBtnLogin"));
if(loginbtn.isDisplayed()) {
loginbtn.click();
}
WebElement username = selenium.findElement(By.id("txtMobileNumber"));
if(username.isDisplayed()) {
username.clear();
username.sendKeys("******");
}
WebElement pwd = selenium.findElement(By.id("txtMsgPwd"));
if(pwd.isDisplayed()) {
pwd.sendKeys("******");
}
WebElement submit = selenium.findElement(By.id("btnSubmit"));
if(submit.isDisplayed()) {
submit.click();
//Alert aler = selenium.switchTo().alert().accept();
selenium.switchTo().activeElement();
}
WebElement conti = selenium.findElement(By.id("btnContinue"));
if(conti.isDisplayed()) {
conti.click();
}
// selenium.close();
After running this I'm Getting Error
Exception in thread "main" org.openqa.selenium.NoSuchElementException: Unable to locate element:
{"method":"id","selector":"btnContinue"}
Command duration or timeout: 31 milliseconds
Since the Continue button is the part of the pop-up (which takes time to load), you need to give some time to webdriver to detect it. For that purpose, give a timeout using Implicit/Explicit waits.
For above, you can use an Implicit timeout at the top like this;
selenium.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
The above gives a 15 seconds time to the webdriver, each time it tries to locate an element.
Also, in this code,
if(conti.isDisplayed())
{
conti.click();
}
for some odd reasons, the Continue button wasn't getting clicked when inside the if ( conti.isDisplayed() ). So, lose that loop. Just use conti.click();. It worked when tried!
Hi use some kind of explicit wait after switching to the popup like
boolean ajaxPopup = new WebDriverWait(driver,10).until(ExpectedConditions
.visibilityOfElementLocated(By.id("btnContinue"))) != null;
Assert.assertTrue(ajaxPopup);

selenium get current url after loading a page

I'm using Selenium Webdriver in Java. I want to get the current url after clicking the "next" button to move from page 1 to page 2. Here's the code I have:
WebDriver driver = new FirefoxDriver();
String startURL = //a starting url;
String currentURL = null;
WebDriverWait wait = new WebDriverWait(driver, 10);
foo(driver,startURL);
/* go to next page */
if(driver.findElement(By.xpath("//*[#id='someID']")).isDisplayed()){
driver.findElement(By.xpath("//*[#id='someID']")).click();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[#id='someID']")));
currentURL = driver.getCurrentUrl();
System.out.println(currentURL);
}
I have both the implicit and explicit wait calls to wait for the page to be fully loaded before I get the current url. However, it's still printing out the url for page 1 (it's expected to be the url for page 2).
Like you said since the xpath for the next button is the same on every page it won't work. It's working as coded in that it does wait for the element to be displayed but since it's already displayed then the implicit wait doesn't apply because it doesn't need to wait at all. Why don't you use the fact that the url changes since from your code it appears to change when the next button is clicked. I do C# but I guess in Java it would be something like:
WebDriver driver = new FirefoxDriver();
String startURL = //a starting url;
String currentURL = null;
WebDriverWait wait = new WebDriverWait(driver, 10);
foo(driver,startURL);
/* go to next page */
if(driver.findElement(By.xpath("//*[#id='someID']")).isDisplayed()){
String previousURL = driver.getCurrentUrl();
driver.findElement(By.xpath("//*[#id='someID']")).click();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
ExpectedCondition e = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return (d.getCurrentUrl() != previousURL);
}
};
wait.until(e);
currentURL = driver.getCurrentUrl();
System.out.println(currentURL);
}
Page 2 is in a new tab/window ?
If it's this, use the code bellow :
try {
String winHandleBefore = driver.getWindowHandle();
for(String winHandle : driver.getWindowHandles()){
driver.switchTo().window(winHandle);
String act = driver.getCurrentUrl();
}
}catch(Exception e){
System.out.println("fail");
}
It's been a little while since I coded with selenium, but your code looks ok to me. One thing to note is that if the element is not found, but the timeout is passed, I think the code will continue to execute. So you can do something like this:
boolean exists = driver.findElements(By.xpath("//*[#id='someID']")).size() != 0
What does the above boolean return? And are you sure selenium actually navigates to the expected page? (That may sound like a silly question but are you actually watching the pages change... selenium can be run remotely you know...)

Categories

Resources