简体   繁体   English

通过 Selenium 驱动程序执行 Javascript elementFromPoint

[英]Executing Javascript elementFromPoint through Selenium driver

I am trying to implement an "object picker" to my Selenium based framework as is common on most commercial automation tools.我正在尝试为我的基于 Selenium 的框架实现一个“对象选择器”,这在大多数商业自动化工具中很常见。 To do this I am using a Javascript command to find the element at the mouse location, but I am not getting the element I expect.为此,我使用 Javascript 命令在鼠标位置查找元素,但我没有得到我期望的元素。

If I am using ChromeDriver or InternetExplorerDriver the script always returns the header object.如果我使用 ChromeDriver 或 InternetExplorerDriver,脚本总是返回标头对象。 No matter what webpage I look at or the position of the mouse.无论我看什么网页或鼠标的位置。 Although it sounds like the script is taking the coordinates 0, 0 instead of the mouse position I have confirmed that Cursor.Position is sending the correct values.虽然听起来脚本采用坐标 0, 0 而不是鼠标位置,但我已经确认 Cursor.Position 正在发送正确的值。

If I am using FirefoxDriver I get an exception:如果我使用 FirefoxDriver,则会出现异常:

"Argument 1 of Document.elementFromPoint is not a finite floating-point value. (UnexpectedJavaScriptError)"

Can anyone see what I am doing wrong?谁能看到我做错了什么?

    private void OnHovering()
    {
        if (Control.ModifierKeys == System.Windows.Forms.Keys.Control)
        {
            IWebElement ele = null;
            try
            {
                // Find the element at the mouse position
                if (driver is IJavaScriptExecutor)
                    ele = (IWebElement)((IJavaScriptExecutor)driver).ExecuteScript(
                        "return document.elementFromPoint(arguments[0], arguments[1])", 
                        new int[] { Cursor.Position.X, Cursor.Position.Y });

                // Select the element found
                if (ele != null)
                    SelectElement(ele);
            }
            catch (Exception) { }
        }
    }

Thanks!谢谢!

It's actually about how you are passing the coordinates into the script.这实际上是关于您如何将坐标传递到脚本中。 Script arguments has to be specified separately as separate ExecuteScript() arguments .脚本参数必须单独指定为单独的ExecuteScript()参数 What was happening in your case is that you have basically specified one x argument which made it think that y should be considered a default 0 value.在您的情况下发生的情况是您基本上指定了一个x参数,这使它认为y应该被视为默认值0 And at y=0 there is usually a header.y=0 ,通常有一个标题。

Instead of:代替:

ele = (IWebElement)((IJavaScriptExecutor)driver).ExecuteScript(
                        "return document.elementFromPoint(arguments[0], arguments[1])", 
                        new int[] { Cursor.Position.X, Cursor.Position.Y });

You should do:你应该做:

ele = (IWebElement)((IJavaScriptExecutor)driver).ExecuteScript(
                        "return document.elementFromPoint(arguments[0], arguments[1])", 
                        Cursor.Position.X, Cursor.Position.Y);

The code from alecxe works in most cases, but it will fail if the page contains frames or iframes.来自 alecxe 的代码在大多数情况下都可以工作,但如果页面包含框架或 iframe,它将失败。

Much more code is required to respect also frames / iframes.还需要更多的代码来尊重框架/ iframe。

/// <summary>
/// Get the element at the viewport coordinates X, Y
/// </summary>
static public RemoteWebElement GetElementFromPoint(RemoteWebDriver i_Driver, int X, int Y)
{
    while (true)
    {
        String s_Script = "return document.elementFromPoint(arguments[0], arguments[1]);";

        RemoteWebElement i_Elem = (RemoteWebElement)i_Driver.ExecuteScript(s_Script, X, Y);
        if (i_Elem == null)
            return null;

        if (i_Elem.TagName != "frame" && i_Elem.TagName != "iframe")
            return i_Elem;

        Point p_Pos = GetElementPosition(i_Elem);
        X -= p_Pos.X;
        Y -= p_Pos.Y;

        i_Driver.SwitchTo().Frame(i_Elem);
    }
}

/// <summary>
/// Get the position of the top/left corner of the Element in the document.
/// NOTE: RemoteWebElement.Location is always measured from the top of the document and ignores the scroll position.
/// </summary>
static public Point GetElementPosition(RemoteWebElement i_Elem)
{
    String s_Script = "var X, Y; "
                    + "if (window.pageYOffset) " // supported by most browsers 
                    + "{ "
                    + "  X = window.pageXOffset; "
                    + "  Y = window.pageYOffset; "
                    + "} "
                    + "else " // Internet Explorer 6, 7, 8
                    + "{ "
                    + "  var  Elem = document.documentElement; "         // <html> node (IE with DOCTYPE)
                    + "  if (!Elem.clientHeight) Elem = document.body; " // <body> node (IE in quirks mode)
                    + "  X = Elem.scrollLeft; "
                    + "  Y = Elem.scrollTop; "
                    + "} "
                    + "return new Array(X, Y);";

    RemoteWebDriver i_Driver = (RemoteWebDriver)i_Elem.WrappedDriver;
    IList<Object>   i_Coord  = (IList<Object>)  i_Driver.ExecuteScript(s_Script);

    int s32_ScrollX = Convert.ToInt32(i_Coord[0]);
    int s32_ScrollY = Convert.ToInt32(i_Coord[1]);

    return new Point(i_Elem.Location.X - s32_ScrollX,
                     i_Elem.Location.Y - s32_ScrollY);
}

This should be implemented in the WebDriver.这应该在 WebDriver 中实现。

I was having this issue as well.我也遇到了这个问题。 The reason it was being thrown I found out was because the element I was trying to get the location of was hidden (had the attribute display:none).我发现它被抛出的原因是因为我试图获取位置的元素被隐藏(具有属性 display:none)。 And therefore didn't have a location.因此没有位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM