如何在Selenium WebDriver中使用xPath来获取SVG元素?

时间:2015-07-20 15:36:09

标签: java selenium xpath svg

我正在使用Selenium OpenLayers(Java版)测试基于WebDriver的API。

我想测试使用OpenLayers的功能.Control.ModifyFeature。我想点击绘制的特征(SVG),然后拖动并检查它们是否存在,可见或隐藏。

我画了一个多边形,我选择了它。见下图:

polygon_and_handles

这些SVG元素的HTML在这里:

<svg id="OpenLayers_Layer_Vector_161_svgRoot" width="1235" height="495" viewBox="0 0 1235 495" style="display: block;">
    <g id="OpenLayers_Layer_Vector_161_root" transform="" style="visibility: visible;">
        <g id="OpenLayers_Layer_Vector_161_vroot">
            <path id="OpenLayers_Geometry_Polygon_200" d=" M 393.0000000000964,213.9999999999891 486.0000000003338,275.9999999997126 384.00000000036925,284.9999999994434 393.0000000000964,213.9999999999891 z" fill-rule="evenodd" fill="blue" fill-opacity="0.4" stroke="blue" stroke-opacity="1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="none" pointer-events="visiblePainted" cursor="pointer" />
            <circle id="OpenLayers_Geometry_Point_619" cx="439.50000000021464" cy="244.99999999985084" r="6" fill="#009900" fill-opacity="0.5" stroke="#ee9900" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="none" pointer-events="visiblePainted" cursor="inherit" />
            <circle id="OpenLayers_Geometry_Point_621" cx="435.00000000035106" cy="280.49999999958163" r="6" fill="#009900" fill-opacity="0.5" stroke="#ee9900" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="none" pointer-events="visiblePainted" cursor="inherit" />
            <circle id="OpenLayers_Geometry_Point_623" cx="388.50000000023283" cy="249.4999999997126" r="6" fill="#009900" fill-opacity="0.5" stroke="#ee9900" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="none" pointer-events="visiblePainted" cursor="inherit" />
            <circle id="OpenLayers_Geometry_Point_202" cx="393.0000000000964" cy="213.9999999999891" r="6" fill="#990000" fill-opacity="1" stroke="#ee9900" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="none" pointer-events="visiblePainted" cursor="inherit" />
            <circle id="OpenLayers_Geometry_Point_203" cx="486.0000000003338" cy="275.9999999997126" r="6" fill="#990000" fill-opacity="1" stroke="#ee9900" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="none" pointer-events="visiblePainted" cursor="inherit" />
            <circle id="OpenLayers_Geometry_Point_204" cx="384.00000000036925" cy="284.9999999994434" r="6" fill="#990000" fill-opacity="1" stroke="#ee9900" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="none" pointer-events="visiblePainted" cursor="inherit" />
        </g>
        <g id="OpenLayers_Layer_Vector_161_troot" />
    </g>
</svg>

假设我想选择红点。

我这样做了:

String xpath = "//circle[contains(@id, 'OpenLayers_Geometry_Point') AND fill = '#990000']";
List<WebElement> vertices = driver.findElements(By.xpath(xpath));

但它总是返回一个空列表[]

我在这里做错了什么?请问有人帮帮我吗?

非常感谢。

编辑1 - 功能:verticesAreVisible

在点击操作之前,我想获取元素并检查它们是否可见。我正在使用这个功能。

public static boolean verticesAreVisible(WebDriver driver, String xpath) {
    List<WebElement> list = driver.findElements(By.xpath(xpath));
    if (list.isEmpty()) {
        return false;
    }
    boolean visible = true;
    for (int i = 0; i < list.size(); i++) {
        visible = visible && list.get(i).isDisplayed();
    }
    return !verticesAreNotVisible(driver) && visible;
}

编辑2 - 更正xPath

// This solution from Razib is valid if the SVG is on the root note
String xpath = "/*[name()='svg']/*[name()='circle']";
// I changed it so that any descendant is valid "//"
String xpath = "//*[name()='svg']//*[name()='circle']";
// Since I wanted only the red vertices, I added this
String xpath = "//*[name()='svg']//*[name()='circle' and @fill='#990000']";

6 个答案:

答案 0 :(得分:13)

您可能需要在BufferedReader中使用name属性的操作。 在你的XPath中使用它 -

Xpath

然后尝试以下代码段 -

"/*[name()='svg']/*[name()='SVG OBJECT']"  

答案 1 :(得分:3)

尝试使用@fill代替fillOpenLayers_Geometry_Point代替OpenLayers.Geometry.Point

答案 2 :(得分:0)

要获得可以使用的可见元素:

wait = new WebDriverWait(driver, 5);
wait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.xpath("bla bla")));

答案 3 :(得分:0)

       We also faced the similar issue in one of the screens where we have SVG implementation, I resolved using action class.

Action Class Package :
java.lang.Object
org.openqa.selenium.interactions.Actions

Sample Code : 

        WebElement svgObject= driver.findElement(By.xpath(XPATH));
        Actions actionBuilderObj = new Actions(driver);
        actionBuilderObj .click(svgObject).build().perform();

答案 4 :(得分:0)

尝试了各种技巧来潜水Inn,但最终我找到了一种解决这种情况的简便方法。 当您所需的svg没有名称且正确的xpath动态更改时,我使用了“ cssSelector”

            Id1  Id2
[183, 257]  257  183
[257, 286]  286  257
[286, 409]  286  409

答案 5 :(得分:0)

要找到红色点,即属性为fill="#990000"且元素为 id 且包含 OpenLayers_Geometry_Point 的元素,可以使用以下任一Locator Strategies

  • 使用

    //*[name()='svg']/*[name()='g']/*[name()='g']//*[name()='circle' and contains(@fill, '990000')][starts-with(@id, 'OpenLayers_Geometry_Point')]
    
  • 使用

    svg > g > g circle[fill$='990000'][id^='OpenLayers_Geometry_Point']
    

理想情况下,您需要为visibilityOfAllElementsLocatedBy()引入WebDriverWait,并且可以使用以下 Locator Strategies 定位器策略之一:

  • 使用 cssSelector

    List<WebElement> vertices = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.cssSelector("svg > g > g circle[fill$='990000'][id^='OpenLayers_Geometry_Point']")));
    
  • 使用 xpath

    List<WebElement> vertices = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.xpath("//*[name()='svg']/*[name()='g']/*[name()='g']//*[name()='circle' and contains(@fill, '990000')][starts-with(@id, 'OpenLayers_Geometry_Point')]")));
    

参考文献

您可以在以下位置找到几个相关的详细讨论: