Container test with Selenium in C# - c#

How do I continue the selenium test if an element does not exist, in c#?
if (type == "ID" && Event == "Click") {
Thread.Sleep(TimeSpan.FromSeconds(time));
WebDriverWait wait = new WebDriverWait(webDriver,
TimeSpan.FromSeconds(20));
IWebElement element =
wait.Until(ExpectedConditions.ElementIsVisible(By.Id(id)));
element.Click();
}
else if (type == "ID") {
webDriver.FindElement(By.Id(id)).SendKeys(key[data]);
Thread.Sleep(TimeSpan.FromSeconds(time));
}
I want to skip the selenium element if it's not on the page.

You may use exception handling to avoid test fail when there is no element
try
{
webDriver.FindElement(By.Id(id));
}
catch(NoSuchElementException)
{
}
Or use array, since finding multiple elements do not cause exception, just empty array.
IWebElement[] elements = webDriver.FindElements(By.Id(id)).ToArray();
if (elements.Count() != 0)
{
do what you want
}

Related

How to wait for one of multiple elements to be displayed first using Selenium?

I'm very new to Selenium so I'm looking for some insight on how to achieve this.
Essentially, I want my driver to wait for one of multiple elements to be visible. This is because the website can produce mixed results when using automation, so I want to treat this like it's "error handling" (if that makes sense).
Basically, if element a is visible first, do this. However, if element b is visible first, do that.
How would I be able to achieve this using the Selenium webdriver for C#? I read that combining the elements' XPath value by using "|" worked, however when I tried it with my application, I had no luck.
Any answers are greatly appreciated! Thank you in advance!
To me this is kind of tough because your elements could be displayed within a split second of each other. Wonder if you could put this in a case and break when you get one?
So what I was thinking was seeing if the element was present first.
public static bool IsElementPresent_byXpath(string xpath)
{
bool result;
try { result = Driver.FindElement(By.XPath(xpath)).Displayed; }
catch (NoSuchElementException) { return false; }
catch (StaleElementReferenceException) { return false; }
return result;
}
So if you do it this way, then you can write something like the below but my concern is that if the page is not changing, ele1, ele2 and ele3 could be invoked. So this code would need to be changed.
bool ele1 = Browser.IsElementPresent_byXpath("//[#id='1']");
bool ele2 = Browser.IsElementPresent_byXpath("//[#id='2']");
bool ele3 = Browser.IsElementPresent_byXpath("//[#id='3']");
if (ele1)
{
//do this
}
else if (ele2 || ele1 == false)
{
//do this
}
else if (ele3 || ele1 == false || ele2 == false)
{
//do this
}
I would go with Wait.Until, so that I can combine the benefits of waiting with set timeout for an event, and returning me matching locator, so I can base my logic on the result.
This is java code, but C# has equivalents.
Assuming I am waiting for either firstBy, secondBy or thirdBy:
By locatorOfElementThatIsPresent = new WebDriverWait(webDriver, timeoutInSeconds).<By>until(driver -> {
// findElements does not throw when element not found, so I skip try-catch
if (driver.findElements(firstBy).size() > 0) return firstBy;
if (driver.findElements(secondBy).size() > 0) return secondBy;
if (driver.findElemetns(thirdBy).size() > 0) return thirdBy;
return null; // neither found, so the method will be retried until timeout
});

Check if element is clickable in Selenium ChromeDriver

