Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use xPath in Selenium WebDriver to grab SVG elements?

Tags:

I am testing an API, based on OpenLayers, with Selenium WebDriver (Java version).

I want to test a functionality that uses OpenLayers.Control.ModifyFeature. I want to click on drawn features (SVG), drag then and check if they are present, visible or hidden.

I have drawn a polygon, and I have selected it. See the image below:

polygon_and_handles

The HTML of these SVG elements is here:

<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> 

Suppose I want to select the red points.

I tried:

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

But it always returns an empty list [].

What am I doing wrong here? Could anybody help me, please?

Thanks a lot.

EDIT 1 - Function: verticesAreVisible

Before the clicking actions, I want to get the elements and check if they are visible. I am using this function.

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; } 

EDIT 2 - Correct xPath

// This solution from Razib is valid if the SVG is on the root node 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']"; 
like image 313
joaorodr84 Avatar asked Jul 20 '15 15:07

joaorodr84


1 Answers

May be you need to use the Actions with name attribute in Xpath. In your XPath use it -

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

Then try the following code snippet -

WebElement svgObj = driver.findElement(By.xpath(XPATH)); Actions actionBuilder = new Actions(driver); actionBuilder.click(svgObj).build().perform(); 
like image 89
Razib Avatar answered Sep 29 '22 12:09

Razib