Is there a way for Selenium/Cucumber to throw a more descriptive error when an element is not found? Currently it only throws:
The element could not be found (Selenium::WebDriver::Error::NoSuchElementError)
I'd like to also include the locator.
It depends how your test fixture code is designed and structured. You can wrap FindElement code inside try/catch block. Something like:
Public void TestMethod(string elementId)
{
try
{
driver.FindElement(By.CssSelector(elementId));
}
catch(NoSuchElementException exception)
{
Assert.Fail("Can't find the element in the page. The element is: " +elementId)
}
}
Related
I'm using maven and selenium for testing in java. I would like to know if there is a way to call a function every time a test fails. I already have a function that takes an screenshot of the browser. I would like to use it every time selenium throws NoSuchElNoSuchElementExeption for example.
Is there an "easy" way to implement this?
Thank you!
You can create a method to find the element and implement a try-catch block inside that to catch the NoSuchElementException. Call your function to take the screenshot inside that catch block.
e.g.
public WebElement findElement(By locator) {
try {
WebElement element = driver.findElement(locator);
return element;
} catch (NoSuchElementException nse) {
// call the function to take a screenshot
}
}
I eventually found this solution to the problem:
https://darrellgrainger.blogspot.com/2011/02/generating-screen-capture-on-exception.html?m=1
Consists on using WebDriverEventListener.
//getElementByXPath function for static xpath
public WebElement getElementByXPath(String Key){
try{
//This block will find element using Key value from web page and return It.
return driver.findElement(By.xpath(Object.getProperty(Key)));
}catch(Throwable t){
//If element not found on page then It will return null.
Add_Log.debug("Object not found for key --"+Key);
return null;
}
}
Here when some element is not found, my script stop and exit. But I want it just give me error so I can use it in test result and move to next test case.
I recommned using a webelement variable to store the result and then define return it... Sorry im not good at Java.
Some thing like this.
//getElementByXPath function for static xpath
public WebElement getElementByXPath(String Key){
try{
//This block will find element using Key value from web page and return It.
WebElement xpathElem = driver.findElement(By.xpath(Object.getProperty(Key)));
if(xpathElem != null)
{
return xpathElem;
}
else
{
Add_Log.debug("Object not found for key --"+Key);
return null;
}
}catch(Throwable t){
//If element not found on page then It will return null.
Add_Log.debug("Object not found for key --"+Key);
return null;
}
}
As you are using try/catch, when ever exception is came it is handled by catch block. if you want to throw this same exception after log statement then you can try like this
public WebElement getElementByXPath(String Key){
try{
//This block will find element using Key value from web page and return It.
return driver.findElement(By.xpath(Object.getProperty(Key)));
}catch(Throwable t){
//If element not found on page then It will return null.
Add_Log.debug("Object not found for key --"+Key);
//error message is thrown as exception which will appear in testng reports generally if you are using
throw new Exception(t.getMessage());
}
}
I am a newbie in automation testing, and m really confused about assert and verify.Since, I am using TestNG, according to my research I came to know that in webdriver, we dont have verify, we have hard and soft assertion. But when I search for it, I get all mixed answers. and nowhere can I find a detailed example.
For soft assertion I saw someone using 'customverification' but when I try to write that in my program I get error, asking to create a class or interface.
Can someone please help me in this. I am studying through internet so its really hard to get correct answers.
Thanks
package revision;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.Test;
public class Six {
WebDriver driver=new FirefoxDriver();
#Test
public void SandyOne() {
driver.get("file:///C:/Users/Sandeep%20S/Desktop/Test.html");
Assert.assertTrue(IsElementPresent(By.xpath("//input[#id='custom']")), "tab was missing");
driver.findElement(By.xpath("//input[#id='custom']")).sendKeys("abcd");
System.out.println("1st program");
System.out.println("blah 1");
System.out.println("blah 2");
}
public boolean IsElementPresent(By by) {
try {
driver.findElements(by);
return true;
} catch (org.openqa.selenium.NoSuchElementException e) {
return false;
}
}
}
If you have an assert that fails the test will be stopped, where for verify the test will be continued and the error will be logged.
Ideally you will have only one assert per test (e.g. the correct page has loaded) and verify will be used to check the information on that page in this case.
Therefore, if the correct page was not loaded, there is no point in checking the stuff on the page is correct.
You can get an idea and a visual example here.
Your test probably fails here:
Assert.assertTrue(IsElementPresent(By.xpath("//input[#id='custom']")), "tab was missing");
because IsElementPresent returns false. One way to avoid that would be:
try {
Assert.assertTrue(IsElementPresent(By.xpath("//input[#id='custom']")), "tab was missing");
driver.findElement(By.xpath("//input[#id='custom']")).sendKeys("abcd");
}
catch (AssertionError ae) {
//ignore
}
However, catching errors is quite ugly code. A better way would be to use WebDriver.findElements(By by) and check if the resulting list is empty or not.
Hard Assertions:Test execution stops as soon as assertion failure found.
Soft Assertions:Test execution continues even if assertion failure found.
e.g. You have 3 assert statements Assert1,Assert2,Assert3
Now if Assert2 fails in case of hard assertion the test will terminate.
In case of soft assertion it will move to next steps in test and then terminate.
You need to instantiate soft assertion as:
SoftAssertions softAssertion = new SoftAssertions();
softAssertion.assertTrue(condition,message)
In your given code snippet hard assertion makes sense since you cannot move to next step to send text until the input box is found.
In given example you don't need to assert element presence. If it's missing the findElement method will throw an error and you will know that it's not there.
If you have elements's Id, use it instead of xpath. This will make the code more readable and faster:
driver.findElement(By.Id("custom")).sendKeys("abcd");
Instead of directly calling the findElement method, it's recommended to use the PageObject pattern and pick elements with annotations, see PageFactory:
public class TestPage {
#FindBy(id = "custom")
WebElement custom;
private WebDriver driver;
public TestPage (WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public TestPage inputCustom(String txt) {
custom.sendKeys(txt);
return this;
}
}
#Test
public void SandyOne() {
// ...
TestPage page = new TestPage(driver);
page.inputCustom("abcd");
// ...
}
I am using below code to check for element on my web page
private boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
catch (Exception e)
{
return false;
}
}
I need to check in my program if a particular region appears in result as below
isElementPresent(By.xpath(".//*[#id='header']")));
If this is present this function completes quickly but if above is not present then it run for very long.
Could some one please help me in resolving this issue so that this check can be performed quickly?
Here you are missing somethings that is why it is waiting If there is not element. findElement will wait for an element implicitly specified time. so need to set that time to zero in that method.
isElementPresent(WebDriver driver, By by) {
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
} finally {
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
}
There are 4 important things going on here. In order:
Setting implicity_wait to 0 so that WebDriver does not implicitly wait.
Returning True when the element is found.
Catching the NoSuchElementException and returning False when we discover that the element is not present instead of stopping the test with an exception.
Setting implicitly_wait back to 30 after the action is complete so that WebDriver will implicitly wait in future.
Apparently, it's long to send the exception because your DOM is big and the xpath isn't the fastest way to get an element. But if you want to use xpath, try to put the best path and avoid that kind of function where is substring checking.
Your actual xpath : .//*[#id='header'] takes so long because you check all tags of your DOM. So if put the tag that what you're looking for, example : you want to catch an input. your xpath should start like that //input[#id='1234'] and it will be shorter than looking all tags.
I want to check error messages. These error messages appear only when my website encounters a problem.
My problem is that I use findElement in order to check the error message. So when something goes wrong, Selenium finds it, and everything is O.K.
But when it doesn't (meaning - my website is O.K with no problems) - then Selenium indicates that it doesn't find the element, and rises an exception.
Any idea?
you can surround the findElement in a try-catch block, which will do nothing if the element is not found. e.g.
private boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
//or do nothing
}
}
Take a look at the answer Selenium Webdriver NoSuchElementException
It suggests the following (I've adapted it a bit for your needs) :
List<WebElement> errorElements = driver.findElements(By.id("ERROR_ID"));
if (!errorElements.empty()) {
// Tests your errors
}
1.For this you should design your test case in such a way that you writes code to check error message only when you are sure that you will get error message.
2.But the point is why are you checking for error message when you know that there will be no problem and code will run fine.
3.If you doesn't know that error will occur.. You can place the risky code in try block and write a catch block which will find error message and check it.