WebDriverWait with multiple conditions C# - c#

Wait.Until gets a selector and returns an element.
First Question
How can you wait (poll) for multiple conditions to be met?
Problem:
DefaultWait<IWebDriver> wait = new WebDriverWait(driver, timeout);
IWebElement element = wait.Until(ExpectedConditions.ElementExists(selector));
Wait.Until doesn't have an overload or a constructor with params...
Second Question
Wait.Until appears to get only one condition per each poll.
Is there a way to poll over multiple conditions?
Meaning, in that same polling, check if element exists and also check if its visible (which are two different things..)
in 1 polling sequence,
Something like the following:
DefaultWait<IWebDriver> wait2 = new DefaultWait<IWebDriver>(driver);
IWebElement element = wait2.Until<IWebElement>((d) =>
{
ExpectedConditions.ElementExists(selector);
ExpectedConditions.ElementIsVisible(selector);
return d.FindElement(selector);
});

Related

C# Selenium - Explicitly waiting By.CssSelector(...)

I am doing an explicit wait with a TimeSpan of 30 seconds and wait.Until(By.CssSelector("#content .data-grid > .data-row")).
I obviously have a data-grid that is being populated here.
Result:
The wait.Until(...) is returned right away (it does not wait for this CssSelector to evaluate with satisfactory results).
Expected result:
I expect there to be a wait until the data is asynchronously returned.
Is this a valid scenario for explicitly waiting?
wait.Until(By.CssSelector("#content .data-grid > .data-row"))
I think you are missing the ExpectedConditions...
You declare the wait:
WebDriverWait wait = new WebDriverWait(driver.driver, TimeSpan.FromSeconds(30));
Then you add ExpectedConditions here I am using ElementIsVisible for the example:
wait.Until(ExpectedConditions.ElementIsVisible(By.CssSelector("#content .data-grid > .data-row")));
Hope this does the trick!

Selenium - waiting until element disappears last long

I am looking for better solution to wait until element disappear. Now I am using:
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeout));
wait.Until((ExpectedConditions.InvisibilityOfElementLocated(element)));
This method is working, but it last long. Element is invisible in dom after ~2sec but driver is waiting for this condition <20 sec. I was looking for another solutions, but couldn't find one which will work in .net.
I am using IE to run my tests.
I'd assume that you're mixing implicit and explicit waits, which causes collision. You should make sure that implicit waits are set to 0 in case of using WebDriverWait.

What is the fastest way to see if an element contains a child element?

I have an IWebElement (a div) that contains a child element half of the time. I want to see if it contains the child element and if so, I want to capture it. I do something like this:
IWebElement firstChild;
try
{
firstChild = divElement.FindElement(By.XPath("*"));
}
catch (NoSuchElementException e)
{
// catch and handling...
}
But this is slow on three parts:
1. The use of By.XPath("*")
2. FindElement that is slow in case an element does not exist
3. try/catch is a slower mechanism, I'd rather want a returned boolean on an existing of an item
How can I speed up this way of detecting child elements?
EDIT:
To clarify: The test I am performing runs on grids with divs, a typical grid is 4 x 16, so 64 fields. I want to transform this grid into a DataTable to compare it to the expected outcome. The capturing of these fields to the datatable runs in 22 seconds in total. It is not performing very bad, but I'd like to shave off those precious seconds.
UPDATE:
I managed to do it by capturing the grid with the HTML Agility Pack. Unfortunately (there is always something), the values for the input elements could not be captured because they are dynamically set. As a solution I'd let the HAP return the Ids of the input elements and capture the values with FindElement(By.Id(inputId)) which is blazingly fast compared to other Selenium selection methods.
To keep a long story short: I managed to reduce the capture time from around 22 seconds to less than 3 seconds, a more than 600% performance improvement.
You need to add a . in front of your XPath to search among the descendants:
var elems = divElement.FindElements(By.XPath("(.//*)[1]"));
IWebElement firstChild = elems.Count > 0 ? elems[0] : null;
As an alternative you can use a CSS selector. It might be slightly faster:
var elems = divElement.FindElements(By.CssSelector("*"));
IWebElement firstChild = elems.Count > 0 ? elems[0] : null;
Create an extension method on ISearchContext like this:
public static IWebElement FindElementInstant(this ISearchContext context, By by)
{
Driver.Instance.Manage().Timeouts().ImplicitlyWait(TimeSpan.Zero);
var matchingElement = context.FindElements(by).FirstOrDefault();
Driver.Instance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(/* whatever your implicit wait is normally */));
return matchingElement;
}
Used like:
var firstChild = divElement.FindElementInstant(By.XPath("*"));
If you don't need to access the matching element, you can just return bool out of FindElementInstant.
By temporarily disabling your implicit waiting, FindElements will return an empty collection instantly if no matching elements exist and by using FindElements instead of FindElement within a try-catch you avoid the extra time that comes from exceptions.

