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)
Related
How can I create click method which can be click in the button until the attribute shows? Something like loop until but with timer (if it's not found attribute after 10 seconds, display an error). I have created something like that, but code give me NullPointerException when not found attribute:
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
WebElement button = driver.findElement(By.xpath("xpath"));
String attribute = button.getAttribute("disabled");
button.click();
if(attribute .equals("true"))
return true;
else
return false;
}
});
I got similar problem and my solution was to write a function that tries to click on the object and when it is not present it waits a second and tries once again. After 10 times of trying it returns null.
It works beautifully for me. Goes like this:
WebElement tryfind(WebDriver browser, By id)
{
WebElement ttwel=null;
for (int i=0;i<10;i++)
{
try
{
ttwel=browser.findElement(id);
break;
}
catch (NoSuchElementException ex)
{
sleep(1000);
}
}
return ttwel;
}
void sleep(int mills)
{
try
{
Thread.sleep(mills);
}
catch (InterruptedException ex)
{
}
}
You might add waiting for disabled attribute to this method, something like:
for (int i=0;i<10;i++)
{
try
{
ttwel=browser.findElement(id);
String attribute = button.getAttribute("disabled");
if (attribute==null) sleep(1000);
else break;
}
catch (NoSuchElementException ex)
{
sleep(1000);
}
}
Why don't you add a try catch block like this below to catch the NullPointerException and return false in that case
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30));
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
WebElement button = driver.findElement(By.xpath("xpath"));
try {
String attribute = button.getAttribute("disabled");
button.click();
if (attribute.equals("true")) {
return true;
}
} catch (NullPointerException e) {
return false;
}
return false;
}
});
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;
}
}
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();
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));
}
Complete code is written to fetch data from excel and login to Gmail, but while trying to do so my browser had opened and also the desired page got opened and as well as login id was picked from excel and stored in the variable sUsername, but unable to locate the xpath as- element=driver.findElement(by.id("Email")); but when I print element it holds "null", where as expected was some address of the locator id. Further by using the address of id I would had used with sendkeys to enter the email address in the text box.
But the following error was displayed:
java.lang.NullPointerException
at appModules.SignIN.Execute(SignIN.java:21)
Login class-where the locator issue exists: at - Login1.userName(driver).sendKeys(sUsername);
public class Login1 {
//private static WebDriver driver=null;
private static WebElement element=null;
public static WebElement userName(WebDriver driver)
{
try {
System.out.println("aaa");
System.out.println("bb");
element=driver.findElement(By.name("Email"));
System.out.println("ccc");
} catch (Exception e) {
// TODO: handle exception
System.out.println(element);
}
return element;
}
public static WebElement btn_login(WebDriver driver)
{
element= driver.findElement(By.id("next"));
return element;
}
public static WebElement passWord(WebDriver driver)
{
element= driver.findElement(By.id("Passwd"));
return element;
}
public static WebElement btn_SignIN(WebDriver driver)
{
element= driver.findElement(By.id("signIn"));
return element;
}
}
This is the SigniN class where iam getting the java null pointer exception--issue exists: at- Login1.userName(driver).sendKeys(sUsername);
public class SignIN {
private static WebDriver driver=null;
public static void Execute (int iTestCaseRow)
{
String sUsername=ExcelUtils1.getCellData(iTestCaseRow,Constant1.col_UserName);
System.out.println(sUsername);
//driver.ma3nage().window().maximize();
//driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);
Login1.userName(driver).sendKeys(sUsername);
//driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);
Login1.btn_login(driver).click();
String pass=ExcelUtils1.getCellData(iTestCaseRow, Constant1.col_password1);
Login1.passWord(driver).sendKeys(pass);
Login1.btn_SignIN(driver).click();
}
}
This is where I have instantiate the browser--
public class Utils1 {
public static WebDriver driver;
public static WebDriver OpenBrowser(int iTestCaseRow) {
String sBrowserName;
System.out.println(iTestCaseRow);
sBrowserName = ExcelUtils1.getCellData(iTestCaseRow,
Constant1.col_browser);
if (sBrowserName.equals("Mozilla")) {
driver = new FirefoxDriver();
// Log.info("New driver instantiated");
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
// Log.info("Implicit wait applied on the driver for 10 seconds");
driver.get(Constant1.URL);
// Log.info("Web application launched successfully");
}
return driver;
}
}
It is good practice to deal with internally as well explicit wait for locating element. If there is page related activity then also need to use wait for page to load.
Please follow bellow code
For internal Wait
protected WebElement waitForPresent(final String locator) {
// timeout is your default wait timeout in long.
return waitForPresent(locator, timeout);
}
For Explicit Wait
protected WebElement waitForPresent(final String locator, long timeout) {
WebDriverWait wait = new WebDriverWait(driver, timeout);
WebElement ele = null;
try {
ele = wait.until(ExpectedConditions
.presenceOfElementLocated(locator));
} catch (Exception e) {
throw e;
}
return ele;
}
protected WebElement waitForNotPresent(final String locator, long timeout) {
timeout = timeout * 1000;
long startTime = System.currentTimeMillis();
WebElement ele = null;
while ((System.currentTimeMillis() - startTime) < timeout) {
try {
ele = findElement(locator);
Thread.sleep(1000);
} catch (Exception e) {
break;
}
}
return ele;
}
Just spit balling here, but in addition to the copy/paste issues stated above.. I don't see where you do a 'get' to load the gmail page for the driver instance you are creating? Something like..
driver.get("https://mail.google.com/something");
Also, it would probably be a good idea to put an explicit wait in place for the "Email" field before doing the findElement as the page may still be rendering:
Wait<WebDriver> doFluentWait = fluentWait = new FluentWait<>(driver).withTimeout(PAGE_LOAD_WAIT, TimeUnit.SECONDS)
.pollingEvery(POLLING_INTERVAL, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
and then do something like
doFluentWait.until(WebDriverUtil.elementIsVisible(By.name("Email")));