I am attempting to automate a task involving a JavaServer Page using the Selenium Webdriver. I have built a test that works about 90% of the time, meaning that the Webdriver makes it through all the tasks without any errors. During the test the browser executes the actions below:
opens a page
clicks on a link and switches windows
closes the original window
logs into a system
switches frames
clicks a link
fills out a form
submits the form
...more similar tasks
Unfortunatly, some of the time the Webdriver will randomly fail on one of the steps. This is because it could not find something, for example 'no frame found', 'unable to find element with link text...' and other similar errors. I am not sure why this happens sometimes and it appears to happen randomly at different stages in the test. I searched around for a solution and the best I could do was slow down the Webdriver with thread.sleep at various stages in the program. This seems like a very haphazard way to solve the problem to me and I am not even sure the problem is that the driver is moving too quickly. Even if I slow it down half a second I still sometimes get errors. I am a new user of Selenium and I do not know if this is usually a problem. Does anyone have a better way to address this problem? Am I overlooking something simple?
I did the same initially using thread sleep to develop my scripts. However, even though the scripts work while development, but it will be unrealiable on a production run as it fail inconsistently --which adds to the frustration. This is because thread sleep utilizes fixed waiting time and if elements do not get attached in time, it will fail the tests. singe31 has given a valid solution. Another solution would be by using fluentWait:
public void fluentWait(final By by)
{
FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(60, TimeUnit.SECONDS)
.pollingEvery(5, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(by);
}
});
}
Here, the Selenium Webdriver will wait for at least 60 seconds to find an element until it throws of an TimeOutException. Otherwise, it will poll the DOM to find the element every 5 seconds and if the element is not found "NoSuchElementException" exception will be ignored.
Another problem which you are bound to face is, StaleStateReference or NoSuchElementException. You can check this link for solving that issue.
Hope it helps.
It's a common issue, instead of using Thread.sleep(duration) you should better create some utility method like
public WebElement waitForElementPresent(By by, int timeout) {
WebDriverWait wait = new WebDriverWait(driver, timeout);
WebElement element = null;
try {
element = wait.until(ExpectedConditions.presenceOfElementLocated(by));
} catch (TimeoutException e) {
e.printStackTrace();
}
return element;
}
This way if the element is already there you won't wait, and if it's loading it will wait until it finds it or until the timeout is triggered
Related
I am new to selenium (but experienced java developer).
I am using something like below:
WebElement searchBasket = pDriver.findElement(By.xpath("//a[contains(.,'Search&Baskets')]"));
WebElement searchproduct = pDriver.findElement(By.xpath("//a[contains(.,'Search a product')]"));
//if search an agreement is not show up, then click on other menu, then click it back
pWait.until(ExpectedConditions.elementToBeClickable(By.xpath("//a[contains(.,'Search&Baskets')]")));
pDriver.findElement(By.xpath("//a[contains(.,'Search&Baskets')]")).click();
// click on search an agreement
try {
pWait.until(ExpectedConditions.elementToBeClickable(By.xpath("//a[contains(.,'Search&Baskets')]")));
action = new Actions(pDriver);
action.moveToElement(searchBasket).build().perform();
pWait.until(ExpectedConditions.elementToBeClickable(By.xpath("//a[contains(.,'Search a product')]")));
searchproduct.click();
} catch (TimeoutException e) {
}
where pWait is:
WebDriverWait wait = new WebDriverWait(driver, 15);
however when I run the test case I get below error:
Unable to locate element: {"method":"xpath","selector":"//a[contains(.,'Search&Baskets')]"}
Command duration or timeout: 4 milliseconds
I thought it should have wait atleast 15 seconds before throwing this exception. From the log above it looks like it threw exception only in 4ms.
and i could see on console that as soon as it hit that line, it threw exception.
I have implicit waiting set as 0 and using explicit wait.
Am i missing anything here.
Also, in explicit and implicit wait, is it upto that much time OR exact that much time,
example if I set implicit wait as 10 sec, then does it mean wait for exact 10 sec OR wait upto 10 sec (if element found then proceed, even if element founf on 6th second)
is above same for explicit wait as well?
Please help
Let us analyze what is happening in our code.
We have defined two WebElements searchBasket and searchproduct as follows :
WebElement searchBasket = pDriver.findElement(By.xpath("//a[contains(.,'Search&Baskets')]"));
WebElement searchproduct = pDriver.findElement(By.xpath("//a[contains(.,'Search a product')]"));
We havn't tried to use those WebElements in our code at immediate basis, so had No Impact.
Next, we tried WebDriverWait for an WebElement as follows :
pWait.until(ExpectedConditions.elementToBeClickable(By.xpath("//a[contains(.,'Search&Baskets')]")));
Again we didn't capture the return type of the result, so had No Impact.
Now, within the try{} block we have again tried WebDriverWait:
pWait.until(ExpectedConditions.elementToBeClickable(By.xpath("//a[contains(.,'Search&Baskets')]")));
But again we havn't captured/acted on the return type of the result. That's why moving ahead when we did :
action.moveToElement(searchBasket).build().perform();
searchBasket referred to the WebElement which we have stored earlier as :
WebElement searchBasket = pDriver.findElement(By.xpath("//a[contains(.,'Search&Baskets')]"));
As this first search result (which was without WebDriverWait) may not have returned any WebElement at all and have returned Null.
Finally, the most important factor for the error Unable to locate element: {"method":"xpath","selector":"//a[contains(.,'Search&Baskets')]"} is, the
WebDriverWait instance was wait. Instead of using wait we have always tried to use pWait
So for all these reasons, WebDriverWait was never implemented properly in our code.
Mixing up ImplicitWait & ExplicitWait
The Selenium Documentation clearly mentions the following :
WARNING: Do not mix implicit and explicit waits. Doing so can cause unpredictable wait times. For example setting an implicit wait of 10 seconds and an explicit wait of 15 seconds, could cause a timeout to occur after 20 seconds.
ExpectedConditions.elementToBeClickable invokes isDisplayed() and isEnabled() methods on EXISTING WebElement.
You are providing By as a parameter which means, the driver has to find your element first. It failed to do this.
Make sure your element is present by using wait until presenceOfElementLocatedBy(By by).
Example:
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.presenceOfElementLocatedBy(By.xpath("//a[contains(.,'Search&Baskets')]")));
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//a[contains(.,'Search&Baskets')]")));
Overview : I have already prepared the automation script in Selenium Web driver script in Java which will login into a website and make the selections automatically and once the selections are completed it will run the report.
What I want : I am facing issue while optimizing my automation script.
Brief Explanation : Actually I am familiar with different kinds of wait we are using in Selenium but all those wait i.e implicit,explicit or fluent wait didn't able to help me out in making the code more optimized.Currently I am using Thread.sleep() method everywhere in order to run the script completely without any fail but I know this should not be best practice to be get followed because sometime Elements loads fast and sometime slow because of that either my Script execution took long time or failed based on Element availability.I created one separate method for Webdriver wait and Which I can call for various webelements whenever I needed in my main script but this approach also sometime works or sometime not even though I am passing 800 Second as Time period to wait but if I use Thread.sleep(5000) it will work without any issue not sure why ??
What I want to be have a separate method for wait which can be called in main script whenever required and I want my script to be worked flawless the moment webeelment visible just like what we human do when we interacting with any web.
Note : I have tried ExpectedCondition methods like elementtobeclickable, visibilityOfElementLocated,presenceofElementLocated all of them sometime these work but sometime won't.
Separate Method of wait I have created
public static WebElement waiting(WebDriver driver,String path){
WebDriverWait wait = new WebDriverWait(driver,800);
WebElement element=wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(path)));
return element;
}
Piece of main code where I am calling this Method.
if(nam.equals("Some name"))
{
WebElement e=driver.findElement(By.xpath("1st Webelement path"));
e.click();
System.out.println("Value clicked under First Drop Down is:"+e);
Listing.waiting(driver,"2nd WebElement xpath").click();
//Thread.sleep(5000);
//driver.findElement(By.xpath("2nd WebElement xpath")).click();
System.out.println("Second Dropdown clicked");
}
When I commenting the Thread.sleep() then it will throw the ElementNotFound exception even though I have used 800 Seconds in Webdriver wait method but the moment I removed the comment from Thread.sleep() method it will work.
Kindly Help me in getting the reusable and useful wait method which I can call several times in my main code.
Thanks in Advance !!
This usually works for me (not FluentWait though):
WebDriverWait wait = new WebDriverWait(driver, TIMEOUT);
ExpectedCondition elementIsDisplayed = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver arg0) {
try {
webElement.isDisplayed();
return true;
}
catch (NoSuchElementException e ) {
return false;
}
catch (StaleElementReferenceException f) {
return false;
}
}
};
wait.until(elementIsDisplayed);
Of course, setup TIMEOUT with the amount of time you want to wait for the element to be found (that is in seconds).
I'm using web driver wait as explicit wait in selenium web driver. But It's not consistent it seems. before mouse over operations, links It's throwing unable to locate element error. Please see the below method and suggest where am I going wrong.
public WebElement waitForElement(String xPathExpression) {
WebDriverWait wait = new WebDriverWait(driver,30);
WebElement element = wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.xpath(xPathExpression))));
return element;
}
Just a guess, but I might have seen similar behavior on very dynamic pages. I.e the element on the page changes while being evalued.
I'm able to workaround these kind of problems by using FluentWait#ignoring
WebDriverWait wait = new WebDriverWait(driver,30)
.ignoring(NoSuchElementException.class);
I am using Webdriver in Java and I encountered an issue repeatedly that I can't find a proper solution yet.
It is to do with doing actions on a page that will cause this page DOM to change (for example, Javascript lightbox), then my JUnit test is expecting new elements after the DOM change but my test is getting the old DOM element.
To give you an example, I have a scenario as below.
First of all click “Add item” button in the below image and the light box appears:
Then fill in all the item details and click "Add & Close". You will see the screen below:
Notice that now there is an info message Your item ... has been added.
Now I put keywords in the Search text box and hit enter and the info message will be changed to below:
In my JUnit test, the flow is like below:
....
itemDetailsPage.clickAddAndClose();
itemDetailsPage.searchItemBy("Electricity");
assertEquals("Your search for 'electricity' returned 2 results.",
itemDetailsPage.getInfoMsg());
....
Now this test is not very robust, because if the network is slow, most of the times, getInfoMsg() will return the previous info message Your item ... has been added instead of the latest info message, which causes the test to fail. Just a side note that these two info message have share the same html element id.
The solution I am trying to implement here are:
add explicit wait in clickAddAndClose()
So it looks something like:
public void clickAddAndClose() {
...
clickWhenReady(driver, By.id(addAndCloseButtonId));
...
waitForElementByLocator(driver,By.id(itemInfoMsgId),10);
}
The second wait proves to be useless because, itemInfoMsgId already exist when the user added the item from the add item lightbox.
add waitForPageLoaded() method at the end of clickAddAndClose() to try to wait for the page to finish reloading. The generic method for waitForPageLoaded() below:
public void waitForPageLoaded(WebDriver driver) {
ExpectedCondition<Boolean> expectation = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return ((JavascriptExecutor) driver).executeScript(
"return document.readyState").equals("complete");
}
};
Wait<WebDriver> wait = new WebDriverWait(driver, 30);
try {
wait.until(expectation);
} catch (Throwable error) {
assertFalse("Timeout waiting for Page Load Request to complete.",
true);
}
}
I am expect at the end of clickAddAndClose(), it will see this page is still being updated so it will wait until the info message has been updated. But this does not seem to work either.
That leaves me to the last choice will is to add a thread sleep at the end of clickAddAndClose(). I want to avoid using it.
Is there a generic way of solving this kind of problem? How do I detect that the page DOM is still changing and tell Webdriver to wait until it finishes refreshing?
Waiting for the page to be loaded won't work if (as it seems to be the case) your page is being modified by AJAX operations.
Instead of waiting for the page to load, wait for the condition you are testing to become true. This way, you give the AJAX operation time to execute and if your there is a problem you will get an error when the time out occurs.
I usually use the Python bindings for Selenium and it has been quite a while since I wrote Java code but I believe it would look something like this, with X being replaced with a type appropriate for the itemDetailsPage object:
new FluentWait<X>(itemDetailsPage)
.until(new Function<X, Boolean>() {
public Boolean apply(X itemDetailsPage) {
return "Your search for 'electricity' returned 2 results." == itemDetailsPage.getInfoMsg();
};
});
Seems like you need to wait until ajax has finished its job. In a similar situation I've used a method similar to waitForJQueryProcessing described here. Take a look, it might help.
I am using selenium webdriver along with TestNG in eclipse.The problem is the page relaods in the midway for some data and the time of this reload is flexible thats why I am not able apply explicit wait time.I want to make webdriver wait until this reload completes.
I am trying to do this through this code...but it is not working
public void waitForPageLoadingToComplete() throws Exception {
ExpectedCondition<Boolean> expectation = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return ((JavascriptExecutor) driver).executeScript(
"return document.readyState").equals("complete");
}
};
Wait<WebDriver> wait = new WebDriverWait(driver, 30);
wait.until(expectation);
}
try the below code for handling page load/page refresh time outs
WebDriver driver = new FireFoxDriver();
driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
please use latest version of chrome driver, as the page wait is not handled in older version of chrome driver.
Waiting for an indefinite time is not a good idea. Timing of a website is also a part of testing. If possible find out the Service Level Agreement of the "page" you are testing. If not run a speed test for the website(here is a method to test : http://tools.pingdom.com/fpt/ ) and use an average of time you get. If this also doesn't work the last option is to work with industry wide standards.
document.readyState() does not reflect the correct page load time(example- it does not wait for images/scripts to load fully). It is suggested and tested option to wait for an element on the page(preferrably the one you will operate upon in your next step of test). As others have suggested use WebDriverWait with expected conditions methods like "visibilityOf", "presenceOfElement" or many more and it should be fine.
You should use WebDriverWait and set the timeout to the maximum time you can wait. As soon as you discover that the page loaded the required data (e.g. by checking for visibility of a certain element), you may proceed with the test case.
See an example in the selenium docs.
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
For java 8 onwards:
JavascriptExecutor js = (JavascriptExecutor) driver;
new WebDriverWait(driver, 10).until(webDriver ->(js).executeScript("return document.readyState;").equals("complete"));
For java below 8 you can try the below solution from the below link. I am using it and it's working for me.
Wait for page load in Selenium