Thunderforge
Thunderforge

Reputation: 20595

How to wait until an element no longer exists in Selenium

I am testing a UI in which the user clicks a delete button and a table entry disappears. As such, I want to be able to check that the table entry no longer exists.

I have tried using ExpectedConditions.not() to invert ExpectedConditions.presenceOfElementLocated(), hoping that it would mean "expect that there is not a presence of the specified element". My code is like so:

browser.navigate().to("http://stackoverflow.com");
new WebDriverWait(browser, 1).until(
        ExpectedConditions.not(
                ExpectedConditions.presenceOfElementLocated(By.id("foo"))));

However, I found that even doing this, I get a TimeoutExpcetion caused by a NoSuchElementException saying that the element "foo" does not exist. Of course, having no such element is what I want, but I don't want an exception to be thrown.

So how can I wait until an element no longer exists? I would prefer an example that does not rely on catching an exception if at all possible (as I understand it, exceptions should be thrown for exceptional behavior).

Upvotes: 57

Views: 113750

Answers (8)

Ilnarello
Ilnarello

Reputation: 29

You can use the following logic:

C# code sinppet:

//wait is the instance of WebDriverWait
wait.Until(driver => driver.FindElements(By.Xpath("your element expath")).Count == 0);    

Notice how I use FindElements that does NOT throw NoSuchElementException which is swallowed by Until() function. So when element is gone collection size is zero.

Upvotes: 0

Trev14
Trev14

Reputation: 4116

Good news, it's built in now (I'm using Node.js in 2021)

It looks like elementIsNotVisible has been added to until after the previous answers were given. I'm using selenium webdriver 4.0.0-beta.3

Check it out:

const timeout = 60 * 1000; // 60 seconds
const element = await driver.findElement(By.id(elementId));

// this is the important line 
await driver.wait(until.elementIsNotVisible(element), timeout);

Upvotes: 1

Vivek Singh
Vivek Singh

Reputation: 3649

You can also use -

new WebDriverWait(driver, 10).until(ExpectedConditions.invisibilityOfElementLocated(locator));

If you go through the source of it you can see that both NoSuchElementException and staleElementReferenceException are handled.

/**
   * An expectation for checking that an element is either invisible or not
   * present on the DOM.
   *
   * @param locator used to find the element
   */
  public static ExpectedCondition<Boolean> invisibilityOfElementLocated(
      final By locator) {
    return new ExpectedCondition<Boolean>() {
      @Override
      public Boolean apply(WebDriver driver) {
        try {
          return !(findElement(locator, driver).isDisplayed());
        } catch (NoSuchElementException e) {
          // Returns true because the element is not present in DOM. The
          // try block checks if the element is present but is invisible.
          return true;
        } catch (StaleElementReferenceException e) {
          // Returns true because stale element reference implies that element
          // is no longer visible.
          return true;
        }
      }

Upvotes: 77

Huy H&#243;m Hỉnh
Huy H&#243;m Hỉnh

Reputation: 617

I don't know why but ExpectedConditions.invisibilityOf(element) is the only work for me while ExpectedConditions.invisibilityOfElementLocated(By), !ExpectedConditions.presenceOfElementLocated(By) ... not. Try it!

Hope this help!

Upvotes: 2

Abhinav Saxena
Abhinav Saxena

Reputation: 3924

I found a workaround to fix this for me in efficient way, used following C# code to handle this, you may convert it to Java

    public bool WaitForElementDisapper(By element)
    {
        try
        {
            while (true)
            {
                try
                {
                    if (driver.FindElement(element).Displayed)
                        Thread.Sleep(2000);
                }
                catch (NoSuchElementException)
                {
                    break;
                }
            }
            return true;
        }
        catch (Exception e)
        {
            logger.Error(e.Message);
            return false;
        }
    }

Upvotes: 0

Nagaraju
Nagaraju

Reputation: 21

// pseudo code
public Fun<driver,webelement> ElemtDisappear(locator)
{
    webelement element=null;
    iList<webelement> elemt =null;
    return driver=>
    {
    try
    {
    elemt = driver.findelements(By.locator);
    if(elemt.count!=0)
    {
    element=driver.findelement(By.locator);
    }
    }
    catch(Exception e)
    {
    }
    return(elemnt==0)?element:null;
};

// call function
public void waitforelemDiappear(driver,locator)
{
    webdriverwaiter wait = new webdriverwaiter(driver,time);
    try
    {
    wait.until(ElemtDisappear(locator));
    }
    catch(Exception e)
    {
    }
}

As findelement throws exception on element unaviability.so i implemented using findelements. please feel free to correct and use it as per your need.

Upvotes: 0

alecxe
alecxe

Reputation: 474161

The solution would still rely on exception-handling. And this is pretty much ok, even standard Expected Conditions rely on exceptions being thrown by findElement().

The idea is to create a custom Expected Condition:

  public static ExpectedCondition<Boolean> absenceOfElementLocated(
      final By locator) {
    return new ExpectedCondition<Boolean>() {
      @Override
      public Boolean apply(WebDriver driver) {
        try {
          driver.findElement(locator);
          return false;
        } catch (NoSuchElementException e) {
          return true;
        } catch (StaleElementReferenceException e) {
          return true;
        }
      }

      @Override
      public String toString() {
        return "element to not being present: " + locator;
      }
    };
  }

Upvotes: 5

Saifur
Saifur

Reputation: 16201

Why don't you simply find the size of elements. We know the the collection of elements' size would be 0 if element does not exist.

if(driver.findElements(By.id("foo").size() > 0 ){
    //It should fail
}else{
    //pass
}

Upvotes: 3

Related Questions