Selenium Webdriver: best practice to handle a NoSuchElementException - java

After much searching and reading, I'm still unclear as to the best way to handle a failed assertion using Webdriver. I would have thought this was a common and core piece of functionality. All I want to do is:
look for an element
if present - tell me
if not present - tell me
I want to present the results for a non technical audience, so having it throw 'NoSuchElementExceptions' with a full stack trace is not helpful. I simply want a nice message.
My test:
#Test
public void isMyElementPresent(){
// WebElement myElement driver.findElement(By.cssSelector("#myElement"));
if(driver.findElement(By.cssSelector("#myElement"))!=null){
System.out.println("My element was found on the page");
}else{
System.out.println("My Element was not found on the page");
}
}
I still get a NoSuchElementException thrown when I force a fail. Do I need a try/catch as well? Can I incorporate Junit assertions and/or Hamcrest to generate a more meaningful message without the need for a System.out.println?

I have encountered similar situations. According to the Javadoc for the findElement and findElements APIs, it appears that the findElement behavior is by design. You should use findElements to check for non-present elements.
Since in your case, there's a chance that the WebElement is not present, you should use findElements instead.
I'd use this as follows.
List<WebElement> elems = driver.findElements(By.cssSelector("#myElement"));
if (elems.size == 0) {
System.out.println("My element was not found on the page");
} else
System.out.println("My element was found on the page");
}

you can do something to check if element exists
public boolean isElementExists(By by) {
boolean isExists = true;
try {
driver.findElement(by);
} catch (NoSuchElementException e) {
isExists = false;
}
return isExists;
}

What about using an xPath inside of a try-catch, passing the elementype, attribute and text as follows?
try {
driver.FindElement(
By.XPath(string.Format("//{0}[contains(#{1}, '{2}')]",
strElemType, strAttribute, strText)));
return true;
}
catch (Exception) {
return false;
}

Even running it in a try block, it behaves as if unhandled,
neither of the catch blocks runs when the selenium exception occurs.
try {
wait.Until(webDriver => webDriver.PageSource.Contains(waitforTitle));
wait.Until(webDriver => webDriver.FindElement(By.Id(waitforControlName)).Displayed);
}
catch (OpenQA.Selenium.NoSuchElementException nse) {
nse = nse = null;
success = false;
}
catch (Exception ex) {
ex = ex = null;
success = false;
}

Related

if else?? try?? I need help on methods

