3

I would like to add a static string property that will track the name of the current test running. I figured the best way to go about this was to use the WebDriver since it is the only object that is carried throughout all of my page objects.

Is there a way to extend the WebDriver class to add a string property that I can set?

EDIT: Since WebDriver uses the IWebDriver interface rather would I extend the interface perhaps?

EDIT #2: Adding example of what I currently have to load my WebDriver:

protected static NLog.Logger _logger = LogManager.GetCurrentClassLogger();
protected static IWebDriver _driver;

/// <summary>
/// Spins up an instance of FireFox webdriver which controls the browser using a
/// FireFox plugin using a stripped down FireFox Profile.
/// </summary>
protected static void LoadDriver()
{
    ChromeOptions options = new ChromeOptions();
    try
    {
        var profile = new FirefoxProfile();
        profile.SetPreference("browser.helperApps.neverAsk.saveToDisk", "application/octet-stream doc xls pdf txt");

        _driver = new FirefoxDriver(profile);
        _driver.Navigate().GoToUrl("http://portal.test-web01.lbmx.com/login?redirect=%2f");
    }
    catch(Exception e)
    {
        Console.WriteLine(e.Message);
        throw;
    }
}
Milo
  • 3,365
  • 9
  • 30
  • 44
  • Can you provide an example? – Florent B. Aug 15 '16 at 14:33
  • Added example of what I currently have to load WebDriver. This is within an abstract class that takes care of setup/cleanup/util of tests. – Milo Aug 15 '16 at 14:59
  • why not to init the static string in your execution function ? – Leon Barkan Aug 15 '16 at 15:06
  • @LeonBarkan The class is abstract w/ static methods for execution. I don't believe it is possible to set a string that I can change for each different test. If I am wrong please show an example. – Milo Aug 15 '16 at 15:09

4 Answers4

5

Ok let's stop the half answer practice (That is the full implementation of generic IWebDriver) after that you can call all the regular methods like you use in standard driver + you have your additional CurrentTest variable.

you can add more constructors for best compatibility.

class MyWebDriver<T> where T : IWebDriver, new()
{
    IWebDriver driver;
    public string CurrentTest { get; set; }

    public MyWebDriver()
    {
        driver = new T();
    }

    public void Dispose()
    {
        this.driver.Dispose();
    }

    public IWebElement FindElement(By by)
    {
        return this.driver.FindElement(by);
    }

    public ReadOnlyCollection<IWebElement> FindElements(By by)
    {
        return this.driver.FindElements(by);
    }

    public void Close()
    {
        this.driver.Close();
    }

    public void Quit()
    {
        this.driver.Quit();
    }

    public IOptions Manage()
    {
        return this.driver.Manage();
    }

    public INavigation Navigate()
    {
        return driver.Navigate();
    }

    public ITargetLocator SwitchTo()
    {
        return this.SwitchTo();
    }

    public string Url
    {
        get
        {
            return this.driver.Url;
        }
        set
        {
            this.driver.Url = value;
        }
    }

    public string Title
    {
        get
        {
            return this.driver.Title;
        }
    }

    public string PageSource
    {
        get
        {
            return this.driver.PageSource;
        }
    }

    public string CurrentWindowHandle
    {
        get
        {
            return this.driver.CurrentWindowHandle;
        }
    }

    public ReadOnlyCollection<string> WindowHandles
    {
        get
        {
            return this.WindowHandles;
        }
    }
}

public class MyTest
{
    public void main()
    {
        MyWebDriver<FirefoxDriver> driver = new MyWebDriver<FirefoxDriver>();
        driver.CurrentTest = "Entering to google website with Firefox Driver";
        driver.Navigate().GoToUrl("www.google.com");
    }
}
Leon Barkan
  • 2,676
  • 2
  • 19
  • 43
3

You will need to wrap the WebDriver using the "Decorator" design pattern.

