WebDriverWait.until(ExpectedConditions.elementToBeClickable(someAjaxMagic)) never returns - java

I have a problem with Selenium. In the following test, it should go to the website, take a product, add it to the cart and go to the cart. In between, it waits for some elements to appear.
On my machine the test works fine up to adding the product to the cart. After this, a div is filled with ajax and the test should wait for an element in there. The element appears in the browser, but the test goes on waiting. Even the timeout seems not to be interesting enough to bother it.
If I wait with wait.until(pause(2)); instead or set driver.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS); everything works fine but this can't be the correct solution.
Any idea?
My system:
MacOS X 10.8.2 or Windows 7 (64 bit)
Firefox 17.0.1
Java 1.6, JUnit 4.10, selenium-api-2.25.0, selenium-support-2.25.0, selenium-firefox-driver-2.25.0, guava-12.0
My test:
import static org.openqa.selenium.support.ui.ExpectedConditions.elementToBeClickable;
import javax.annotation.Nullable;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import com.google.common.base.Function;
public class TestSomeWebsite {
#Test
public void test() throws Exception {
FirefoxDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 30);
driver.get("http://www.obi.de");
// take first product
driver.findElement(By.cssSelector("p.product_desc > a")).click();
// add to cart
wait.until(elementToBeClickable(By.id("addtocart")));
driver.findElement(By.id("addtocart")).submit();
// go to cart
/** everything fine by now **/
wait.until(elementToBeClickable(By.partialLinkText("Zum Warenkorb")));
/** we never come to this point :( **/
driver.findElement(By.partialLinkText("Zum Warenkorb")).click();
}
private Function<WebDriver, Object> pause(final int time) {
return new Function<WebDriver, Object>() {
int count = 0;
#Nullable
public Object apply(#Nullable WebDriver input) {
count++;
return count >= time;
}
};
}
}

#snieke, try upgrading your selenium version to 2.28.0. I'm 99% sure that will work for you.
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.28.0</version>
</dependency>

Do you get a timeout exception, you are supposed to get it after 30 seconds.
You can try:
try {
wait.until(elementToBeClickable(By.partialLinkText("Zum Warenkorb")));
} catch (TimeoutException e) {
// Do not stop the test, continue and see what happens
LOG.info("Timed out", e);
}
driver.findElement(By.partialLinkText("Zum Warenkorb")).click();
it should continue after 30 seconds
EDIT:
Then try writing your own condition, here is what I have(you need to tweak it to suit your needs):
public class WebElementIsVisible implements ExpectedCondition<Boolean> {
private WebElement element;
private String elementId;
public WebElementIsVisible(WebElement elementId) {
this.element = elementId;
}
public WebElementIsVisible(String elementId) {
this.elementId = elementId;
}
#Override
public Boolean apply(WebDriver webDriver) {
if (element != null) {
return isElementVisible(element, webDriver);
} else if (elementId != null) {
return isElementIdVisible(elementId, webDriver);
} else {
throw new RuntimeException("Not supposed to reach here");
}
}
private Boolean isElementIdVisible(String elementId, WebDriver webDriver) {
try {
webDriver.findElement(By.id(elementId));
return true;
} catch (NoSuchElementException e) {
return false;
}
}
private Boolean isElementVisible(WebElement element, WebDriver webDriver) {
try {
webDriver.findElement(By.id(element.getAttribute("id")));
return true;
} catch (NoSuchElementException e) {
return false;
}
}
}

Related

How do I return boolean value from ExpectedCondition objects

I do have a method that waits for the JavaScript to load in the browser. From Selenium 3 (3.141.59), I have shifted to Selenium 4 (4.0.0-alpha-7)
This return code/statement doesnt work with Selenium 4
return wait.until(jQueryLoad) && wait.until(jsLoad);
What would be the correct return statement for this? I have tried several options but nothing worked. Please see the code structure for the method/function below. Your thoughts, ideas and answers will be highly appreaciated.
public static boolean waitForJStoLoad() {
WebDriverWait wait = new WebDriverWait(getDriver(), Duration.ofSeconds(30));
// wait for jQuery to load
ExpectedCondition<Boolean> jQueryLoad = new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver arg0) {
try {
Long state = (Long) ((JavascriptExecutor) arg0).executeScript("return jQuery.active");
return (state == 0);
} catch (Exception e) {
return true;
}
}
};
// wait for Javascript to load
ExpectedCondition<Boolean> jsLoad = new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver arg0) {
String state = (String) ((JavascriptExecutor) arg0).executeScript("return document.readyState;");
return state.equalsIgnoreCase("complete");
}
};
return wait.until(jQueryLoad) && wait.until(jsLoad);
}
Well, I'm using standard Selenium 3 and not checking JavaScripts, but I do have several simple methods validating some conditions with the Expected Conditons and returning Boolean.
Something like this:
public boolean waitForElementToDisappear(By element){
try {
wait.until((ExpectedConditions.invisibilityOfElementLocated(element)));
return true;
}catch (Throwable t){
return false;
}
}

