How to check if an Element exists, when using Page Objects with webdriver.
So far I am doing it this way.
DefaultPage defaultPage = PageFactory.initElements(this.driver,
DefaultPage.class);
assertTrue(defaultPage.isUserCreateMenuLinkPresent());
Page Object:
public class DefaultPage {
#FindBy(id = "link_i_user_create")
private WebElement userCreateMenuLink;
public boolean isUserCreateMenuLinkPresent() {
try {
this.userCreateMenuLink.getTagName();
return true;
} catch (NoSuchElementException e) {
return false;
}
}
}
But I can not believe that this try/catch is the way one should do it. So what would be a better way to check if the elements exits (with using Page Objects)?
The problem is the pattern itself. It uses #FindBy annotation (used by PageFactory to init the fields that must be wrapped by Proxy) that replaces the standard elements with their proxy instances which contain InvocationHandler.
Each time you try to access a field, annotated with #FindBy, the invocation handler tries to find the element using the default ElementLocator.The problem is that the ElementLocator.findElement() method throws an TimeoutException / NoSuchElementException if there are no elements presented in the DOM.
public WebElement findElement(SearchContext context) {
List<WebElement> allElements = findElements(context);
if (allElements == null || allElements.isEmpty())
throw new NoSuchElementException("Cannot locate an element using "
+ toString());
return allElements.get(0);
}
Therefore, each time you need to check whether an element is displayed or not you have to search for a List of elements and check its size.
#FindBy(css = "div.custom")
private List<WebElement> elements
...
public isElementPresented(){
return elements != null && elements.size > 0
}
Another way to solve this problem is to create your own implementation of LocatingElementHandler and ElementLocator
So, if you need your own isDisplayed() method to return false instead of Exception, you have to replace the findElement() method in ElementLocator with something like that:
...
List<WebElement> elements = searchContext.findElements(by)
if(elements != null && elements.size() > 0){
List<WebElement> visibleElements = []
elements.each {
if(it.displayed){
visibleElements.add(it)
}
}
if(visibleElements.size() > 0){
return visibleElements.get(0)
}
}
return null
...
And add new conditions to LocatingElementHandler.invoke()
Something like:
element = locator.findElement()
if(element == null){
if(method.name == "isDisplayed"){
return false
}
}
Webdriver is designed to throw an exception if an element is not found, So there aren't any methods to verify presence of an element in Webdriver.
Check this - http://groups.google.com/group/webdriver/browse_thread/thread/909a9b6cb568e341
#Ralph: I do it the same way: try/catch. I've never found another way.
You could swap out the try/catch block in a super class and design it generic. In other words: You could write a method which expects an object of type WebElement. This method contains the try/catch block and return true/false...
So I wrote the following public method in the test framework's super class and am now able to use it in every page object:
public boolean isElementExisting(WebElement we) {
try {
we.isDisplayed();
return true;
} catch(NoSuchElementException e) {
LOGGER.severe("Element does not exist.");
return false;
}
}
I don't know why this is not implemented in WebDriver...
Otherwise you could use WebDriverWait.
I'm using this pattern, works fine for me:
public void login()
{
if (!loginButton.isDisplayed())
{
throw new IllegalStateException("Login button is not displayed!");
} else
{
loginButton.click();
}
}
or:
public boolean loginButtinIsDisplayed() {
try {
this.loginButton.getTagName();
return true;
} catch (NoSuchElementException e) {
e.printStackTrace();
return false;
}
}
I recently came across this old post and believe I've found one solution.
I was testing a page that had an Add User button. When the button was clicked, various editable text fields appeared (for First Name, Last Name, Email, etc..) and a single dropdown.
When a Cancel button was clicked, the fields disappeared and no longer existed. Using WebDriverWait with ExpectedConditions.visibilityOf() would not work since the elements no longer existed in the DOM.
I found that #FindAll was a solution for me, though I must admit my test ran noticeably slow at the my List assertion.
For your code, something like this:
public class DefaultPage {
#FindAll({#FindBy(id = "link_i_user_create")}) List<WebElement> userCreateMenuLink;
public boolean isUserCreateMenuLinkPresent() {
if (this.userCreateMenuLink.isEmpty()) fail("Link does not exist");}
I am able to use something similar in my own tests though, and it seems like a dependable way to skirt the 'No such element' exception. It's basically a page object adaptation of asserting: driver.findElements(By.locator).size() < 1.
Here is a nice pattern to access optional elements on a page:
#FindBy(...)
private List<WebElement> element;
public Optional<WebElement> getElement() {
return element.stream().findFirst();
}
In a test, you could then use the following assertions:
assertEquals(Optional.empty(), page.getElement()); // element should be absent
assertTrue(page.getElement().isPresent()); // element should be present
var e = page.getElement().orElseThrow(AssertionFailedError::new); // check and use element
Arquillian has implemented that feature in Graphene extension.
Check ElementLocatorConditionFactory.isPresent() function.
They more or less do what you wrote in your question (from ExpectedConditions.findElement in selenium-support.jar) :
try {
return driver.findElement(by);
} catch (NoSuchElementException e) {
throw e;
} catch (WebDriverException e) {
// [...] some log
throw e;
}
Using C# bindings:
using System.Collections.Generic;
using System.Linq;
public class DefaultPage
{
[FindsBy(How = How.Id, Using = "link_i_user_create")]
private IList<IWebElement> userCreateMenuLink;
public bool isUserCreateMenuLinkPresent()
{
return userCreateMenuLink.Any();
}
}
You're telling Selenium to grab all elements that match that Id and put them into a List of IWebElement. You then call .Any() on the list which evaluates to true if at least one IWebElement was found.
try this is defiantly work in pom
public boolean isPrebuiltTestButtonVisible() {
try {
if (preBuiltTestButton.isEnabled()) {
return true;
} else {
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
this will definitely work in page object model surround with try catch
Related
I declare a button as field in following fashion:
#AndroidFindBy(name = "Schedule")
private WebElement calendarButton;
... and later I make sure it's NOT displayed because the app is in some special mode.
Assert.assertFalse(this.calendarButton.isDisplayed());
It gives me org.openqa.selenium.NoSuchElementException, but the test is failed. Any ideas how can I make such assertion?
The thing I don't want to define By condition a few times in the code, so using property is handy.
After some thinking I came up with following solution:
public static boolean elementIsPresent(AndroidElement element) {
try {
element.isDisplayed();
} catch (org.openqa.selenium.NoSuchElementException e) {
return false;
}
return true;
}
I use this method in following way:
Assert.assertFalse(elementIsPresent(this.calendarButton));
I was inspired by one of the answers in this thread.
I am testing a UI in which the user clicks a delete button and a table entry disappears. As such, I want to be able to check that the table entry no longer exists.
I have tried using ExpectedConditions.not() to invert ExpectedConditions.presenceOfElementLocated(), hoping that it would mean "expect that there is not a presence of the specified element". My code is like so:
browser.navigate().to("http://stackoverflow.com");
new WebDriverWait(browser, 1).until(
ExpectedConditions.not(
ExpectedConditions.presenceOfElementLocated(By.id("foo"))));
However, I found that even doing this, I get a TimeoutExpcetion caused by a NoSuchElementException saying that the element "foo" does not exist. Of course, having no such element is what I want, but I don't want an exception to be thrown.
So how can I wait until an element no longer exists? I would prefer an example that does not rely on catching an exception if at all possible (as I understand it, exceptions should be thrown for exceptional behavior).
You can also use -
new WebDriverWait(driver, 10).until(ExpectedConditions.invisibilityOfElementLocated(locator));
If you go through the source of it you can see that both NoSuchElementException and staleElementReferenceException are handled.
/**
* An expectation for checking that an element is either invisible or not
* present on the DOM.
*
* #param locator used to find the element
*/
public static ExpectedCondition<Boolean> invisibilityOfElementLocated(
final By locator) {
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driver) {
try {
return !(findElement(locator, driver).isDisplayed());
} catch (NoSuchElementException e) {
// Returns true because the element is not present in DOM. The
// try block checks if the element is present but is invisible.
return true;
} catch (StaleElementReferenceException e) {
// Returns true because stale element reference implies that element
// is no longer visible.
return true;
}
}
The solution would still rely on exception-handling. And this is pretty much ok, even standard Expected Conditions rely on exceptions being thrown by findElement().
The idea is to create a custom Expected Condition:
public static ExpectedCondition<Boolean> absenceOfElementLocated(
final By locator) {
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driver) {
try {
driver.findElement(locator);
return false;
} catch (NoSuchElementException e) {
return true;
} catch (StaleElementReferenceException e) {
return true;
}
}
#Override
public String toString() {
return "element to not being present: " + locator;
}
};
}
Why don't you simply find the size of elements. We know the the collection of elements' size would be 0 if element does not exist.
if(driver.findElements(By.id("foo").size() > 0 ){
//It should fail
}else{
//pass
}
I don't know why but ExpectedConditions.invisibilityOf(element) is the only work for me while ExpectedConditions.invisibilityOfElementLocated(By), !ExpectedConditions.presenceOfElementLocated(By) ... not. Try it!
Hope this help!
// pseudo code
public Fun<driver,webelement> ElemtDisappear(locator)
{
webelement element=null;
iList<webelement> elemt =null;
return driver=>
{
try
{
elemt = driver.findelements(By.locator);
if(elemt.count!=0)
{
element=driver.findelement(By.locator);
}
}
catch(Exception e)
{
}
return(elemnt==0)?element:null;
};
// call function
public void waitforelemDiappear(driver,locator)
{
webdriverwaiter wait = new webdriverwaiter(driver,time);
try
{
wait.until(ElemtDisappear(locator));
}
catch(Exception e)
{
}
}
As findelement throws exception on element unaviability.so i implemented using findelements. please feel free to correct and use it as per your need.
I found a workaround to fix this for me in efficient way, used following C# code to handle this, you may convert it to Java
public bool WaitForElementDisapper(By element)
{
try
{
while (true)
{
try
{
if (driver.FindElement(element).Displayed)
Thread.Sleep(2000);
}
catch (NoSuchElementException)
{
break;
}
}
return true;
}
catch (Exception e)
{
logger.Error(e.Message);
return false;
}
}
Good news, it's built in now (I'm using Node.js in 2021)
It looks like elementIsNotVisible has been added to until after the previous answers were given. I'm using selenium webdriver 4.0.0-beta.3
Check it out:
const timeout = 60 * 1000; // 60 seconds
const element = await driver.findElement(By.id(elementId));
// this is the important line
await driver.wait(until.elementIsNotVisible(element), timeout);
You can use the following logic:
C# code sinppet:
//wait is the instance of WebDriverWait
wait.Until(driver => driver.FindElements(By.Xpath("your element expath")).Count == 0);
Notice how I use FindElements that does NOT throw NoSuchElementException which is swallowed by Until() function. So when element is gone collection size is zero.
Created a function to check whether an element is present on a page or not. Intention is to wait for a specified period of time and then return false, if not present.
public boolean isElementPresent(final WebElement element) {
Wait<WebDriver> wait = new WebDriverWait(driver, 60);
return wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver webDriver) {
return element.isDisplayed() != false;
}
});
}
But this is throwing exception in case of element not found
It is throwing exception because findElement will throw exception if no element is found. It is used in isDisplayed() method. You can 1st check, whether element is present on page then check whether it is displayed. Use following to make 1st check.
driver.findElements(byLocator).size>0
The following is a crude solution. But it works nevertheless :p
public boolean isElementPresent() {
try {
new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocatedBy(By.id(""));
return true;
} catch (TimeOutException e) {
return false;
}
}
When we use the WebDriverWait Class for waiting for a element to be present in the web page, a TimeOut Exception is thrown after the specified time. We catch it and return false. If no exception is thrown(if element is found), we return true.
If you are looking for checking whether the element is enabled or is displayed, explore the isDisplayed or isEnabled methods associated with WebElement. But please note that if the element is not physically present in the webpage, an exception is thrown.
Here is another less 'barbaric' method :-
public boolean isElementPresent() {
List<WebElement> elements = new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementsLocatedBy(By.id(""));
if (elements.isEmpty()) {
return false;
} else {
return true;
}
}
This will help you.
public boolean fncCheckElement() {
try {
WebElement element = (new WebDriverWait(driver,1)).until(ExpectedConditions.presenceOfElementLocated((By.id("ID"))));
system.out.println("Element is present in web page")
return true;
} catch (Throwable e) {
ex.printStackTrace();
system.out.println("Element is not present in web page")
return false;
}}
Enjoy!
This question already has answers here:
Test if an element is present using Selenium WebDriver
(21 answers)
Closed 6 years ago.
How can I 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;
}
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()
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.
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.
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
}
I extended the Selenium WebDriver implementation, in my case HtmlUnitDriver to expose a method,
public boolean isElementPresent(By by){}
like this:
check if the page is loaded within a timeout period.
Once the page is loaded, I lower the implicitly wait time of the WebDriver to some milliseconds, in my case 100 milliseconds, but it probably should work with 0 milliseconds too.
call findElements(By). The WebDriver, even if it 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");
}
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);
}
}
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 an assertion.
String link = driver.findElement(By.linkText(linkText)).getAttribute("href")
This will give you the link the element is pointing to.
As I understand it, this is the default way of using the web driver.
With version 2.21.0 of selenium-java.jar you can do this;
driver.findElement(By.id("...")).isDisplayed()
Hello all
I am using webdriver so if I want to use selenium;s rc function isElementPresent I have to emulate selenium rc so I do something like this:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverBackedSelenium;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
public class new {
private static void one_sec() {
Thread.sleep(4000);
}
public static void main(String[] args) {
WebDriver driver = new FirefoxDriver();
driver.get(something1);
Selenium selenium = new WebDriverBackedSelenium(driver, something1);
selenium.click("//html...");
one_sec();
System.out.println(selenium.isElementPresent("text"));
WebDriver driverInstance = ((WebDriverBackedSelenium) selenium).getWrappedDriver();
...
}
and I always get false as result of isElementPresent and of course element "text" is on the web (which is using GWT).
I really like Rostislav Matl's alternative Moving to Selenium 2 on WebDriver, Part No.1:
driver.findElements(By.className("someclass")).size() > 0;
Javadoc: org.openqa.selenium.WebDriver.findElements(org.openqa.selenium.By by)
You can implement it yourself using pure webdriver:
private boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
}
In the Selenium 2 world, if you want to find if an element is present you would just wrap the find call in a try catch because if it isnt present it will throw an error.
try{
driver.findElement(By.xpath("//div"));
}catch(ElementNotFound e){
//its not been found
}
Not a part of Selenium 2, you can do the following:
// Use Selenium implementation or webdriver implementation
Boolean useSel = false;
/**
* Function to enable us to find out if an element exists or not.
*
* #param String An xpath locator
* #return boolean True if element is found, otherwise false.
* #throws Exception
*/
public boolean isElementPresent(String xpathLocator) {
return isElementPresent(xpathLocator, false, "");
}
/**
* Function to enable us to find out if an element exists or not and display a custom message if not found.
*
* #param String An xpath locator
* #param Boolean Display a custom message
* #param String The custom message you want to display if the locator is not found
* #return boolean True if element is found, otherwise false.
* #throws Exception
*/
public boolean isElementPresent(String xpathLocator, Boolean displayCustomMessage, String customMessage) {
try {
if (useSel) {
return sel.isElementPresent(xpathLocator);
} else {
driver.findElement(By.xpath(xpathLocator));
}
} catch (org.openqa.selenium.NoSuchElementException Ex) {
if (displayCustomMessage) {
if (!customMessage.equals("")) {
System.out.print(customMessage);
}
} else {
System.out.println("Unable to locate Element: " + xpathLocator);
}
return false;
}
return true;
}
Sometimes the element you are trying to find is loading, s0 will throw an exception using findElement(By.xpath(xpathLocator))
Therefore we would need do what Dejan Veternik has recommended, it will help wait until the ELEMENT has been loaded in the webpage, I am passing Selenium and extracting webdriver, this is helpful incase you are using WebDriverBackedSelenium just like me ...
private boolean isElementPresent(WebDriverBackedSelenium driver, String id) {
try {
driver.getWrappedDriver().findElement(By.id(id));
return true;
} catch (Exception e) {
return false;
}
}
I'm using the Node library selenium-webdriver 3.6.0.
It has driver.findElements (return zero or more items) and driver.findElement (returns first item found or throw NoSuchElementError).
So I'd like to recommend this as a check for if at least one element can be found. Perhaps useful in Java.
driver.findElement(By.className("someclass"));
This code works for me. It may not be the most elegant, but it is functional.
Boolean elementExists=true;
try {
SoftAssert sAssert = new SoftAssert();
sAssert.assertTrue (element.isDisplayed());
}catch (NoSuchElementException e){
elementExists = false;
}
Assert.assertFalse(elementExists);
You have to be careful that "NoSuchElementException" is "org.openqa.selenium" not "java.util" because otherwise, it won't work