I am using Java and Selenium to write a test. I have a drop down menu from which I need to select something. This is my code:
Select s= new Select(driver.findElement(By.xpath("blabla")));
s.selectByVisibleText("theName");
it works on Chrome but on Firefox 47 I get this error:
org.openqa.selenium.ElementNotVisibleException:
Element is not currently visible and so may not be interacted with
I know how to handle selecting from drop down menu by other ways, but I need to use Select object.
Use fluent wait to wait element, chrome is faster:
public static void waitUntilElementIsVisible(WebElement element, WebDriver driver)
{
FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver);
wait.pollingEvery(250, TimeUnit.MILLISECONDS);
wait.withTimeout(2, TimeUnit.MINUTES);
wait.ignoring(ElementNotVisibleException.class); //make sure that this exception is ignored
Function<WebDriver, WebElement> function = new Function<WebDriver, WebElement>()
{
public WebElement apply(WebDriver driver) {
System.out.println("Checking for the element!!");
if(element.isDisplayed() != true)
{
System.out.println("Target element is not visible");
}
return element;
}
};
wait.until(function);
}
Then you can call it:
WebElement el = driver.findElement(By.xpath("blabla"));
waitUntilElementIsVisible(el, driver);
You can use the WebDriverWait class to wait for the visibility of the element like this:
WebDriverWait wait = new WebDriverWait(driver, customTime);
WebDriver driver = new FirefoxDriver();
Select s = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("blabla")));
s.selectByVisibleText("theName");
Related
I need to wait for a specific loader to complete loading once the button has been pressed, please take a look at the following image below:
As you can see from the image above, once the button has been pressed the ajax loader appears inside the button.
I have created the following selector to locate the button:
//form[contains(#id, 'messageform')]//button/span
Currently accepting the request (Clicking on the button) fails my test case as the script continues to the next test steps without waiting for the loader to complete.
I have tried the following and more, with no luck:
Injecting JS to wait for the page to fully load.
ExpectedCondition<Boolean> expectation = driver -> ((JavascriptExecutor) driver).executeScript("return document.readyState").toString().equals("complete");
ExpectedConditions.invisibilityOf(element)
WebDriver driver = getDriver();
WebDriverWait exists = new WebDriverWait(driver, timer);
exists.until(ExpectedConditions.refreshed(
ExpectedConditions.invisibilityOf(element)));
Any ideas?
You should use .stalenessOf() to wait until an element is no longer attached to the DOM.
Something like this (tweak to your case):
WebElement somePageElement = driver.findElement(By.id("someId"));
WebDriverWait wait = new WebDriverWait(webDriver, 10);
// do something that changes state of somePageElement
wait.until(ExpectedConditions.stalenessOf(somePageElement));
And the good thing is you don't have to handle any exceptions.
Alternatively, you can also create a method and handle exceptions like so:
public static void WaitForCommission (WebDriver driver) throws Exception {
for (int second = 0; second++) {
if (second >= 30) fail("timeout");
try {
if (IsElementActive(By.id("someElementID"), driver))
break;
} catch (Exception e) {}
Thread.sleep(1000);
}
}
private static boolean IsElementActive(By id, WebDriver driver) {
WebElement we = driver.findElement(id);
if(we.isEnabled())
return true;
return false;
}
I'm trying to use FluentWait instead of sleep and this is my first practice. First of all and most importantly am I doing it right at all? Secondly I got through two elements so I thought it kind of works (PaymentMethod button and CheckOut button). Before I implemented FluentWait it wouldn't find them. And finally it won't find the third(backToDesktop button) element. Keeps throwing Element not visible, although I added the wait.ignore(ElementNotVisibleExcecption.class).
FluentWait<WebDriver> wait = new FluentWait<WebDriver>(login.getDriver());
wait.withTimeout(5, TimeUnit.SECONDS);
wait.pollingEvery(250, TimeUnit.MILLISECONDS);
wait.ignoring(NoSuchElementException.class);
wait.ignoring(ElementNotVisibleException.class);
WebElement paymentMethod = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return login.getDriver().findElement(By.xpath("//*[#id='paymentMethodHolder']/div[1]/div[1]/button"));
}
});
paymentMethod.click();
System.out.println("FOUND PAYMENTMETHOD BUTTON");
WebElement checkOut = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return login.getDriver().findElement(By.xpath("//*[#id='checout-footer-buttons']/button[2]"));
}
});
checkOut .click();
System.out.println("FOUND KINNITA BUTTON");
WebElement backToDesktop= wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return login.getDriver().findElement(By.className("modal-button-text"));
}
});
backToDesktop.click();
System.out.println("FOUND BACKTODESKTOP BUTTON");
FluentWait is a custom wait. You shouldn't need it in most cases. You should always start with a WebDriverWait and ExpectedConditions and if that doesn't work, then maybe investigate a FluentWait. My guess is that something simple like the below will work for you. This is just one example. You should look at all the different conditions you can wait for that are provided by ExpectedConditions. Probably the most common ones are waiting for an element to be visible or clickable.
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("someId")));
I'm unable to click on an element within a list, once i have clicked on the dropdown list?
Method I have created which Doesn't work.
public static void waitForTextToAppearAndClick(WebDriver driver, WebElement element, String textToAppear) throws InterruptedException{
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.visibilityOf(element));
WebElement locator = element;
locator.click();
WebElement textToClick = driver.findElement(By.linkText(textToAppear));
wait.until(ExpectedConditions.elementToBeClickable(textToClick));
textToClick.click();
}
Using thread.sleep seems to works but I don't want to use this method, can anybody recommend a way to wait and click on a specific text element once I have clicked on the primary button?
public static void waitForTextToAppearAndClick(WebDriver driver, WebElement element, String textToAppear) throws InterruptedException{
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.visibilityOf(element));
WebElement locator = element;
locator.click();
Thread.sleep(3000);
driver.findElement(By.linkText(textToAppear)).click();;
}
Please note I need to click on BBQ Sauce, the thread.sleep() is successful when needing to click on BBQ Sauce
Thanks your for help
Use your own implementation of FluentWait in order to wait until text is present after your click:
Wait wait = new FluentWait<>(this.driver)
.withTimeout(driverTimeoutSeconds, TimeUnit.SECONDS)
.pollingEvery(500, TimeUnit.MILLISECONDS)
.ignoring(StaleElementReferenceException.class)
.ignoring(NoSuchElementException.class)
.ignoring(ElementNotVisibleException.class);
WebElement foo = wait.until(new Function() {
public WebElement apply(WebDriver driver) {
return element.getText().length() > 0;
}
});
all thanks for your help the following method seems to of done the trick:
public static void waitForTextToAppearAndClick(WebDriver driver, WebElement element, String textToAppear) throws InterruptedException{
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.visibilityOf(element));
WebElement locator = element;
locator.click();
wait.until(ExpectedConditions.elementToBeClickable(By.linkText(textToAppear)));
driver.findElement(By.linkText(textToAppear)).click();
}
Selenium is displaying number of links on a page as 0 although there are many links on the page.
This is my code in java
dr.get("https://www.ebay.com");
List<WebElement> linksize = dr.findElements(By.tagName("a"));
System.out.println(linksize.size());
Output :
0
Wait until page loads for links
Modify your code to
dr.get("https://www.ebay.com");
waitForLoad(dr); // Here you are calling the below method
List<WebElement> linksize = dr.findElements(By.tagName("a"));
System.out.println(linksize.size());
You can use the below method as your util and can call anytime
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);
}
#Subhrapratim Bhattacharjee, it seems that you need to wait for the page to load. Try following code
WebDriver driver = new FirefoxDriver();
driver.get("https://www.ebay.com");
driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
WebDriverWait wait = new WebDriverWait(driver, 30);
List<WebElement> linksize = wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.tagName("a")));//driver.findElements(By.tagName("a"));
System.out.println(linksize.size());
I want to use a WebElement as a root to find elements from instead of the driver. I know this is possible since the WebElement and WebDriver both extends the SearchContext class. But I want to be able to have a search that looks like this.
WebDriver chromeDriver = new ChromeDriver();
WebDriver driver = chromeDriver;
// Set a new search root
public void setSearchRoot(){
if(i want a element as a root){
this.driver = (WebDriver)this.driver.findElement(By.xpath("PATH"));
}else{
this.driver = chromeDriver;
}
}
//find a element
public void findMyElement(){
this.driver.findElement(By.xpath("PATH"));
}
instead of something like this
WebDriver driver = new ChromeDriver();
WebDriver rootElement = this.driver.findElement(By.xpath("PATH"));
//find a element
public void findMyElement(){
if(i want a element as a root){
this.rootElement.findElement(By.xpath("PATH"));
}else{
this.driver.findElement(By.xpath("PATH"));
}
}
It might look a bit messy but basically I want to be able to set a WebElement as a starting point instead of a WebDriver without having to do a if statement or have two different methods whenever I want to get a element. Because sometimes I want to use the WebDriver as a root and sometimes a Webelement and this without having to change anything with the get code. is it possible somehow? And yes I am aware that this might not be best practice, just wondering if it's possible.
using OpenQA.Selenium.Support.UI;
if element is a type of ISearchContext or IWebElement
then this cast worked for me
var driver = ((IWrapsDriver)element).WrappedDriver;
No, WebElement and WebDriver are not descendants of each other.
If your IWebElement happens to be a RemoteWebElement, then you can get the IWebDriver with
var remoteElement = (RemoteWebElement)element;
var webDriver = remoteElement.WrappedDriver;
If you only need to use the "root" to find elements under it and not to do other WebDriver specific stuff (like navigation or managing options or timeouts) you can use SearchContext instead of WebDriver.
Your code would look like this:
WebDriver chromeDriver = new ChromeDriver();
SearchContext driver = chromeDriver; // Use SearchContext instead of WebDriver
// Set a new search root
public void setSearchRoot() {
if(i want a element as a root) {
this.driver = this.driver.findElement(By.xpath("PATH")); // No cast needed
} else {
this.driver = chromeDriver;
}
}
//find a element
public void findMyElement() {
this.driver.findElement(By.xpath("PATH"));
}
I noticed in my own projects that I often had methods expecting a parameter of type WebDriver when really it only called findElements on it. By changing the type to SearchContext my utilities became a lot more flexible.
public WebElement findMyElement(SearchContext webDriver) {
return webDriver.findElement(By.xpath("PATH"));
}
Use it like this:
WebDriver webDriver = new ChromeDriver();
WebElement customElement = findMyElement(webDriver);
WebElement nestedElement = findMyElement(customElement);