0

I have a table with several rows. Some of these rows may have a specific element and others may not. For sure some will and some won't.

I find the row and have it into a WebElement. Now to see whether an element is there I do the following (assume xp = ".//someelement)

 List<WebElement> eles = row.findElements(By.xpath(xp)); 
 if (eles.size() == 0) {
    // element is not there
 } else {
   // element is there
 }

This is fine when the element is present. When it is not, it takes like 30 seconds or a minute to figure out that it is not there. If called often this can really slow down the test. I can do

 try {
    WebElement ele = row.findElement(by.xpath(xp));
 } catch (Exception ex) {
   // element is not there
 }

using a more detailed Exception. This works fine too but same problem. It waits a minute or half a minute.

Is there a way to check more quickly whether an element is present or not? If it were relative to driver (driver.findElementBy()) instead of an element (row.findElementBy()) I think I might know how to do it.

This is Java.

Tony
  • 1,127
  • 1
  • 18
  • 29
  • Check out WebDriverWait http://stackoverflow.com/questions/11736027/webdriver-wait-for-element-using-java – pbuck Apr 20 '17 at 20:25

2 Answers2

0

In your first example where you have a List of Elements you are not trying to locate one element; but several (let's say a collection of rows instead of one row). The second element ele is finding (or trying to find) a specific item (let's say 1 row). Hence, ideally you should say in your comments that some elementS were not there for eles . Nevertheless, the time issue is probably down to an implicit or explicit wait. Read here for more.

I prefer the first way where you check for a collection of elements (so you can aim it at a xpath and find all the tags included (or none at all). Ideally though you should go for an explicit wait.

Here is the method for waiting, it will return true/or false based on if the element was present during the polling time (10sec for example); worth noting that if the element is found as present earlier than the 10sec limit the loop will break and will return true. Of course you can play with timeOut to achieve the desired result; don't go to fast though (like 2 sec) otherwise you are risking your test occasionally failing because the tables were not loaded yet:

public boolean waitForElement(String elementXpath, int timeOut) {

    try{                    
    WebDriverWait wait = new WebDriverWait(driver, timeOut); 
    boolean elementPresent=wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(elementXpath)).isDisplayed());

    System.out.printf("%nElement is present [T/F]..? ")+elementPresent;
    }        
    catch(TimeoutException e1){e1.printStackTrace();elementPresent=false;}          

    return elementPresent;   
 }

I'm guessing that you are already using an explicit wait of 30sec for all of your findElement attempts hence the discrepancy.

Hope the above helps,

Best of luck!

Xwris Stoixeia
  • 1,831
  • 21
  • 22
  • How do I pass the row element to the wait? Can you say new WebDriverEwait(someElement, 30)? – Tony Apr 20 '17 at 20:59
  • Yes, almost there! Just use the method with the row's xpath. so you can type: waitForElement("//div[@class=''row_xpath'//td//tr", 10) – Xwris Stoixeia Apr 21 '17 at 08:31
  • But instead of typing a timeout everytime; you are better off storing it in a var (timeout) and change it only on exceptional circumstances where you know you need to wait more. – Xwris Stoixeia Apr 21 '17 at 08:32
  • Hi Tony, if I helped, can you please upvote my answer? Thanks in advance! :) – Xwris Stoixeia Apr 21 '17 at 14:32
0

Another option is to use WebDriverWait (explicit waits) rather than implicit ones.

This basically makes it so your tests will only wait a long time when you tell them too, otherwise they'll instantly fail if they don't find the elements you're looking for.

Adapted from slide52 of tourdedave's slideshare


// Use this class whenever you have to access the driver
// And you should only have to setDriver in a BeforeMethod when setting up.
// This method shows how to do it with a single browser
// This could be converted quite easily to threadlocals for parallel test runs 
public class DriverManager {
private final WebDriver driver;
public static WebDriver getDriver() {
  return driver;
}
public static setDriver(WebDriver driver) {
  DriverManager.driver = driver;
}

public class WaitUntil {
public static Boolean displayed(By locator, Integer... timeout) {
    try {
        waitFor(ExpectedConditions.visibilityOfElementLocated(locator),
        (timeout.length = 0 : null ? timeout[0];    
    } catch (TimeoutException exception) {
        return false;
    }
    return true;
}
// add additional methods you want to wait for
// Look at the source of the ExpectedConditions class to see how to create 
// your own
// e.g. presence of element
// number of results from locator changes
// element done moving
// url changes, etc.


private static void waitFor(ExpectedCondition<WebElement> condition, Integer timeout) {
    timeout = timeout != null ? timeout[0] : 5; //default timeout if no value given
    WebDriverWait wait = new WebDriverWait(driver, timeout);
    wait.until(condition);
}

}

Then in any class you can By submitButtonBy = By.cssSelector(".submit); use WaitUntil.displayed(submitButtonBy); And it will wait for 5 seconds. If you want to wait for 10: use WaitUntil.displayed(submitButtonBy, 10);

The nice thing about making a class with a bunch of methods like this is it's easy to add additional exceptions so you can choose to return false if there's a stale element or something else, rather than have to deal with a try catch in page classes or test classes.

James Affleck
  • 293
  • 1
  • 5
  • 10