3

I have created the following method:

public void waitAndClickElement(WebElement element) throws InterruptedException {
    try {
        Boolean elementPresent = this.wait.until(ExpectedConditions.elementToBeClickable(element)).isEnabled();
        if (elementPresent == true && element.isDisplayed()) {
            element.click();
            System.out.println("Clicked on the element: " + element.getText());
        }
    } catch (StaleElementReferenceException elementUpdated) {
        Boolean elementPresent = wait.until(ExpectedConditions.stalenessOf(element));
        if (elementPresent == true) {
            WebElement staleElement = element;
            staleElement.click();
            System.out.println("Clicked on the 'Stale' element: " + element.getText());
        }
    } catch (NoSuchElementException e) {
        System.out.println("Exception! - Could not click on the element: " + element.getText() + ", Exception: "+ e.toString());
        throw (e);
    } finally {
    }
}

But I Still seem to get the following exception below:

Expected condition failed: waiting for element (Proxy element for: DefaultElementLocator 'By.xpath: //a[text()='Exchange Now »']') to become stale (tried for 20 second(s) with 500 MILLISECONDS interval) enter image description here

But the same method will work on let's say 18 out of 20 builds, any ideas?

thanks for you help

Sanchit Patiyal
  • 4,910
  • 1
  • 14
  • 31
Gbru
  • 1,065
  • 3
  • 24
  • 56
  • Instead of all of your logic in your `catch (StaleElementReferenceException)` block, why not just call `waitAndClickElement(element)` again? Although this depends on how you are creating the `WebElement`, if you're using a cached lookup it'll always be stale, but if you're using a method where it's being found when used, like with `FindBy`'s, it'll keep trying to click until it's not stale. – mrfreester Feb 10 '17 at 20:49

2 Answers2

1

If you change site with another driver.get("http://completely.different.site.com/");, this element will be stale (no more in DOM). Staleness means that the element in DOM is not accessible.

Grzegorz Górkiewicz
  • 4,496
  • 4
  • 22
  • 38
  • thanks, but most of my test executions pass with the same tests its only a the odd time this error will appear for example 3 builds will fail out of 20. – Gbru Feb 08 '17 at 16:47
  • Stale element is never present. So there is something wrong here: `Boolean elementPresent = wait.until(ExpectedConditions.stalenessOf(element));`, depending on what you want to do. – Grzegorz Górkiewicz Feb 08 '17 at 16:52
  • its just weird because even with the listed method the element still seems to be stale – Gbru Feb 08 '17 at 16:53
  • I'd rather go for a loop with try-catch like [this](http://stackoverflow.com/a/7474518/4280359). Still not clear, what you want to achieve. – Grzegorz Górkiewicz Feb 08 '17 at 16:57
  • thanks @Grzegorz Górkiewicz i need to know why when clicking on the intended element my code seems to fail only on a small manority of test cases when uses the same method for all test cases – Gbru Feb 08 '17 at 17:07
  • please see the above comment – Gbru Feb 08 '17 at 17:07
1

The direct answer to your question is that you are waiting for an already stale element to become stale. I'm not sure what your intent was there.

Your function is overly complex and won't work as you think it might.

If an element is clickable it's also enabled and displayed, so you don't need to check all three. If the element is throwing a StaleElementReferenceException, it's not going to become "unstale."

I would recommend you replace your current function with the below.

public void waitAndClickElement(By locator)
{
    try
    {
        this.wait.until(ExpectedConditions.elementToBeClickable(locator)).click();
    }
    catch (TimeoutException e)
    {
        System.out.println("Count not click element <" + locator.toString() + ">");
    }
}

Pass the locator instead of the element instead of the element itself, that will simplify a lot of things. If the element exists and is clickable, it will be clicked. If it does not exist or never becomes clickable, it will throw a TimeoutException which you can catch.

Also, writing element.toString() is going to write some ID for the element which is not going to be human readable or meaningful. You're better off to write locator.toString() which will return the type of locator, e.g. By.cssSelector: #hplogo.

JeffC
  • 22,180
  • 5
  • 32
  • 55
  • thanks so much again for you help, do you think i should add an extra precaution and try another attempt at clicking the object? – Gbru Feb 09 '17 at 08:59
  • No. I would wait as much time as you think is necessary once. Waiting twice doesn't accomplish anything. For example, waiting once for 30s is the same as waiting twice for 15s. It just makes more sense, is more clear, and is less code to wait once for 30s. – JeffC Feb 09 '17 at 14:03
  • thanks so much for your help again, would it be better to use 'Exception e' inside a try and catch block instead? – Gbru Feb 09 '17 at 14:29
  • or use: Throwable? – Gbru Feb 09 '17 at 14:46
  • The best practice is to only catch what you want to handle. In this case, I would only handle the `TimeoutException` because that's what I would expect. It really depends on what you want to do with other exceptions you might catch here. – JeffC Feb 09 '17 at 16:08
  • thanks would you be able to adice on the following? http://stackoverflow.com/questions/42142132/why-dosnt-my-method-catch-my-timeout-exception-and-print-to-console – Gbru Feb 09 '17 at 16:39
  • If you found this answer useful, please upvote it. If it answered your question, please accept it as the answer. – JeffC Feb 09 '17 at 17:17
  • I put an answer in your other question. – JeffC Feb 09 '17 at 17:22