Executing JavascriptFromPoint element through Selenium driver
I am trying to implement an "object collector" on my Selenium based framework, as is the case with most commercial automation tools. To do this, I am using a Javascript command to find the element at the mouse location, but I am not getting the expected element.
If I use ChromeDriver or InternetExplorerDriver the script always returns a header object. No matter what web page I am looking at or the position of the mouse. Although it seems that the script is accepting coordinates 0, 0 instead of the mouse position, I have confirmed that Cursor.Position is sending the correct values.
If I use FirefoxDriver I get an exception:
"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) { }
}
}
Thank!
source to share
Actually about how you pass coordinates to script. Script arguments must be specified separately as separate arguments ExecuteScript()
. What was happening in your case is that you basically provided one argument x
, which made it think it y
should be considered the default 0
. And y=0
usually there is a headline.
Instead:
ele = (IWebElement)((IJavaScriptExecutor)driver).ExecuteScript(
"return document.elementFromPoint(arguments[0], arguments[1])",
new int[] { Cursor.Position.X, Cursor.Position.Y });
You should:
ele = (IWebElement)((IJavaScriptExecutor)driver).ExecuteScript(
"return document.elementFromPoint(arguments[0], arguments[1])",
Cursor.Position.X, Cursor.Position.Y);
source to share
The code from alecxe works in most cases, but it will fail if the page contains frames or frames.
A lot more code to respect frames / frames as well.
/// <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.
source to share