1

I need to hover over a menu option of a website, so that a context menu appears. So I tried both: using the Actions-Class and using the JavaScriptExecutor with a dedicated script in my Page-Object-Model-Selenium project with Pagefactory. But it turns out both of them throw exceptions in POM, while they don't in a non-POM Selenium project. I provided two quick examples, so you can compare the behaviors yourself.

Below is the version without POM, it works:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium.Support.Events;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium;
using OpenQA.Selenium.Interactions;

namespace UnitTestProject1
{
[TestClass]
public class SimpleTest
{
    public static EventFiringWebDriver Driver { get; set; }

    [TestMethod]
    public void TestMethod1()
    {
        var caps = new DesiredCapabilities();
        caps.SetCapability("browserName", "internet explorer");
        SimpleTest.Driver = new EventFiringWebDriver(new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), caps, TimeSpan.FromSeconds(120)));
        SimpleTest.Driver.Navigate().GoToUrl("https://www.stackoverflow.com");
        var element = SimpleTest.Driver.FindElement(By.Id("nav-questions"));

        // using Actions
        // does not throw an exception
        new Actions(SimpleTest.Driver).MoveToElement(element).Perform();

        // using JavaScript
        // does not throw an exception
        var mouseOverScript = @"if(document.createEvent){var evObj = document.createEvent('MouseEvents');evObj.initEvent('mouseover', true, false); arguments[0].dispatchEvent(evObj); } else if(document.createEventObject) { arguments[0].fireEvent('onmouseover'); }";
        ((IJavaScriptExecutor)SimpleTest.Driver).ExecuteScript(mouseOverScript, element);
    }

    [TestCleanup]
    public void Cleanup()
    {
        SimpleTest.Driver.Quit();
    }
}
}

And here is the version with POM, which only throws exceptions, even though everything else is the same as in the other example:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium.Support.Events;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium;
using OpenQA.Selenium.Interactions;
using OpenQA.Selenium.Support.PageObjects;

namespace UnitTestProject1
{
[TestClass]
public class PomTest
{
    public PomTest()
    {
        var caps = new DesiredCapabilities();
        caps.SetCapability("browserName", "chrome");
        PomTest.Driver = new EventFiringWebDriver(new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), caps, TimeSpan.FromSeconds(120)));
        PomTest.Driver.Navigate().GoToUrl("https://www.stackoverflow.com");
    }

    public static EventFiringWebDriver Driver { get; set; }

    [TestMethod]
    public void TestMethod1()
    {
        var page = new SoPage();
        page.HoverWithActions();
        page.HoverWithJS();
    }

    [TestCleanup]
    public void Cleanup()
    {
        PomTest.Driver.Quit();
    }
}

public class SoPage
{
    public SoPage()
    {
        PageFactory.InitElements(PomTest.Driver, this);
    }

    public void HoverWithActions()
    {
        // using Actions
        // throws System.Reflection.TargetException;
        new Actions(PomTest.Driver).MoveToElement(this.Element).Perform();
    }

    public void HoverWithJS()
    {
        // using JavaScript
        // throws System.ArgumentException
        var mouseOverScript = @"if(document.createEvent){var evObj = document.createEvent('MouseEvents');evObj.initEvent('mouseover', true, false); arguments[0].dispatchEvent(evObj); } else if(document.createEventObject) { arguments[0].fireEvent('onmouseover'); }";
        ((IJavaScriptExecutor)PomTest.Driver).ExecuteScript(mouseOverScript, this.Element);
    }

    [FindsBy(How = How.Id, Using = "nav-questions")]
    public IWebElement Element { get; set; }
}
}

The exceptions are this for Actions:

