Skip to main content
SeleniumDecoded

Check Whether an Element Exists Without an Exception

Test for presence, visibility or absence of an element cleanly, without try/catch and without waiting the implicit timeout.

Stable Verified against Selenium 4.48.0

Problem

You want to assert that an error banner is not shown, or branch on whether an optional element is present. findElement throws when nothing matches, and wrapping it in try/catch is ugly and slow if an implicit wait is set.

Solution

Use findElements (plural): it returns an empty list instead of throwing. Check the count, and for visibility filter by isDisplayed.

Presence and visibility checks
Selenium 3 & 4 Stable
public static boolean isPresent(SearchContext ctx, By by) {
return !ctx.findElements(by).isEmpty();
}
public static boolean isVisible(SearchContext ctx, By by) {
return ctx.findElements(by).stream().anyMatch(WebElement::isDisplayed);
}
// Assert an error is NOT shown
assertFalse(isVisible(driver, By.cssSelector(".alert-error")));
// Branch on an optional element
if (isPresent(driver, By.id("cookie-banner"))) {
driver.findElement(By.cssSelector("#cookie-banner button.accept")).click();
}
def is_present(ctx, locator):
return len(ctx.find_elements(*locator)) > 0
def is_visible(ctx, locator):
return any(el.is_displayed() for el in ctx.find_elements(*locator))
# Assert an error is NOT shown
assert not is_visible(driver, (By.CSS_SELECTOR, ".alert-error"))
# Branch on an optional element
if is_present(driver, (By.ID, "cookie-banner")):
driver.find_element(By.CSS_SELECTOR, "#cookie-banner button.accept").click()
const isPresent = async (ctx, locator) => (await ctx.findElements(locator)).length > 0;
async function isVisible(ctx, locator) {
for (const el of await ctx.findElements(locator)) {
if (await el.isDisplayed()) return true;
}
return false;
}
assert.strictEqual(await isVisible(driver, By.css('.alert-error')), false);
if (await isPresent(driver, By.id('cookie-banner'))) {
await driver.findElement(By.css('#cookie-banner button.accept')).click();
}
public static bool IsPresent(ISearchContext ctx, By by) => ctx.FindElements(by).Count > 0;
public static bool IsVisible(ISearchContext ctx, By by) => ctx.FindElements(by).Any(e => e.Displayed);
Assert.That(IsVisible(driver, By.CssSelector(".alert-error")), Is.False);
if (IsPresent(driver, By.Id("cookie-banner")))
driver.FindElement(By.CssSelector("#cookie-banner button.accept")).Click();

Why It Works

findElements is specified to return an empty collection when nothing matches; there is no exception path. isDisplayed on each match covers elements that exist but are hidden by CSS.

Gotchas

  • With an implicit wait configured, findElements still waits the full timeout before returning empty. Keep the implicit wait at zero; this is one of the main reasons.
  • A negative assertion right after an action can pass because the banner has not appeared yet. When asserting absence after an action, first wait for the positive signal that the action completed (a success message, a URL change), then check the negative.
  • For “wait until it disappears”, use an explicit wait with invisibilityOfElementLocated rather than this snapshot check.

Learn the theory