Waiting for element to be really clickable in Selenium [duplicate] - java

This question already has answers here:
Element MyElement is not clickable at point (x, y)... Other element would receive the click
(5 answers)
Closed 3 years ago.
I do have a Select and I try to wait patiently for it to be available, but that won't do.
WebDriverWait wait = new WebDriverWait(getWebDriver(), 20);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("myxpath")));
Select select = new Select(element);
select.selectByVisibleText(text);
When I run the code on this particular Element I get an error message:
... is not clickable at point (1311,183) because another element <p class="ng-tns-c4-0"> obscures it
I suppose this is because the page has these annoying status messages showing on the upper right corner for some seconds and then fading away. Though they are far away from my dropdown, they still seem to obscure it.
The whole thing works if I add a 2 second explicit wait, but that somehow offends my sense of stile and I most likely would end up spreading them all over the tests and slow them down a lot.
Is there any generic way of waiting for an element not to be obscured? I mean a way without having to know which particular message pops in.
POSTSCRIPT:
Since I cannot add an answer on my own, I add this postscript. In the end I have settled for this solution:
protected void secureSelect(String text, Select select) {
try {
select.selectByVisibleText(text);
} catch(ElementClickInterceptedException e) {
Wait.seconds(2);
select.selectByVisibleText(text);
}
}
I know that these problems will occur all over the application with different messages of the same type. So in case of an error I just try once again and the let it fail if it goes wrong again.

To answer your last question, is there a generic way of waiting for an element to not be obscured? Outside of elementToBeClickable, not really. Web pages are dynamic and each one of them loads content differently so there's not exactly a catch-all for this. It is unfortunate that elementToBeClickable is encountering a ClickIntercepted error for your scenario, but there are a few workarounds.
You could try adding an additional wait to wait on invisibilityOfAllElements for the status messages that keep popping up, if these are what is getting in the way:
wait.until(ExpectedConditions.invisibilityOfAllElements(By.xpath("//p[contains(#class, 'ng-tns')]")));
This may encounter a timeout exception depending on the nature of displayed p elements compared with the rest of the page content. Another possible workaround would be leaving your code as it, and using Javascript to select elements from the Select instead:
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("myxpath")));
JavascriptExecutor js = (JavascriptExecutor)driver;
// expand the Select dropdown
js.executeScript("arguments[0].click();", element);
// wait for Select options menu to expand
WebElement optionToClick = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("xPathForDropdownOption")));
// select desired option
js.executeScript("arguments[0].click();", optionToClick);
The above code is a bit more 'explicit' in what we are waiting on -- specifically, the dropdown option value. Clicking both the Select dropdown and the dropdown option with Javascript are meant to be workarounds for the ClickIntercepted error.

Related

Stale Element when using List of WebElement but works fine with individual elements in Selenium

