Wait for a page to fully load in Selenium - java

I am using selenium with Java. I want to wait for page to load fully before doing any action on that page.
I have tried the following method, but it is failing to work as expected.
public void waitForElementToBeVisible(final WebElement element) {
WebDriverWait wait = new WebDriverWait(WebDriverFactory.getWebDriver(), WEBDRIVER_PAUSE_TIME);
wait.until(ExpectedConditions.visibilityOf(element));

WebDriverWait inherits methods like wait until.
So something like
webDriverWait.until(ExpectedConditions.visibilityOfElementLocated( elementLocator)
should work. You can use ExpectedConditions, it would make things simpler. You can also use the method visibilityOfAllElements

This method will wait until element is visible.
Firstly this method will check, whether element is available in html and whether it's display.. it will wait until element will display..
public void E_WaitUntilElementDisplay() throws Exception
{
int i=1;
boolean eleche,eleche1 = false;
while(i<=1)
{
try{
eleche = driver.findElements(by.xpath("path")).size()!=0;
}catch(InvalidSelectorException ISExcep)
{
eleche = false;
}
if(eleche == true)
{
while(i<=1)
{
try{
eleche1=driver.findElement(By.xpath("Path")).isDisplayed();
}catch(org.openqa.selenium.NoSuchElementException NSEE){
eleche1=false;
}
if(eleche1 == true)
{
i=2;
System.out.println("\nElement Displayed.");
}
else
{
i=1;
Thread.sleep(1500);
System.out.println("\nWaiting for element, to display.");
}
}
}
else
{
i=1;
Thread.sleep(1500);
System.out.println("\nWaiting for element, to display.");
}
}
}

As another option maybe you can try something like:
if(element.isDisplayed() && element.isEnabled()){
//your code here
}
or if you know how long you want to wait:
thread.sleep(3000); //where 3000 is time expression in milliseconds, in this case 3 secs

You can use this function in java to verify whether the page is fully loaded or not. The verification happens two-fold. One using the javascript document.readystate and imposing a wait time on javascript.
/* Function to wait for the page to load. otherwise it will fail the test*/
public void waitForPageToLoad() {
ExpectedCondition<Boolean> javascriptDone = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
try {
return ((JavascriptExecutor) getDriver()).executeScript("return document.readyState").equals("complete");
} catch (Exception e) {
return Boolean.FALSE;
}
}
};
WebDriverWait wait = new WebDriverWait(getDriver(), waitTimeOut);
wait.until(javascriptDone);
}

This works for me:
wait.until(ExpectedConditions.not(
ExpectedConditions.presenceOfElementLocated(
By.xpath("//div[contains(text(),'Loading...')]"))));

Here is the ultimate solution specifically when you are dealing with Angular 7 or 8.
Instead of waiting for a longer duration using sleep or implicit wait methods, you can divide your wait time into the partition and use it recursively.
Below logic will wait for the page to render for a minimum of 300 seconds and a maximum of 900 seconds.
/**
* This method will check page loading
*
*/
public void waitForLoadingToComplete() {
waitLoadingTime(3); // Enter the number of attempts you want to try
}
private void waitLoadingTime(int i) {
try {
// wait for the loader to appear after particular action/click/navigation
this.staticWait(300);
// check for the loader and wait till loader gets disappear
waitForElementToBeNotPresent(By.cssSelector("Loader Element CSS"));
} catch (org.openqa.selenium.TimeoutException e) {
if (i != 0)
waitLoadingTime(i - 1);
}
}
/**
* This method is for the static wait
*
* #param millis
*/
public void staticWait(final long millis) {
try {
TimeUnit.MILLISECONDS.sleep(millis);
} catch (final InterruptedException e) {
System.err.println("Error in staticWait." + e);
}
}
public void waitForElementToBeNotPresent(final By element) {
long s = System.currentTimeMillis();
new WebDriverWait(this.getDriver(), 30)
.until(ExpectedConditions.not(ExpectedConditions.presenceOfAllElementsLocatedBy(element)));
System.err.println("Waiting for Element to be not present completed. " + (System.currentTimeMillis() - s));
}

