Check if element is clickable in Selenium ChromeDriver - c#

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

Related

Unhandled Alert Exception in selenium, c#

I am new to Selenium, and I am trying to verify that if user has successfully landed on the Home page or not. Here is the snippet:
LoginPage.GoTo();//Goes Well
LoginPage.LoginAs("UserName").WithPassword("Password").Login();//goes Well
Assert.IsTrue(HomePage.IsAt, "Failed to login");//Below is the implementation of HomePAge.IsAt
public static bool IsAt
{
get
{
var wait = new WebDriverWait(Driver.Instance, TimeSpan.FromSeconds(5));
wait.Until(x => x.SwitchTo().ActiveElement().GetAttribute("id") == "IDHere");//Here the exception is occuring.
}
var homePage = Driver().Instance.FindElement(By.Id("IDHere"));
// return true or False;
Can someone please help?
When an alert is present on your browser, it prevents you from actually doing ANYTHING else.
FYI, when I try to run my application, a window authentication pop up
comes and after that Page loads.
Well, yeah. That's the alert part from "Unhandled Alert Exception". The unhandled part, is because you didn't use any line of code to show your program how to handle the alert. Selenium goes to login page. Then tries to run this line x.SwitchTo().ActiveElement().GetAttribute("id") == "IDHere", but there is an alert on your page that prevents you from doing anything.
You have to actually try to handle it (close it or accept the message) and THEN do anything else.
It might be considered a good practice to wait for your alert to appear (since it might not appear instantly), and then, after (e.g.) 5 seconds, if there is no alert, run your code.
Try the code below to see if it resolves your problem:
public static boid WaitForAlert(bool accept)
{
//Initialize your wait.
WebDriverWait wait = new WebDriverWait(Driver.Instance, TimeSpan.FromSeconds(5));
//Wait for alert
try
{
wait.Until(ExpectedConditions.AlertIsPresent());
if (accept)
{
Driver().Instance.SwitchTo().Alert().Accept();
}
else
{
Driver().Instance.SwitchTo().Alert().Dismiss();
}
}
catch (WebDriverTimeoutException) { /*Alert did not appear, do nothing*/ }
}
And then do:
LoginPage.GoTo();
LoginPage.LoginAs("UserName").WithPassword("Password").Login();
LoginPage.WaitForAlert(true); //True to accept the alert
Assert.IsTrue(HomePage.IsAt, "Failed to login");

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

Handling Lazy loading with webdriver in C#

I am trying test a single page web application with webdriver in page object model using C#. The website javascript intensive and does Lazy loading
i have tried using Explicit wait and used the following code to check if the javascript is active
return jQuery.active == 0
I have tried using a combination of both to know if the page has loaded
WebDriverWait _wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(25));
bool WhenToExit = true;
while (WhenToExit) // Handle timeout somewhere
{
var ajaxIsComplete = (bool)(Browser.Driver as IJavaScriptExecutor).ExecuteScript("return jQuery.active == 0");
if (ajaxIsComplete)
{
bool isDisplayed = _wait.Until(d => d.FindElement(By.ClassName("example"))).Displayed;
if(isDisplayed)
{
break;
}
}
Thread.Sleep(100);
int Timer = 0;
Timer++;
if (Timer == 100)
{
WhenToExit = false;
}
}
.But still the webdriver does not wait for the page to load , it just keeps executing the steps ,So i have been forced to use Thread.Sleep(), which i dont want use and its not good practices.
Can some tell me how to Get around this issue,Thank u in advance

Selenium.WebDriver 2.32.1 C# - Wait untill LOADING DIV is hidden after Page Load

I am really sorry if this question has already been asked/answered. but I could not find it.
Please excuse my ignorance as I am new to WebDriver.
When the page is initially loads, it displays a LOADING DIV untill all the data is loaded. How can I wait until this div is hidden before I proceed with other actions on page elements?
I am trying to know as follows:
public static void waitForPageLoad(string ID, IWebDriver driver)
{
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>
{
return d.FindElement(By.Id(ID));
});
}
I pass the Id of SOME OTHER ELEMENT to this function which I will use when the LOADING DIV disappears. It returns the wrong result as the element by ID is actually present/loaded but is behind the grey DIV that shows "Loading... Please wait" message. So this does not work. I would like to know when that LOADING div disappears.
Any help is greatly appreciated.
By waiting on a bool value instead of IWebElement, the .NET WebDriverWait class will wait until a value of true is returned. Given that, how about trying something like the following:
public static void WaitForElementToNotExist(string ID, IWebDriver driver)
{
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until<bool>((d) =>
{
try
{
// If the find succeeds, the element exists, and
// we want the element to *not* exist, so we want
// to return true when the find throws an exception.
IWebElement element = d.FindElement(By.Id(ID));
return false;
}
catch (NoSuchElementException)
{
return true;
}
});
}
Note that this is the appropriate pattern if the element you're looking for is actually removed from the DOM. If, on the other hand, the "waiting" element is always present in the DOM, but just made visible/invisible as required by the JavaScript framework your app is using, then the code is a little simpler, and looks something like this:
public static void WaitForElementInvisible(string ID, IWebDriver driver)
{
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until<bool>((d) =>
{
try
{
IWebElement element = d.FindElement(By.Id(ID));
return !element.Displayed;
}
catch (NoSuchElementException)
{
// If the find fails, the element exists, and
// by definition, cannot then be visible.
return true;
}
});
}

Categories

Resources