Domanda

I developed some tests for a website and wanted to add logging. It appears that EventFiringWebDriver class does the job I need. However I'm having troubles accessing WrappedDriver property of IWebElement that was gotten via EventFiringWebDriver instance. Please find the code that demonstrates the issue below:

IWebDriver webDriver = new ChromeDriver();
EventFiringWebDriver driver = new EventFiringWebDriver(webDriver);
driver.Navigate().GoToUrl("http://www.google.com/");
IWebElement element = driver.FindElement(By.Name("q"));

// ...
// throws a InvalidCastException    
IWebDriver drv = ((IWrapsDriver)element).WrappedDriver;

Here is the more detailed code that demonstrates why I need this:

class Program
{
    static void Main(string[] args)
    {
        IWebDriver webDriver = new ChromeDriver();
        EventFiringWebDriver driver = new SeleniumEventListener(webDriver);

        driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));

        driver.Navigate().GoToUrl("http://www.google.com/");
        IWebElement element = driver.FindElement(By.Name("q"));
        element.SendKeys("Cheese!");
        element.Submit();

        element.Snapshot().Save("./snapshot.png");
    }
}

public class SeleniumEventListener : EventFiringWebDriver
{
    public SeleniumEventListener(IWebDriver driver)
        : base(driver)
    {
        ElementValueChanged += new EventHandler<WebElementEventArgs>((sender, e) =>
        {
            Console.WriteLine("Element value changed");
        });

        Navigated += new EventHandler<WebDriverNavigationEventArgs>((sender, e) =>
        {
            Console.WriteLine("Navigated to: " + e.Url);
        });
    }
}

public static class WebElementExtension
{
    public static Bitmap Snapshot(this IWebElement element)
    {
        IWrapsDriver wrappedElement = element as IWrapsDriver;
        if (wrappedElement == null)
        {
            // This exception is thrown if element is retrieved through EventFiringWebDriver instance.
            throw new ArgumentException("Element must wrap a web driver", "element");
        }

        IWebDriver driver = wrappedElement.WrappedDriver;
        Screenshot screenshot = driver.TakeScreenshot();
        using (MemoryStream stream = new MemoryStream(screenshot.AsByteArray))
        using (Bitmap bitmap = new Bitmap(stream))
        {
            Size size = new Size(
                Math.Min(element.Size.Width, bitmap.Width),
                Math.Min(element.Size.Height, bitmap.Height));
            Rectangle crop = new Rectangle(element.Location, size);
            return bitmap.Clone(crop, bitmap.PixelFormat);
        }
    }
}

You can see that I use extension methods for IWebElement, and I need to access the driver via IWebElement instance.

Questions:

  • Is this the correct way to use the EventFiringWebDriver class?

  • Why the IWebElement gotten via EventFiringWebDriver instance does not implement IWrapsDriver interface?

È stato utile?

Soluzione

Resolved with Reflections

    public static IWebDriver GetDriver(this IWebElement element)
    {
        IWrapsDriver wrappedElement = element as IWrapsDriver;
        if (wrappedElement == null)
        {
            FieldInfo fieldInfo = element.GetType().GetField("underlyingElement", BindingFlags.NonPublic | BindingFlags.Instance);
            if (fieldInfo != null)
            {
                wrappedElement = fieldInfo.GetValue(element) as IWrapsDriver;
                if (wrappedElement == null)
                    throw new ArgumentException("Element must wrap a web driver", "element");
            }
        }

        return wrappedElement.WrappedDriver;
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top