Waiting for elements with Selenium WebDriver - selenium

I am automating a web page that essentially has a button which, each time it is pressed, creates a new text field.
I am using the FindBy annotation with PageFactory to find the list of text fields.
I have a synchronization problem when I press the button several times, thus creating several text fields, and then try to write into one of them. Stepping through the debugger it works fine, but out of the debugger there is a delay before the FindBy finds all the text fields.
My current workaround performs sleeps until the required number of text fields are found but I find this quite unsatisfactory. Any suggestions how the synchronization could best be done?
#FindBy(how= How.XPATH, using="//*[contains(#id, 'TextField')]")
private List<WebElement> textFields;
:
:
public void enterText(Integer index, String text){
int attempts = 0;
// Check every 10th of a second for 10 seconds if all the textFields have been found
while ((textFields.size() <= index) && attempts < 100){
Thread.sleep(100);
}
textFields.get(index).sendKeys("blah blah");
}

First of all use Implicit wait for all element present in script.
This wait is wait for all element present in the script
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
Initiate above just after get.("URL");
Now for specific element which need additional time you can use below code:-
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Refer below:-
http://toolsqa.com/selenium-webdriver/wait-commands/
Hope it will help you :)

Related

Fluent wait not ignoring exceptions

I am using a fluent wait so I can ignore certain exceptions for a certain time, especially the ElementClickInterceptedException
This is how I declare the wait:
private Wait<WebDriver> initiateWebDriverWait(int timeoutSeconds) {
List allExceptions = new ArrayList();
allExceptions.add(NoSuchElementException.class);
allExceptions.add(ElementNotVisibleException.class);
allExceptions.add(StaleElementReferenceException.class);
allExceptions.add(ElementClickInterceptedException.class);
return new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(timeoutSeconds))
.pollingEvery(Duration.ofMillis(100))
.ignoreAll(allExceptions);
}
usage:
public void waitForElementThenClick(WebElement webElement, int timeOutSeconds) {
waitForElementToBeClickable(webElement, timeOutSeconds);
webElement.click();
}
public void waitForElementToBeClickable(WebElement webElement, int timeoutSeconds) {
Wait<WebDriver> wait = initiateWebDriverWait(timeoutSeconds);
wait.until(ExpectedConditions.elementToBeClickable(webElement));
}
So when I'm using waitForElementThenClick I still get
org.openqa.selenium.ElementClickInterceptedException: element click intercepted: Element ... is not clickable at point (1338, 202). Other element would receive the click:
This is some random overlay that is there for just a smallest fraction of time, and I could add a 100ms wait and whatnot, but my main issue is why am I even seeing this exception, when I specifically said it to ignore it for at least 5 seconds? And it's not waiting these 5 seconds, so this is not a timeout thing.
Any ideas?
is the webElement.click(); throwing the exception? if So, why the waitForElementToBeClickable returned true?
Thanks
If webdriver says the element is clickable, it's not always mean that element is really clickable. It's can be while the target element is covered by another element.
Here is an example. Open https://stackoverflow.com/jobs?so_medium=StackOverflow&so_source=SiteNav . Let's try to check if this element is clickable and click it:
But, we hide this element under dropdown like that:
There is xpath: By.xpath("//*[text()='Developer jobs']")
So, if we check this element for condition ExpectedConditions.elementToBeClickable, it will return true(like element is clickable). But while you execute element.clickm you will occur an ElementClickInterceptedException.
The exceptions list is considered only while until is waiting for the condition to be true. The click() occurs after that, so there is nothing to catch the ElementClickInterceptedException.
elementToBeClickable checks if the element is visible, which will be true if even part of the element is visible, and if the element is enabled, that will be true unless it has explicit disabled attribute, but Selenium tries to click in the middle of the element which might be covered. To pass this problem you can wait for the overlay to disappear and then wait for the element to be clickable
wait.until(ExpectedConditions.invisibilityOfElementLocated(ovferlayLocator));
waitForElementThenClick();

