0

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

}

Richard C
  • 513
  • 1
  • 7
  • 26
  • few things, remove unncessary code, you have pasted so much code which is not nedded. I guess `WaitUntilVisible` is not working as expected, right? what is happening. any error or exception or it's not working. please update the question rather than replying in comment. – Gaurang Shah Jul 17 '17 at 11:38
  • I have updated the post, I had included all the code to try and show the structure of my Framework. Because this is all new to me I wasn't sure if there was something fundamental I was doing wrong to begin with that was causing this issue. – Richard C Jul 17 '17 at 12:00
  • what is the stacktrace, I don't much C# but seems like `WaitUntilVisible` is custom function and not provided by webdriver. Can you update the question with implementation of `WaitUntilVisible` and stack-trace. – Gaurang Shah Jul 17 '17 at 12:17
  • have amended my code given both Jordans Comment and what I had myself realised. However still cant get WebDriverWait to work correctly. – Richard C Jul 17 '17 at 12:45
  • I don't think that was the case, i think `WaitUntilVisible` is a overloaded method. you should search for the implementation, also I don't see any stacktrace. – Gaurang Shah Jul 17 '17 at 13:01
  • @Guarang Shah C# has extension methods which allow for some syntactic sugar. OP's above extension method is called in C#: `myElement.WaitUntilVisibile(time)` and can be translated to: `MyWaitExtensionsClass.WaitUntilVisible(myElement, time)` I do not believe Java has support for extension methods in this way (I think Java 8 has Default methods?). More info on that can be found here - https://stackoverflow.com/questions/24096421/java-8-add-extension-default-method-to-class – Jordan Jul 17 '17 at 13:23

2 Answers2

0

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.

Jordan
  • 639
  • 1
  • 13
  • 30
  • As you posted this I realised my mistake there. – Richard C Jul 17 '17 at 12:29
  • Ok tried putting my WebDriver wait command inside the method WebDriverWait wait = new WebDriverWait(TimeSpan.FromSeconds(10)); However I am getting an error now stating WebDriverWait does not contain a constructor that takes 1 argument? – Richard C Jul 17 '17 at 12:39
  • Updated my answer. – Jordan Jul 17 '17 at 12:45
  • Ok tried doing that have updated code accordingly, 2 issues now appearing I have annotated the code accordingly. – Richard C Jul 17 '17 at 13:18
  • Seem to have resolved the driver issues but still have an issue passing the element into the Function (cannot convert from .IWebElement to .By) – Richard C Jul 17 '17 at 14:10
  • have marked this as solved as I have moved beyond the original issue, will create a new post for the new specific issue. – Richard C Jul 17 '17 at 14:18
0

I am not an C# programmer, however JAVA and C# is similar and so you can probably convert following Java Code.

WaitUntilVisible Should look like this

public static void WaitUntilVisible(WebElement element, int timeOut){
    WebDriverWait wait = new WebDriverWait(driver, timeOut);
    wait.until(ExpectedConditions.visibilityOf(element));
}
Gaurang Shah
  • 11,764
  • 9
  • 74
  • 137