Selenium and Appium and WaitForSomeElementToBeVisible

I have this method implemented some time ago. I use it pretty extensively in my web automation.
The gist is to wait for one of several elements to be visible.
public void waitForSomeElementToBeVisible(int timeout, final By... locators) throws Exception, TimeoutException {
boolean found = false;
try {
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
WebDriverWait wait = new WebDriverWait(driver, timeout);
ExpectedCondition<?>[] conditionsToEvaluate = new ExpectedCondition[locators.length];
for (int i = 0; i < locators.length; i++) {
conditionsToEvaluate[i] = ExpectedConditions.visibilityOfElementLocated(locators[i]);
}
found = wait.until(ExpectedConditions.or(conditionsToEvaluate));
} catch (TimeoutException e) {
throw e;
} catch (Exception e) {
throw e;
} finally {
driver.manage().timeouts().implicitlyWait(<default>, TimeUnit.SECONDS);
}
if (!found) throw new Exception("Nothing found");
}
Now I’m trying to use this method with a mobile browser. Specifically, iOS Safari via Appium. It works on iOS occasionally but usually fails and in the Appium log I see when executing the line:
found = wait.until(ExpectedConditions.or(conditionsToEvaluate));
(It does work consistently with Android+Appium).
[WD Proxy] Got response with status 404: {"value":{"error":"no such alert","message":"An attempt was made to operate on a modal dialog when one was not open","traceback":""},"sessionId":"03E95205-9E98-4DB4-BB61-0F125C2C5B3E"}
[debug] [W3C] Matched W3C error code 'no such alert' to NoSuchAlertError
There is, of course, no alert AND one of the elements does exist.
What’s going wrong here?
Is there a better way to wait for one of several elements to be visible?
Please try this java method :
public static boolean waitForElement(WebElement element) throws IOException {
log.info("Waiting for an element in the page...");
boolean isElementPresent = true;
try {
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.visibilityOf(element));
log.info("Element is visible");
return isElementPresent;
} catch (Exception e) {
log.info("waitForElement method failed! " + e.getMessage());
return !isElementPresent;
}
}
or this method:
public static WebElement fluentWait(final WebElement webElement, int timeinsec) {
log.info("waiting ..."+ timeinsec +" seconds");
FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(timeinsec, TimeUnit.SECONDS).pollingEvery(timeinsec, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
WebElement element = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return webElement;
}
});
return element;
}
FYI: Both of these method are present under the below maven Dependency I created a while ago. It has a lot of re-usable method that you can use :
<dependency>
<groupId>com.github.mbn217</groupId>
<artifactId>MyUtilities</artifactId>
<version>1.0.2</version>
</dependency>
To use it you just need to call the class name and the method. No need to create an object from the class
example:
SeleniumUtils.waitForElement(pass your element here)

Wait for a page to fully load in Selenium

