I created few test cases on Selenium using Java. Unfortunately when I click an element on the page, before I could move on to any other action, I have to wait till the page loads.
I have tried driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);. Unfortunately this creates another problem. Even if the page loads, it waits 30 seconds before it started testing on the page.
What I found the best way is to send ESCAPE key to stop page load.
Is there anyway I could check if an element exists and when it does, send ESCAPE key to the browser to stop page load?
This part is bugging my mind as I have to wait till page loads before Java reads the next line of the code so I can't send ESCAPE key to browser till the page actually stops loading.
Edit
I have just tried using a new thread to do the job but it seems driver is completely locked out, can't do any process on it before page stops loading.
I'm out of ideas for the moment but I believe there should be a way.
Using timeouts() is causing whole test case to stop.
First I'd like to say this isn't a best practice. The selenium click method states that if the click triggers a page load, selenium will do its best to block until the page is loaded. Instead of clicking via the click method you could try sending the click event via JavaScript. Then wait for the element like normal.
You can try driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS); It is supposed to throw an error after timeout is over. I have never used it but maybe you can try and catch this error and continue with your test. But your page could end up in an unstable state with everything not loading and test interacts with elements.
I did it in C#, scenario is the same elsewhere.
Define driver like this:
var firefoxOptions = new FirefoxOptions();
firefoxOptions.PageLoadStrategy = PageLoadStrategy.None;
driver = new FirefoxDriver(firefoxOptions);
PageLoadStrategy.None means when open a URL, continue to next line regardless of the results and do not wait to load the page.
Usually, it takes some seconds to load a page and element appears, suppose I'm waiting for email_user element to appears:
int user_emailID = 0, popupAlert = 0;
do
{
float timeToWait = 0;
driver.Navigate().GoToUrl("https://stackoverflow.com");
do
{
await Task.Delay(500);
timeToWait += 0.5F;
user_emailID = driver.FindElements(By.XPath("//input[#id=\'user_email\']")).Count;
}
while (user_emailID == 0 && timeToWait < 10);
if (user_emailID == 1)
{
//Element exists now!do something and don't wait for page to load completely
}
}
while (user_emailID != 1);
More explanation: when open a URL, first loop check the presence of element every 0.5 second, if it appears, the loop stops. If after 10 seconds it couldn't find the element, the page will reloaded !!
Hope this get you the idea.
Remember, exception must not happen in your codes !!
Related
I have an element on a web page that is updated by AJAX almost immeditely after page load. I know what I expect the change to be and want Selenium to wait for the change and capture it. I am trying to use an explicit wait for this. However, I am getting a timeoutException as Selenium is not detecting the change.
I know I am properly selecting the element and value as I have used print statements. I've solved the issue using
Java Thead.sleep(1000)
and then using
driver.findElement(By.id("balance-sms")).getText()
but this is not an acceptable solution.
private void modalSend(String newBalence){
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.elementToBeClickable(modalSendButton)); //this wait works fine
modalSendButton.click(); //this results in a page refresh
//now check for the AJAX change to this element...normally takes about 1 second
wait.until(ExpectedConditions.textToBePresentInElement(driver.findElement(By.id("balance-sms")),newBalence));
//continue...
}
Try the locator using xpath and visibilityOfElementLocated with a few modifications :
//now check for the AJAX change to this element...normally takes about 1 second
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[#id='balance-sms' and contains(text(),'" +newBalence +"')]")));
//continue...
Try with fluent wait like below instead of Thread.sleep
Wait wait = new FluentWait(WebDriver reference)
.withTimeout(timeout, SECONDS)
.pollingEvery(timeout, SECONDS)
.ignoring(Exception.class);
i have the following issue, after perform the login, the system load the main page, its like 5 seconds doing it, so after that, the script should type over 3 fields and perform a tab to get more info, but the thing is that sometimes is working and sometimes does not, in 5 chances, only one worked, i do not know if its something about the time to get all fields or something like that, am using IE 9 cause the app only works on IE
Here´s the code:
`
System.setProperty("webdriver.ie.driver","C:\\Apps\\eclipse\\IEDriverServer.ex;
WebDriver driver = new InternetExplorerDriver();
driver.get("http://15.192.41.95/Cabina/asp/Login.asp");
WebElement text1 = driver.findElement(By.id("text1"));
text1.sendKeys("xxxx");
WebElement password1 = driver.findElement(By.id("password1"));
password1.sendKeys("xxxx");
WebElement aceptar = driver.findElement(By.id("ok1"));
aceptar.click();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.switchTo().frame(driver.findElement(By.name("menu")));
WebElement txtNumPolSol = driver.findElement (By.id("txtNumPolSol"));
txtNumPolSol.sendKeys("877885");
WebElement Text8 = driver.findElement(By.name("txtNumofic"));
Text8.sendKeys("228");
WebElement txtCveInc = driver.findElement(By.name("txtCveInc"));
txtCveInc.sendKeys("1");
WebElement clave = driver.findElement(By.id("txtCveInc"));
clave.sendKeys(Keys.TAB);
driver.switchTo().frame(driver.findElement(By.name("dest")));
WebElement txtNomrepo = driver.findElement(By.id("txtNomrepo"));
txtNomrepo.sendKeys("Jorge Villarreal");
driver.findElement(By.id("txtRelacion")).sendKeys("Conductor");
WebElement txtTelrepo = driver.findElement(By.id("txtTelrepo"));
txtTelrepo.sendKeys("83029090");`
Here the different issues i got:
1) Unable to find element with name == txtOficina
2) Element is no longer valid
3) Unable to find element with id == txtCveInc (the field is there)
4) Unable to find element with name == txtCveInc (the field is there)
The steps that the system to get the issues are:
1) Log in (so far so good)
2) The system load the main page (the page has frames and gets all fields in 5 secs...)
3) The script type over the txtNumPolSol, txtNumofic and txtCveInc (most of the issues are in the last two fields)
4) The script performs a tab
5) The system load the some information regarding the record and the script continue...
Note: Almost all the issues occur on step 3...
Thanks for your feedback!
This sounds like a timing problem. Your simulated user is proceeding faster than the page becomes ready. Depending on the timing of the page loading, different problems occur.
The solution is to add a wait after steps that trigger a DOM change than influences your next step, but doesn't cause WebDriver to wait before returning. Google 'webdriver wait for element' to get lots of ways to do it.
I was also facing the similar kind of problem but i tried to find the elements with Css_Selectors and X paths instead of ids, that worked for me
The key here is to add atleast 1 second of implicit wait after every action, i.e. send keys etc. It will allow 'driver.findElement' enough time to find the element. Though I would suggest keeping this code in a testBase or a reusable method.
driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
It will help in making your webtests less flaky.
I'm using webdriver(java) for a unique test where a page reloads itself when you log on, I've been unable to wait for the element to load because it is already there before the reload. So far the only way I've been able to get it to work is to use a thread.sleep, is there a way to listen for a page refresh?
One way to solve this is, to get a reference to the element you need, that appears both on the login-page and the reloaded page.
Then you can use the ExpectedConditions.stalenessOf to occur, and then you can be sure, that the element is removed from the DOM and a new element is created. Well, the last part is not guaranteed by this method, but at least you know that the old element is gone.
The code could look something like this:
WebElement elementOldPage = driver.findElement(By.id("yourid"));
... do login etc ...
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.stalenessOf(elementOldPage));
WebElement elementNewPage = driver.findElement(By.id("yourid"));
Building upon the accepted answer from Kim Schiller one might be interested in the following piece of code. It is surely not perfect due to the sleeps, so be free to suggest improvements to make it more bulletproof. Also note I'm no expert with selenium.
The if branch waits for the top level node in the html to go stale in case of a page reload. The else branch simply waits until the drivers url matches the request url in case we load a different page.
def safe_page_load(url):
if driver.current_url == url:
tmp = driver.find_element_by_xpath('/html')
driver.get(url)
WebDriverWait(driver, 2).until(ExpectedConditions.staleness_of(tmp))
else:
driver.get(url)
while(driver.current_url) != url:
sleep(0.3)
sleep(0.3)
Happy if I could help someone.
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.
The button type is image, and the relevant code in HTML code attached. I have entered all the data and clicked on Apply Now button, it is not at all saving. But when I try to create it manually, it is saved in less than 15 seconds.
Please find the attached screen shot.
The relevant code for the same:
//Navigating to Quick Application
driver.get(QAurl);
Thread.sleep(15000);
driver.findElement(By.id("DdlSalesPerson")).sendKeys("Swamy m Kumara");
driver.findElement(By.id("TxtFName")).sendKeys("Kumar");
driver.findElement(By.id("TxtLName")).sendKeys("Swamy");
driver.findElement(By.id("TxtAddress")).sendKeys("434, Main Road, Somajiguda");
driver.findElement(By.id("TxtZip")).sendKeys("79081");
driver.findElement(By.id("TxtSSN1")).sendKeys("881");
Thread.sleep(15000);
driver.findElement(By.id("TxtSSN2")).sendKeys("72");
driver.findElement(By.id("TxtSSN3")).sendKeys("4365");
Thread.sleep(5000);
driver.findElement(By.id("TxtDayPhone1")).sendKeys("963");
driver.findElement(By.id("TxtDayPhone2")).sendKeys("210");
driver.findElement(By.id("TxtDayPhone3")).sendKeys("5478");
Thread.sleep(5000);
driver.findElement(By.id("ChkIAgree")).click();
driver.findElement(By.id("TxtSignature")).sendKeys("Kumar Swamy");
Thread.sleep(5000);
System.out.println("Entered all the required fields");
//Reading the value in the image.
WebElement element = driver.findElement(By.id(OR.getProperty("FP_SImg_ID")));
String src = ((JavascriptExecutor)driver).executeScript("return arguments[0].attributes['src'].value;", element).toString();
img =src.split("=");
System.out.println("Value retrieved from the Image source: "+img[1]);
driver.findElement(By.id(OR.getProperty("FP_TxtSImg_ID"))).sendKeys(img[1]);
Thread.sleep(5000);
driver.findElement(By.id("TxtEmailId")).sendKeys("abc#abc.com");
driver.findElement(By.name("BtnSubmit")).click();
Thread.sleep(35000);
System.out.println("Successfully Applied from the QuickApp");
HTML code for the Apply now button:
<input id="BtnSubmit" type="image" style="height:33px;width:121px;border-width:0px;"
onclick="javascript:return validateControls();" src="../Common/Images/HybridQA
/apply_now.png" title="Submit Here" tabindex="45" name="BtnSubmit">
Any help will be appreciated.
You have 1 minute 25 seconds of Thread.sleep() in your code...
Remove all the thread.sleep(), if you are waiting for elements to appear do it properly, use an explicit wait:
http://docs.seleniumhq.org/docs/04_webdriver_advanced.jsp
To take an example from the page linked above:
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Have a look at the ExpectedConditions class to see the available conditions built into selenium, if they don't meet your needs it's trivial to write your own expected conditions.
-------------------Edit-------------------
For the record this answer is for the original question that was asked which is quoted below (you can have a look at the edit history of the original question to verify this as well).
Taking long time to save after clicking on Apply Now button using Webdriver in Java
Taking long time to save after clicking on Apply Now button using
Webdriver in Java. I have entered all the data and clicked on Apply
now button, it is not at all saving. But when i try to create it
manually, it is saved in less than 15 seconds. Please find the
attached screen shot.
There could be 2 reasons for this problem.
One is from the HTML code of 'Apply Now' button, I could see that it shows as "input
id='BtnSubmit'", but in your script its written as
'driver.findElement(By.name("BtnSubmit")).click();'.
Shouldn't it be "driver.findElement(By.id("BtnSubmit")).click()"?; 'name' must be
replaced with 'id'.
At the end of the script you click 'BtnSubmit', the session might expire immediately after
you click that button. This problem usually occurs when you use an older and new version
of selenium standalone jar file. See to that you use only the latest version and not in
addition to an old version.
Use this,
driver.findElement(By.id("TxtEmailId")).sendKeys(Keys.ENTER);
after this,
driver.findElement(By.id("TxtEmailId")).sendKeys("abc#abc.com");
and comment,
driver.findElement(By.name("BtnSubmit")).click();
So your code looks like,
driver.findElement(By.id("TxtEmailId")).sendKeys("abc#abc.com");
driver.findElement(By.id("TxtEmailId")).sendKeys(Keys.ENTER);
//driver.findElement(By.name("BtnSubmit")).click();
Sometimes it's difficult to handle image buttons because these buttons are activated when all required fields are entered. Make sure you filled all mandatory fields and press enter after entering last field in the form. First try to do it manually. Instead of clicking on button press enter at last input field and use same stratefy with automation.
Update:
Use your own code and replace Thread.sleep() with below method.
Call it like,
waitForElementToBePresent(By.id("DdlSalesPerson"), 15000);
It waits for next element whichever you pass as argument. It returns true if found or false if not. If element found within the given time it will return true immediately instead of waiting for given time.
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;
}