If one method work and other doesn't then how do I make the code try a alternative method?
Here is the code
1st method
driver.findElement(By.id("com.simplemobiletools.gallery:id/dir_thumbnail")).click();
driver.findElement(By.id("com.simplemobiletools.gallery:id/medium_thumbnail")).click();
2nd method
driver.findElement(By.id("com.offerup:id/circle")).click();
driver.findElement(By.id("com.offerup:id/done")).click();
If the first method doesn't work I want it to go ahead and try the second method but, I don't know what command to use for this.
I am not very experienced at programming so please bear with me.
You can use try catch block for this purpose :
try {
driver.findElement(By.id("com.simplemobiletools.gallery:id/dir_thumbnail")).click();
driver.findElement(By.id("com.simplemobiletools.gallery:id/medium_thumbnail")).click();
catch (Exception e) {
driver.findElement(By.id("com.offerup:id/circle")).click();
driver.findElement(By.id("com.offerup:id/done")).click();
}
you can give a specific exception too, for example "ElementNotFoundException" or "ElementNotVisibleException" in your catch parameter type
I assume by "doesn't work" you mean the element wasn't found. Two options:
According to the documentation, findElement raises a NoSuchElementException if the element isn't found. So you can continue to use findElement and catch the exception via try/catch.
Alternately, use findElements, which returns a List, and branch based on whether any were found. As LuisGP pointed out, avoiding exceptions is often helpful.
Option 1:
try {
driver.findElement(By.id("com.simplemobiletools.gallery:id/dir_thumbnail")).click();
driver.findElement(By.id("com.simplemobiletools.gallery:id/medium_thumbnail")).click();
} catch (NoSuchElementException e) {
driver.findElement(By.id("com.offerup:id/circle")).click();
driver.findElement(By.id("com.offerup:id/done")).click();
}
Or if you meant to handle those one-by-one:
try {
driver.findElement(By.id("com.simplemobiletools.gallery:id/dir_thumbnail")).click();
} catch (NoSuchElementException e) {
driver.findElement(By.id("com.offerup:id/circle")).click();
}
try {
driver.findElement(By.id("com.simplemobiletools.gallery:id/medium_thumbnail")).click();
} catch (NoSuchElementException e) {
driver.findElement(By.id("com.offerup:id/done")).click();
}
Option 2 (if you want to handle them one-by-one, you should be able to tweak if you want to branch on just the first result):
List<WebElement> elements;
elements = driver.findElements(By.id("com.simplemobiletools.gallery:id/dir_thumbnail"));
if (element.size() == 0) {
driver.findElement(By.id("com.offerup:id/circle")).click();
} else {
elements.get(0).click();
}
elements = driver.findElements(By.id("com.simplemobiletools.gallery:id/medium_thumbnail"));
if (elements.size() == 0) {
driver.findElement(By.id("com.offerup:id/done")).click();
} else {
elements.get(0).click();
}
You can try click on an element out of 4 given elements which is visible and clickable. It will make you to safe to clicking on element after catching exception and good practice to follow. It will throw exception only when no element will be found out of 4 and it is valid case.
MobileElement A = driver.findElement(By.id("com.simplemobiletools.gallery:id/dir_thumbnail"));
MobileElement B = driver.findElement(By.id("com.simplemobiletools.gallery:id/medium_thumbnail"));
MobileElement C = driver.findElement(By.id("com.offerup:id/circle"));
MobileElement D = driver.findElement(By.id("com.offerup:id/done"));
public void clickOnElement() {
try {
if(A.isDisplayed() && A.isEnabled())
{
A.click();
}
if(B.isDisplayed() && B.isEnabled())
{
B.click();
}
if(C.isDisplayed() && C.isEnabled())
{
C.click();
}
if(D.isDisplayed() && D.isEnabled())
{
D.click();
}
}catch (Exception e) {
e.printStackTrace();
}
}
Just call 'clickOnElement' method in your test case.

POP function for Present&enabled checking in selenium (Java)

I working in selenium and now for checking visibility of element i use following wait until:
#FindBy (css=".delete-basket-modal-btn") WebElement deleteItemFromBasketCancelButton;
public void clickDeleteItemFromBasketCancelButton() throws InterruptedException {
wait.until(ExpectedConditions.elementToBeClickable(deleteItemFromBasketCancelButton));
deleteItemFromBasketCancelButton.click();
}
that's not good idea, this function is not checking for presence of element, so sometimes i get 'stale element reference element is not attached to the page document'
Now i trying to create universal function which will be inherited by all of mine page object class. In this function i need checking (5 sec) for presence, enability, clickability and visibilty of WebElement passed in argument.
For this moment i have new function below, but i dont know that is good approach for my problem
public void verifyElement(WebElement element) throws InterruptedException {
boolean isPresent = false;
for (int i = 0; i < 5; i++) {
try {
if (element != null) {
isPresent = true; // metoda do czekania na element
break;
}
} catch (Exception e) {
// System.out.println(e.getLocalizedMessage());
Thread.sleep(1000);
}
}
Assert.assertTrue(isPresent, "\"" + element + "\" is not present.");
boolean isEnabled = false;
for (int i = 0; i < 5; i++) {
try {
if (element.isEnabled()==true) {
isEnabled = true;
break;
}
}catch (Exception e) {
Thread.sleep(1000);
}
}
Assert.assertTrue(isEnabled, "\"" + element + "\" is not enabled.");
}
Do you have any suggestion or similar problem for this issue?
StaleElementReferenceException doesn't (necessarily) mean the element is not present, it means the DOM had changed/refreshed since the element was located, so the element reference which the driver holds is no longer valid. This is a disadvantage of using PageFactory model.
The solution is to locate the element just before the click operation, however this will break the consistency of the page object. Instead of using FindBy send By to the method and locate the element there
public void clickDeleteItemFromBasketCancelButton(By by) throws InterruptedException {
WebElement deleteItemFromBasketCancelButton = wait.until(ExpectedConditions.elementToBeClickable(by));
deleteItemFromBasketCancelButton.click();
}
The first written code is enough. To overcome stale element exception write code in try/catch block and use ExpectedConditions.stalenessOf(deleteItemFromBasketCancelButton) for presence, enability, clickability and visibilty (for any type of operation).
Try below one, hope it's help for you.
try{
wait.until(ExpectedConditions.elementToBeClickable(deleteItemFromBasketCancelButton));
deleteItemFromBasketCancelButton.click();
}
catch(Exception e){
wait.until(ExpectedConditions.refreshed(ExpectedConditions.stalenessOf(deleteItemFromBasketCancelButton)))
deleteItemFromBasketCancelButton.click();
}

Appium can not find any element

I'm have on automation project(java, appium, android)
In this project, the elements are stored in the database.
I get elements from database and try to find it:
1) Locator search using findElements:
if (!elementPath.equals("")){
List elementFound = driverCommands.findElements(By.xpath(elementPath));
if (elementFound.size() == 0){
return null;
}
return (AndroidElement) elementFound.get(0);
}
2) Locator search using findElement:
String elementPath = entity.getElementPath();
driverCommands.findElement(By.xpath(elementPath));
In both cases I get nothing. But if I add sleep() before usage findElemen(s) with a wait of at least 4 seconds, as shown in the example below, then the element will be found.
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!elementPath.equals("")){
List elementFound = driverCommands.findElements(By.xpath((elementPath));
if (elementFound.size() == 0){
return null;
}
return (AndroidElement) elementFound.get(0);
How can I solve this problem?

Click on element of a dynamic loaded page using Selenium WebDriver java

I need to click on particular element of an dynamically loaded page.Web element generated when we scroll the page.It similar like an jabong webpage.
I try to do that on jabong webpage this is my code
WebDriver driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.navigate().to("http://www.jabong.com/men/clothing/"
+ "?source=topnav");
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
System.out.println("Close the modal popup");
driver.findElement(By.id("jab-vchr-cls")).click();
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
/**
* while(true) loop is required to search the
* element until element found.We put find
* element within try-catch and if it get
* exception it scroll the page and again
* try to find the element.
*/
while(true) {
((JavascriptExecutor)driver).executeScript("window.scrollBy(0,100)", "");
try {
WebElement element = driver.findElement(By.xpath("//*[#id='http: //static3.jassets.com/p/The-Indian-Garage-Co.-Checks-Red-Casual-Shirt-2889-679124-1-catalog.jpg']/img"));
Wait<WebDriver> wait_element=new WebDriverWait(driver, 10);
wait_element.until(ExpectedConditions.elementToBeClickable(element));
element.click();
System.out.println("!!!!!!!!!!!!!!At Last Get Success!!!!!!!!!!!!!!!!");
break;
}
catch (Exception ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
System.out.println(ex.getMessage());
}
}
}
}
My question is
1.Is there any better way to do this things?
2.How to make this script faster?
you can do this way if you want to avoid while(true) though I donot think there is any problem with this loop.
boolean reachedbottom = Boolean.parseBoolean(js.executeScript("return $(document).height() == ($(window).height() + $(window).scrollTop());").toString());
while (!reachedbottom) {
((JavascriptExecutor) driver).executeScript("window.scrollBy(0,600)", "");
try {
reachedbottom=Boolean.parseBoolean(js.executeScript("return $(document).height() == ($(window).height() + $(window).scrollTop());").toString());
WebElement element = driver.findElement(By.xpath("//*[#id='http://static3.jassets.com/p/The-Indian-Garage-Co.-Checks-Red-Casual-Shirt-2889-679124-1-catalog.jpg']/img"));
Wait<WebDriver> wait_element = new WebDriverWait(driver, 5);
wait_element.until(ExpectedConditions.elementToBeClickable(element));
element.click();
System.out.println("!!!!!!!!!!!!!!At Last Get Success!!!!!!!!!!!!!!!!");
break;
} catch (Exception ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
System.out.println(ex.getMessage());
}
}
In the Getting Started with Selenium framework, the AutomationTest#waitForElement method is a great way to handle things. It's an alternative to the webdriver wait, but works all the same.
/**
* Private method that acts as an arbiter of implicit timeouts of sorts.. sort of like a Wait For Ajax method.
*/
private WebElement waitForElement(By by) {
int attempts = 0;
int size = driver.findElements(by).size();
while (size == 0) {
size = driver.findElements(by).size();
if (attempts == MAX_ATTEMPTS) fail(String.format("Could not find %s after %d seconds",
by.toString(),
MAX_ATTEMPTS));
attempts++;
try {
Thread.sleep(1000); // sleep for 1 second.
} catch (Exception x) {
fail("Failed due to an exception during Thread.sleep!");
x.printStackTrace();
}
}
if (size > 1) System.err.println("WARN: There are more than 1 " + by.toString() + " 's!");
return driver.findElement(by);
}
You can take it out of the infinite loop. If a page doesn't load something within 10 seconds then i'd say it's an app issue that needs to be rectified. Take it out out of the infinite loop, and using something like waitForElement specified above, or just use a WebDriverWait class.
Furthermore, you shouldn't ever have to scroll to an element. I still have yet to find a reason to do something like this. As long as the element is on the DOM, it should be able to be operated on.