Related

How do I return boolean value from ExpectedCondition objects

I do have a method that waits for the JavaScript to load in the browser. From Selenium 3 (3.141.59), I have shifted to Selenium 4 (4.0.0-alpha-7)
This return code/statement doesnt work with Selenium 4
return wait.until(jQueryLoad) && wait.until(jsLoad);
What would be the correct return statement for this? I have tried several options but nothing worked. Please see the code structure for the method/function below. Your thoughts, ideas and answers will be highly appreaciated.
public static boolean waitForJStoLoad() {
WebDriverWait wait = new WebDriverWait(getDriver(), Duration.ofSeconds(30));
// wait for jQuery to load
ExpectedCondition<Boolean> jQueryLoad = new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver arg0) {
try {
Long state = (Long) ((JavascriptExecutor) arg0).executeScript("return jQuery.active");
return (state == 0);
} catch (Exception e) {
return true;
}
}
};
// wait for Javascript to load
ExpectedCondition<Boolean> jsLoad = new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver arg0) {
String state = (String) ((JavascriptExecutor) arg0).executeScript("return document.readyState;");
return state.equalsIgnoreCase("complete");
}
};
return wait.until(jQueryLoad) && wait.until(jsLoad);
}
Well, I'm using standard Selenium 3 and not checking JavaScripts, but I do have several simple methods validating some conditions with the Expected Conditons and returning Boolean.
Something like this:
public boolean waitForElementToDisappear(By element){
try {
wait.until((ExpectedConditions.invisibilityOfElementLocated(element)));
return true;
}catch (Throwable t){
return false;
}
}

Selenium and Appium and WaitForSomeElementToBeVisible

I have this method implemented some time ago. I use it pretty extensively in my web automation.
The gist is to wait for one of several elements to be visible.
public void waitForSomeElementToBeVisible(int timeout, final By... locators) throws Exception, TimeoutException {
boolean found = false;
try {
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
WebDriverWait wait = new WebDriverWait(driver, timeout);
ExpectedCondition<?>[] conditionsToEvaluate = new ExpectedCondition[locators.length];
for (int i = 0; i < locators.length; i++) {
conditionsToEvaluate[i] = ExpectedConditions.visibilityOfElementLocated(locators[i]);
}
found = wait.until(ExpectedConditions.or(conditionsToEvaluate));
} catch (TimeoutException e) {
throw e;
} catch (Exception e) {
throw e;
} finally {
driver.manage().timeouts().implicitlyWait(<default>, TimeUnit.SECONDS);
}
if (!found) throw new Exception("Nothing found");
}
Now I’m trying to use this method with a mobile browser. Specifically, iOS Safari via Appium. It works on iOS occasionally but usually fails and in the Appium log I see when executing the line:
found = wait.until(ExpectedConditions.or(conditionsToEvaluate));
(It does work consistently with Android+Appium).
[WD Proxy] Got response with status 404: {"value":{"error":"no such alert","message":"An attempt was made to operate on a modal dialog when one was not open","traceback":""},"sessionId":"03E95205-9E98-4DB4-BB61-0F125C2C5B3E"}
[debug] [W3C] Matched W3C error code 'no such alert' to NoSuchAlertError
There is, of course, no alert AND one of the elements does exist.
What’s going wrong here?
Is there a better way to wait for one of several elements to be visible?
Please try this java method :
public static boolean waitForElement(WebElement element) throws IOException {
log.info("Waiting for an element in the page...");
boolean isElementPresent = true;
try {
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.visibilityOf(element));
log.info("Element is visible");
return isElementPresent;
} catch (Exception e) {
log.info("waitForElement method failed! " + e.getMessage());
return !isElementPresent;
}
}
or this method:
public static WebElement fluentWait(final WebElement webElement, int timeinsec) {
log.info("waiting ..."+ timeinsec +" seconds");
FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(timeinsec, TimeUnit.SECONDS).pollingEvery(timeinsec, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
WebElement element = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return webElement;
}
});
return element;
}
FYI: Both of these method are present under the below maven Dependency I created a while ago. It has a lot of re-usable method that you can use :
<dependency>
<groupId>com.github.mbn217</groupId>
<artifactId>MyUtilities</artifactId>
<version>1.0.2</version>
</dependency>
To use it you just need to call the class name and the method. No need to create an object from the class
example:
SeleniumUtils.waitForElement(pass your element here)