I am using selenium with Java. I want to wait for page to load fully before doing any action on that page.
I have tried the following method, but it is failing to work as expected.
public void waitForElementToBeVisible(final WebElement element) {
WebDriverWait wait = new WebDriverWait(WebDriverFactory.getWebDriver(), WEBDRIVER_PAUSE_TIME);
wait.until(ExpectedConditions.visibilityOf(element));
WebDriverWait inherits methods like wait until.
So something like
webDriverWait.until(ExpectedConditions.visibilityOfElementLocated( elementLocator)
should work. You can use ExpectedConditions, it would make things simpler. You can also use the method visibilityOfAllElements
This method will wait until element is visible.
Firstly this method will check, whether element is available in html and whether it's display.. it will wait until element will display..
public void E_WaitUntilElementDisplay() throws Exception
{
int i=1;
boolean eleche,eleche1 = false;
while(i<=1)
{
try{
eleche = driver.findElements(by.xpath("path")).size()!=0;
}catch(InvalidSelectorException ISExcep)
{
eleche = false;
}
if(eleche == true)
{
while(i<=1)
{
try{
eleche1=driver.findElement(By.xpath("Path")).isDisplayed();
}catch(org.openqa.selenium.NoSuchElementException NSEE){
eleche1=false;
}
if(eleche1 == true)
{
i=2;
System.out.println("\nElement Displayed.");
}
else
{
i=1;
Thread.sleep(1500);
System.out.println("\nWaiting for element, to display.");
}
}
}
else
{
i=1;
Thread.sleep(1500);
System.out.println("\nWaiting for element, to display.");
}
}
}
As another option maybe you can try something like:
if(element.isDisplayed() && element.isEnabled()){
//your code here
}
or if you know how long you want to wait:
thread.sleep(3000); //where 3000 is time expression in milliseconds, in this case 3 secs
You can use this function in java to verify whether the page is fully loaded or not. The verification happens two-fold. One using the javascript document.readystate and imposing a wait time on javascript.
/* Function to wait for the page to load. otherwise it will fail the test*/
public void waitForPageToLoad() {
ExpectedCondition<Boolean> javascriptDone = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
try {
return ((JavascriptExecutor) getDriver()).executeScript("return document.readyState").equals("complete");
} catch (Exception e) {
return Boolean.FALSE;
}
}
};
WebDriverWait wait = new WebDriverWait(getDriver(), waitTimeOut);
wait.until(javascriptDone);
}
This works for me:
wait.until(ExpectedConditions.not(
ExpectedConditions.presenceOfElementLocated(
By.xpath("//div[contains(text(),'Loading...')]"))));
Here is the ultimate solution specifically when you are dealing with Angular 7 or 8.
Instead of waiting for a longer duration using sleep or implicit wait methods, you can divide your wait time into the partition and use it recursively.
Below logic will wait for the page to render for a minimum of 300 seconds and a maximum of 900 seconds.
/**
* This method will check page loading
*
*/
public void waitForLoadingToComplete() {
waitLoadingTime(3); // Enter the number of attempts you want to try
}
private void waitLoadingTime(int i) {
try {
// wait for the loader to appear after particular action/click/navigation
this.staticWait(300);
// check for the loader and wait till loader gets disappear
waitForElementToBeNotPresent(By.cssSelector("Loader Element CSS"));
} catch (org.openqa.selenium.TimeoutException e) {
if (i != 0)
waitLoadingTime(i - 1);
}
}
/**
* This method is for the static wait
*
* #param millis
*/
public void staticWait(final long millis) {
try {
TimeUnit.MILLISECONDS.sleep(millis);
} catch (final InterruptedException e) {
System.err.println("Error in staticWait." + e);
}
}
public void waitForElementToBeNotPresent(final By element) {
long s = System.currentTimeMillis();
new WebDriverWait(this.getDriver(), 30)
.until(ExpectedConditions.not(ExpectedConditions.presenceOfAllElementsLocatedBy(element)));
System.err.println("Waiting for Element to be not present completed. " + (System.currentTimeMillis() - s));
}

Selenium IE .click() works inconsistently

