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

17

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)");
  }
}
Dividers answered 19/7, 2010 at 17:17 Comment(0)
N
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..

Normand answered 17/2, 2012 at 1:29 Comment(2)
Link broken nowDogged
The OPs original problem seems to indicate an exception was thrown when the element isn't present.Conversationalist
K
45

It's easier to do this:

driver.findElements(By.linkText("myLinkText")).size() < 1
Karlise answered 30/11, 2012 at 14:34 Comment(3)
Thanks, this seems the best approach even for non-Java bindings.Choreodrama
This is by far the better answer to avoid having the exception thrown by findElement.Conversationalist
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.Powers
B
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 */ 
    }
}
Blenheim answered 20/7, 2010 at 9:1 Comment(7)
nice idea. Though strange there isn't a mechanism to deal with this kind of assertion already available in Web DriverOrtolan
to make this more genetic you could pass in a By.id/cssSelector etc. instead of the String Text.Jackijackie
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.Peroxy
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.Bjork
Due to implicit wait issue this needs to be downvoted hard.Ens
@Jackijackie you cant assert on an absent element without knowing its id or cssSelector. This answer addresses the question appropriately.Phaedra
@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.Jackijackie
N
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..

Normand answered 17/2, 2012 at 1:29 Comment(2)
Link broken nowDogged
The OPs original problem seems to indicate an exception was thrown when the element isn't present.Conversationalist
C
9

There is an Class called ExpectedConditions:

  By loc = ...
  Boolean notPresent = ExpectedConditions.not(ExpectedConditions.presenceOfElementLocated(loc)).apply(getDriver());
  Assert.assertTrue(notPresent);
Cathicathie answered 10/6, 2013 at 14:35 Comment(2)
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)));.Standridge
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("<xpath expression>")))Deconsecrate
F
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;
    }
}
Fragonard answered 1/10, 2012 at 7:1 Comment(2)
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.Choreodrama
How can you findElement using a locator for which a locator is not present since the element is not present. Doesnt make sensePhaedra
K
4

With Selenium Webdriver would be something like this:

assertTrue(!isElementPresent(By.linkText("Empresas en Misión")));
Karachi answered 3/10, 2013 at 22:52 Comment(1)
Better just assertFalse(...)Powers
M
2
boolean titleTextfield = driver.findElement(By.id("widget_polarisCommunityInput_113_title")).isDisplayed();
assertFalse(titleTextfield, "Title text field present which is not expected");
Marston answered 31/7, 2012 at 6:28 Comment(0)
C
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...

Choosy answered 4/10, 2017 at 21:18 Comment(0)
P
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.

Philistine answered 28/6, 2013 at 9:32 Comment(0)
C
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))
            }
Civilian answered 25/5, 2016 at 7:7 Comment(2)
You code can fall into infinite loop if element doesn't dissapearHanford
An excellent point. Fixed that. I'm not going to add error handling.Civilian
P
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
Powers answered 20/9, 2018 at 13:47 Comment(0)
P
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

Pinup answered 1/5, 2019 at 7:59 Comment(0)
F
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");
    }
Fernferna answered 7/5, 2020 at 4:42 Comment(0)
F
0

This is the best approach for me

public boolean isElementVisible(WebElement element) {
    try { return element.isDisplayed(); } catch (Exception ignored) { return false; }
}
Filide answered 31/1, 2022 at 17:29 Comment(0)
H
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"

Hot answered 15/3, 2022 at 11:15 Comment(0)
F
-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;
}
Fragonard answered 1/10, 2012 at 9:23 Comment(0)
S
-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());
Spillage answered 29/11, 2016 at 9:43 Comment(1)
better directly assertFalse(...)Powers

© 2022 - 2024 — McMap. All rights reserved.