public class MyWebDriver : IWebDriver
{
    private IWebDriver webDriver;
    public string CurrentTest { get; set; }

    public MyWebDriver(IWebDriver webDriver)
    {
        this.webDriver = webDriver
    }

    public Method1()
    {
        webDriver.Method1();
    }

    public Method2()
    {
        webDriver.Method2();
    }

    ...
}

And then pass in whichever driver you are using at the time.

var profile = new FirefoxProfile();
MyWebDriver driver = new MyWebDriver(new FirefoxDriver(profile));

This way you are delegating the interface methods of IWebDriver to FirefoxDriver but can add whatever additions are appropriate.

Nick Spicer
  • 2,279
  • 3
  • 21
  • 26
  • 1
    Thank you. This is along the lines of what @LeonBarkan suggested but this seems like the most correct implementation. I've started to implement it and will report back if I get it working. – Milo Aug 15 '16 at 16:00
  • I am trying to implement this and Intellisense had me implement all the IWebDriver methods w/ 'throw new NotImplementedException()' as their bodies. How do I use the default IWebDriver version of the method in most cases? For example the FindElement method: `public IWebElement FindElement(By by) { throw new NotImplementedException(); }` – Milo Aug 15 '16 at 17:00
  • you don't need to implement the IWebDriver in MyWebDriver or if you doing that you must to implement (write) all the interface Methods like FindElement, navigate and more... – Leon Barkan Aug 15 '16 at 18:49
  • in this example is driver.webDriver.FindElements(By.Id("...")).Click(); if you use implementation and implement FindElement function with your inner instance of webDriver will give you the possibility to write driver.FindElement – Leon Barkan Aug 15 '16 at 18:50
  • inner function will look something like : public IWebElement FindElement(By by) { return this.webElement.FindElement(by) } – Leon Barkan Aug 15 '16 at 18:59
  • Interface used to make classes use same functionality like IComparable you must to write compare function to do compare operations on your objects, the same for IWebDriver [implementing all methods will keep your inner webBrowser instance in the functions you implementing and will make your code cleaner] – Leon Barkan Aug 15 '16 at 19:08
  • @Milo Imagine MyWebDriver is the manager, and FirefoxDriver is the employee, the manager implements IWebDriver and says "hey look I can do all these things for you" - but what actually happens? The manager has hired FirefoxDriver because he also implements IWebDriver and *knows for certain* he can just delegate all the responsibility to him. So for every method you need to implement for IWebDriver - just delegate it to the driver you pass in the constructor. How? public IWebElement FindElement(By by) { return webDriver.FindElement(by); } – Nick Spicer Aug 15 '16 at 21:27
  • Thank you all for the help. I ended up coming up with another solution to my initial problem (which was proper test result logging) by implementing try/catches in the correct places throughout my code. I further asked another question related to this [here](http://stackoverflow.com/questions/38959923/c-sharp-decorator-class-using-default-class-version-of-method/38960209?noredirect=1#38960209) - you may check the answers there for a possible way of doing this. – Milo Aug 16 '16 at 17:10
1

what if you do something like

class MyWebDriver
{
   private IWebDriver driver;
   private static string CurrentTest;
   ....
   //make constractors / getters, setters
}

execution

MyWebDriver d = new MyWebDriver(....)
...
Leon Barkan
  • 2,676
  • 2
  • 19
  • 43
-2

Just use a sub class that has WebDriver as its parent:

public class MyWebDriver : WebDriver
{
    private string _currentTest;
}

Then you can use MyWebDriver everywhere and set _currentTest as needed.

dur
  • 15,689
  • 25
  • 79
  • 125
Brendan
  • 4,327
  • 1
  • 23
  • 33
  • WebDriver uses the IWebDriver interface. I tried the above but WebDriver does not show up in IntelliSense only IWebInterface does. Is there a way to extend the interface? Thank you. – Milo Aug 15 '16 at 14:15