selenium element.click() not working (doesn't click)

String selector = ".rmcAlertDialog .buttons :first-child";
RemoteWebElement selection = (RemoteWebElement) driver.findElement(By.cssSelector(selector));
WebDriverWait wait = new WebDriverWait(driver, 60);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(selection));
if (element == selection) selection.click();
But the element in question (a button) is not responding to the click.
If I click the button manually it works so its not the web page at fault, but the automation.
I have verified the button is there by comparing it's text content.
updated for clarification
This code works (or worked) for most buttons. The code is from a script interpreter which is parsing:-
select ".rmcAlertDialog .buttons :first-child" click
This code was working prior to more recent versions of chrome/selenium/chromedriver.
The code now doesn't work for some buttons.
selection.click() IS being called (verified in a debugger), as element will always equal selection, it just is not working.
.buttons is the class name of the container div for the button(s)
The selector is not directing to the element with button class. You have a space between .button and :first-child in the selector. Remove the space. The given selector is searching for a child element of the tag with button class. But I'm assuming you are trying to click on the first element with button class not the child node of the button class element.
Use this:
String selector = ".rmcAlertDialog .buttons:first-child";
I think the main reason it's failing is because your if statement will never be true. I've never done any comparisons like this but you can simplify your code significantly and still get the desired effect.
A few suggestions:
Don't define locators as Strings, define them as Bys. The By class is defined for just such a task and makes using and passing them around MUCH easier.
String selector = ".rmcAlertDialog .buttons:first-child";
would turn into
By locator = By.cssSelector(".rmcAlertDialog .buttons:first-child");
Note the correction that S Ahmed pointed out in his answer.
You don't need to find the element to wait for it to be clickable. There is an overload that takes a By locator, use that instead.
RemoteWebElement selection = (RemoteWebElement) driver.findElement(By.cssSelector(selector));
WebDriverWait wait = new WebDriverWait(driver, 60);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(selection));
becomes
WebElement element = new WebDriverWait(driver, 60).until(ExpectedConditions.elementToBeClickable(locator));
Skip the RemoteWebElement and WebElement comparison. I don't think this will work and there's no need for it anyway. Your locator will locate the same element consistently.
So your final code should look something like
By locator = By.cssSelector(".rmcAlertDialog .buttons:first-child");
new WebDriverWait(driver, 60).until(ExpectedConditions.elementToBeClickable(locator)).click();

Wait for element for certain amount of time

I have been experiencing one issue during test automation implementation. Particularly test checks if a hamburger menu is displayed.
So far I defined the element and subelement, and I need to really wait just one second, and not to waste time If I know that element will not be displayed after several seconds.
WebDriverWait wait = new WebDriverWait(getDriver(), 1);
WebElement hamMenu = el.findElement(By.xpath(HAMBURGER_MENU_GENERAL_XPATH));
How to implement the method findElement in the way it will try to find the element in one sec? I do not wish to stay longer... Thanks
Try this -
WebElement elem = new WebDriverWait(driver, 1).until(ExpectedConditions.visibilityOfElementLocated(By.xpath(HAMBURGER_MENU_GENERAL_XPATH)));
If I summarize your requirement is as follows :
Check if a hamburger menu is displayed only for 1 second : You need WebDriverWait with proper ExpectedConditions
Element may/not not be displayed after several seconds : You need to wrapup your code in a try-catch {} block to be able to proceed further in absence of the hamburger.
Youe effective code can be :
try {
WebElement hamburger = new WebDriverWait(getDriver(), 1).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("HAMBURGER_MENU_GENERAL_XPATH")));
System.out.println("Hamburger is displayed in 1 sec");
//rest of your code
} catch (NoSuchElementException e){
System.out.println("Hamburger wasn't displayed in 1 sec");
//rest of your code
}
I got it. Thanks for all hints. This will wait just only for short time which is intended.
public boolean isHamMenuDisplayed(){
getDriver().manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
if (el.findElements(By.xpath(HAMBURGER_MENU_GENERAL_XPATH)).size() == 0)
return false;
else
return true;}

Test dynamically loaded content with Selenium Web Driver

