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;
}
}
Related
I have a selenium test in Java and I am doing some assertions like that:
assertFalse(isElementPresent(By.xpath("//td[2]/div")));
private boolean isElementPresent(By by) {
try { driver.findElement(by); return true; }
catch (NoSuchElementException e) {
return false; }
It´s the standard method Selenium is generating when export from IDE to Java Webdriver.
(Yes I want to assert that this element is not present)
I always get errors when I am testing at this above code line
Error: stale element reference: element is not attached to the DOM
But when I put a thread.sleep in front of that step it works.
The fact I don´t get is that it is enough to wait 1 milli sec.
Is it typical to wait before an assertion?
Is there another way to solve this? (Implicit wait is not helping here)
Greetings from Germany!
As you are facing staleelementreferenceexception in assertFalse() function, to negate the FalsePossitive usecase you can induce WebDriverWait with ExpectedConditions clause set to stalenessOf within assertTrue() function as follows :
Assert.assertTrue(new WebDriverWait(driver, 20).until(ExpectedConditions.stalenessOf(driver.findElement(By.xpath("//td[2]/div")))));
Explaination
The ExpectedConditions clause stalenessOf will check for the staleness of the element identified as (By.xpath("//td[2]/div")). When the intended element becomes stale, you can check for assertTrue(boolean condition). assertTrue() would assert that a condition is true. If it isn't, an AssertionError would be raised.
assertFalse(condition)
If you still want to implement the FalsePossitive case of assertFalse(condition) raising Error you still can :
Assert.assertFalse(new WebDriverWait(driver, 20).until(ExpectedConditions.stalenessOf(driver.findElement(By.xpath("//td[2]/div")))));
I think, timeouts are not set to WebDriver. try this
assertFalse(isElementPresent(By.xpath("//td[2]/div")));
private boolean isElementPresent(By by) {
driver.timeouts().implicitlyWait(5, TimeUnit.SECONDS);
driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
try { driver.findElement(by); return true; }
catch (NoSuchElementException e) {
return false; }
I am trying to automate an application which involves CAPTCHA.
I tried to use WebDriverWait with below code:
WebDriverWait mywait = new WebDriverWait(driver,20);
mywait.until(ExpectedConditions.attributeToBeNotEmpty(driver.findElementByClassName("loginCaptcha"),"value"));
Now the problem here is as soon as I enter the first character of captcha in the text, the above condition becomes true and the next statements are getting executed which results in invalid captcha error.
Is there any way to wait until 5 characters are entered in the text box(my captcha is always 5 characters fixed in length.)
PS: I dont want to use static waits.
First of all, you should not try and solve CAPTCHA with selenium. The whole purpose of CAPTCHA is to prevent UI automation. If you want to overcome CAPTCHA, you should use internal APIs of your SUT.
Regarding waiting for specific text length, it should be something like:
//First init WebDriverWait to 20 sec
WebDriverWait mywait = new WebDriverWait(driver, 20);
//Locator to your DOM element
By byClass = By.class("loginCaptcha");
//Wait until text box has value greater or equal 5 character
mywait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return (d.findElement(byClass).getAttribute ("value").length() >= 5)
}
});
You can do this by using the following:
FluentWait
private Wait<WebDriver> wait = new FluentWait<>(yourWebDriverInstance).withTimeout(10, TimeUnit.SECONDS).pollingEvery(500, TimeUnit.MILLISECONDS).ignoring(NoSuchElementException.class);
A custom expected conditions method:
private Function<WebDriver, Boolean> expectedConditions(boolean condition) {
return driver -> condition;
}
Method calling the custom expected conditions:
public void waitUntilElemValueLengthEquals(WebElement element, int length) {
try {
wait.until(expectedConditions(element.getAttribute("value").length == length));
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
throw e;
}
}
USAGE:
WebElement e = driver.findElementByClassName("loginCaptcha");
waitUntilElemValueLengthEquals(e,5);
SIDE NOTE:
For an actual implementation, it would be good if you can create a class which implements the WebDriver interface. That class will contain all the WebDriver interface methods AND all your custom methods (like the ones above).
You should use some expected condition like to wait until the submit button is clickable if it's grayed out until you typed 5 characters or to save in a variable the fifth captcha character and then to wait until the this fifth character is typed in the input element.
I'm currently checking to see if a WebElement is stale by doing the following:
public static boolean isStale(WebElement element) {
try {
element.click();
return false;
} catch (StaleElementReferenceException sere) {
return true;
}
}
This is the same as the solution offered to this question:
Check for a stale element using selenium 2?
However, this seems rather messy to me. Is there a cleaner way that I can check if an element is stale, without having to throw and catch an exception?
(Also, as a side, if I have to stick with throwing and catching an exception, is there something better to do than clicking/sending keys/hovering to throw said exception? I might have a WebElement that I don't want to do any of these actions on, as it may inadvertently affect something else.)
Webdriver itself uses the try/catch-construction to check for staleness as well.
from org.openqa.selenium.support.ui.ExpectedConditions.java:
public static ExpectedCondition<Boolean> stalenessOf(final WebElement element) {
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver ignored) {
try {
// Calling any method forces a staleness check
element.isEnabled();
return false;
} catch (StaleElementReferenceException expected) {
return true;
}
}
#Override
public String toString() {
return String.format("element (%s) to become stale", element);
}
};
}
The isEnabled() check is better than using a click action - clicking an element might cause unwanted side effects, and you just want to check the element's state.
I know this already has an accepted answer and I don't know the bigger context of how you use the staleness check but maybe this will help you or others. You can have ExpectedConditions.stalenessOf(WebElement) do the work for you. For example,
WebElement pageElement = driver.findElement(By.id("someId"));
WebDriverWait wait = new WebDriverWait(webDriver, 10);
// do something that changes state of pageElement
wait.until(ExpectedConditions.stalenessOf(pageElement));
In this case, you don't have to do pageElement.click(), etc. to trigger the check.
From the docs, .stalenessOf() waits until an element is no longer attached to the DOM.
References: ExpectedConditions
Classic statement for C# to check staleness of web element
protected bool IsStale
{
get { return ExpectedConditions.StalenessOf(webElement)(WebDriver); }
}
I don't fully understand what you want to do. What do you mean by 'messy' solution?
Maybe you can use an explicite wait an as expected condition stalenessOf in combination with not.
But every solution with that don't seems stable to me.
What I do is, that I have an clicking routine in a helperclass, the idea is like:
public void ClickHelper(WebDriver driver, By by){
int counter = 1;
int max = 5;
while (counter <= max) {
try {
WebElement clickableWebElement = driver.findElement(by);
clickableWebElement.click();
return;
} catch (StaleElementReferenceException e) {
System.out.print("\nTry " + counter + " with StaleElementReferenceException:\n" + e.getMessage() + "\n");
}
versuche++;
}
throw new RuntimeException("We tried " + max + " times, but there is still an Exception. Check Log!");
}
Be careful, I just entered this by simplyfying my own methode (there are some more checks and personally I use xpath and not by etc). There might be some typo-mistakes, but i guess you will understand the basic idea. Since I use this Helpermethode, I don't have to care about Staleness of webelements. You can alter the max-value, but personally I think, if the website is such unstable, that the Element is stale so much, I would talk to the developer, because this would not be a good website.
This should work without dependency of display/ enabled:
def is_element_on_page(element):
try:
element.get_attribute('')
return True
except StaleElementReferenceException:
return False
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 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