Assert that a WebElement is not present using Selenium WebDriver with java

Viewed 127480

In tests that I write, if I want to assert a WebElement is present on the page, I can do a simple:

driver.findElement(By.linkText("Test Search"));

This will pass if it exists and it will bomb out if it does not exist. But now I want to assert that a link does not exist. I am unclear how to do this since the code above does not return a boolean.

EDIT This is how I came up with my own fix, I'm wondering if there's a better way out there still.

public static void assertLinkNotPresent (WebDriver driver, String text) throws Exception {
List<WebElement> bob = driver.findElements(By.linkText(text));
  if (bob.isEmpty() == false) {
    throw new Exception (text + " (Link is present)");
  }
}
17 Answers

It looks like findElements() only returns quickly if it finds at least one element. Otherwise it waits for the implicit wait timeout, before returning zero elements - just like findElement().

To keep the speed of the test good, this example temporarily shortens the implicit wait, while waiting for the element to disappear:

static final int TIMEOUT = 10;

public void checkGone(String id) {
    FluentWait<WebDriver> wait = new WebDriverWait(driver, TIMEOUT)
            .ignoring(StaleElementReferenceException.class);

    driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
    try {
        wait.until(ExpectedConditions.numberOfElementsToBe(By.id(id), 0));
    } finally {
        resetTimeout();
    }
}

void resetTimeout() {
    driver.manage().timeouts().implicitlyWait(TIMEOUT, TimeUnit.SECONDS);
}

Still looking for a way to avoid the timeout completely though...

Not an answer to the very question but perhaps an idea for the underlying task:

When your site logic should not show a certain element, you could insert an invisible "flag" element that you check for.

if condition
    renderElement()
else
    renderElementNotShownFlag() // used by Selenium test

Please find below example using Selenium "until.stalenessOf" and Jasmine assertion. It returns true when element is no longer attached to the DOM.

const { Builder, By, Key, until } = require('selenium-webdriver');

it('should not find element', async () => {
   const waitTime = 10000;
   const el = await driver.wait( until.elementLocated(By.css('#my-id')), waitTime);
   const isRemoved = await driver.wait(until.stalenessOf(el), waitTime);

   expect(isRemoved).toBe(true);
});

For ref.: Selenium:Until Doc

The way that I have found best - and also to show in Allure report as fail - is to try-catch the findelement and in the catch block, set the assertTrue to false, like this:

    try {
        element = driver.findElement(By.linkText("Test Search"));
    }catch(Exception e) {
        assertTrue(false, "Test Search link was not displayed");
    }

This is the best approach for me

public boolean isElementVisible(WebElement element) {
    try { return element.isDisplayed(); } catch (Exception ignored) { return false; }
}

For a JavaScript (with TypeScript support) implementation I came up with something, not very pretty, that works:

  async elementNotExistsByCss(cssSelector: string, timeout=100) {
    try {
      // Assume that at this time the element should be on page
      await this.getFieldByCss(cssSelector, timeout);
      // Throw custom error if element s found
      throw new Error("Element found");
    } catch (e) {
      // If element is not found then we silently catch the error
      if (!(e instanceof TimeoutError)) {
        throw e;
      }
      // If other errors appear from Selenium it will be thrown
    }
  }

P.S: I am using "selenium-webdriver": "^4.1.1"

Related