Selenium - unable to find element- during second time - selenium

I am trying to find element like this -
Select servTypeDA = new Select (driver.findElement(By.xpath("//select[#id='ServicesType']")));
servTypeDA.selectByVisibleText(servTypeData);
This works fine perfectly for the first time, when I load this page.
I am trying to do a workflow so when this page loads after couple of steps, for the same line it throws the error -
org.openqa.selenium.NoSuchElementException: Unable to locate element
But I am able to see the element in the screen and its visible but still not accessible by code.
I tried to add wait time, still throws error.
Why the same element is not accessible for the second time?

NoSuchElement is thrown when webdriver is not able to find the element in DOM. The main cause of this is probaly you are searching for the element too early. I would suggest to use some explicit wait and do a check for the element with regular interval.
By byXpath = By.xpath("//select[#id='ServicesType']");
WebElement element = new WebDriverWait(driver,10).until(ExpectedConditions.visibilityOfElementLocated(byXpath));
Select servTypeDA = new Select(element);
servTypeDA.selectByVisibleText(servTypeData);

Or you can set implicitlyWait which is by default 0.
By setting this, Webdriver will wait for given amount of time before throwing NoSuchElementException
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
It will save your effort of adding webdriverWait almost before each Element.

The way that webdriver works is that each page load it copies the page. So what is shown does not have to be what is loaded in the webdriver instance. For example if you change the webpage via JavaScript, the webdriver would not be aware of it.
These often is the couse for
NoSuchElementException
or
StaleElementReferenceException
I found that the only cure for this is to catch the exception and try again. I had to create a new function for each type of action. I will show you my example for "selectByVisibleText"
public void selectByLabel(final By by, final String label){
act(by, 3, new Callable<Boolean>() {
public Boolean call() {
logger.trace("Trying to select label: "+label+" in select box "+stripBy(by) );
Boolean found = Boolean.FALSE;
int attempts = 0;
wait.until(ExpectedConditions.refreshed(ExpectedConditions.elementToBeClickable(by)));
Select select = new Select(driver.findElement(by));
select.selectByVisibleText(label);
if(isLabelSelected(by,label)){
found = Boolean.TRUE; // FOUND IT
logger.info("Selected value "+label+" in select box "+stripBy(by));
}
return found;
}
});
}
It will retry for a few times.
All my special implementetation of action use a function for catching exceptions
private void act(By by, int tryLimit, boolean mode, Callable<Boolean> method){
logger.trace( "Looking for element: " + stripBy(by) );
driver.manage().timeouts().implicitlyWait( 5, TimeUnit.SECONDS );
boolean unfound = true;
int tries = 0;
while ( unfound && tries < tryLimit ) {
tries += 1;
try {
WebDriverWait wait = new WebDriverWait(driver, 500);
unfound = !method.call(); // FOUND IT, this is negated since it feel more intuitive if the call method returns true for success
} catch ( StaleElementReferenceException ser ) {
logger.error( "ERROR: Stale element exception. " + stripBy(by) );
unfound = true;
} catch ( NoSuchElementException nse ) {
logger.error( "ERROR: No such element exception. " + stripBy(by)+"\nError: "+nse );
unfound = true;
} catch ( Exception e ) {
logger.error( e.getMessage() );
}
}
driver.manage().timeouts().implicitlyWait( Constants.DEFAULT_IMPLICIT_WAIT, TimeUnit.SECONDS );
if(unfound)
Assert.assertTrue(false,"Failed to locate element by locator " + stripBy(by));
}

Related

Selenium webdriver throwing timeout exception

I am new to Selenium.
My issue is that I'm trying to click an element but Selenium is throwing a timeout exception, even if I increase the timeout value.
Do I need to use xpath instead of id?
The HTML Code is:
My code looks like this
void searchquotation() throws TimeoutException {
try {
WebDriverWait wait = new WebDriverWait(driver, 15);
WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(By.name("SearchButton")));
element.click();
}
catch(TimeoutException e) {
System.out.println("Timeout occured");
}
Am I doing anything wrong?
The input type here is submit (by looking at your HTML code) so I would strongly advise to try the submit() function of Selenium.
Instead of By.name, you should use By.id instead. Therefore, use either of these:
By.Id("SearchButton")
By.CssSelector("input#SearchButton")
By.Xpath("//input[#id='SearchButton']")
Note: syntax could be wrong, please adjust depending on your programming language
try below code, even timeout exception occurs, it will try 4 time to click on it. assuming locator is correct By.name("SearchButton")
public void searchquotation()
int count=0;
while(count<4)
{
try {
WebElement x = driver.findElement(By.name("SearchButton")));
WebDriverWait element=new WebDriverWait(driver,15);
element.until (ExpectedConditions.presenceOfElementLocated(By.name("SearchButton")));
x.click();
count=count+4;
}
catch(TimeoutException e) {
count=count+1;
System.out.println("Timeout occured");
continue;
}
}