I have 5 elements which I am tryin to hover 1 by 1. I am putting these elements in a List. But when I use List for Hover(with and without loop) it gives Stale Element Exception. Note I can perform it when I use individual elements without using list. I have printed the elements from List and the xpath returned also looks correct.
System.out.println("=====================All star start ================");
Actions actions= new Actions(driver);
List<WebElement> starList= new ArrayList<WebElement>();
ArrayList<WebElement> starColorList= new ArrayList<WebElement>();
Reporter.log("Started adding star elements", true);
for(i=11,j=22;i<=15;i++,j=j+2)
{
Reporter.log("Started adding star elements"+i+j, true);
WebElement s = driver.findElement(By.xpath("(//*[name()='svg'][#class='rvs-star-svg'])["+i+"]"));
WebElement sc = driver.findElement(By.xpath("(//*[name()='svg']//*[name()='path'])["+j+"]"));
starList.add(s);
starColorList.add(sc);
}
//Does not work even without loop
actions.moveToElement(starList.get(2)).build().perform();
//Works
actions.moveToElement(star1).build().perform();
Does not work
for(i=0;i<starList.size();i++)
{
Reporter.log("Started Hover"+i, true);
actions.moveToElement(starList.get(i)).build().perform();
Thread.sleep(2000);
System.out.println(starList.get(i));
//System.out.println("Star"+i+"has color "+starColorList.get(i).getAttribute("stroke"));
}
'''
There are several problems to watch out for:
StateElementReferenceException is always thrown when you try to interact with an element which is no longer accessible because the DOM has changed. Are you trying to interact with the second element after you hovered over the first one? Does this cause a new element, like a tooltip, to show up and thus invalidating the WebElements from the list? You'd have to re-execute the search after that. One basic solution is to keep locators, and not located WebElements in the list, so that you run findElement(locators.get(i)).click() in a loop.
This not necessarily matches your example, but it seems to be quite common problem: if you use findElements - the variant returning a list of multiple elements matching a single locator - make sure your locator is not too generic, as sometimes the found elements are not necessarily what you are expecting them to be. Like finding nested <td> elements inside other <td> and not after the ones you'd expect.
All in all, the list use here is probably a red herring - the real problem is what happens in the DOM between calls to findElement() and whatever interaction you have with that element.
StateElementReferenceException will occur on when trying to access the element before page load or after the element is vanished. so please try to add visibility wait conditions.
By tmpBy = By.xpath("//div[contains(text(),'"+deno+"')]");
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.elementToBeClickable(tmpBy));
wait.until(ExpectedConditions.visibilityOfElementLocated(tmpBy));
driver.findElement(tmpBy).click();
And please add code to take screenshot whenever it is failing. it will be easy for you debug.

Can we use one pageobject among different pages?

I am working on one selenium project. My scenario is, I have multiple forms one after another. After filling them I have to click on the Next button. I have 4 pages with the next button and they have the same XPath. When I try to use the same web element for the next button it works once but when I try to use that same thing again on a different page It shows element intreactable error.
I would try the following to identify why you get the interactable error (it would help to give us the error at least as is found on the Selenium Documentation)
try to click using javascript executor,
try to add webelements for each action you need to perform (so 4 webelements for each 'Next' button). If it works in this way maybe the webelement is not refreshed after you use it (maybe is a static field). Try also to work with Page Factory pattern.
If nothing works, we should receive more information to be able to help.

Using Click() on href Button HTML

I am working on a project in selenium, in which once it fills out a textbox, clicks next page, a captcha comes up. First you need to verify, then the captcha shows up. It is just a pop up box in the middle of the page and makes everything else unclickable with a white haze over the page behind it. Once the verification is clicked on I already have a method for solving the captcha.
The issue I am having is that with the methods I have tried, the webdriver cannot seem to find any trace of this button. I always get an no such element exception, when trying to use click(). I have tried wait.until(ExpectedConditions.elementToBeClickable(By.id("home_children_button"))).click();, wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.id("home_children_button")))).click(); , I have also tried putting a thread.sleep(Num) instead of using a wait, along with many other methods on google. Then when I did some research about href buttons, I found people recommend to use By.linkText. So I tried that with all the methods I tried before, and element still cannot be located. I couldn't find anything else on google, so I thought I would ask for help.
I have attatched the HTML Code I currently am looking at for the button, along with the link for the website. Unfortunately to encounter this page, you must make an account. This page normally comes up once I put the DOB in. Thank you for any clarification provided.
Verify
https://account.battle.net/creation/flow/creation-full
Code I have tried:
wait2.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.id("fc-iframe-wrap")));
wait2.until(ExpectedConditions.elementToBeClickable(By.id("home_children_button"))).click();
WebDriverWait wait2 = new WebDriverWait(driver, 10);
wait2.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.id("CaptchaFrame")));
wait2.until(ExpectedConditions.elementToBeClickable(By.id("home_children_button"))).click();
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("home_children_button"))).click();
wait.until(ExpectedConditions.elementToBeClickable(By.id("home_children_button"))).click();,
wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.id("home_children_button")))).click();
Thread.sleep(5000) //wait for it to pop up
driver.findElement(By.id("home_children_button"))).click();
Along with trying to use By.linkText.
Solution:
After being told it's an iframe, I looked closer at the HTML to see there was multiple iframes. So I waited to switch through them in order to click the button.
WebDriverWait wait2 = new WebDriverWait(driver, 20);
wait2.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.xpath("/html/body/div[4]/iframe")));
wait2.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.xpath("/html/body/div/div[1]/div/iframe")));
wait2.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.xpath("/html/body/div[1]/div[2]/div[1]/iframe")));
wait2.until(ExpectedConditions.elementToBeClickable(By.id("home_children_button"))).click();
As I suspected, it is in iframe, you need to switch the focus of your driver to interact with verify button :
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.id("CaptchaFrame")));
wait.until(ExpectedConditions.elementToBeClickable(By.id("home_children_button"))).click();
and once you are done with it, you may want to use defaultContent()
driver.switchTo().defaultContent();

Can not find selenium WebElement twice

Working with selenium and InternetExplorer 11, I can navigate around this site.
I got a method that finds an input box on the page then inputs text. It works the first time, but when I go to another page it says that element does not exist and the page just refreshes randomly.
I a m just using a simple wait:
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(text(), 'Enter Name')]")));
WebElement nameField = driver.findElement(By.xpath("//*[contains(text(), 'Enter Name')]"));
It crashes and says the element can not be found during the wait.
I am not sure if this is just site specific or if I am doing something wrong.
If anyone has any idea I'd appreciate it :)
Here is the Answer to your Question:
As you mentioned when I go to another page the entire HTML DOM gets changed and now if you try to locate or use findElement() with a previously found id/name/css/xpath Selenium will fail to do that.
So when we are on a new page we have to search for the element again using the current id/name/css/xpath in-order to use click() or sendKeys() methods.
Let me know if this Answers your Question.

Facing an issue while selecting drop down in Selenium webdriver

I am trying to select a drop down using selenium web driver, using this code:
WebElement admissionSource = driver.findElement(By.name("ABC"));
Select admissionSource_select= new Select(admissionSource);
Thread.sleep(10000);
Here, ABC is the value name attribute for that element.
It is selecting as expected, however once it moves to the next drop down just below that, it deselects the previous one.
Things I've tried:
1) After filling the next drop down, going back and filling the previous drop down again. However this second attempt selects the first drop down but deselects the next drop down(as is the application). Filling the next drop down again throws below exception:
org.openqa.selenium.StaleElementReferenceException: Element is no longer valid
2) Thread.sleep()
3) Implicit wait
4) Explicit wait
Please suggest on how to resolve this issue.
StaleElementException occurs when your referenced element is no more available or the element/page is refreshed. In your case, selecting from first dropdown refreshes/reloads your second dropdown. Hence, the StaleElementException occurs. To overcome this, after selecting from first dropdown, get the location of the second dropdown and select your element afresh each time.
This issue was coming because the in the 2nd dropdown, the options were dependent on the first one. So earlier i was just waiting for the dropdown box to get loaded. However in this scenario, even though the dropdown box had loaded but the dropdown options had not yet loaded for the 2nd drop down. Hence it was giving StaleElement Exception.
The way to tackle this is to use FluentDriver wait on the any (random) dropdown option and once it is loaded then only proceed further.
Between these two sentences from your question:
Select admissionSource_select= new Select(admissionSource);
Thread.sleep(10000);
Won't you need to do something like:
admissionSource_select.selectByVisibleText("Abc");
Where Abc is the name visible for that element.
You have just declared the drop-down element to be an instance of Select class. Is merely that sufficient? May be actually selecting the element was missing when you tried. You can try with adding above statement and then waiting while 2nd drop-down populates.

Categories