Continue execution after failure then Fail entire test if theres at least one failure

I currently have a loop that goes through a total of 16 website URL's, each time checking for specific text within each home page. There's sometimes a case when a few of the websites takes longer than the specified amount of time to load, thereby failing and stopping execution. What I would like is for the loop to continue until completion, then Fail the entire test if there's at least one failure that occurred during execution and pass the entire test if there were no failures.
Below is the actual code being used to set and check the load time against. Please advise how to modify the below code such that I can get the desired result above?
public static Boolean isTextPresentAfterWaitOnServer(final String strStringToAppear, RemoteWebDriver rwd, String strLoc){
try{
Wait<WebDriver> wait = new FluentWait<WebDriver>(rwd)
.withTimeout(30, TimeUnit.SECONDS)
.pollingEvery(2, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
Boolean foo = wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(final WebDriver webDriver) {
return (webDriver.getPageSource().indexOf(strStringToAppear) >= 0);
}
});
return foo;
}
catch(TimeoutException e){
throw new RuntimeException("Could not find text " + strStringToAppear +" on server "+strLoc +" - " + e);
}
};
I haven't used FluentWait so not sure if you can ignore the timeout exception as well like you are doing for nosuchelementexception. If it has then i guess you can ignore that as well. OR instead of raising the runtimeexception, create an errorCounter, keep incrementing it in the catch block and in finally block raise an exception based on its value.
I think in your case simple Asser.fail(String message); is very helpful. Please try this code:
public static Boolean isTextPresentAfterWaitOnServer(final String strStringToAppear, RemoteWebDriver rwd, String strLoc){
(...)
}
catch(TimeoutException e){
throw new RuntimeException("Could not find text " + strStringToAppear +" on server "+strLoc +" - " + e);
}
};
and catch this RuntimeExecption in test method:
#Test
public void someTestMethod(){
try{
(...)
isTextPresentAfterWaitOnServer("strStringToAppear", rwd, "strLoc");
}catch(RuntimeException re){
Assert.fail(re.getMessage());
} //you can specify another exceptions
}
I use fail in JUnit and works fine (all test cases running). May be has same behavior in testNG.

Categories

Resources