Selenium WebDriver:使用 XPath 单击 SVG 中的元素
Posted
技术标签:
【中文标题】Selenium WebDriver:使用 XPath 单击 SVG 中的元素【英文标题】:Selenium WebDriver: clicking on elements within an SVG using XPath 【发布时间】:2013-01-13 13:44:54 【问题描述】:我有一个带有一些圆形和矩形元素的 SVG 对象。使用 webdriver,我可以单击主 svg 对象,但不能单击其中的任何元素。问题似乎只在于单击(或任何鼠标交互),因为我可以使用 getAttribute() 来返回其下任何内容的宽度、ID、x/y、文本等值。
以下是 html 示例:
<div id="canvas">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" style="overflow: hidden; position: relative;">
<image x="0" y="0" preserveAspectRatio="none">
<circle cx="272.34" cy="132.14">
<rect x="241.47" y="139.23">
<text style="text-anchor: middle; x="272.47" y="144.11">
</svg>
</div>
还有一个 WebDriver 尝试右键单击矩形元素(但失败)的示例:
WebElement mapObject = driver.findElement(By.xpath("//*[name()='svg']/*[name()='rect']"));
Actions builder = new Actions(driver);
builder.contextClick(mapObject).perform();
但这有效并返回一个值:
driver.findElement(By.xpath("//*[name()='svg']/*[name()='rect']")).getAttribute("x");
当WebDriver出错时,通常是这样的:
org.openqa.selenium.WebDriverException: '[javascript Error: "a.scrollIntoView is not a function" file: "file:///var/folders/sm/jngvd6s97ldb916b7h25d57r0000gn/T/anonymous490577185394048506webdriver-profile/extensions/fxdriver@googlecode.com/components/synthetic_mouse.js" line: 8544]' when calling method: [wdIMouse::move]
我花了一些时间研究这个问题,这似乎是 Selenium 和 SVG 的一个常见问题,但我想知道是否有解决方法。我发现的唯一解决方案是与 SVG 本身进行交互,我已经可以做到了。
我正在使用带有 Java + Firefox 17 的 Selenium 2.28(并尝试过 2.29)。
非常感谢任何想法。
【问题讨论】:
可能不相关,但为什么不使用driver.findElement(By.xpath("//svg/rect")).getAttribute("x");
?
因为为了在 Selenium 中通过 XPath 与 SVG 交互,您必须调用 name() 或 local-name() 方法。我不知道为什么,但是,没有它,它就行不通。
【参考方案1】:
actual = driver.findElement(By.xpath(
"//div[contains(@class,'review-action')]//div[contains(@class,'rating')]/*[name()='svg'][1]/*[name()='g']/*[name()='path'][2]"))
.getAttribute("stroke");
【讨论】:
这个答案没有上下文,即使它回答了原始问题,它也只留下一个新问题,即为什么它会起作用。你能解释一下答案告诉我们什么以及它为什么有效吗?【参考方案2】:以下是 C# 中的解决方法示例:
IWebElement svgElement = Driver.FindElement(By.CssSelector("svg"));
IList<IWebElement> rectElements = svgElement.FindElements(By.CssSelector("rect"));
【讨论】:
【参考方案3】:对于 JS 解决方案:
var selector = "//*[name()='svg']/*[name()='rect']";
browser.moveToObject(selector, 5, 5);//Move to selector object with offsets.
browser.buttonPress(null);//Left-click
【讨论】:
【参考方案4】:我的项目中有不同的高位图表,我的目标是双击图表的一部分以深入了解更多信息,我已经设法使用以下代码行来做到这一点。 XPath 对我不起作用,但 CssSelector 工作得很好。
var elementToClick= Browser.Driver.FindElementEx(By.CssSelector("#highcharts-0 > svg > g.highcharts-series-group > g.highcharts-series.highcharts-tracker > path:nth-child(1)"), 10);
Actions action = new Actions(Browser.Driver);
action.Click(elementToClick).Build().Perform();
action.DoubleClick(elementToClick).Build().Perform();
【讨论】:
【参考方案5】:给你:
driver.findElement(By.cssSelector("#canvas > svg > rect")).getAttribute("x")
driver.findElement(By.cssSelector("#canvas > svg > rect")).getAttribute("y")
这样你就可以做到。
【讨论】:
在 Ubuntu 中的 ChromeDriver 上简单而有效......非常感谢! :)【参考方案6】:通过做这两件事,我们能够避免奇怪的 xpath 选择
WebElement mapObject = (WebElement) driver.executeScript('return document.querySelector(arguments[0])', "svg rect")
((JavascriptExecutor) driver).executeScript("arguments[0].dispatchEvent(new MouseEvent('click', view: window, bubbles:true, cancelable: true))", mapObject);
这适用于 osx 和 phantomjs,但我认为在任何现代浏览器中都应该没问题。
(我们使用的是 js 驱动,所以请随时修复任何编译错误)
【讨论】:
这个具有指定参数的 dispatchEvent 是唯一对我来说在深度嵌套的 SVG<text>
元素上有效的解决方案。【参考方案7】:
对于任何感兴趣的人,我通过以下方式解决了这个问题:
1) 我最初是在 OSX 上使用 Firefox 17 和 Selenium 2.28/29 进行测试,但发现它只能在使用 Firefox 18 和 Selenium 2.29 的 Windows 上运行(至少对我而言)
2) 使用标准与 SVG 交互:
driver.findElement(By.xpath(YOUR XPATH)).click();
不起作用。您需要使用操作。
3) 与 SVG 对象交互,以下 XPath 起作用:
"/*[name()='svg']/*[name()='SVG OBJECT']";
SVG 对象是 SVG 元素下的任何东西(例如圆形、矩形、文本等)。
单击 SVG 对象的示例:
WebElement svgObject = driver.findElement(By.xpath(YOUR XPATH));
Actions builder = new Actions(driver);
builder.click(svgObject).build().perform();
注意:需要在click()函数内部调用路径;使用:
moveToElement(YOUR XPATH).click().build().perform();
没用。
【讨论】:
使用 name() 进行 XPath 检查是必要的,因为 SVG DOM 节点位于不同的命名空间中。 另外,我可以让它在 FF17.0.1 中工作,但我确实需要使用 Actions,直接 WebElement.click() 失败了。 您不一定需要 xpath,至少对于 JS 驱动程序而言。它适用于任何元素,即使您通过 CSS 或 Id 找到它们。 我得到'元素在点(231.1666717529297、312.04998779296875)不可点击。当我尝试单击 svg 中的圆圈时,其他元素会收到 click:' 异常。有什么想法吗? 我需要更多的上下文来理解为什么这不起作用。代码、环境等【参考方案8】:试试这个解决方法:
WebElement mapObject = driver.findElement(By.xpath("//*[name()='svg']/*[name()='rect']"));
((JavascriptExecutor) driver).executeScript("arguments[0].click();", mapObject);
每当我在尝试单击某些元素时遇到太多问题时,我都会使用此解决方法。
【讨论】:
所以,这里有进展。首先,使用 JavascriptExecutor 不再引发我在与 SVG 对象交互时在 WebDriver 中遇到的错误。但是,当我运行测试时,它说它成功单击/悬停/等,但我没有在屏幕上看到交互发生。理论上,如果测试成功点击了一个矩形或圆形,我应该会看到一个菜单弹出来显示被点击的元素..但这并没有发生,即使 WebDriver 说它这样做了。还值得一提的是,“arguments[0].click();”对我不起作用,但是 .click 和 .click;做。附:感谢您的回复。 @jgode 你找到解决方案了吗?我有同样的问题,它执行没有错误,但我没有看到网页导航到新页面。 @FebianShah,是的.. 看我上面的帖子,我描述了我是如何在 Firefox 中工作的:***.com/a/14761832/2023074 另外,值得注意的是,在 IE 中,可以通过它们的 RaphaelID 来定位 SVG 元素,这使它更容易。虽然在我的情况下,因为我必须在多个浏览器中测试 SVG 页面,所以我最终使用了坐标,我讨厌自动化,但这是最稳定的方式。以上是关于Selenium WebDriver:使用 XPath 单击 SVG 中的元素的主要内容,如果未能解决你的问题,请参考以下文章
如何使用selenium webdriver来判断一个网页加载完毕
Selenium & webdriver.io 如何使用 executeScript?