Please comment the following code I found on YouTube. It checks whether an element is present at the time
public boolean isElementPresent(By locator)
{
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
List<WebElement> list = driver.findElements(locator);
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
if (list.size() == 0)
return false;
else
return list.get(0).isDisplayed();
}
It dynamically changes implicitlyWait in the method. In all Selenium resources are always stated that the implicitWait can be set only once in the test class. The code above is similar to some extent to the explicit wait since it adapts to different situations.
What is your opinion about this code?
In the Selenium documentation it is said that Once set, the implicit wait is set for the life of the session.
However, in the code above we change the implicitlyWait twice.
Is the documentation wrong?
Implicit wait
The Implicit wait is to notify the WebDriver instance to poll the HTML DOM for a certain amount of time when trying to find an element or elements if they are not immediately available within the DOM Tree.
Once set, the implicit wait is set for the life of the session
Yes, you saw it right. That's because implicit waits are implemented on the remote side of the WebDriver system. That means they are baked in to GeckoDriver, ChromeDriver, IEDriverServer, etc WebDriver variants that gets installed into the anonymous Firefox/Chrome profile, and the Java remote WebDriver server. However, you can always re-configure the implicitlyWait.
You can find a detailed discussion in Using implicit wait in selenium
This usecase
Syntactically, your code is flawless. Ideally, you would set the implicitlyWait while looking out for the desired elements. Once the elements are ideantified and stored in a list you can reset the implicitlyWait back to 0. So effectively your code block will be:
public boolean isElementPresent(By locator)
{
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
List<WebElement> list = driver.findElements(locator);
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
if (list.size() == 0)
return false;
else
return list.get(0).isDisplayed();
}
Related
After reviewing the selenium docs, I am wondering if I am attempting to implement explicit waits incorrectly.
In the docs, it always shows identifying a new element, then assigning the defined wait to said element
WebDriver driver = new ChromeDriver();
driver.get("https://google.com/ncr");
driver.findElement(By.name("q")).sendKeys("cheese" + Keys.ENTER);
// Initialize and wait till element(link) became clickable - timeout in 10 seconds
WebElement firstResult = new WebDriverWait(driver, Duration.ofSeconds(10))
.until(ExpectedConditions.elementToBeClickable(By.xpath("//a/h3")));
// Print the first result
System.out.println(firstResult.getText());
In this example, a new element firstResult is created, then the defined wait assigned to it.
Is this required? Should always be done this way?
This is why I ask.
I am using the PageFactory model and have my elements defined via the FindBy annotation, as shown here.
// Input field for slice ID
#FindBy(how = How.XPATH, using = "//input[#name='id']")
private WebElement inputSliceId;
Then, in that same class, I have defined some convenience methods to use them.
So now, in my convenience methods, should I do things like this?
inputSliceId = new WebDriverWait(driver, Duration.ofSeconds(10))...
inputSliceId.sendKeys(...
What I have been doing, which is what I'm questioning now, is putting wait statements that are not being assigned directly to the element in question.
For example, I've been doing things like this.
buttonSubmit.click();
WebDriverWait wait = new WebDriverWait(driver, 5);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[#role='alertdialog']")));
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//div[#role='alertdialog']")));
Why? (could totally be wrong here)
Upon clicking the button, I need to wait for a pop-up to display
Once it does, I am then waiting for it to disappear, before proceeding
Here's the main question
Are these two wait lines not really doing anything because I am not assigning them to an element? Or are they still causing the web driver to hold until the conditions specified by the wait occur?
No, You can't assigned wait statement as above to your web element. If you want to wait for your element using Page factory model for a below element then you have to create
public void isLoaded() throws Error {
// Initial loading, called when creating the page object to make sure that the page is loaded to a state where it is ready to interact with us, in our case it means that button is present in DOM and visible.
public class BaseClass
{
private void waitForVisibility(WebElement element) throws Error{
new WebDriverWait(driver, 60)
.until(ExpectedConditions.visibilityOf(element));
}
}
And then in your page object model class you can extend this BaseClass.
public class page extends BaseClass
{
#FindBy(how = How.XPATH, using = "//input[#name='id']")
private WebElement inputSliceId;
waitForVisibility(inputSliceId);
}
I have defined wait in the BaseClass to achieve re-usability of waitForVisibility code across all page object classes.
Also after button clicking if you want to wait for a pop up to be appear then you can include code like below:
#FindBy(xpath = "//div[#role='alertdialog']")
private WebElementFacade alertPopup;
buttonSubmit.click();
waitForVisibility(alertPopup);
There are a couple of things:
If your usecase is to invoke getText() on an element, instead of elementToBeClickable(), using visibilityOfElementLocated() would be just perfect.
To extract the text you don't have to create any new element, instead you can directly invoke visibilityOfElementLocated() once the element is returned as follows:
System.out.println(new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//a/h3"))).getText());
If your usecase doesn't include any validation for the pop-up which gets displayed and disappear, you don't need to induce any waiter for it and safely ignore it. So once you invoke click() on the buttonSubmit you can proceed to your next validation point adjusting the timespan for the pop-up to be displayed and disappear.
So, your optimized code block will be:
buttonSubmit.click();
// consider the total timespan for the wait to be cumulative of: pop-up displayed + pop-up disappear + next interactable element to become clickable
new WebDriverWait(driver, Duration.ofSeconds(20)).until(ExpectedConditions.elementToBeClickable(By.xpath("xpath_next_element_to_click")));
You can find a relevant detailed discussion in How to add explicit wait in PageFactory in PageObjectModel?
First, you can declare a method where set up the wait itself, in a separate class used like base or parent, like that:
protected void waitForElementToBeLoaded(WebElement element) {
wait.until(ExpectedConditions.elementToBeClickable(element));
}
Then, you can declare a second method where use the first one, in a separate class used like fictional page, like that:
public void sendMessageForm( ){
waitForElementToBeLoaded(sendBtn);
sendBtn.click();
}
Finally, every time you use the previous method the wait will be triggered, example:
contactUsPage.sendMessageForm();
In my learning curve I have been looking at the right way to wait for an element to be loaded and you get lots of pages on google.
Got down to 2 but in my view Method2(ExpectedConditions.ElementIsVisible) is more elegant and does what method1 is trying to achieve do you agree or is there a better way?
Method 1
public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds)
{
if (timeoutInSeconds > 0)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
return wait.Until(drv => drv.FindElement(by));
}
return driver.FindElement(by);
}
Method 2
public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds)
{
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
var element = wait.Until(ExpectedConditions.ElementIsVisible(by));
return element;
}
Any suggestions or improvements also what happens if "NoFoundElement exception is thrown is it already handled or should I ignore it?
I would say yes, "Method 2" is the preferred way of doing it. Simply because if something is already implemented in WebDriver, there's no need for you to reimplement it in your testing framework.
As to your question regarding the NotFoundException: If the condition that you're waiting for isn't met after the specified timeout, the WebDriverWait will raise a WebDriverTimeoutException. Depending on the condition that you wanted to wait for, the WebDriverTimeoutException will have an inner exception with more details. If for example you use ExpectedConditions.ElementIsVisible(By.Id("myid")) and the element couldn't be located at all, the inner exception will be a NoSuchElementException. If the element could be located but isn't visible after the given timeout you'll just get the WebDriverTimeoutException.
Depending on what you want to do once you're sure that the element is "there", you can also use different ExpectedConditions. If the element you're waiting for is a button and you want to click on it, you can use ExpectedConditions.ElementToBeClickable as this will not only wait for the element to get loaded into the DOM and visible, but also wait for the element to get enabled.
Webdriver wait class extends Fluent wait, hence it(webdriver wait) has all feature like polling the page, ignoring exception and others of fluent wait. Hence is there any specific condition in which we would use fluent wait?
WebDriverWait is nothing but a specialised case of FluentWait<T> where the type is WebDriver. So if you want to wait for an event to occur on a driver instance it should be used instead of FluentWait. It reduces some keystrokes :)
Within the context of selenium other object we work with is WebElement. If you are looking to wait for an event to occur on a element, using FluentWait is a better option.
For example:
FluentWait<WebElement> wait = new FluentWait<WebElement>(element).withTimeout(30, TimeUnit.SECONDS).pollingEvery(5, TimeUnit.SECONDS);
wait.until(new Predicate<WebElement>() {
#Override public boolean apply(WebElement arg0) {
return arg0.isEnabled();
}
});
You can use the Function variant, for example, to wait for a text on a button to change.
I'm using Selenium Webdriver and have run into the following issue with my app under test.
The app has multiple pages each with an appropriate ".page-title" element which contains the name of the page (e.g. "Other Documents"). As the tests navigate around the app they assert that the browser is on the expected page using these elements before doing other stuff.
The issue is that if you click a button in the app which performs an action, then check that you're on the right page (e.g. check page-title element displays correct text), Webdriver doesn't wait for the action to be performed (e.g. new page load), it returns straight away and the test fails.
If you add a short thread sleep (500ms) between performing the action and checking you're on the right page, then you get StaleElementReferenceException (some of the time) and if you add a large thread sleep the test passes (but not quite all the time).
My aim is to reduce the flakiness of the tests, does anyone have a suggestion as to how I can do this without Thread.sleep?
instead of inserting thread.sleep method explicity
do try the WebDriver in built Implicitwait method..(C# code snippet)
Driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(Max_Time_Limit));
This makes WebDriver to wait till the element is visible/available. In case if it finds elements before the Max_Time_Limit, it snaps out of sleep mode and resumes the execution.
So no hassle of waiting till the Hard bound Max_Time_Limit.This way it helps speeding up your execution Time as well.
I hope this helps...All the best :-)
Try using this wait: using this you can wait for max time 15 secs/wait for the expected condition to be true i.e. wait for some element to be present.
You can give the xpath of some element on the next page, when that element is visible then the next step will be executed.
WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("\xpath of some element on the next page")));
//Assert page title
driver.getTitle();
use fluentWait mechanism . Considered to be a robust approach. As documentation on fluent wait gives:
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.
details you can get here
here is the code of method I use:
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; } ;
String xPathElement="...blablabla...";
fluentWait(By.xpath(xPathElement)).click();
//fluentWait(By.xpath(xPathElement)).getText();
Hope it works for you.
You can use Selenium's ExpectedCondition.
The code below (written in JAVA) waits for a maximum of inTimeout seconds for the element you want to appear. If the element appears sooner, it ends the wait.
public static void wait(WebDriver b,long inTimeout) {
final SlnDriver browser=b;
final long NO_LOADING_TIMEOUT = inTimeout;
class HasCondition implements ExpectedCondition<Boolean> {
#Override
public Boolean apply(WebDriver d) {
Boolean expected=false;
WebElement e = browser.findElement(By.xpath("blabla"));
if (e.getText().contains("TextYouWant")) {
expected= true;
break;
}
}
return expected;
}
}
}
for (;;) {
try {
new WebDriverWait(browser, NO_LOADING_TIMEOUT).until(new HasCondition());
} catch (TimeoutException e) {
return;
}
}
}
I am new to Selenium WebDriver and am trying to understand the correct way to 'wait' for elements to be present.
I am testing a page with a bunch of questions that have radio button answers. As you select answers, Javascript may enable/disable some of the questions on the page.
The problem seems to be that Selenium is 'clicking too fast' and not waiting for the Javascript to finish. I have tried solving this problem in two ways - explicit waits solved the problem. Specifically, this works, and solves my issue:
private static WebElement findElement(final WebDriver driver, final By locator, final int timeoutSeconds) {
FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(timeoutSeconds, TimeUnit.SECONDS)
.pollingEvery(500, TimeUnit.MILLISECONDS)
.ignoring(NoSuchElementException.class);
return wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver webDriver) {
return driver.findElement(locator);
}
});
}
However, I would prefer to use an implicit wait instead of this. I have my web driver configured like this:
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
This does not solve the problem and I get a NoSuchElementException. Additionally, I do not notice a 10 second pause - it just errors out immediately. I have verified this line in the code is being hit with a debugger. What am I doing wrong? Why does implicitlyWait not wait for the element to appear, but FluentWait does?
Note: As I mentioned I already have a work around, I really just want to know why Implicit wait isn't solving my issue. Thanks.
Remember that there is a difference between several scenarios:
An element not being present at all in the DOM.
An element being present in the DOM but not visible.
An element being present in the DOM but not enabled. (i.e. clickable)
My guess is that if some of the page is being displayed with javascript, the elements are already present in the browser DOM, but are not visible. The implicit wait only waits for an element to appear in the DOM, so it returns immediately, but when you try to interact with the element you get a NoSuchElementException. You could test this hypothesis by writing a helper method that explicits waits for an element to be be visible or clickable.
Some examples (in Java):
public WebElement getWhenVisible(By locator, int timeout) {
WebElement element = null;
WebDriverWait wait = new WebDriverWait(driver, timeout);
element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
return element;
}
public void clickWhenReady(By locator, int timeout) {
WebDriverWait wait = new WebDriverWait(driver, timeout);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(locator));
element.click();
}
basic idea is in the following:
Explicit wait
WebDriverWait.until(condition-that-finds-the-element);
Implicit wait
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
In other words, explicit is associated with some condition to be held, whereas implicit with some time to wait for something.
see this link
To make work fluentWait properly try this:
public WebElement fluentWait(final By locator){
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(Duration.ofSeconds(30))
.pollingEvery(Duration.ofMillis(100))
.ignoring(NoSuchElementException.class);
WebElement foo = wait.until(
new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
}
);
return foo;
};
Hope this helps)
Word of warning for a common mistake:
Once you set implicit waiting, you cannot use explicit- or fluent wait until you reset the implicit waiting again. This means that ExpectedConditions, which contain driver.findElement calls will not work as expected with implicit wait! You'll often encounter cases where you want to check for an element or its non-existence instantly - but you can't do that either.
After ~2 years of experience and problems with this I strongly recommend against using implicit wait.
A kotlin version of the https://stackoverflow.com/users/503060/hedley answer:
clickWhenReady("#suggest",10,driver)
via
fun clickWhenReady(selector: String,timeout: Long, webdriver: WebDriver?) {
val wait = WebDriverWait(webdriver, timeout);
val element = wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector(selector)));
element.click();
}
I wrote a small method in C# using the WebDriverWait class. Works great for me.
public static void WaitForAjaxElement(IWebDriver driver, By byElement, double timeoutSeconds)
{
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutSeconds));
wait.Until(x => x.FindElement(byElement));
}
Using:
WaitForAjaxElement(driver, By.ClassName("ui-menu-item"), 10);
Hope it helps.
From Seleniumhq.com:
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.
If you post your test code what you actually want to do I can provide more information.
I have another solution to solve this issue (only for IE, i never try other browser):
1) after create Selenium driver instance, you can get its ie COM instance
Add-Type -Path .\SePSX.NET35\WebDriver.dll
$ieDriver = New-Object "OpenQA.Selenium.IE.InternetExplorerDriver"
$ieShell = $null
$shell_apps = (New-Object -ComObject Shell.Application).Windows()
foreach($app in $shell_apps)
{
if ($app.LocationURL -eq $ieDriver.URL)
{
$ieShell = $app
break
}
}
if ($ieShell -eq $null)
{
throw "Can't get WebDriver IE Instance"
}
2) after each call GotoURL or click action, check $ieShell.Busy status, it will wait for until page is loaded.
$ieDriver.Navigate().GotoUrl("www.google.com")
while ($ieShell.Busy -eq $true) {sleep 1}
then call Selenium driver to get element id and do the further action
$ieDriver.FindElementById ...
use this way, you don't need to set page load and findElement timeout for Selenium
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;
FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver);
wait.pollingEvery(250, TimeUnit.MILLISECONDS);
wait.withTimeout(20, TimeUnit.SECONDS);
wait.ignoring(NoSuchElementException.class);
Predicate<WebDriver> predicate = new Predicate <WebDriver>()
{
public boolean apply(WebDriver arg0) {
WebElement element = arg0.findElement(By.id("colorVar"));
String color = element.getAttribute("color");
System.out.println("The color if the button is " + color);
if(color.equals("blue"))
{
return true;
}
return false;
}
};
wait.until(predicate);
Below is the code equivalet code for fluient wait in c#.Net using DefaultWait.
IWait<IWebDriver> wait = new DefaultWait<IWebDriver>(driver);
wait.Timeout = TimeSpan.FromSeconds(10);
wait.PollingInterval = TimeSpan.FromMilliseconds(100);
IWebElement elementt = wait.Until<IWebElement>(ExpectedConditions.ElementIsVisible(By.Id("selectedfirstlast1")));
SelectElement se = new SelectElement(driver.FindElement(By.Id("selectedfirstlast1")));
element = se.SelectedOption;
if (element.Text.Contains("Mumbai") && element.Selected)
driver.FindElement(By.XPath("//table/tbody/tr[2]/td[7]/a")).Click();