If Xpath is not found my script not moving to other test cases and stop everything and exit. I am using selenium testng frame work

//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());
}
}

Using Selenium, best way to verify something is not on the page after a max time?

Using Selenium, what would be the best way (or design pattern) to verify something is not on the page after a max time?
I know we could wait for a element to appear with a string on it, like so:
(new WebDriverWait(driver, 10)).until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return d.getTitle().toLowerCase().startsWith("cheese!");
}
});
BUT, what if I wanted to make sure that for 10 seconds, the OPPOSITE was true, and no element had appeared on the page with a certain text in it? Basically, a condition that is expected to usually, but not always, reach the max timeout.
In my use case, its important that the call to the method not throw any exceptions that will exit the JUnit/TestNG test case and instead always allow successive test steps to continue and the final softAsserts to occur.
The method should have a signature like this:
Boolean verifyElementWithTextDoesNotAppear( By locator, String, text, long timeout )
Is there a good design pattern that any of you use that could do this most efficiently? The method must not throw a TimeoutException nor throw any particular type of WebDriverException before or after the timeout is reached and must likely instead return a reliable boolean result.
My best guess so far, if you expect a FALSE, calling this method would be safe, I think:
public Boolean elementExistsWithinSeconds(By locator, int seconds)
{
ExpectedCondition<List<WebElement>> elementListCondition =
ExpectedConditions.presenceOfAllElementsLocatedBy(locator);
WebDriverWait wait = webDriverManager.getCachedWebDriverWait(seconds);
try {
List<WebElement> elementList = wait.until(elementListCondition);
if ( elementList.size() > 0 ) return Boolean.TRUE;
} catch ( TimeoutException te ) {
LOG.debug( "Element '" + locator.toString() + "' with text '" + text +
"' was not found within timeout.", te);
}
return Boolean.FALSE;
}
In testng, we have a feature which doesnt throw the exception. expectedExceptions = NoSuchElementException.class put in the #Test method.

isElementPresent is very slow in case if element does not exist.

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.

Selenium WebDriver reliable tests