I am working on a system that has a web based frontend that I am testing with Selenium. On one page the content is dynamically loaded when scrolling down (maybe you know that from Facebook's friend-list), because it is one of the requirements.
Scrolling down with Selenium Webdriver (I use Chrome) should be no problem via Javascript. But there is a problem with the dynamically added content. How can I make the Webdriver find those elements?
I tried the following to scroll down until no more content is loaded:
int oldSize = 0;
int newSize = 0;
do {
driver.executeScript("window.scrollTo(0,document.body.scrollHeight)");
newSize = driver.findElementsBy(By.cssSelector("selector").size();
} while(newSize > oldSize);
But though the page scrolls down the first time and some now content is loaded correctly, they will not be found by the drivers' findElementsBy(By) function.
Has someone ever faced this problem?? I'd be very glad if someone could help me figuring a solution for that!
Regards, Benjamin
I would recommend using WebDriverWait with ExpectedConditons.
//scroll down with Javascript first
WebDriverWait wait = new WebDriverWait(driver, 30);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("selector")));
//interact with your element
element.click()
Take a look at the guidance provided by Selenium Official page:
http://seleniumhq.org/docs/04_webdriver_advanced.html
try using fluent wait in particular. The main feature is:
An implementation of the Wait interface that may have its timeout and polling interval configured on the fly.
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.
public WebElement fluentWait(final By locator){
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(30, TimeUnit.SECONDS)
.pollingEvery(5, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
WebElement foo = wait.until(
new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
}
);
return foo; } ;
The method described returns you web element you can operate with.
So the approach be the following:
1) you need to find the selectors of elements you expect to be rendered after scrolling
e.g.
String cssSelector = "blablabla"
2) scroll down with js
3)
WebElement neededElement = fluentWait(cssSelector);
neededElement.click();
//neededElement.getText().trim();
you can get more info about fluent wait here
I think the problem is waiting for the dynamic content to finish loading. Try to wait 3 seconds just before findElementsBy? In C# the code would be Thread.Sleep(3000);

WebDriver does not use latest page source

I'm running into problems when executing Selenium 2.18 WebDriver tests against an Oracle SSXA-based site, which translates to tons of popups, Ajax-loaded content and iframes. For a given page, based on manual observation, the page is initially loaded with an empty sslw_doc_content_id span (no text). About a second later, the span still exists and contains text.
To check that this page has loaded, I'm using a WebDriverWait with a Predicate that checks that the sslw_doc_content_id span has non-empty text:
new Predicate<WebDriver>() {
#Override
public boolean apply(final WebDriver input) {
return StringUtils.isNotEmpty(input.findElement(By.id("sslw_doc_content_id")).getText());
}
}
Somehow, WebDriver always finds the WebElement but always returns an empty string when calling WebElement.getText(). And so this predicate always evaluates to false.
Inspecting the page with Chrome or Firefox shows that the element exists and does have text. When debugging the predicate, I've observed that input.getPageSource() contains the span with no text on its first invocation, but that input.getPageSource() contains the span with some text on its second invocation (after the page has been ajax-refreshed).
Why doesn't WebDriver consider the refreshed page source on the second invocation?
Thanks!
You can try loop:
int seconds = 0;
for (int seconds =0; seconds<30; seconds++) {
if (apply(driver)){
break;
}
Thread.sleep(1000);
}
The above loop will check every second if text is there and do it for 30 seconds. If it finds it, it will escape the loop. You can still add one more check after:
if (!apply(driver)){
throw new RuntimeException("Expected text still not there");
}
Or another approach, which I am using: Whenewer I have page to load for long time, I select element which is loaded among the last on the page and check its presence the same way:
for (int seconds =0; seconds<30; seconds++){
try{
driver.findElement(By.id("lastelementonpage"));
}catch (Exception e){
Thread.sleep(1000);
}
}
It turns out that WebDriver does not allow access to hidden elements, and this span was hidden.
http://code.google.com/p/selenium/wiki/FrequentlyAskedQuestions#Q:_Why_is_it_not_possible_to_interact_with_hidden_elements?
I've resorted to using the JavaScript-based solution described in the above link.