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 &lt;text&gt; 元素上有效的解决方案。【参考方案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?

Selenium WebDriver的使用

Selenium Webdriver概述

使用 Java 在 Selenium WebDriver (selenium 2) 中处理警报

如何使用selenium webdriver来判断一个网页加载完毕