How to test a polling javascript ajax call with Selenium Java WebDriver

I have a page with JavaScript code that polls an API every second and replaces and element in the HTML page with the response. I would like to test this page using Selenium WebDriver. I have WebDriver setup in my Junit Test but I don't know how to deal with the polling Java Script.
RemoteWebDriver driver = chrome.getWebDriver();
driver.get("http://localhost:8080");
The JavaScript code configures a timer to call the getMessage() is setup like so.
<body>
<h1 id="message"> Loading ... </h1>
</body>
<script>
function getMessage()
{
$.ajax({
url : '/message',
type: 'GET',
success: function(data){
$('#message').text(data.message);
},
error: function (data) {
$('#message').text("Error Response");
}
});
}
$(document).ready(function() {
window.setInterval(getMessage, 1000);
});
</script>
I want to test the H1 message value changed to something every second or so for 30 seconds, so I am expecting to see 25 changes in 30 second run of the test. How can I do this with Selenium WebDriver?
Below is one of the hacky way of printing the message every two seconds
We can write our own function and pass that function to Until method of FluentWait. It will call this method every 2 second & Timeout is set to 30 seconds. We are using counter Once count > 10 . It should come out of until . May need some refactoring as per your needs.
Function<WebDriver, Boolean> function = new Function<WebDriver, Boolean>()
{
int count = 1;
public Boolean apply(WebDriver arg0) {
count++;
WebElement element = arg0.findElement(By.id("message"));
String text= element.getText();
System.out.println("Message " + text); // your logic
if(count > 10))
{
return true;
}
return false;
}
}
Example use . Assuming driver paths etc. are set properly
public static void main(String[] args) throws InterruptedException {
WebDriver driver = new FirefoxDriver();
driver.get("http://localhost:8080");
FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver);
wait.pollingEvery(Duration.ofSeconds(2));
wait.withTimeout(Duration.ofSeconds(30));
wait.ignoring(NoSuchElementException.class);
Function<WebDriver, Boolean> function = new Function<WebDriver, Boolean>()
{
int count = 1;
public Boolean apply(WebDriver arg0) {
count++;
WebElement element = arg0.findElement(By.id("message"));
String text= element.getText();
System.out.println("Message " + text); // your logic
if(count > 10))
{
System.out.println(count + "++++++++++++++++++");
return true;
}
return false;
}
};
wait.until(function);// You can handle timeout exception using try-catch as per your
//use case
}
Here is another approach:
private boolean testElementFor1SecChange(SearchContext searchContext, By locator, Duration testDuration){
String baseElementText = searchContext.findElement(locator).getText();
for(int i = 0; i < testDuration.get(ChronoUnit.SECONDS); i++){
try {
Thread.sleep(1000);
String nextElementText = searchContext.findElement(locator).getText();
if(baseElementText == null || baseElementText.equals(nextElementText)){
return false;
}
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
}
return true;
}
So the test would look like:
#Test
public void testChanges(){
driver.get("http://localhost:8080");
Assert.assertTrue(
testElementFor1SecChange(driver, By.id("message"), Duration.ofSeconds(30))
);
}

Not able to delete all cookies of current domain in Selenium webdriver

I am working on Selenium webDriver in which I am using the method driver.manage().deleteAllCookies();
But this method is deleting all cookies from the current domain except one. Strange!!
I am using Chrome right now.
Can anyone suggest what could be the possible cause and what we can do to delete all cookies for the current domain?
driver.manage().deleteAllCookies();
This will only delete cookies on current domain. It won't delete cookies of any other domain.
So if you need to delete cookies of those domain then you need to first browse to a page from that domain and then call the deleteAllCookies method again
I had to wait all ajax operations to finish then call deleteAllCookies(), then it worked.
public void ajaxWait(long seconds) {
try{
while(!waitForJSandJQueryToLoad()) {
try {
Thread.sleep(1000);
seconds -= 1;
if (seconds <= 0) {
return;
}
} catch (InterruptedException var4) {
var4.printStackTrace();
}
}
} catch(Exception e){
e.printStackTrace();
}
}
public boolean waitForJSandJQueryToLoad() {
WebDriverWait wait = new WebDriverWait(driver, 20);
// wait for jQuery to load
ExpectedCondition<Boolean> jQueryLoad = new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driver) {
try {
return ((Long)((JavascriptExecutor)driver).executeScript("return jQuery.active") == 0);
}
catch (Exception e) {
// no jQuery present
e.printStackTrace();
return true;
}
}
};
// wait for Javascript to load
ExpectedCondition<Boolean> jsLoad = new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driver) {
return ((JavascriptExecutor)driver).executeScript("return document.readyState")
.toString().equals("complete");
}
};
return wait.until(jQueryLoad) && wait.until(jsLoad);
}
I had the same issue. I wanted to log out of the system. I thought that I had deleted all cookies by calling:
driver.manage().deleteAllCookies();
After the statement finished, however, the system navigated me to the home page.
The solution for me is to navigate to log in page then delete the cookies again:
driver.get(target_url);
driver.manage().deleteAllCookies();