I am trying to find an element by XPath, and if it is not found then execute the function again. It seems to be getting stuck on the finding element function, and I'm not sure why. I have this working on another site with the same method. Here are my attempts:
Attempt 1:
while (url == "https://drygoods.phish.com/dept/posters-prints-and-paper-goods")
try
{
driver[task].FindElement(By.XPath($"//img[contains(#alt, '{Keyword}')]")).Click();
}
catch
{
Thread.Sleep(1000);
DryGoodsFindProductKeyword(Keyword, task);
}
Attempt 2:
if (driver[task].Url != "https://drygoods.phish.com/dept/posters-prints-and-paper-goods")
{
driver[task].FindElement(By.XPath("//div[2]/div[2]/div/button")).Click();
driver[task].Url = "https://drygoods.phish.com/cart/";
//SolveCaptcha(task);
driver[task].FindElement(By.Id("GoToCheckout")).Click();
MessageBox.Show("Click Checkout");
Thread.Sleep(5000);
}
else
{
driver[task].FindElement(By.XPath($"//img[contains(#alt, '{Keyword}')]")).Click();
WebDriverWait wait = new WebDriverWait(driver[task], TimeSpan.FromSeconds(5));
wait.Until(ExpectedConditions.UrlContains("product"));
Thread.Sleep(1000);
DryGoodsFindProductKeyword(Keyword, task);
Here is my full method as well:
public void DryGoodsFindProductKeyword(string Keyword, int task)
{
String url = driver[task].Url;
driver[task].Url = "https://drygoods.phish.com/dept/posters-prints-and-paper-goods";
if (driver[task].Url != "https://drygoods.phish.com/dept/posters-prints-and-paper-goods")
{
driver[task].FindElement(By.XPath("//div[2]/div[2]/div/button")).Click();
driver[task].Url = "https://drygoods.phish.com/cart/";
//SolveCaptcha(task);
driver[task].FindElement(By.Id("GoToCheckout")).Click();
MessageBox.Show("Click Checkout");
Thread.Sleep(5000);
}
else
{
driver[task].FindElement(By.XPath($"//img[contains(#alt, '{Keyword}')]")).Click();
WebDriverWait wait = new WebDriverWait(driver[task], TimeSpan.FromSeconds(5));
wait.Until(ExpectedConditions.UrlContains("product"));
Thread.Sleep(1000);
DryGoodsFindProductKeyword(Keyword, task);
}
}
Thank you in advance for the help! Please let me know if I can add anymore information.
To make sure the page is loaded instead of just your URL changing you can use
wait.Until(d => ((IJavaScriptExecutor)d).ExecuteScript("return document.readyState").Equals("complete"));
Maybe your element isn't displayed yet or it isn't enabled. They're both properties on your IWebElement. You could use this to see if it's clickable:
wait.Until(ExpectedConditions.ElementToBeClickable(byLocatorGoesHere)).Click();
If it's slightly out of view you may need to use Javascript to click it (or just scroll it into view).

How to add expected condition to function which finds element

I have code which finds element with delay, but sometimes element is already but not clickable and not available in DOM, so what i should to add to my code to check those arguments
public IWebElement FindElement(IWebDriver driver, By howBy, int timeoutInSeconds = 10)
{
TimeSpan elementTimeOut = TimeSpan.FromSeconds(20);
IWebElement elementfound = null;
try
{
WebDriverWait wait = new WebDriverWait(driver, elementTimeOut);
elementfound = wait.Until<IWebElement>(d =>
{
try
{
elementfound = driver.FindElement(howBy);
}
catch (NoSuchElementException e)
{
Debug.WriteLine("Please fail NoSuchElementException");
throw;
}
return elementfound;
});
}
catch (WebDriverTimeoutException e)
{
Debug.WriteLine("Please fail WebDriverTimeoutException");
throw;
}
return elementfound;
}
Firstly, It'll check if it's 'visible' by using the standard ExpectedConditions.visibilityOfElementLocated, it'll then simply check if the element.isEnabled() is true or not.
This can be condensed slightly, this basically means (simplified, in C#):
Wait until the element is returned from the DOM
Wait until the element's .Displayed property is true (which is essentially what visibilityOfElementLocated is checking for).
Wait until the element's .Enabled property is true (which is essentially what the elementToBeClickable is checking for).
I would implement this like so (adding onto the current set of ExpectedConditions, but there are multiple ways of doing it:
// <param name="locator">The locator used to find the element.</param>
// <returns>The <see cref="IWebElement"/> once it is located, visible and clickable.</returns>
public static Func<IWebDriver, IWebElement> ElementIsClickable(By locator)
{
return driver =>
{
var element = driver.FindElement(locator);
return (element != null && element.Displayed && element.Enabled) ? element : null;
};
}
Above method can be used something like:
var wait = new WebDriverWait(driver, TimeSpan.FromMinutes(1));
var clickableElement = wait.Until(ExpectedConditions.ElementIsClickable(By.Id("id")));
However, you can pass howBy as the param of ElementIsClickable() method.
elementToBeClickable is used to wait for an element to be clickable .
Please use the following code inside your method.
elementfound = wait.until(ExpectedConditions.elementToBeClickable(howBy);

Selenium c# Find element exist on a page using Pagefactory

I am migrating my selenium scripts to PageFactory and currently stuck with find if an element exist on the page
My current implementation is
public bool IsElementExist(string element)
{
try
{
Driver.FindElement(By.XPath(element));
return true;
}
catch (NoSuchElementException)
{
return false;
}
}
My page has multiple items on its basket and if I need to delete all/some of the item. Everytime I delete the page refreshes, but the Pagefactory FindsBy is not getting refreshed and retains the very first value. Any assistance please.
When you have multiple elements matching a given locator, the findElement() method simply picks the first one and returns the corresponding WebElement. This could be confusing sometimes, because you might interact with a different element unintentionally.
A slightly better implementation of your function would be as below (example in Java but works similarly in C#):
public Boolean objectExists(By by) {
int numberOfMatches = driver.findElements(by).size();
if(numberOfMatches == 1) {
return true;
}
else {
// 0 matches OR more than 1 match
return false;
}
}
Not sure if this is directly related to your issue, but worth a try.
Below I am performing a wait but it provides an example of how you can pass an IWebElement to find an object and perform an action. The method you provided is going to expect you to provide the XPath as a string rather than the name of an already identified element on the page.
// Wait Until Object is Clickable
public static void WaitUntilClickable(IWebElement elementLocator, int timeout)
{
try
{
WebDriverWait waitForElement = new WebDriverWait(DriverUtil.driver, TimeSpan.FromSeconds(10));
waitForElement.Until(ExpectedConditions.ElementToBeClickable(elementLocator));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
throw;
}
}
This lives in a BaseUtil.cs that I call from MyPageFunctionality.cs like this:
BaseUtil.WaitUntilClickable(btnLogin, 10);
Would this work?
//call the method and pass the xpath. You can also create css, id etc.
page.WaitForElementNoLongerDisplayed_byXpath("//div[contains(#class, 'my-error-message')]");
public static void WaitForElementNoLongerDisplayed_byXpath(string elementXpath)
{
try
{
_wait.Until(driver => driver.FindElements(By.XPath(elementXpath)).Count == 0);
}
catch (Exception)
{
LogFunctions.WriteError("Element is still displayed and should not be");
TakeScreenshot("elementStillShown");
throw;
}
}

Possible to make generic function to find a particular item with Selenium WebDriver?

I would like to make a generic function to find a particular item?
I do this C# code (Src : Use Explicit Waits in Selenium WebDriver Correctly)
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) =>
{
try
{
return d.FindElement(By.Id("someDynamicElement"));
}
catch
{
return null;
}
});
I would replace wait.Until((....); using a generic function.
How can Ideclare a generic By selector to find a particular item?
Here is a list of the built-in Selenium2 selectors:
ClassName
CssSelector
Id
LinkText
PartialLinkText
Name
TagName
XPath
For example :
IWebElement myDynamicElement = WaitForElement(????) // for exemple By.TagName = "Test"
public static IWebElement WaitForElement(**By selector**)
{
wait.Until<IWebElement>((d) =>
{
try
{
return d.FindElement(**By selector**);
}
catch
{
return null;
}
});
}
public static IWebElement WaitForElement(IWebDriver driver, By selector)
{
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10);
return wait.Until<IWebElement>(d =>
{
try
{
return d.FindElement(selector);
}
catch
{
return null;
}
});
}
This would be called with something like:
WaitForElement(driver, By.Id("someDynamicElement"));
You just give it an instance of a By selector. The underlying d.FindElement call will then deal with the rest, it will deal with figuring out what 'kind' of selector it is. You don't need to do much.
The whole concept behind the By class, is to make it generic in the first place. You will be duplicating work.
You will also have to pass in the driver as well, unless you plan to have it as a static field or an extension method on the driver itself.

Categories

Resources