9

I am new to Selenium webdriver, maybe this question is obvious. I am after situation like this:

If the element exists, click it and go back to index page:

driver.findElement(By.id("...."])).click();

if doesn't exit, skip it and go back to index page. The test still goes on without any exception thrown.

I know one solution to this:

driver.findElements( By.id("...") ).size() != 0

so i tried:

if(driver.findElements(By.id("....")).size() > 0)
    {
        driver.findElement(By.id("....")).click();
        driver.findElement(By.cssSelector("...")).click();
    } 
else
    {
        driver.findElement(By.cssSelector("....")).click();
    }

This turned out really ugly though because if I have 10 elements to verify, this IF condition needs to be written 10 times.

Any workaround to make it neat?

Eugene S
  • 6,709
  • 8
  • 57
  • 91
user1282634
  • 131
  • 1
  • 6

3 Answers3

1

There are ways to find elements without throwing exceptions by using try-catch conditions inside of loops. For example, this method I wrote (which can be simplified depending on what you use if for) will return a WebElement and it makes sure that it's clickable before returning it to you:

public static WebElement getElementByLocator( By locator ) {
  driver.manage().timeouts().implicitlyWait( 5, TimeUnit.SECONDS );
  WebElement we = null;
  boolean unfound = true;
  int tries = 0;
  while ( unfound && tries < 10 ) {
    tries += 1;
    try {
      we = driver.findElement( locator );
      unfound = false; // FOUND IT
    } catch ( StaleElementReferenceException ser ) {                        
      unfound = true;
    } catch ( NoSuchElementException nse ) {                        
      unfound = true;
    } catch ( Exception e ) {
      staticlogger.info( e.getMessage() );
    }
  } 
  driver.manage().timeouts().implicitlyWait( DEFAULT_IMPLICIT_WAIT, 
      TimeUnit.SECONDS );
  return we;
}
djangofan
  • 28,471
  • 61
  • 196
  • 289
1

Solution could be many but that may hinder your architecture.

So easiest solution could be as follows:

Just create a method like optionalClick() in some utility class or somewhere with the arguments as:

  1. locator_keyword: {values : id or cssSelector or xpath etc}
  2. locator : {values : "q" }

Steps in method:

  1. Get element based on the locator_keyword and locator
  2. Check if element is there and click it
  3. Otherwise don't do anything

This method can be used as a generic kind of thing for any type of objects.

Eugene S
  • 6,709
  • 8
  • 57
  • 91
Nayan
  • 316
  • 3
  • 2
  • thanks for the feedback!! another issue is, using if syntax is horribly slow...is there any way to make it faster? – user1282634 Mar 21 '12 at 10:56
  • Ok so don't use if statement at all Instead of that use try/catch block as folows: try{WebElement elemnt = driver.findElement(By.ID(".."));elemnt.click();}catch(Exception e){//Nothing to do} – Nayan Mar 22 '12 at 05:20
0

Thanks for the pointer on using findelements. I think you'll also need wait logic though if you dont want it to return too early.

here is my solution in c#.

It basically reimplements the wait logic in the selenium library - unfortunately the method that does the waiting isnt exposed (annoyingly it also rethrows exceptions the wrong way and loses the stack traces!).

You'd probably have to modify it a little for java - not sure what the selenium API is there when you cant just pass around functions.

Wait reimplementation:

    private IWebElement WaitAndSeeIf(Func<IWebElement> canGet)
    {
        var end = DateTime.Now.AddSeconds(1);

        IWebElement element;
        while (true)
        {
            element = canGet();

            if (element != null)
                break;

            var time = DateTime.Now;
            if (time > end)
                break;

            Thread.Sleep(200);
        }
        return element;
    }

calling code:

        var dashboardButton = WaitAndSeeIf(() =>
                                               {
                                                   var elements = Driver.FindElements(By.XPath("//button[contains(.//*,'Dashboard')]"));
                                                   return elements.Any() ? elements.Single() : null;
                                               });

So far I've found this useful in a couple of places (checking for the presence of dialogs in extjs etc) but have yet had the need to muck around and make it configurable. I supppose the nicest thing to do would be to have it take the implicit wait time as mentioned in the other answer.

Community
  • 1
  • 1
JonnyRaa
  • 7,559
  • 6
  • 45
  • 49