I have been running into intermittent errors with some java selenium-rc tests which I think are related to a page which has an ajax poll and automatically refreshes when some condition is reached on the server. In this scenario, I have no way of asking selenium to wait for the page to load, and so I run into a bunch of random "Couldn't access document.body" errors.
So, is there some way I can cause selenium to gracefully handle this situation? If not, is there some way I could detect whether the user is selenium from the page's javascript, and disable the automatic refresh?
If it helps at all, the javascript code in the page looks something like...
var ajax = new Ajax(url, {
update: state,
method: 'get',
onComplete: function(message) {
if (some_condition) {
window.location.replace(unescape(window.location));
}
}
});
One solution might be to always use a waitForCondition using isElementPresent before attempting to interact with the application under test. You could put the following method in a superclass to keep your tests more readable. Alternatively you could create helper methods for common Selenium commands that perform this wait.
/** Waits for an element to be present */
public static void waitForElementToBePresent(String locator) {
session().waitForCondition("var value = selenium.isElementPresent('" + locator.replace("'", "\\'") + "'); value == true", "60000");
}
You may also want to wait for the element to be visible, as waiting for it to just be present isn't always enough (imagine a textbox that is always present but hidden until a certain condition). You can combine this with the above method:
/** Waits for an element to be visible */
public static void waitForElementToBeVisible(String locator) {
waitForElementToBePresent(locator);
session().waitForCondition("var value = selenium.isVisible('" + locator.replace("'", "\\'") + "'); value == true", TIMEOUT);
}
Incidentally, the WebDriver (Selenium 2) team are working on having implicit waits, specifically to address AJAX issues where elements are not present immediately.
My solution was to disable the refresh in javascript by wrapping it in something like the following...
var isSeleniumActive = parent.seleniumAlert;
if (isSeleniumActive) {
alert("Selenium");
} else {
alert("Not selenium");
}
I'm not sure if the seleniumAlert function here is likely to sick around forever, so be aware if you're taking this that you may be relying on internal selenium implementation details of selenium.
There i was facing the same problem and i use a single line of code and it helps.
i was getting the error about the page is getting auto refresh
plus this warning:
-1490472087141 Marionette WARN Using deprecated data structure for setting timeouts
all i use is
Thread.sleep(2000)
and it worked for me.
I think that you can pause, or use a click and wait. There are a few good articles on the google. Good luck.
Edit for your comment:
How about the waitFor command?
Related
java-selenium
Hi,
I am recently working with selenium-java for project automation.
I found that in a lot of codes are using this method.
waitForAngularRequestsToFinish();
I don't know exactly why is this in the main function.
And in the next example is my code, cause I don't know what is the benefit of using at the beginning and at the end this method.
Example of this code:
public void ActualizarEstadoDeFinalizacion(String caso) {
waitForAngularRequestsToFinish();
JavascriptExecutor js = (JavascriptExecutor) getDriver();
js.executeScript("window.scrollBy(850)");
WebElement htmlScrollProblemaDeCierre = findBy(String.format("//*[#title='%s']//ancestor::div[#class='oneWorkspaceTabWrapper']//span/span[contains(.,'Estado de finalización')]//following::a[1]/parent::div/parent::div/parent::Div/parent::div",caso));
htmlScrollProblemaDeCierre.click();
waitForAngularRequestsToFinish();
}
The author of the code has created a function called waitForAngularRequestsToFinish().
This is a way to wait for all the pending requests to load...
Generally, it will be implemented with JavaScript... You can see it in paul-hammant's ngWebDriver.
If you want you can implement it yourself:
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("var injector = window.angular.element('body').injector(); var $http = injector.get('$http'); return ($http.pendingRequests.length === 0);")
The benefit of using it at the beginning and at the end of the method is to ensure that the page you come to and the page you lead to are fully loaded.
Hope this helps you!
This method waitForAngularRequestsToFinish(); is used to wait for the elements or request in Angular application. This method will wait until all the request has been completed. This is mostly used in Angular application. For more check its documentation in the given link.
https://github.com/paul-hammant/ngWebDriver
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 am testing the newly built framework, and am often encountering org.openqa.selenium.StaleElementReferenceException while working in the Chrome browser. Could there be an issue with the framework design?
There are no issues when I run my tests in other browsers. I tried many types of custom waits that catch the StaleElementReferenceException and then loops to find the element, but no luck.
Has anyone faced a similar issue and found a solution?
Chrome version: 38.0.2125.111
Selenium version: 2.43.1
public WebElement waitTill(By by){
WebElement ele = null;
for(int i=0; i<15; i++){
try {
ele = driver.findElement(by);
if(ele==null)
Thread.sleep(2000); //in last attempt used thread...we wont use this in actual practice
else
break;
} catch (NoSuchElementException | InterruptedException e) {
System.out.println(e.getMessage());
}
}
return ele;
}
public WebElement getElement(String loc) {
String locator = initUtils.ORProp.getProperty(loc);
WebElement element = null;
try{
By by = getBy(locator);
element = waitTill(by);
}catch(NoSuchElementException e){
System.out.println(e.getMessage());
}catch(StaleElementReferenceException e){
By by = getBy(locator);
element = waitTill(by);
}
return element;
}
This sort of error is caused by the webpage changing in between times the element is checked.
This exception is mostly caused by bad tests I am afraid to say. A few things to check for are:
Make sure that you are giving the page time to load when you go to it
before you start interacting with it, even if you think it has
finished loading it may still be waiting for something in the
background and when it arrives the page changes.
Make sure that if you interact with any element that changes the page
make sure you again wait for the page to change and any html requests
to process.
These two things may be the cause of most of your problems, I would recommend using a ajax that uses jQuery ajax start and stop in order to make sure that the page is loaded before modifying it. What you need to remember is selenium is so much faster than a user could possibly interact with the page and you need to handle that by increasing checks.
I would also recommend checking whether an element is on the page and that it is visible before even trying to interact with it.
In a worse case senario you could use a try and catch block to check for the element but if you make sure the page is not changing then you shouldnt get the exception. It does differ between browsers due to browser speed and webdriver speed.
Some of the code I use is:
var finished = false;
function ready() {
if (finished == true) {
$( "#main" ).addClass("ready");
}
}
$( document ).ajaxStart(function() {
$( "#main" ).removeClass("ready");
finished = false;
});
$( document ).ajaxStop(function() {
finished = true;
window.setTimeout(ready,500);
});'
This checks that the page is fully loaded and no requests are pending, I just execute this once the browser is open, I then can just check whether the class is present and if it is I am ready to go. I call the same check whenever the page changes as well.
Programmatically, I might use an explicit wait with ExpectedConditions instead of Thread.sleep():
public WebElement element2Click (By by){
WebElement myClickableElement = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.elementToBeClickable(by));
return myClickableElement;
}
But if this does not solve the problem and your automated test program is quite stable across the other browsers, it could be that the web page or webapp you are testing does not support Chrome, and you may be seeing StaleElementReferenceException errors because the HTTP messages are not communicating properly. In this case, check out the HTTP traffic on the browser.
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.
How would you go about checking to see if a particular WebElement has been updated?
I have a test that performs a form save and then the UI returns a success/error message.
I am doing a series of saves and I need to test and see if the message is what is expected.
Selenium goes so fast that the browser does not have a chance to catch up.
This is the code that I have for testing for an error message (There is an equivalent success message function as well)
public void assertErrorMessage(String errorMsg) {
// set the wait time a bit so the page can load.
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
List<WebElement> results = driver.findElements(By.xpath("//div[#id='lift__noticesContainer__']/descendant::*"));
boolean success = false;
String message = "";
for (WebElement result : results) {
String id = result.getAttribute("id");
if (id.contains("___error")) {
success = true;
}
if (result.getTagName().equals("li")) {
message += result.getText().trim();
}
}
Assert.assertTrue(success, "No error message generated");
Assert.assertTrue(message.equals(errorMsg), "Expecting message: \"" + errorMsg + "\" but got \"" + message + "\"");
}
As this is written, this looks for the presence of a particular <div> and checks to see if contains certain attributes. If it does, get the message.
The thing is, this will always be true and hence my tests are failing since the message is different than the previous one, but the UI hasn't caught up to where selenium is.
My solution so far to force a Thread.sleep(2000) to just pause a bit to allow for the UI to catch up. I know that it is frowned upon to use Thread.sleep().
i.e. (pseudo-code)
page.setField("value");
page.save();
Thread.sleep(2000);
page.assertErrorMessage("Error message");
Is there any way let me check to see if a WebElement has been updated? If so, I could use the Selenium waits to test for that.
Or perhaps someone else has a suggestion for how to do this?
Thanks in advance.
If the result displayed keeps getting every time you perform page.save().
The best way to make sure that your code waits for the browser to update the message is by using the WebDriverWait object.
A simple example would be -
new WebDriverWait(driver, 10).until(ExpectedConditions.textToBePresentInElement(By.xpath("xpath"), "message"));
You can check if that particular element has the message you are looking for. If that message is not present even after 10 seconds then a TimedOutException will be thrown.
You can check out more variations on the ExpectedConditions as suitable in your situation. Hope this helps you.