I using Selenium 2 and Java 1.7.
I want to wait my HtmlUnitDriver until ajax done when i clicked filter button.
My driver:
Webdriver driver = new HtmlUnitDriver(true);
Filter button and click action:
WebElement weFilterButton = driver.findElement(By.name("filterButton"));
weFilterButton.click();
I tried three ways for wait AJAX done.
first:
WebElement el = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("ctl00_ContentPlaceHolder1_Reports1_ajaxloadingImage")));
second:
Boolean el = wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
JavascriptExecutor js = (JavascriptExecutor) driver;
return (Boolean) js.executeScript("return document.readyState").toString().equals("complete");
}
});
and although it is not a good solution
driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);
but is not work.
EDIT
Selenium dependency is :
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.45.0</version>
</dependency>
Use the code below. It checks if the JQuery is active or not and wait till it is active.
Boolean isJqueryUsed = (Boolean)((JavascriptExecutor)driver).executeScript("return (typeof(jQuery) != 'undefined')"));
if(isJqueryUsed){
while (true){
// JavaScript test to verify jQuery is active or not
Boolean ajaxIsComplete = (Boolean)(((JavascriptExecutor)driver).executeScript("return jQuery.active == 0"));
if (ajaxIsComplete) break;
try{
Thread.sleep(100);
}catch (InterruptedException e) {}
}
}
The main problem is after you click something you have to wait for the ajax load to be invisible not visible.That means you have to wait for the element to fade away or hide.
You can achieve that by using not in ExpectedConditions.It will return a boolean type.If it is true you can proceed .Else increase the wait time and see..
WebDriverWait wait = new WebDriverWait(driver, 60);
Boolean present = wait.until(ExpectedConditions.not(ExpectedConditions.visibilityOfElementLocated(By.id("ctl00_ContentPlaceHolder1_Reports1_ajaxloadingImage"))));
Give a try with "return Ajax.activeRequestCount == 0"
Related
We are running selenium and java automation project in chrome . it was running we want migrated to Micro soft Edge in that process we upgrade to Selenium 4.0 and java 1.8 edge 99. When we run the our project we are facing below error edge-browser
org.openqa.selenium.JavascriptException: javascript error: Function is not a constructor
Same code is working in chrome.
public void waitForLoad(long seconds) {
ExpectedCondition<Boolean> pageLoadCondition = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver wd) {
try {
// this will tell if page is loaded
JavascriptExecutor js = (JavascriptExecutor) getDriver();
String windowState = js.executeScript("return document.readyState").toString();
//String windowState = (String) ((JavascriptExecutor) wd).executeScript("return document.readyState;");
log.debug("wait for window[" + wd.getWindowHandle() + "] sate:" + windowState);
log.debug("WINDOW is generated >>>>>");
return "complete".equals(windowState);
} catch (Exception e) {
log.debug("WINDOW is not loading>>>>>"+e);
return false;
}
}
};
long waitSeconds = seconds;
if(seconds<=0){
waitSeconds = ENV.getPageloadTimeout();
}
WebDriverWait wait = new WebDriverWait(driver, waitSeconds);
// wait for page complete
log.debug("PageLoadState>>"+pageLoadCondition.toString());
wait.until(pageLoadCondition);
We are facing issue in wait.until(pageLoadCondition); line in edge browser . Do any other way uset ExpectedConditio method
As you migrated from lower versions of Selenium to Selenium v4.0, the new constructor for WebDriverWait is updated as:
public WebDriverWait​(WebDriver driver, java.time.Duration timeout)
Wait will ignore instances of NotFoundException that are encountered (thrown) by default in the 'until' condition, and immediately propagate all others. You can add more to the ignore list by calling ignoring(exceptions to add).
Parameters:
driver - The WebDriver instance to pass to the expected conditions
timeout - The timeout when an expectation is called
and the implementation is as follows:
WebDriverWait wait = new WebDriverWait(testDriver, Duration.ofSeconds(1));
You need to change the defination of pageLoadCondition accordingly.
tl; dr
Class WebDriverWait
I am trying to check if web page is loaded completed or not (i.e. checking that all the control is loaded) in selenium.
I tried below code:
new WebDriverWait(firefoxDriver, pageLoadTimeout).until(
webDriver -> ((JavascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete"));
but even if page is loading above code does not wait.
I know that I can check for particular element to check if its visible/clickable etc but I am looking for some generic solution
As you mentioned if there is any generic function to check if the page has completely loaded through Selenium the answer is No.
First let us have a look at your code trial which is as follows :
new WebDriverWait(firefoxDriver, pageLoadTimeout).until(webDriver -> ((JavascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete"));
The parameter pageLoadTimeout in the above line of code doesn't really reseambles to actual pageLoadTimeout().
Here you can find a detailed discussion of pageLoadTimeout in Selenium not working
Now as your usecase relates to page being completely loaded you can use the pageLoadStrategy() set to normal [ the supported values being none, eager or normal ] using either through an instance of DesiredCapabilities Class or ChromeOptions Class as follows :
Using DesiredCapabilities Class :
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
public class myDemo
{
public static void main(String[] args) throws Exception
{
System.setProperty("webdriver.gecko.driver", "C:\\Utility\\BrowserDrivers\\geckodriver.exe");
DesiredCapabilities dcap = new DesiredCapabilities();
dcap.setCapability("pageLoadStrategy", "normal");
FirefoxOptions opt = new FirefoxOptions();
opt.merge(dcap);
WebDriver driver = new FirefoxDriver(opt);
driver.get("https://www.google.com/");
System.out.println(driver.getTitle());
driver.quit();
}
}
Using ChromeOptions Class :
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.PageLoadStrategy;
public class myDemo
{
public static void main(String[] args) throws Exception
{
System.setProperty("webdriver.gecko.driver", "C:\\Utility\\BrowserDrivers\\geckodriver.exe");
FirefoxOptions opt = new FirefoxOptions();
opt.setPageLoadStrategy(PageLoadStrategy.NORMAL);
WebDriver driver = new FirefoxDriver(opt);
driver.get("https://www.google.com/");
System.out.println(driver.getTitle());
driver.quit();
}
}
You can find a detailed discussion in Page load strategy for Chrome driver (Updated till Selenium v3.12.0)
Now setting PageLoadStrategy to NORMAL and your code trial both ensures that the Browser Client have (i.e. the Web Browser) have attained 'document.readyState' equal to "complete". Once this condition is fulfilled Selenium performs the next line of code.
You can find a detailed discussion in Selenium IE WebDriver only works while debugging
But the Browser Client attaining 'document.readyState' equal to "complete" still doesn't guarantees that all the JavaScript and Ajax Calls have completed.
To wait for the all the JavaScript and Ajax Calls to complete you can write a function as follows :
public void WaitForAjax2Complete() throws InterruptedException
{
while (true)
{
if ((Boolean) ((JavascriptExecutor)driver).executeScript("return jQuery.active == 0")){
break;
}
Thread.sleep(100);
}
}
You can find a detailed discussion in Wait for ajax request to complete - selenium webdriver
Now, the above two approaches through PageLoadStrategy and "return jQuery.active == 0" looks to be waiting for indefinite events. So for a definite wait you can induce WebDriverWait inconjunction with ExpectedConditions set to titleContains() method which will ensure that the Page Title (i.e. the Web Page) is visible and assume the all the elements are also visible as follows :
driver.get("https://www.google.com/");
new WebDriverWait(driver, 10).until(ExpectedConditions.titleContains("partial_title_of_application_under_test"));
System.out.println(driver.getTitle());
driver.quit();
Now, at times it is possible though the Page Title will match your Application Title still the desired element you want to interact haven't completed loading. So a more granular approach would be to induce WebDriverWait inconjunction with ExpectedConditions set to visibilityOfElementLocated() method which will make your program wait for the desired element to be visible as follows :
driver.get("https://www.google.com/");
WebElement ele = new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("xpath_of_the_desired_element")));
System.out.println(ele.getText());
driver.quit();
References
You can find a couple of relevant detailed discussions in:
Selenium IE WebDriver only works while debugging
Selenium how to manage wait for page load?
I use selenium too and I had the same problem, to fix that I just wait also for the jQuery to load.
So if you have the same issue try this also
((Long) ((JavascriptExecutor) browser).executeScript("return jQuery.active") == 0);
You can wrap both function in a method and check until both page and jQuery is loaded
Implement this, Its working for many of us including me. It includes Web Page wait on JavaScript, Angular, JQuery if its there.
If your Application is containing Javascript & JQuery you can write code for only those,
By define it in single method and you can Call it anywhere:
// Wait for jQuery to load
{
ExpectedCondition<Boolean> jQueryLoad = driver -> ((Long) ((JavascriptExecutor) driver).executeScript("return jQuery.active") == 0);
boolean jqueryReady = (Boolean) js.executeScript("return jQuery.active==0");
if (!jqueryReady) {
// System.out.println("JQuery is NOT Ready!");
wait.until(jQueryLoad);
}
wait.until(jQueryLoad);
}
// Wait for ANGULAR to load
{
String angularReadyScript = "return angular.element(document).injector().get('$http').pendingRequests.length === 0";
ExpectedCondition<Boolean> angularLoad = driver -> Boolean.valueOf(((JavascriptExecutor) driver).executeScript(angularReadyScript).toString());
boolean angularReady = Boolean.valueOf(js.executeScript(angularReadyScript).toString());
if (!angularReady) {
// System.out.println("ANGULAR is NOT Ready!");
wait.until(angularLoad);
}
}
// Wait for Javascript to load
{
ExpectedCondition<Boolean> jsLoad = driver -> ((JavascriptExecutor) driver).executeScript("return document.readyState").toString()
.equals("complete");
boolean jsReady = (Boolean) js.executeScript("return document.readyState").toString().equals("complete");
// Wait Javascript until it is Ready!
if (!jsReady) {
// System.out.println("JS in NOT Ready!");
wait.until(jsLoad);
}
}
Click here for Reference Link
Let me know if you stuck anywhere by implementing.
It overcomes the use of Thread or Explicit Wait.
public static void waitForPageToLoad(long timeOutInSeconds) {
ExpectedCondition<Boolean> expectation = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
};
try {
System.out.println("Waiting for page to load...");
WebDriverWait wait = new WebDriverWait(Driver.getDriver(), timeOutInSeconds);
wait.until(expectation);
} catch (Throwable error) {
System.out.println(
"Timeout waiting for Page Load Request to complete after " + timeOutInSeconds + " seconds");
}
}
Try this method
This works for me well with dynamically rendered websites:
Wait for complete page to load
WebDriverWait wait = new WebDriverWait(driver, 50);
wait.until((ExpectedCondition<Boolean>) wd -> ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));
Make another implicit wait with a dummy condition which would always fail
try {
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(text(),'" + "This text will always fail :)" + "')]"))); // condition you are certain won't be true
}
catch (TimeoutException te) {
}
Finally, instead of getting the html source - which would in most of one page applications would give you a different result , pull the outerhtml of the first html tag
String script = "return document.getElementsByTagName(\"html\")[0].outerHTML;";
content = ((JavascriptExecutor) driver).executeScript(script).toString();
There is a easy way to do it. When you first request the state via javascript, it tells you that the page is complete, but after that it enters the state loading. The first complete state was the initial page!
So my proposal is to check for a complete state after a loading state. Check this code in PHP, easily translatable to another language.
$prevStatus = '';
$checkStatus = function ($driver) use (&$prevStatus){
$status = $driver->executeScript("return document.readyState");
if ($prevStatus=='' && $status=='loading'){
//save the previous status and continue waiting
$prevStatus = $status;
return false;
}
if ($prevStatus=='loading' && $status=='complete'){
//loading -> complete, stop waiting, it is finish!
return true;
}
//continue waiting
return false;
};
$this->driver->wait(20, 150)->until($checkStatus);
Checking for a element to be present also works well, but you need to make sure that this element is only present in the destination page.
Something like this should work (please excuse the python in a java answer):
idle = driver.execute_async_script("""
window.requestIdleCallback(() => {
arguments[0](true)
})
""")
This should block until the event loop is idle which means all assets should be loaded.
I am trying to automate functional testing of a web application using Selenium and Java. In my application there are several menus. When clicked on a particular menu, a drop down of sub menus appear
click to view screenshot of menu
I use below code to click sub menu
driver.findElement(By.xpath("id=menu")).click();
driver.findElement(By.xpath("id=sub_menu_a")).click();
but the issue is that it throws a 'ElementNotVisibleException' at the second line. The same happens even if I use implicit wait
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
explicit wait
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("id=sub_menu_a")));
and fluent wait.
Wait<WebDriver> fluentWait=new FluentWait<WebDriver>(driver)
.withTimeout(60, TimeUnit.SECONDS)
.pollingEvery(2, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class,ElementNotVisibleException.class);
WebElement element=fluentWait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver){
driver.findElement(By.xpath("id=menu"));
return driver.findElement(By.xpath("id=sub_menu_a"));
}
});
element.click();
but no luck. But the code works fine if add sleep time using
Thread.sleep(sleeptime);
before and after the first line of code. But it is not a permanent solution since the page load time may vary depend on the network speed and the data in the page. Is there any other solution?
Try this
WebElement menu=driver.findElement(By.xpath("id=menu"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", menu);
WebElement subMenu=driver.findElement(By.xpath("id=sub_menu_a"));
executor.executeScript("arguments[0].click();", subMenu);
Hope this work
Try to use Actions class and see if it works or not ...
driver.findElement(By.xpath("id=menu")).click();
WebElement subMenu=driver.findElement(By.xpath("id=sub_menu_a"));
Actions myaction = new Actions(driver);
myaction.moveToElement(subMenu);
WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(ExpectedConditions.elementToBeClickable(subMenu));
myaction.click().perform();
Fluent waits should work fine.
Try using something like this:
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver).withTimeout(10, TimeUnit.SECONDS).ignoring(NoSuchElementException.class);
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("id=sub_menu_a")));
but I would go for css Selectors they are perfect for html pages.
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver).withTimeout(10, TimeUnit.SECONDS).ignoring(NoSuchElementException.class);
wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#sub_menu_a")));
Or if your sub_menu_a is a child of menu I would go for
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver).withTimeout(10, TimeUnit.SECONDS).ignoring(NoSuchElementException.class);
wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#menu #sub_menu_a")));
Could you try
WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("id=sub_menu_a")));
Also it would be better if you can give html to find the right xpath as I think better XPATH will yield the result of click on the submenu.
Long time ago I have the similar issue (don't remember the exact case so indeed your HTML page snipped would be helpful) so I was forced to use Thread.sleep()
To avoid long waits will propose something like this method:
static void waitAndClick(WebDriver driver, By by, int attempts, int sleep) throws InterruptedException {
for (int i = 0; i < attempts; i++) {
WebElement element = null;
try {
element = driver.findElement(by);
} catch (NoSuchElementException e) {
// Do nothing
}
if (element == null) {
int time = sleep * (i + 1);
Thread.sleep(time);
} else {
element.click();
break;
}
}
throw new NoSuchElementException("Error");
}
It's not a 100% complete solution but just an idea.
I'm trying get for page to load completely before doing an action. I don't want to start an action while loading circle on the browser tab is still turning. My wait for ajax function is not working for some cases, especially for new page loading. My function is JQuery based:
JavascriptExecutor jsDriver = (JavascriptExecutor) webDriver;
boolean stillRunningAjax = (Boolean) jsDriver
.executeScript("return window.jQuery != undefined && jQuery.active != 0");
return !stillRunningAjax;
if that comes false, running it again.
But for page loading, after it returns true, browser is still loading (loading circle is turning) for a couple of seconds more (sometimes much more).
I've tried implicitlyWait but it stops the function at the same time with my function.
Some says there is not a complete solution for this in selenium. But there should be. Maybe a JavaScript included solution, anything.
Using javascript to wait for page to load:
void waitForLoad(WebDriver driver) {
ExpectedCondition<Boolean> pageLoadCondition = new
ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return ((JavascriptExecutor)driver).executeScript("return document.readyState").equals("complete");
}
};
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(pageLoadCondition);
}
If you're waiting for an ajax to display an element on page, you can wait for the element itself.
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.presenceOfElementLocated(By.id("myDynamicElement")));
I'm using Selenium Webdriver in Java. I want to get the current url after clicking the "next" button to move from page 1 to page 2. Here's the code I have:
WebDriver driver = new FirefoxDriver();
String startURL = //a starting url;
String currentURL = null;
WebDriverWait wait = new WebDriverWait(driver, 10);
foo(driver,startURL);
/* go to next page */
if(driver.findElement(By.xpath("//*[#id='someID']")).isDisplayed()){
driver.findElement(By.xpath("//*[#id='someID']")).click();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[#id='someID']")));
currentURL = driver.getCurrentUrl();
System.out.println(currentURL);
}
I have both the implicit and explicit wait calls to wait for the page to be fully loaded before I get the current url. However, it's still printing out the url for page 1 (it's expected to be the url for page 2).
Like you said since the xpath for the next button is the same on every page it won't work. It's working as coded in that it does wait for the element to be displayed but since it's already displayed then the implicit wait doesn't apply because it doesn't need to wait at all. Why don't you use the fact that the url changes since from your code it appears to change when the next button is clicked. I do C# but I guess in Java it would be something like:
WebDriver driver = new FirefoxDriver();
String startURL = //a starting url;
String currentURL = null;
WebDriverWait wait = new WebDriverWait(driver, 10);
foo(driver,startURL);
/* go to next page */
if(driver.findElement(By.xpath("//*[#id='someID']")).isDisplayed()){
String previousURL = driver.getCurrentUrl();
driver.findElement(By.xpath("//*[#id='someID']")).click();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
ExpectedCondition e = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return (d.getCurrentUrl() != previousURL);
}
};
wait.until(e);
currentURL = driver.getCurrentUrl();
System.out.println(currentURL);
}
Page 2 is in a new tab/window ?
If it's this, use the code bellow :
try {
String winHandleBefore = driver.getWindowHandle();
for(String winHandle : driver.getWindowHandles()){
driver.switchTo().window(winHandle);
String act = driver.getCurrentUrl();
}
}catch(Exception e){
System.out.println("fail");
}
It's been a little while since I coded with selenium, but your code looks ok to me. One thing to note is that if the element is not found, but the timeout is passed, I think the code will continue to execute. So you can do something like this:
boolean exists = driver.findElements(By.xpath("//*[#id='someID']")).size() != 0
What does the above boolean return? And are you sure selenium actually navigates to the expected page? (That may sound like a silly question but are you actually watching the pages change... selenium can be run remotely you know...)