"System.Reflection.TargetException: Das Objekt stimmt mit dem Zieltyp nicht überein.
   bei System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
   bei System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   bei System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   bei OpenQA.Selenium.Support.PageObjects.WebDriverObjectProxy.InvokeMethod(IMethodCallMessage msg, Object representedValue)
   bei OpenQA.Selenium.Support.PageObjects.WebElementProxy.Invoke(IMessage msg)
   bei System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   bei OpenQA.Selenium.ILocatable.get_Coordinates()
   bei OpenQA.Selenium.Interactions.Internal.MouseAction.get_ActionLocation()
   bei OpenQA.Selenium.Interactions.MoveMouseAction.Perform()
   bei OpenQA.Selenium.Interactions.CompositeAction.Perform()
   bei OpenQA.Selenium.Interactions.Actions.Perform()
   bei UnitTestProject1.SoPage.HoverWithActions() in c:\\users\\lwa\\documents\\visual studio 2015\\Projects\\UnitTestProject1\\UnitTestProject1\\PomTest.cs:Zeile 50.
   bei UnitTestProject1.PomTest.TestMethod1() in c:\\users\\lwa\\documents\\visual studio 2015\\Projects\\UnitTestProject1\\UnitTestProject1\\PomTest.cs:Zeile 28."

And this for the JavaScriptExecutor:

System.ArgumentException: Argument is of an illegal typeOpenQA.Selenium.Support.Events.EventFiringWebDriver+EventFiringWebElement
Parametername: arg
   bei OpenQA.Selenium.Remote.RemoteWebDriver.ConvertObjectToJavaScriptObject(Object arg)
   bei OpenQA.Selenium.Remote.RemoteWebDriver.ConvertArgumentsToJavaScriptObjects(Object[] args)
   bei OpenQA.Selenium.Remote.RemoteWebDriver.ExecuteScriptCommand(String script, String commandName, Object[] args)
   bei OpenQA.Selenium.Remote.RemoteWebDriver.ExecuteScript(String script, Object[] args)
   bei OpenQA.Selenium.Support.Events.EventFiringWebDriver.ExecuteScript(String script, Object[] args)
   bei UnitTestProject1.SoPage.HoverWithJS() in c:\\users\\lwa\\documents\\visual studio 2015\\Projects\\UnitTestProject1\\UnitTestProject1\\PomTest.cs:Zeile 58.
   bei UnitTestProject1.PomTest.TestMethod1() in c:\\users\\lwa\\documents\\visual studio 2015\\Projects\\UnitTestProject1\\UnitTestProject1\\PomTest.cs:Zeile 29."

I am using C# in Visual Studio 2015 with the packages Selenium.WebDriver and Selenium.Support both in version 3.3, there is a bug that prevents me from using 3.4 (see this question). My Selenium Server Standalone is 3.4.0. The behaviors is the same for Chrome, Firefox and Internet Explorer.

Does anyone have an idea of how to make hovering possible in a POM-Project in C#?

Waldi
  • 77
  • 10
  • 1
    Can you check in debug that this.Element has been properly initialized when it's passed to the script/action? – FDM May 23 '17 at 14:13
  • In the first example I can look at the elements in debug without problem, while in the POM example this.Element shows an error "Obtaining the runtime type of a transparent proxy is not supported in this context.", when viewed in debug. So I am guessing it is not initialized properly, how do I change that? – Waldi May 23 '17 at 14:50

1 Answers1

1

I found two workarounds for this. You can either discard the FindsByAttribute and define a property getter yourself

public IWebElement Element => PomTest.Driver.FindElement(By.Id("nav-questions"));

or instead of an IWebElement you can use an IList of IWebElements and then refer to the first Element of the list, credit for this option goes to this question. This will be the variant I am using, and it looks like this:

public void HoverWithActions()
{
    // using actions
    // now it works :)
    new Actions(PomTest.Driver).MoveToElement(this.Elements.First()).Perform();
}

public void HoverWithJS()
{
    // using Javascript
    // now it works :)
    var mouseOverScript = @"if(document.createEvent){var evObj = document.createEvent('MouseEvents');evObj.initEvent('mouseover', true, false); arguments[0].dispatchEvent(evObj); } else if(document.createEventObject) { arguments[0].fireEvent('onmouseover'); }";
    ((IJavaScriptExecutor)PomTest.Driver).ExecuteScript(mouseOverScript, this.Elements.First());
}

[FindsBy(How = How.Id, Using = "nav-questions")]
public IList<IWebElement> Elements { get; set; }
Waldi
  • 77
  • 10