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 shownassertFalse(isVisible(driver, By.cssSelector(".alert-error")));
// Branch on an optional elementif (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 shownassert not is_visible(driver, (By.CSS_SELECTOR, ".alert-error"))
# Branch on an optional elementif 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,
findElementsstill 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
invisibilityOfElementLocatedrather than this snapshot check.