waiting for an element while condition is still fullfilled - selenium

The wait helpers are very useful functions. But it seems they can wait only for an element to exist (Until...)
Is there a wait to say "wait while condition is still fullfilled" ?
Example, click some element and wait for some other element to disappear

You can try (at least with Java, I'm not sure if it's in the other languages) is the ExpectedConditions.not the method, which you can wrap around another ExpectedConditions.
An example would be something like:
new WebDriverWait(driver, 20).until(ExpectedConditions.not(ExpectedConditions.presenceOfElementLocated(By.cssSelector('#loading-spinner'))));
or you can try
new WebDriverWait(driver, 20).until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector('#loading-content')))

Selenium in Java has
wait.until(ExpectedConditions.invisibilityOfElementLocated(element));
and
wait.until(ExpectedConditions.stalenessOf(element));
methods.
Selenium in Python has invisibility_of_element_located and staleness_of methods too.
So you can create a method clicking on some element and waiting for it to disappear, like this:
public void clickVisibleDisappear(By element){
wait.until(ExpectedConditions.visibilityOfElementLocated(element)).click();
wait.until(ExpectedConditions.invisibilityOfElementLocated(element));
}
Or clicking on one element and waiting for some other element to disappear as you asked, like this:
public void clickVisibleDisappear(By element1, By element2){
wait.until(ExpectedConditions.visibilityOfElementLocated(element1)).click();
wait.until(ExpectedConditions.invisibilityOfElementLocated(element2));
}

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();

How to applied a default wait time to visible or find or display of webElement in selenium except using Implicit wait or webdriver wait

I want to apply a one specification to my selenium test's code as webdriver have to wait for web element to display or load on a webpage for anytime. It should be applicable for a every web element in the code. Is there any way to get this. Instead of applying implict wait or Webdriver wait when ever it required. I can use this specification so that even though in future any webElement take sometimes to get visible it will wait default till it is visible.
You can create a method which receives By as parameter and returns WebElement, and use it for all the element search instead of driver.findElement()
// Java syntax
public WebElement findElement(By by) {
WebDriverWait wait = new WebDriverWait(driver, 30);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(by));
return element;
}
You can also put WebDriverWait wait = new WebDriverWait(driver, 30); at class level instead of creating a new instance every time.

Waiting for elements with Selenium WebDriver

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 :)

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);