WebDriver: check if an element exists?
JavaTestingWebdriverSelenium WebdriverJava Problem Overview
How to check if an element exist with web driver?
Is using a try catch really the only possible way?
boolean present;
try {
driver.findElement(By.id("logoutLink"));
present = true;
} catch (NoSuchElementException e) {
present = false;
}
Java Solutions
Solution 1 - Java
You could alternatively do:
driver.findElements( By.id("...") ).size() != 0
Which saves the nasty try/catch
p.s.
Or more precisely by @JanHrcek here
!driver.findElements(By.id("...")).isEmpty()
Solution 2 - Java
I agree with Mike's answer but there's an implicit 3 second wait if no elements are found which can be switched on/off which is useful if you're performing this action a lot:
driver.manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS);
boolean exists = driver.findElements( By.id("...") ).size() != 0
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
Putting that into a utility method should improve performance if you're running a lot of tests
Solution 3 - Java
As the comment stated, this is in C# not Java but the idea is the same. I've researched this issue extensively and ultimately the issue is, FindElement always returns an exception when the element doesn't exist. There isn't an overloaded option that allows you to get null or anything else. Here is why I prefer this solution over others.
-
Returning a list of elements then checking if the list size is 0 works but you lose functionality that way. You can't do a .click() on a collection of links even if the collection size is 1.
-
You could assert that the element exists but often that stops your testing. In some cases, I have an extra link to click depending on how I got to that page and I want to click it if it exists or move on otherwise.
-
It's only slow if you don't set the timeout driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(0));
-
It's actually a very simple and elegant once the method is created. By using FindElementSafe instead of FindElement, I don't "see" the ugly try/catch block and I can use a simple Exists method. That would look something like this:
IWebElement myLink = driver.FindElementSafe(By.Id("myId")); if (myLink.Exists) { myLink.Click(); }
Here is how you extend IWebElement & IWebDriver
IWebDriver.FindElementSafe
/// <summary>
/// Same as FindElement only returns null when not found instead of an exception.
/// </summary>
/// <param name="driver">current browser instance</param>
/// <param name="by">The search string for finding element</param>
/// <returns>Returns element or null if not found</returns>
public static IWebElement FindElementSafe(this IWebDriver driver, By by)
{
try
{
return driver.FindElement(by);
}
catch (NoSuchElementException)
{
return null;
}
}
IWebElement.Exists
/// <summary>
/// Requires finding element by FindElementSafe(By).
/// Returns T/F depending on if element is defined or null.
/// </summary>
/// <param name="element">Current element</param>
/// <returns>Returns T/F depending on if element is defined or null.</returns>
public static bool Exists(this IWebElement element)
{
if (element == null)
{ return false; }
return true;
}
You could use polymorphism to modify the IWebDriver class instance of FindElement but that's a bad idea from a maintenance standpoint.
Solution 4 - Java
This works for me every time:
if(!driver.findElements(By.xpath("//*[@id='submit']")).isEmpty()){
//THEN CLICK ON THE SUBMIT BUTTON
}else{
//DO SOMETHING ELSE AS SUBMIT BUTTON IS NOT THERE
}
Solution 5 - Java
I extended Selenium WebDriver implementation, in my case HtmlUnitDriver to expose a method
public boolean isElementPresent(By by){}
like this:
- check if page is loaded within a timeout period.
- Once page is loaded, I lower the implicitly wait time of the WebDriver to some milliseconds, in my case 100 mills, probably should work with 0 mills too.
- call findElements(By), the WebDriver even if will not find the element will wait only the amount of time from above.
- rise back the implicitly wait time for future page loading
Here is my code:
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
public class CustomHtmlUnitDriver extends HtmlUnitDriver {
public static final long DEFAULT_TIMEOUT_SECONDS = 30;
private long timeout = DEFAULT_TIMEOUT_SECONDS;
public long getTimeout() {
return timeout;
}
public void setTimeout(long timeout) {
this.timeout = timeout;
}
public boolean isElementPresent(By by) {
boolean isPresent = true;
waitForLoad();
//search for elements and check if list is empty
if (this.findElements(by).isEmpty()) {
isPresent = false;
}
//rise back implicitly wait time
this.manage().timeouts().implicitlyWait(timeout, TimeUnit.SECONDS);
return isPresent;
}
public void waitForLoad() {
ExpectedCondition<Boolean> pageLoadCondition = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver wd) {
//this will tel if page is loaded
return "complete".equals(((JavascriptExecutor) wd).executeScript("return document.readyState"));
}
};
WebDriverWait wait = new WebDriverWait(this, timeout);
//wait for page complete
wait.until(pageLoadCondition);
//lower implicitly wait time
this.manage().timeouts().implicitlyWait(100, TimeUnit.MILLISECONDS);
}
}
Usage:
CustomHtmlUnitDriver wd = new CustomHtmlUnitDriver();
wd.get("http://example.org");
if (wd.isElementPresent(By.id("Accept"))) {
wd.findElement(By.id("Accept")).click();
}
else {
System.out.println("Accept button not found on page");
}
Solution 6 - Java
Write the following method using Java:
protected boolean isElementPresent(By by){
try{
driver.findElement(by);
return true;
}
catch(NoSuchElementException e){
return false;
}
}
Call the above method during assertion.
Solution 7 - Java
you can do an assertion.
see the example
driver.asserts().assertElementFound("Page was not loaded",
By.xpath("//div[@id='actionsContainer']"),Constants.LOOKUP_TIMEOUT);
you can use this this is native :
public static void waitForElementToAppear(Driver driver, By selector, long timeOutInSeconds, String timeOutMessage) {
try {
WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds);
wait.until(ExpectedConditions.visibilityOfElementLocated(selector));
} catch (TimeoutException e) {
throw new IllegalStateException(timeOutMessage);
}
}
Solution 8 - Java
String link = driver.findElement(By.linkText(linkText)).getAttribute("href")
This will give you the link the element is pointing to.
Solution 9 - Java
With version 2.21.0 of selenium-java.jar you can do this;
driver.findElement(By.id("...")).isDisplayed()
Solution 10 - Java
As I understand it, this is the default way of using the web driver.