I have the following Problem. I use Selenium 2.42.2 to test our company intranet site. Therefore I implemented an example Testcase with a Testsuite. I test this testcase with Firefox 31 and IE 11. All works fine but some times it seems like the IE doesn't click on some elements. It's very confusing because sometimes it works correctly and sometimes it doens't. However I till now I trief the following solutions without success:
Check Zoom Level and set it in all possible ways
set up all possible waits (explicit, implicit, some weird variants)
use 'sendkeys(\n)' instead of .click()
the only solution which works is to double click. But this call new problems with firefox and if this bug doesn't occur.
Does anyone have a hint or any idea which is the cause for the problem?
Thanks for help upwards.
attached Code:
#RunWith(Parameterized.class)
public class SeleniumTest_WD_used extends AbstractSelenium {
public SeleniumTest_WD_used(RemoteWebDriver d) {
driver = d;
}
private String baseUrl = "company.intranet.site.com";
#Override
#Before
public void setUp() {
driver.get(baseUrl);
driver.manage().timeouts().implicitlyWait(500, TimeUnit.MILLISECONDS);
}
#Test
public void worldClock_autoCity_Test_with_ES() throws InterruptedException {
Thread.sleep(2000);
driver.findElement(By.xpath("some XPath")).click();
Thread.sleep(2000);
new Select(driver.findElement(By.id("some ID"))).selectByVisibleText("Some Text");
driver.findElement(By.cssSelector("Some Css_Element")).click();
driver.findElement(By.xpath("some XPath")).click();
RemoteWebElement e1 = (RemoteWebElement) driver.findElement(By.xpath("some XPath"));
Assert.assertEquals("Some Assert", e1.getText());
}
}
and I override the 'findElement' Method for IE and FF driver in the following way (but I also got this bug if I use the standard method):
public class FirefoxDriver2_0 extends FirefoxDriver {
private static FirefoxDriver2_0 instance = null;
private long startTime;
private long stopTime;
private FirefoxDriver2_0() {
super();
}
public static synchronized FirefoxDriver2_0 getInstance() {
if (instance == null) {
instance = new FirefoxDriver2_0();
}
return instance;
}
#Override
public RemoteWebElement findElement(By by) {
return elementSearch(by, FirefoxDriver2_0.getInstance());
}
private RemoteWebElement elementSearch(By by, FirefoxDriver driver) {
startTime = System.currentTimeMillis();
RemoteWebElement helpingElement = null;
isElementPresent(by);
try {
helpingElement = (RemoteWebElement) super.findElement(by);
} catch (Exception e) {
AllTest.updateLogger("[error] method 'elementSearch' incomplete");
fail("Test not successfull!");
} finally {
stopTime = System.currentTimeMillis();
timeWarning(by.toString());
}
return helpingElement;
}
private boolean isElementPresent(By by) {
try {
super.findElement(by);
return true;
} catch (NoSuchElementException e) {
stopTime = System.currentTimeMillis();
timeWarning(by.toString());
AllTest.updateLogger("[main] ERROR\tThe following expression could not be solved: " + by);
fail("Test not successfull! --> Error: Element not found. Please check the failed XPath's");
return false;
}
}
private void timeWarning(String s){
if(stopTime-startTime > 500){
AllTest.updateLogger("[main] WARNING\tHigh response-time detected: " + (stopTime-startTime) + " ms [#element: " + s + "]");
}
}
If you need some further Code or Information please ask for it. I got two more relevant classes 1.) a Testsuite which initialize the test and 2.) a abstract class as parent for my testcase.
Now I got a solution!
As you can see in my question Code I override the findElement method from the FF and IE Driver. This is the key to solve this really annoying problem. Because I found out that IE some times simple doesn't click on some elements (mostly elements which send out ajax requests). I guess this happens because IE doesn't focus on this elements directly. IE is slow and needs more time either you need to double click the element (1. to set focus, 2. to really click). And here comes the solution:
You could Override the findElement method from IE and add a simple By-element to save the requested elements. If now an element couldn't be found by this method because the parent wasn't really clicked you could click the parent in this method again and vóila it works!
For this solution it's really important that you build an own class (e.g. named: InternetExplorerDriver2_0) which is a singleton (to perform the click in the own class) and which overrides the standard findElement method.
(I guess it's clear that in the following tests you have to use your changed IEDriver class instead of the original 'InternetExplorerDriver' class)
Here you could find the Code for the changed IEDriver class:
import static org.junit.Assert.fail;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebElement;
public class InternetExplorerDriver2_0 extends InternetExplorerDriver {
private static InternetExplorerDriver2_0 instance = null;
private static DesiredCapabilities caps = null;
private long startTime;
private long stopTime;
private By olderBy;
private InternetExplorerDriver2_0() {
super(caps);
}
public static synchronized InternetExplorerDriver2_0 getInstance(
DesiredCapabilities capabilities) {
if (instance == null) {
caps = capabilities;
instance = new InternetExplorerDriver2_0();
}
return instance;
}
#Override
public RemoteWebElement findElement(By by) {
return elementSearch(by, InternetExplorerDriver2_0.getInstance(caps));
}
private RemoteWebElement elementSearch(By by, InternetExplorerDriver driver) {
startTime = System.currentTimeMillis();
RemoteWebElement helpingElement = null;
isElementPresent(by);
try {
helpingElement = (RemoteWebElement) super.findElement(by);
} catch (Exception e) {
System.out.println("[error] method 'elementSearch' incomplete");
fail("Test not successfull!");
} finally {
stopTime = System.currentTimeMillis();
timeWarning(by.toString());
}
olderBy = by;
return helpingElement;
}
private boolean isElementPresent(By by) {
try {
super.findElement(by);
return true;
} catch (NoSuchElementException e1) {
//the following lines are the important!!!
try {
InternetExplorerDriver2_0.getInstance(caps).findElement(olderBy).click();
super.findElement(by);
return true;
} catch (Exception e2) {
stopTime = System.currentTimeMillis();
timeWarning(by.toString());
AllTest.updateLogger("[main] ERROR\tThe following expression could not be solved: " + by);
fail("Test not successfull! --> Error: Element not found. Please check the failed XPath's");
return false;
}
}
}
private void timeWarning(String s) {
if (stopTime - startTime > 500) {
AllTest.updateLogger("[main] WARNING\tHigh response-time detected: " + (stopTime - startTime) + " ms [#element: " + s + "]");
}
}
}
I know it's not the perfectly clean solution but it's a nice workaround and save so much time!

is there any way by which we can go back to try block from catch

I am running a code in Selenium webdriver and whenever an element is not found it goes to catch. But I want java to continue the execution after skipping that element.
import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import net.sourceforge.htmlunit.corejs.javascript.ast.LabeledStatement;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;
import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Label;
import com.sun.org.apache.bcel.internal.generic.GOTO;
public class try_zencart {
private WebDriver driver;
private String baseUrl;
private boolean acceptNextAlert = true;
private StringBuffer verificationErrors = new StringBuffer();
#Before
public void setUp() throws Exception {
driver = new FirefoxDriver();
baseUrl = "http://ipadress/"; //I am providing an ip adress
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
#Test
public void testTryZencart() throws Exception {
driver.get(baseUrl + "/zencart/index.php?main_page=index&cPath=1_16");
try{
int x = 3;
int y = 0;
driver.navigate().refresh();
while(x<10){
y=y+1;
System.out.println("We have now started the " + y + " iteration, which means that whenever we stop the execution the {$y} iteration was going on.");
driver.findElement(By.xpath("//td/div/div/div/a")).click();
driver.findElement(By.xpath("//td/div/div[2]/div/a")).click();
driver.findElement(By.xpath("//div[2]/div/a[2]")).click();
driver.findElement(By.xpath("//div[2]/div/a[3]")).click();
driver.findElement(By.xpath("//div[12]/div/a[4]")).click();
driver.findElement(By.xpath("//a[5]")).click();
driver.findElement(By.xpath("//a[6]")).click();
driver.findElement(By.xpath("//a[7]")).click();
driver.findElement(By.xpath("//a[8]")).click();
driver.findElement(By.xpath("//a[9]")).click();
driver.navigate().refresh();
}
}
catch(NoSuchElementException e)
{
System.out.println("\nArjun no good!!");
driver.navigate().refresh();
}
}
#After
public void tearDown() throws Exception {
driver.quit();
String verificationErrorString = verificationErrors.toString();
if (!"".equals(verificationErrorString)) {
fail(verificationErrorString);
}
}
private boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
}
private boolean isAlertPresent() {
try {
driver.switchTo().alert();
return true;
} catch (NoAlertPresentException e) {
return false;
}
}
private String closeAlertAndGetItsText() {
try {
Alert alert = driver.switchTo().alert();
String alertText = alert.getText();
if (acceptNextAlert) {
alert.accept();
} else {
alert.dismiss();
}
return alertText;
} finally {
acceptNextAlert = true;
}
}
}
so now I want the execution to go back to try block after firing the exception. Is there anyways to do so.
You can do it in while loop
boolean isSuccessful = false;
while(!isSuccessful){
try{
// do whatever you want
isSuccessful = true;
}catch(Exception e){
// Exception so lets do it again
}
}
Put the try/catch block inside the while loop:
while (x < 10)
{
try
{
...
}
catch (NoSuchElementException e)
{
...
}
}
BTW, you should also increment x inside the loop...
Create a new method with the xpath as argument and with a try-catch block in which you call driver.findElement.
Use this method instead of direct call to driver.findElement.
Bit of logic you can introduce to re-execute your try-catch as example one approach - do-while loop, where check in the loop condition that try is executated or not!
boolean reLoop = false;
do{
try{
// your code
}catch(Exception ex){
// handle your exception
reLoop = true;
}
}while(tryExecuted);
One important thing to consider that is infinite-loop, if your try is getting fail every time, In that specific case, consider the maximum number of try block should execute.
boolean reLoop = false;
int loopMaxCount = 3; // assumed maximum number of re looping
int loopCont = 0;
do{
loopCont++;
try{
// your code
}catch(Exception ex){
// handle your exception
if(loopCont < loopMaxCount) // It blocks infinite looping
reLoop = true;
}
}while(tryExecuted);
There is no way of going back from catch to try block.
You will have to redesign your code - either wrap each findElement() method in separate try/catch blocks or use a loop as advised in other answers. (I guess in your code there will be two loops - second one will iterate through your all xpath arguments like: "//td/div/div/div/a" etc.).

Categories