Selenium IE .click() works inconsistently

I have the following Problem. I use Selenium 2.42.2 to test our company intranet site. Therefore I implemented an example Testcase with a Testsuite. I test this testcase with Firefox 31 and IE 11. All works fine but some times it seems like the IE doesn't click on some elements. It's very confusing because sometimes it works correctly and sometimes it doens't. However I till now I trief the following solutions without success:
Check Zoom Level and set it in all possible ways
set up all possible waits (explicit, implicit, some weird variants)
use 'sendkeys(\n)' instead of .click()
the only solution which works is to double click. But this call new problems with firefox and if this bug doesn't occur.
Does anyone have a hint or any idea which is the cause for the problem?
Thanks for help upwards.
attached Code:
#RunWith(Parameterized.class)
public class SeleniumTest_WD_used extends AbstractSelenium {
public SeleniumTest_WD_used(RemoteWebDriver d) {
driver = d;
}
private String baseUrl = "company.intranet.site.com";
#Override
#Before
public void setUp() {
driver.get(baseUrl);
driver.manage().timeouts().implicitlyWait(500, TimeUnit.MILLISECONDS);
}
#Test
public void worldClock_autoCity_Test_with_ES() throws InterruptedException {
Thread.sleep(2000);
driver.findElement(By.xpath("some XPath")).click();
Thread.sleep(2000);
new Select(driver.findElement(By.id("some ID"))).selectByVisibleText("Some Text");
driver.findElement(By.cssSelector("Some Css_Element")).click();
driver.findElement(By.xpath("some XPath")).click();
RemoteWebElement e1 = (RemoteWebElement) driver.findElement(By.xpath("some XPath"));
Assert.assertEquals("Some Assert", e1.getText());
}
}
and I override the 'findElement' Method for IE and FF driver in the following way (but I also got this bug if I use the standard method):
public class FirefoxDriver2_0 extends FirefoxDriver {
private static FirefoxDriver2_0 instance = null;
private long startTime;
private long stopTime;
private FirefoxDriver2_0() {
super();
}
public static synchronized FirefoxDriver2_0 getInstance() {
if (instance == null) {
instance = new FirefoxDriver2_0();
}
return instance;
}
#Override
public RemoteWebElement findElement(By by) {
return elementSearch(by, FirefoxDriver2_0.getInstance());
}
private RemoteWebElement elementSearch(By by, FirefoxDriver driver) {
startTime = System.currentTimeMillis();
RemoteWebElement helpingElement = null;
isElementPresent(by);
try {
helpingElement = (RemoteWebElement) super.findElement(by);
} catch (Exception e) {
AllTest.updateLogger("[error] method 'elementSearch' incomplete");
fail("Test not successfull!");
} finally {
stopTime = System.currentTimeMillis();
timeWarning(by.toString());
}
return helpingElement;
}
private boolean isElementPresent(By by) {
try {
super.findElement(by);
return true;
} catch (NoSuchElementException e) {
stopTime = System.currentTimeMillis();
timeWarning(by.toString());
AllTest.updateLogger("[main] ERROR\tThe following expression could not be solved: " + by);
fail("Test not successfull! --> Error: Element not found. Please check the failed XPath's");
return false;
}
}
private void timeWarning(String s){
if(stopTime-startTime > 500){
AllTest.updateLogger("[main] WARNING\tHigh response-time detected: " + (stopTime-startTime) + " ms [#element: " + s + "]");
}
}
If you need some further Code or Information please ask for it. I got two more relevant classes 1.) a Testsuite which initialize the test and 2.) a abstract class as parent for my testcase.
Now I got a solution!
As you can see in my question Code I override the findElement method from the FF and IE Driver. This is the key to solve this really annoying problem. Because I found out that IE some times simple doesn't click on some elements (mostly elements which send out ajax requests). I guess this happens because IE doesn't focus on this elements directly. IE is slow and needs more time either you need to double click the element (1. to set focus, 2. to really click). And here comes the solution:
You could Override the findElement method from IE and add a simple By-element to save the requested elements. If now an element couldn't be found by this method because the parent wasn't really clicked you could click the parent in this method again and vóila it works!
For this solution it's really important that you build an own class (e.g. named: InternetExplorerDriver2_0) which is a singleton (to perform the click in the own class) and which overrides the standard findElement method.
(I guess it's clear that in the following tests you have to use your changed IEDriver class instead of the original 'InternetExplorerDriver' class)
Here you could find the Code for the changed IEDriver class:
import static org.junit.Assert.fail;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebElement;
public class InternetExplorerDriver2_0 extends InternetExplorerDriver {
private static InternetExplorerDriver2_0 instance = null;
private static DesiredCapabilities caps = null;
private long startTime;
private long stopTime;
private By olderBy;
private InternetExplorerDriver2_0() {
super(caps);
}
public static synchronized InternetExplorerDriver2_0 getInstance(
DesiredCapabilities capabilities) {
if (instance == null) {
caps = capabilities;
instance = new InternetExplorerDriver2_0();
}
return instance;
}
#Override
public RemoteWebElement findElement(By by) {
return elementSearch(by, InternetExplorerDriver2_0.getInstance(caps));
}
private RemoteWebElement elementSearch(By by, InternetExplorerDriver driver) {
startTime = System.currentTimeMillis();
RemoteWebElement helpingElement = null;
isElementPresent(by);
try {
helpingElement = (RemoteWebElement) super.findElement(by);
} catch (Exception e) {
System.out.println("[error] method 'elementSearch' incomplete");
fail("Test not successfull!");
} finally {
stopTime = System.currentTimeMillis();
timeWarning(by.toString());
}
olderBy = by;
return helpingElement;
}
private boolean isElementPresent(By by) {
try {
super.findElement(by);
return true;
} catch (NoSuchElementException e1) {
//the following lines are the important!!!
try {
InternetExplorerDriver2_0.getInstance(caps).findElement(olderBy).click();
super.findElement(by);
return true;
} catch (Exception e2) {
stopTime = System.currentTimeMillis();
timeWarning(by.toString());
AllTest.updateLogger("[main] ERROR\tThe following expression could not be solved: " + by);
fail("Test not successfull! --> Error: Element not found. Please check the failed XPath's");
return false;
}
}
}
private void timeWarning(String s) {
if (stopTime - startTime > 500) {
AllTest.updateLogger("[main] WARNING\tHigh response-time detected: " + (stopTime - startTime) + " ms [#element: " + s + "]");
}
}
}
I know it's not the perfectly clean solution but it's a nice workaround and save so much time!

Categories