DefaultWait<T>.until behavior for polling

I have a piece of code such as
DefaultWait<IWebDriver> wait = new DefaultWait<IWebDriver>(driver);
wait.PollingInterval = TimeSpan.FromMilliseconds(250);
wait.Message = "Can't find element";
wait.Timeout = TimeSpan.FromSeconds(30);
driver.Navigate().GotoUrl('.....');
IWebElement elem = wait.Until(x => x.FindElement(By.ClassName("abc")));
Now lets say that the URL I navigated to does not contain that element with a class name "abc".
My understanding of DefaultWait is that it is supposed to find that element by polling every 250 milliseconds and timeout after 30 seconds. But I see that
it almost immediately returns that the element is not present or throws an exception.
I am a little confused because, technically after 10 seconds or so the DOM could have been altered to create an element of that class and the wait should have been successful/ or could have been successful.
So the question is what is the behavior of the DefaultWait? Should it wait until the given timeout or am I completely missing the behavior of the DefaultWait?
It is easiest to let the ElementExists expected condition handle this.
IWebElement elem = new WebDriverWait(Driver, TimeSpan.FromSeconds(30))
.Until(ExpectedConditions.ElementExists(By.ClassName("abc"));
The reason your example is not working as expected is because FindElement throws an exception on failure. You could rework your example to use FindElements, which will happily return an empty collection, but even then, you'd need to add logic to handle an empty collection, since DefaultWait.Until considers any non-null return value to be a success.
The easiest thing is to use the logic provided in ExpectedConditions to do all the heavy lifting for you.
The default polling interval is 500ms. You can set the polling interval by passing in the optional third parameter, like this:
IWebElement elem =
new WebDriverWait(Driver,
TimeSpan.FromSeconds(30), // time out
TimeSpan.FromMilliseconds(250)) // polling interval
.Until(ExpectedConditions.ElementExists(By.ClassName("abc"));

What's the alternative to use Thread.Sleep when working with Selenium in system testing?

I have a TestMethod using Selenium as below:
[TestMethod]
public void ShouldSendPasswordReminder()
{
// go to loginregister url
_fireFoxWebDriver.Navigate().GoToUrl(UkPaBaseUrl + "loginregister.aspx");
Thread.Sleep(1000);
// click the forgotten password
_fireFoxWebDriver.FindElement(By.LinkText("Forgotten your password?")).Click();
Thread.Sleep(1000);
// enter your email address
_fireFoxWebDriver.FindElement(By.Id("PasswordResetRequest1_PasswordResetRequest_Username"))
.SendKeys("username.lastname#domain.com");
Thread.Sleep(1000);
// click submit
_fireFoxWebDriver.FindElement(By.Id("PasswordResetRequest1_PasswordResetRequest_PasswordResetRequestSubmit")).Click();
Thread.Sleep(5000);
// assert
Assert.IsTrue(_fireFoxWebDriver.Url.Contains("ThankYou"));
}
As you can see, I'd have to call Thread.Sleep many times (because the page might take some time to finish what it does due to javascript, etc) almost after each action because Selenium doesn't seem to be able to handle page loads and delays unlike WatiN.
This makes the code rather ugly and not very much reliable.
What's the better way to handle such scenarios? Do you write frequent Thread.Sleep calls in your tests as well?
Thanks,
You could use the manage functionality to set the base line time you want FindElement() to wait for before failing:
_fireFoxWebDriver.Manage()
.Timeouts()
.ImplicitlyWait(TimeSpan.FromSeconds(1000));
Explicit wait.
According to official documentation (http://www.seleniumhq.org/docs/0...), Thread.sleep() is the worst case of explicit wait.
In explicit wait, without waiting for the maximum time to get over, it proceeds as soon as the condition occurs, if that condition occurs before the specified maximum time gets over. Hence having to wait till the maximum time (because the condition did not occur during the specified maximum time) is the worst case of explicit wait.
I think Thread.sleep() is considered as the worst case of explicit wait because, for Thread.sleep(), it has to wait for the full time specified as the argument of Thread.sleep(), before proceeding further.
You may think why Thread.sleep() isn't implicit wait. I think that is because effect of Thread.sleep() is only at the place where it is written, like explicit wait. Effect of implicit wait however, is for the entire lifetime of the driver instance.
**JAVA**
WebDriver driver = new FirefoxDriver();
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = (new WebDriverWait(driver, 10)).until(ExpectedConditions.presenceOfElementLocated(By.id("myDynamicElement")));
**C#**
using (IWebDriver driver = new FirefoxDriver())
{
driver.Url = "http://somedomain/url_that_delays_loading";
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement myDynamicElement = wait.Until<IWebElement>(d => d.FindElement(By.Id("someDynamicElement")));
}
This waits up to 10 seconds before throwing a TimeoutException or if it finds the element will return it in 0 - 10 seconds.
My sample code, my test case wanted me to wait for a maximum of 10 seconds, earlier I was waiting for 10 seconds before finding my next element using Thread.Sleep. Now I use the the WebDriverWait so if the element is found it proceeds, this speeds up my day to day activities and also saves time.
using (IWebDriver driver = new ChromeDriver(options))
{
TimeSpan t = TimeSpan.FromSeconds(10);
WebDriverWait wait = new WebDriverWait(driver,t);
try
{
driver.Navigate().GoToUrl("URL");
//IWebElement username = driver.FindElement(By.Name("loginfmt"));
IWebElement username = wait.Until(ExpectedConditions.ElementIsVisible(By.Name("loginfmt")));
username.SendKeys(dictionaryItem);
//Thread.Sleep(10000); Removed my Thread.Sleep and tested my wait.Until and vola it works awesome.
IWebElement next = wait.Until(ExpectedConditions.ElementIsVisible(By.Id("idSIButton9")));
//IWebElement nextdriver.FindElement(By.Id("idSIButton9"));
next.Click();
My general heuristic on introducing delays when my script gets faster than my app is to really think about what I'm waiting for. In my opinion, sleep type calls are really only appropriate in cases where I'm actually waiting for time to elapse. A case where I was testing an automatic timeout might make sense to have a Thread.sleep type call in it, because I'm actually waiting for a specific amount of time to elapse. Usually, however, I'm waiting for other things to occur - pages to load, javascript to execute, etc. In these cases, waiting for a set period of time is an easy way to seem to get past the potentially greater complexity of checking for what I'm actually waiting for. This has multiple pitfalls though - you may be slowing down your tests too much (what if each of your waits above only needed to be 200ms, for example - now even the brief snippet above takes an extra 2.5 seconds (and that's without adjusting the 5 second wait at the end). That may not seem like much by itself but it adds up as your suite gets bigger.) Another pitfall happens when you move to a slower machine or environmental things slow down your app - what if it took 1.5 seconds before you could click the Forgotten your password? link on one machine. Your test would fail, but that may still be within acceptable performance thresholds for your app, so you now have a false failure. This is often dealt with by simply increasing the wait time, but that leads back to the first pitfall I mentioned again.
To break out of this cycle, I find it's very important to be as specific as possible when I'm waiting for things. Selenium provides a Wait class that can be used to wait until a particular condition is met. I don't know if the .Net bindings include it, but i would go into using them expecting it. In the Ruby version, we give Wait a block of code - it can look for the presence of an element or whatever else we need to check. The wait method takes a timeout value and an interval value, and then runs the block every interval seconds until either the block returns true or the timeout period has elapsed. Setting up a class like this allows you to set your timeout values high enough to handle the low end of the performance scale but not to incur the penalty of waiting a lot longer than you really need to in a given run.

Categories