I know that this question was asked many times before, but I still couldn't find a solution that works for me. When I run my tests with Selenium WebDriver most of the times they fail with "NoSuchElementException". I tried using Explicit and Implicit Waits but nothing seems to work. So, is there any other way besides using Waits in which I can make my tests more reliable?
I'm using selenium-java-2.31.0 with FirefoxDriver. Below are some samples of code I tried to make my tests more reliable:
public void waitAndClickElement(WebDriver driver, final By selector) {
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(50, TimeUnit.SECONDS)
.pollingEvery(5, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
WebElement elementToClick = wait
.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(selector);
}
});
waitForElementVisible(driver, selector);
elementToClick.click();
}
..and this:
public WebElement waitForElementPresent(WebDriver driver, final By selector){
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(70, TimeUnit.SECONDS)
.pollingEvery(5, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
WebElement elementToClick = wait
.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(selector);
}
});
return elementToClick;
}
...and this:
WebDriverWait wait = new WebDriverWait(driver, 50);
WebElement user_name = wait.until(visibilityOfElementLocated(By.xpath("//*#id='userName']")));
...and this:
driver.manage().timeouts().implicitlyWait(50, TimeUnit.SECONDS);
...and finally one of the tests that I try to make more reliable:
#Test
public void test1{
waitAndClickElement(driver, By.xpath("//*[#id='linkLogIn']"));
waitForElementPresent(driver, By.xpath("//*[#id='userName']")).sendKeys("name");
waitForElementPresent(driver, By.xpath("//*[#id='inputEmail']")).sendKeys("email#gmail.com");
waitForElementPresent(driver,By.xpath("//*[#id='resetPassword']")).click();
assertTrue(isElementPresent(By.xpath("//*[#id='moduleMain']")));
}
Thank you!
Try below custom method. It works fine for me,
public boolean waitForElementToBePresent(By by, int waitInMilliSeconds) throws Exception
{
WebDriver driver = getDriver();
int wait = waitInMilliSeconds;
int iterations = (wait/250);
long startmilliSec = System.currentTimeMillis();
for (int i = 0; i < iterations; i++)
{
if((System.currentTimeMillis()-startmilliSec)>wait)
return false;
List<WebElement> elements = driver.findElements(by);
if (elements != null && elements.size() > 0)
return true;
Thread.sleep(250);
}
return false;
}
Use it like,
waitForElementToBePresent(By.id("linkLogIn", 5000);
driver.findElement(By.id("linkLogIn")).click();
WebDriver is perfectly stable if you handle exceptions properly. The problem is that the methods of ExpectedConditions class don't handle the exceptions for you although most people will reply to your question as if it does.
You can try my method if you want. This method returns in between 0 to 90 seconds, depending on the scenario. You may prefer to alter this method a little, but it should work. The important concepts here are:
1. Use the new FluentWait class with the .ignoring method (or .ignoreAll() ).
2. Use findElement() BUT make sure you catch (and nicely handle) the possible
exceptions (that you are ignoring in the wait).
3. Use a loop to retry after exceptions but govern that by either time or
# of tries.
And the code:
public WebElement getElementByLocator( final By locator ) {
LOGGER.info( "Get element by locator: " + locator.toString() );
final long startTime = System.currentTimeMillis();
Wait<WebDriver> wait = new FluentWait<WebDriver>( driver )
.withTimeout(30, TimeUnit.SECONDS)
.pollingEvery(5, TimeUnit.SECONDS)
.ignoring( NoSuchElementException.class )
.ignoring( StaleElementReferenceException.class ) ;
int tries = 0;
boolean found = false;
WebElement we = null;
while ( (System.currentTimeMillis() - startTime) < 91000 ) {
LOGGER.info( "Searching for element. Try number " + (tries++) );
try {
we = wait.until( ExpectedConditions.visibilityOfElementLocated( locator ) );
found = true;
break;
} catch ( StaleElementReferenceException e ) {
LOGGER.info( "Stale element: \n" + e.getMessage() + "\n");
} catch ( NoSuchElementException nse ) {
LOGGER.info( "No such element: \n" + nse.getMessage() + "\n");
}
}
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
if ( found ) {
LOGGER.info("Found element after waiting for " + totalTime + " mill." );
} else {
LOGGER.info( "Failed to find element after " + totalTime + " mill." );
}
return we;
}
When you run findElement, you will get an error when it's not found. This occurs for one of three reasons:
Your selector is wrong
If the selector is wrong, the best thing to do debug until you get to that spot and pause test execution. Then use the console to figure out the correct selector to find the element.
The element isn't there
You may notice in your first action that the element you're looking for isn't actually there. In that case, find out why you're in that wrong state and fix it. If you're expecting the element to not be there, Here is a great C# example on how to extend your IWebElement object to allow for a .Exists() method.
The element is late
Determining if the element is just late is easy. Run the test normally once and then run in debug mode stepping over each step manually. If your normal test run fails while your manual steps work, you know you found your issue. Typically the issue is due to AJAX loads not occurring on page load. In these instances, a good webdev will typically add some kind of spinner image that you can easily search for. I created a helper method called WaitForPageLoad() that first waits till page load, then verifies that the spinner isn't present, then waits again for page load to complete. You want 2 page load waits because a modal will spin then load while a new page load will load then spin. Finally, the page is complete, your element will be present.
I have faced with the same type of problem, while using WebDriver with C#.
I can propose 2 different ways on how you can avoid(not completely, but minimize) NoSuchElementException in your tests:
First of all you should figure out how your application works - does it use a lot of Ajax and other asynch. requests/responses. Then you can use explicit wait for every element, which can not be located at once.
You can write your own implementation of WebElement class based on Selenium WebDriver WebElement class.
Main idea - everytime you will use your webelement it will relocated - so you will not be worry about NoSuchElement or StaleElementException.
Did you try to catch element by element without all theses wait and wait.until?
simply like : WebElement username = driver.findelement(By.id("userName"));
Can you drop your html by the way ?
EDIT:
What i can suggest is :
protected void sleep(int i) {
driver.manage().timeouts().implicitlyWait(i, TimeUnit.SECONDS);
}
#test
void test(){
driver.findElement(By.id("linkLogIn")).click(); sleep(6);
driver.findElement(By.id("userName")).sendKeys("user"); sleep(1);
driver.findElement(By.id("inputEmail")).sendKeys("mail#gmail.com"); sleep(1);
driver.findElement(By.id("resetPassword")).click(); sleep(10);
Assert.assertTrue(isElementPresent(By.id("moduleMain")));
}
Well your code tells me that you are only waiting until the element is present.
waitForElementPresent(driver, By.xpath("//*[#id='userName']")).sendKeys("name");
waitForElementPresent(driver, By.xpath("//*[#id='inputEmail']")).sendKeys("email#gmail.com");
It tells me nothing that you clicked the field, then using sendkeys to input the text.
How about adding click
waitForElementPresent(driver, By.xpath("//*[#id='userName']"));
driver.findElement(by.id ="userName").click();
driver.findElement(by.id ="userName").sendKeys("name");
The problem is the mouse focus on webdriver, it need to be focused in appropriate field AFAIK