Richard C Richard C - 2 months ago 13
C# Question

using ElementIsVisible in Page Factory Model

I am attempting to set up a Page Factory Model Framework using Selenium in C#

I have got my tests running using Selenium but want to separate out my Tests from the Framework.

Several tests require me to wait for an element to be visible before I do anything with the element. In my other versions of my Selenium testing I would do something like

By selector = By.XPath("/html/body/header/div/div[4]/div/div/div[2]/div[1]/form/div[2]/span[2]");
new WebDriverWait(driver.Instance, TimeSpan.FromSeconds(5)).Until(ExpectedConditions.ElementIsVisible(selector));


However I cant get Element Is Visible to work so have used Wait Until Visible in my Extension Method (Code Below).

When I run my test even with the Wait Until Visible Selenium is not waiting for the Element to appear before continuing. When I Debug the test it is failing with a stackOverflow at the WaitUntilVisible step.

When I run the test normally I am getting the message does not show error, however it is showing (I can see it on the screen). I know from experience of running this test in my alternative frameworks that this is simply because the test is looking for the element before it has appeared.

I am already running an ImplicitWait as part of my Browser Factory Class.

Am I understanding and using my waits correctly in the Page Factory Model?

Test I am running

[Test]
public void Framework_Invalid_Location()
{
BrowserFactory.InitBrowser("Chrome");
BrowserFactory.LoadApplication("xxxxxxxxxxxxxx");
Page.HomePage.SearchForRestaurant("CFYUGHGYHYTDFD");
Assert.That(Page.HomePage.InvalidPostcode(), Is.EqualTo("Please enter a valid location or postcode"), "message does not show");
BrowserFactory.CloseAllDrivers();
}


HomePage Class

private IWebDriver driver;
[FindsBy(How = How.CssSelector, Using = "#js-postcode")]
[CacheLookup]
private IWebElement PostcodeInput { get; set; }



[FindsBy(How = How.XPath, Using = "/html/body/header/div/div[4]/div/div/div[2]/div[1]/form/div[2]/span[2]")]
[CacheLookup]
private IWebElement ErrorMessageInvalidEntry { get; set; }


public void SearchForRestaurant(string Postcode)
{
PostcodeInput.SendKeys(Postcode);
SearchButton.ClickOnIt("SearchButton");



public string InvalidPostcode()
{
ErrorMessageInvalidEntry.WaitUntilVisible(10);
return ErrorMessageInvalidEntry.Text;
}


Element Extension function I am calling for my Wait. Updated from comments and suggestions

public static void Wait(this IWebElement element, IWebDriver driver, float TimeOut)
{

WebDriverWait Wait = new WebDriverWait(driver, TimeSpan.FromSeconds(TimeOut));
return Wait.Until(ExpectedConditions.ElementIsVisible(element));


There is still one error with this code for (element)
Cannot convert from OpenQa.Selenium.IWebElement to open.Qa.Selenium.By

Really feel I am at the very edge of the little knowledge I have learnt over the past few months so thankyou for all help.

Page Class

namespace KukdFramework.PageObjects
{
public class Page
{
private static T GetPage<T>() where T : new()


public static HomePage HomePage
{
get { return GetPage<HomePage>(); }
}


Browser Factory Code

private static readonly IDictionary<string, IWebDriver> Drivers = new Dictionary<string, IWebDriver>();
private static IWebDriver driver;

public static IWebDriver Driver
{
get
{
if (driver == null)
throw new NullReferenceException("The WebDriver browser instance was not initialized. You should first call the method InitBrowser.");
return driver;
}
private set
{
driver = value;
}
}

public static void InitBrowser(string browserName)
{
switch (browserName)
{
case "Firefox":
if (driver == null)
{
driver = new FirefoxDriver();
Drivers.Add("Firefox", Driver);
BrowserSettings();

}
break;

case "IE":
if (driver == null)
{
driver = new InternetExplorerDriver();
Drivers.Add("IE", Driver);
BrowserSettings();
}
break;

case "Chrome":
if (driver == null)
{
driver = new ChromeDriver();
Drivers.Add("Chrome", Driver);
BrowserSettings();
}
break;
}


}

Answer Source

It looks like your WaitUntilVisible() extension method calls itself recursively with no way out.

This will cause a stack overflow exception.

Instead of calling this method recursively, you could put your above WebDriverWait call inside this method and the return the found IWebElement.

UPDATE (from comments): You'll need to pass in the WebDriver instance as well. In your above WebDriverWait line you use driver.Instance.

Another option would be to modify the extension method to require an instance of WebDriverWait instead of just a float for waiting time. This way you wouldn't need to pass the driver object in by itself.