44

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)");
  }
}
Paul D. Waite
  • 96,640
  • 56
  • 199
  • 270
True_Blue
  • 1,387
  • 2
  • 10
  • 13

17 Answers17

45

It's easier to do this:

driver.findElements(By.linkText("myLinkText")).size() < 1
Sarhanis
  • 1,577
  • 1
  • 12
  • 19
  • Thanks, this seems the best approach even for non-Java bindings. – d.k Mar 01 '13 at 13:20
  • 4
    This is by far the better answer to avoid having the exception thrown by findElement. – DMart Jun 12 '17 at 19:41
  • 2
    Good solution. However, this tries for `timeout` seconds to find the element. So you might want to set (and then reset) the drivers timeout. Perhaps in a method. – DerMike Apr 20 '18 at 09:09
12

I think that you can just catch org.openqa.selenium.NoSuchElementException that will be thrown by driver.findElement if there's no such element:

import org.openqa.selenium.NoSuchElementException;

....

public static void assertLinkNotPresent(WebDriver driver, String text) {
    try {
        driver.findElement(By.linkText(text));
        fail("Link with text <" + text + "> is present");
    } catch (NoSuchElementException ex) { 
        /* do nothing, link is not present, assert is passed */ 
    }
}
Sergii Pozharov
  • 17,366
  • 4
  • 29
  • 30
  • 1
    nice idea. Though strange there isn't a mechanism to deal with this kind of assertion already available in Web Driver – DevDave Jul 10 '12 at 10:31
  • 1
    to make this more genetic you could pass in a By.id/cssSelector etc. instead of the String Text. – Dave Jan 09 '13 at 20:06
  • 3
    While this works I don't think it is ideal. When you have the webdriver configured with an implicit wait the test will become very slow. – Hugo Apr 23 '13 at 06:08
  • 3
    this is really unrecommended, it will slow down you test and can be source of hard-to-find bugs: - if the element is not there (the most common) your test will wait for the implicit wait every time - if the element is there but it's disappearing, the implicit wait will not be used, and your test will fail immediately, a false positive. – Benja Jul 15 '15 at 23:33
  • Due to implicit wait issue this needs to be downvoted hard. – Ben George Dec 23 '15 at 06:09
  • @Dave you cant assert on an absent element without knowing its id or cssSelector. This answer addresses the question appropriately. – Sanu Jun 22 '22 at 02:17
  • @sanu I believe what I was thinking was the function could take the data type `findElement` is expecting instead of a string, that way you can use this more generally. Whether it's by linkText, by ID, by cssSelector, etc. But that was 9 years ago, who knows what I was thinking. – Dave Aug 04 '22 at 12:47
11

Not Sure which version of selenium you are referring to, however some commands in selenium * can now do this: http://release.seleniumhq.org/selenium-core/0.8.0/reference.html

  • assertNotSomethingSelected
  • assertTextNotPresent

Etc..

Andre
  • 2,449
  • 25
  • 24
9

There is an Class called ExpectedConditions:

  By loc = ...
  Boolean notPresent = ExpectedConditions.not(ExpectedConditions.presenceOfElementLocated(loc)).apply(getDriver());
  Assert.assertTrue(notPresent);
Fabian Barney
  • 14,219
  • 5
  • 40
  • 60
  • For some reason this does not work for me (at least in Selenium `2.53.0`). Instead I had to use the presence of **all** elements like this: `ExpectedConditions.not(ExpectedConditions.presenceOfAllElementsLocatedBy(locator)));`. – stiemannkj1 Jun 20 '17 at 16:09
  • Using some latest Versions of Selenium there is now a Methode called `invisibilityOfElementLocated` for this check. Usage is straight forward: `webDriver.wait(ExpectedConditions.invisibilityOfElementLocated(xpath("")))` – Waize Mar 11 '19 at 11:20
4

Try this -

private boolean verifyElementAbsent(String locator) throws Exception {
    try {
        driver.findElement(By.xpath(locator));
        System.out.println("Element Present");
        return false;

    } catch (NoSuchElementException e) {
        System.out.println("Element absent");
        return true;
    }
}
some_other_guy
  • 3,364
  • 4
  • 37
  • 55
  • I suspect that this won't work. I use Perl bindings and tried to use this approach and the problem was that the driver instance died when no element found. Not sure whether the same happens with Java. – d.k Mar 01 '13 at 13:07
  • How can you findElement using a locator for which a locator is not present since the element is not present. Doesnt make sense – Sanu Jun 22 '22 at 02:18
4

With Selenium Webdriver would be something like this:

assertTrue(!isElementPresent(By.linkText("Empresas en Misión")));
Andre Silva
  • 4,782
  • 9
  • 52
  • 65
2
boolean titleTextfield = driver.findElement(By.id("widget_polarisCommunityInput_113_title")).isDisplayed();
assertFalse(titleTextfield, "Title text field present which is not expected");
Ripon Al Wasim
  • 36,924
  • 42
  • 155
  • 176
2

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...

df778899
  • 10,703
  • 1
  • 24
  • 36
1

You can utlilize Arquillian Graphene framework for this. So example for your case could be

Graphene.element(By.linkText(text)).isPresent().apply(driver));

Is also provides you bunch of nice API's for working with Ajax, fluent waits, page objects, fragments and so on. It definitely eases a Selenium based test development a lot.

Petr Mensik
  • 26,874
  • 17
  • 90
  • 115
0

For node.js I've found the following to be effective way to wait for an element to no longer be present:

// variable to hold loop limit
    var limit = 5;
// variable to hold the loop count
    var tries = 0;
        var retry = driver.findElements(By.xpath(selector));
            while(retry.size > 0 && tries < limit){
                driver.sleep(timeout / 10)
                tries++;
                retry = driver.findElements(By.xpath(selector))
            }
QualiT
  • 1,934
  • 2
  • 18
  • 37
0

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
DerMike
  • 15,594
  • 13
  • 50
  • 63
0

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

Miroslav Savovski
  • 2,300
  • 2
  • 10
  • 12
0

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");
    }
Amr El Massry
  • 371
  • 3
  • 4
0

This is the best approach for me

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

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"

ka_lin
  • 9,329
  • 6
  • 35
  • 56
-1

findElement will check the html source and will return true even if the element is not displayed. To check whether an element is displayed or not use -

private boolean verifyElementAbsent(String locator) throws Exception {

        boolean visible = driver.findElement(By.xpath(locator)).isDisplayed();
        boolean result = !visible;
        System.out.println(result);
        return result;
}
some_other_guy
  • 3,364
  • 4
  • 37
  • 55
-1

For appium 1.6.0 and above

    WebElement button = (new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(By.xpath("//XCUIElementTypeButton[@name='your button']"))));
    button.click();

    Assert.assertTrue(!button.isDisplayed());
DrPatience
  • 1,736
  • 2
  • 15
  • 33