I'm trying synchronization with selenium webdriver and something is not working with implicitlyWait().
The way I understand implicitlyWait(..) is that the code is waiting until the element is available for a max of time.
The code below crash with the error:
org.openqa.selenium.InvalidElementStateException: invalid element state: Element is not currently interactable and may not be manipulated
The System.out ist printing: -->> false true false (isDiplayed(), isEnabled(), is Selected())
private static WebDriver driver;
public static void main(String[] args) throws InterruptedException {
setupWebDriverChrome();
//Thread.sleep(1000);
final String cssSelectorFromAirport = "div.od-airportselector.airportselector_root input[tabindex='11']";
final By cssSelector = By.cssSelector(cssSelectorFromAirport);
WebElement fromAirportElement = driver.findElement(cssSelector);
System.out.println("-->> " + fromAirportElement.isDisplayed() + " " + fromAirportElement.isEnabled() + " " + fromAirportElement.isSelected());
fromAirportElement.clear();
fromAirportElement.sendKeys("MUC");
}
private static void setupWebDriverChrome() {
System.setProperty("webdriver.chrome.driver", "C:\\...\\chromedriver.exe");
setupLocation();
}
private static void setupLocation() {
driver.manage().timeouts().implicitlyWait(1000, TimeUnit.MILLISECONDS);
driver.get("https://www.opodo.de/");
}
I tried that also with the Geckodriver with the same result.
I have also increased the wait time but same result.
The only way to make it works, is to use Thread.sleep() (Commented above)
EDIT
Pls. note that I do not see any duplication with Selenium implicitwait not working.
You have to wait that your element is clickable. Try adding this:
WebElement element = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.elementToBeClickable(By.cssSelector(cssSelectorFromAirport)));
So:
setupWebDriverChrome();
//Thread.sleep(1000);
final String cssSelectorFromAirport = "div.od-airportselector.airportselector_root input[tabindex='11']";
WebElement element = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.elementToBeClickable(By.cssSelector(cssSelectorFromAirport)));
/*final By cssSelector = By.cssSelector(cssSelectorFromAirport);
WebElement fromAirportElement = driver.findElement(cssSelector);
System.out.println("-->> " + fromAirportElement.isDisplayed() + " " + fromAirportElement.isEnabled() + " " + fromAirportElement.isSelected());*/
element.clear();
element.sendKeys("MUC");
EDIT
From the documentation :
An implicit wait is to tell WebDriver to poll the DOM for a certain
amount of time when trying to find an element or elements if they are
not immediately available. The default setting is 0. Once set, the
implicit wait is set for the life of the WebDriver object instance.
This means, in your example, that selenium found the element but it isn't yet "clickable".
You can see this also in your test. If you take a look to:
System.out.println("-->> " + fromAirportElement.isDisplayed() + " " + fromAirportElement.isEnabled() + " " + fromAirportElement.isSelected() );
When it fails, the output is:
-->> false true false
While when it works:
-->> true true false
Related
I was trying to search and add product in the cart using selenium but was not able to successfully do it
driver.get("https://www.bigbasket.com/cl/fruits-vegetables/?nc=nb");
List<WebElement> product = driver.findElements(By.xpath("//div[#qa=\'product\']"));
System.out.println("prdoduct=" + product.size());
for(int i=0;i<product.size();i++)
{
String name = product.get(i).getText();
System.out.println("NAME is" + name);
String xp= "(//button[#qa=\'add\'])" + "["+i+ "]";
System.out.println("xp="+xp);
if(name.contains("Cauliflower"))
{
System.out.println("xp" +xp);
driver.findElement(By.xpath(xp)).click();
}
}
In this previous product is getting selected but when I was debugging it was on the cauliflower but still the previous product is getting selected
there is a chance that some time the element get overlapped by another element. At this time, the normal selenium click will try to click on the overlapped element. so it is better to use js click, it will click the exact element even if it is overlapped
WebElement element= driver.findElement(By.xpath(xp));
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].click();", element);
There is also a chance for issue in your xpath. Since list starts at 0 , you may need to change i in to i+1 in xp for getting current selection add button.do try this xpath too
String xp= "(//button[#qa=\'add\'])" + "["+(i+1)+ "]";
Induce WebDriverWait() and wait for visibilityOfAllElementsLocatedBy() and use following css selector and xpath.
driver.get("https://www.bigbasket.com/cl/fruits-vegetables/?nc=nb");
List<WebElement> product =new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.cssSelector("div[qa='product_name']>a")));
System.out.println("prdoduct=" + product.size());
for(int i=0;i<product.size();i++)
{
String name = product.get(i).getText();
System.out.println("NAME is" + name);
if(name.contains("Cauliflower"))
{
driver.findElement(By.xpath("//div[#qa='product_name']//a[text()='" + name + "']/following::button[1]")).click();
}
}
According to a number of articles I have seen, the use of Thread.sleep() seems to be frowned upon. I have used this frequently in my test classes, where it was necessary to wait for something to load. I have tried using this method to tell me when load is complete, but that did not help. It is not a reliable method.:
try {
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
|| ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
} catch (Exception e) {
System.err.println(thisClass + " Exception caught: " + e.getMessage());
}
What alternatives methods can I use?
This solution worked:
Calling function:
String className = "gwt-Button form-control btn back-button ripple-container";
String textToFind = "back-button-icon";
String htmlElement = "button";
boolean isReady = Common.FluentWait(driver, 60, className, textToFind, htmlElement);
That function:
public static boolean FluentWait(WebDriver driver, int timeOut, String className, String textToFind,
String htmlElement) {
// Waiting timeOut seconds for an element to be present on the page, checking
// for its presence once every 5 seconds.
Common.myPrint(thisClass + " FluentWait. ");
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver).withTimeout(timeOut, TimeUnit.SECONDS)
.pollingEvery(5, TimeUnit.SECONDS).ignoring(NoSuchElementException.class);
WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
Common.myPrint(thisClass + " run returnWebElement. ");
return returnWebElement(className, textToFind, htmlElement, driver);
}
});
if (foo != null) {
return true;
}
return false;
}
and the function I called inside that:
public static WebElement returnWebElement(String className, String textToFind, String htmlElement,
WebDriver driver) {
List<WebElement> elements = Common.findElementsUsingHtmlXpathClass(driver, htmlElement, className);
Common.myPrint(thisClass + " elements count: " + elements.size());
String text = "";
for (WebElement element : elements) {
// select an element
if (element.isDisplayed()) {
text = element.getAttribute("innerHTML");
if (text != "") {
text = text.trim();
if (text.contains(textToFind)) {
Common.myPrint(thisClass + " innerHTML: " + text);
Common.myPrint(thisClass + " returning element found. ");
return element;
}
}
}
}
Common.myPrint(thisClass + " element not found. ");
return null;
}
You can use FluentWait
Each FluentWait instance defines the maximum amount of time to wait for a condition, as well as the frequency with which to check the condition. Furthermore, the user may configure the wait to ignore specific types of exceptions whilst waiting, such as NoSuchElementExceptions when searching for an element on the page.
/*
code snippet will Wait 30 seconds for
an element to be present on the page and check for its
presence once every 5 seconds.
*/
Wait wait = new FluentWait(driver)
.withTimeout(30, SECONDS)
.pollingEvery(5, SECONDS)
.ignoring(NoSuchElementException.class);
WebElement foo = wait.until(new Function() {
public WebElement apply(WebDriver driver) {
return driver.findElement(By.id("foo"));
}
});
another wait also available
I have found another way although it is very similar to Thread.sleep(). I was looking for another wait as the implicit wait and explicit wait with Selenium is not waiting long enough for me.
The alternative I used:
TimeUnit.SECONDS.sleep(int timeUnit)
This delivered the same functionality as Thread.sleep(). I hope this helps.
Your code will just attempt to wait for the page to load, not wait for specific elements, etc. to load. This will work fine for static HTML pages but once you start adding dynamic sections to the page (using AJAX, etc.) , it will not accomplish what you want.
You can use WebDriverWait. See the docs for more info.
Simple example,
// create an instance that can be reused
WebDriverWait wait = new WebDriverWait(driver, 10);
// wait for an element to be clickable and store the return
WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.id("someId"));
// click the returned button
button.click();
There are a bunch of standard conditions provided by ExpectedConditions. See the docs for more info.
Given a site, AJAX components on the page and I need to wait till the whole page is fully loaded.
Here is my wait method using JavascriptExecutor checking document.readyState:
public void waitForLoading2() {
WebDriverWait wait = new WebDriverWait(driver, timeOut);
if(!driver.findElements(By.xpath("//*[#id='wait'][contains(#style, 'display: block')]")).isEmpty()) {
wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//*[#id='wait'][contains(#style, 'display: none')]")));
}
ExpectedCondition<Boolean> expectation = new
ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return ((JavascriptExecutor) driver).executeScript("return document.readyState").toString().equalsIgnoreCase("complete");
}
};
wait.until(expectation);
}
Sometimes it's failing with the following Error msg:
org.openqa.selenium.JavascriptException: JavaScript error (WARNING:
The server did not provide any stacktrace information)
What did I miss here? My assumption is that document.readyState is common and always can be checked.
Thanks
There are more complex options, like this one
public static void waitForAjax(WebDriver driver, String action) {
driver.manage().timeouts().setScriptTimeout(5, TimeUnit.SECONDS);
((JavascriptExecutor) driver).executeAsyncScript(
"var callback = arguments[arguments.length - 1];" +
"var xhr = new XMLHttpRequest();" +
"xhr.open('POST', '/" + action + "', true);" +
"xhr.onreadystatechange = function() {" +
" if (xhr.readyState == 4) {" +
" callback(xhr.responseText);" +
" }" +
"};" +
"xhr.send();");
}
in order
to wait till the whole page is fully loaded
But the following did the trick for me - I check if there are ongoing AJAX calls and wait till those are done:
JavascriptExecutor js = (JavascriptExecutor) driverjs;
js.executeScript("return((window.jQuery != null) && (jQuery.active === 0))").equals("true");
Checking document.readyState will not help you with AJAX calls. Your best bet is to find an element in the area being loaded by AJAX and wait until it is visible. Then you'll know that the page is loaded. If there are multiple/separate areas loaded by AJAX calls, then you will want to pick an element from each area.
If you use jQuery to send AJAX request, you can get the value of jQuery.active. it's equivalent to all AJAX requests complete when jQuery.active=0.
Use executeScript("return jQuery.active==0"). For detail please read this artical
I am testing a angularjs page and using selenium(java) to write automation scripts for the same.
The following is the code that I use for the page synchronization wait before proceeding to next screen action
public static boolean angularHasFinishedProcessing() {
ExpectedCondition<Boolean> pageLoadCondition = new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driver) {
driver = GetDriver();//This is to get the driver in current action.
String hasAngularFinishedScript = "var callback = arguments[arguments.length - 1];\n" +
"var el = document.querySelector('html');\n" +
"if (!window.angular) {\n" +
"console.log('1'); \n" +
" callback('false')\n" +
"}\n" +
"if (angular.getTestability) {\n" +
" angular.getTestability(el).whenStable(function(){callback('true')});\n" +
"} else {\n" +
"console.log('hello3'); \n" +
" if (!angular.element(el).injector()) {\n" +
" callback('false')\n" +
" }\n" +
" var browser = angular.element(el).injector().get('$browser');\n" +
" browser.notifyWhenNoOutstandingRequests(function(){callback('true')});\n" +
"}";
JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver;
String isProcessingFinished = javascriptExecutor.executeAsyncScript(hasAngularFinishedScript).toString();
return Boolean.valueOf(isProcessingFinished);
}
};
WebDriverWait wait = new WebDriverWait(driver, 60);
boolean bRet = (wait.until(pageLoadCondition));
if (bRet) {
return bRet;
} else
return false;
}
The issue is isProcessingFinished is always false, the console always writes 1 (meaning window.angular always returns false).
Also, Since, there is no way I can debug the javascript snippet during the execution, I don't know if there is any other issue. Could someone help please?
1) For how to debug javascript
Add a breakpoint before this wait function, run script until stopped at this breakpoint, Open DevTool of browser and execute window.angular in console Tab to see it's true or false.
And you can continue to execute the rest code lines of your javascript snippet in console Tab to examine any code issue or work as expect.
I am trying to implement a script I found online that automatically loads jQuery into sites that don't currently have them. I am using Selenium Webdriver's JS Executor function; however, it keeps returning a Null Pointer Exception. I tried to look everywhere for an answer, but can't seem to understand what's going on. What gives?
/** Browser automation driver for this test instance. */
private WebDriver driver;
/** JavaScript Executor for this test instance. */
private JavascriptExecutor js = (JavascriptExecutor) driver;
//...Firefox browser initialized here
public void JQuerify(final String Url){
ReporterNG.log("Opening a webpage at: " + Url);
driver.get(Url);
ReporterNG.log("Converting JS file to a String");
String jQueryLoader = getLoadJQuery();
// give jQuery time to load asynchronously
driver.manage().timeouts().setScriptTimeout(10, TimeUnit.SECONDS);
js.executeAsyncScript(jQueryLoader);
//THE PROBLEM ALWAYS OCCURS WITH THIS ^^^^^
ReporterNG.log("jQuery loaded!");
//THIS NEVER PRINTS OUT DUE TO THE ERROR ^^^^
}
/** dynamically load jQuery */
public static String getLoadJQuery(){
String LoadJQuery = "(function(jqueryUrl, callback) {\n" +
"if (typeof jqueryUrl != 'string') {" +
"jqueryUrl = 'https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js';\n" +
"}\n" +
"if (typeof jQuery == 'undefined') {\n" +
"var script = document.createElement('script');\n" +
"var head = document.getElementsByTagName('head')[0];\n" +
"var done = false;\n" +
"script.onload = script.onreadystatechange = (function() {\n" +
"if (!done && (!this.readyState || this.readyState == 'loaded'\n" +
"|| this.readyState == 'complete')) {\n" +
"done = true;\n" +
"script.onload = script.onreadystatechange = null;\n" +
"head.removeChild(script);\n" +
"callback();\n" +
"}\n" +
"});\n" +
"script.src = jqueryUrl;\n" +
"head.appendChild(script);\n" +
"}\n" +
"else {\n" +
"callback();\n" +
"}\n" +
"})(arguments[0], arguments[arguments.length - 1]);\n";
return LoadJQuery;
}
Any help would be greatly appreciated, as I am having the same problems with other similar applications of JS Executor. Thank you!
Make the JavascriptExecutor instance local to that method.
JavascriptExecutor js = (JavascriptExecutor) driver;
// give jQuery time to load asynchronously
driver.manage().timeouts().setScriptTimeout(10, TimeUnit.SECONDS);
js.executeAsyncScript(jQueryLoader);