48

I have an SVG object with a few circle and rectangle elements. Using webdriver, I can click on the main svg object, but not any of the elements within it. The problem only seems to be with clicking (or any mouse interaction), as I can use getAttribute() to return the value(s) of width, ID, x/y, text, etc, for anything under it.

Here is an example of the HTML:

    <div id="canvas">
        <svg height="840" version="1.1" width="757" xmlns="http://www.w3.org/2000/svg" style="overflow: hidden; position: relative;">
            <image x="0" y="0" width="757" height="840" 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>

And an example of WebDriver trying to right click a rectangle element (and failing):

    WebElement mapObject = driver.findElement(By.xpath("//*[name()='svg']/*[name()='rect']"));
    Actions builder = new Actions(driver);
    builder.contextClick(mapObject).perform();

But this works and returns a value:

    driver.findElement(By.xpath("//*[name()='svg']/*[name()='rect']")).getAttribute("x");    

When WebDriver errors, it's usually this:

    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]

I've spent some time researching this and it seems to be a somewhat common issue with Selenium and SVGs, however I'm wondering if there is a workaround. The only solutions I've found are interacting with the SVG itself, which I can already do.

I'm using Selenium 2.28 (and tried 2.29) w/ Java + Firefox 17.

Any ideas greatly appreciated.

jgode
  • 1,821
  • 2
  • 18
  • 14
  • 1
    Maybe unrelated, but why not to use `driver.findElement(By.xpath("//svg/rect")).getAttribute("x");`? – Alex Okrushko Jan 30 '13 at 17:27
  • 2
    Because in order to interact with an SVG via XPath in Selenium, you have to call the name() or local-name() methods. I don't know why, but, without that, it doesn't work. – jgode Jan 30 '13 at 19:51

8 Answers8

33

For anyone interested, I solved this in the following ways:

1) I was originally testing this on OSX with Firefox 17 and Selenium 2.28/29, but figured out it only works (at least for me) on Windows with Firefox 18 and Selenium 2.29

2) interacting with SVGs with the standard:

driver.findElement(By.xpath(YOUR XPATH)).click();

doesn't work. You need to use Actions.

3) to interact with SVG objects, the following XPath works:

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

The SVG object being anything under the SVG element (e.g. circle, rect, text, etc).

An example of clicking an SVG object:

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

Note: you need to call the path inside the click() function; using:

moveToElement(YOUR XPATH).click().build().perform();

doesn't work.

jgode
  • 1,821
  • 2
  • 18
  • 14
  • 3
    The XPath check using name() is necessary because SVG DOM nodes are in a different namespace. – Oliver Bock Feb 20 '13 at 06:21
  • Also, I could get this to work in FF17.0.1, but I did need to use Actions, a straight WebElement.click() failed. – Oliver Bock Feb 21 '13 at 00:41
  • You don't need xpath necessarily, at least for the JS driver. It works with any element, even if you find them by CSS or Id or however. – Mrchief Aug 28 '14 at 20:00
  • 2
    I get 'Element is not clickable at point (231.1666717529297, 312.04998779296875). Other element would receive the click:' exception when I try to click on a circle in my svg. Any idea bout this? – Sakshi Singla Nov 22 '16 at 06:01
  • I'd need a little more context to understand why that doesn't work. Code, environment, etc. – jgode Dec 09 '16 at 17:22
  • What is the reason that it does not work as normal tags, why this much complication for **svg** – Ashok kumar Ganesan Oct 21 '19 at 11:47
  • @AshokkumarGanesan this issue is from 6 years ago, so things have evolved since then with how we can interact with svgs, and how browsers treat them with regards to automation. One issue I still see sometimes, since I still test products with svgs, is, depending on how the developers have configured them, they may not be visible to the DOM. Otherwise, I don't know that the same workarounds are still necessary. – jgode Oct 21 '19 at 14:27
  • Alright,is the svg is a special tag apart from div span etc., – Ashok kumar Ganesan Oct 21 '19 at 15:15
12

Try this workaround :

WebElement mapObject = driver.findElement(By.xpath("//*[name()='svg']/*[name()='rect']"));
((JavascriptExecutor) driver).executeScript("arguments[0].click();", mapObject);

Whenever I have too many problems with some elements while trying to click them, I use this workaround.

Ioan
  • 5,152
  • 3
  • 31
  • 50
  • So, there's progress here. First, using JavascriptExecutor no longer throws the error I was getting in WebDriver when interacting with an SVG object. However, when I run the test, it says it clicks/hovers/etc successfully, but I don't see the interaction happen on screen. In theory, if the test successfully clicks on a rect or circle, I should see a menu pop up for the element being clicked.. but that doesn't happen, even though WebDriver says it did so. Also worth mentioning, "arguments[0].click();" didn't work for me, but .click and .click; does. P.S. Thanks for the reply. – jgode Jan 31 '13 at 17:25
  • @jgode did you find a solution? I have the same problem where it executes without an error but I don't see the webpage navigate to the new page. – Febian Shah Oct 17 '14 at 04:10
  • @FebianShah, yes.. see my above post where I describe how I got it working in Firefox: http://stackoverflow.com/a/14761832/2023074 Also, it's worth noting that in IE it's possible to target SVG elements by their RaphaelID, which makes it easier. Although in my case, because I have to test SVG pages in multiple browsers, I ended up using coordinates, which I hate for automation, but it was the most stable way. – jgode Oct 17 '14 at 13:58
5

We were able to avoid the odd xpath select by doing these two things

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

This worked on osx and phantomjs but I think it should be ok in any modern browser.

(We used the js driver so feel free to fix any compile errors)

case nelson
  • 3,537
  • 3
  • 30
  • 37
  • 1
    This dispatchEvent with the specified parameters is the only solution that worked for me on a deeply nested SVG `` element. – dlauzon Apr 03 '19 at 12:37
  • Doing a straightforward click() on the element within the svg without the need for the JavaScript Executor was working just fine for me in all browsers except Safari v14. After trying many different solutions, using the above solution (for all browsers) was the only way I could get it to work in Safari, thank you :) – Martin Bamford Oct 18 '22 at 10:34
3

Here you go:

driver.findElement(By.cssSelector("#canvas > svg > rect")).getAttribute("x") 
driver.findElement(By.cssSelector("#canvas > svg > rect")).getAttribute("y") 

This way you can do it.

ConcurrentHashMap
  • 4,998
  • 7
  • 44
  • 53
user3487861
  • 340
  • 2
  • 2
1

For a JS solution:

var selector = "//*[name()='svg']/*[name()='rect']";
browser.moveToObject(selector, 5, 5);//Move to selector object with offsets.
browser.buttonPress(null);//Left-click
atahan
  • 706
  • 1
  • 10
  • 11
0

I have different high charts in my project and my aim was to double click on a section of a chart to drill down for further information and I've managed to do it using following lines of code. XPath didn't work for me but CssSelector worked just fine.

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();
Vish
  • 81
  • 8
0

Here is an example of a workaround in C#:

IWebElement svgElement = Driver.FindElement(By.CssSelector("svg"));

IList<IWebElement> rectElements = svgElement.FindElements(By.CssSelector("rect"));
-2
actual = driver.findElement(By.xpath(
"//div[contains(@class,'review-action')]//div[contains(@class,'rating')]/*[name()='svg'][1]/*[name()='g']/*[name()='path'][2]"))
.getAttribute("stroke");
Dharman
  • 30,962
  • 25
  • 85
  • 135
  • There is no context to this answer and, even if it answers the original question, it leaves only a new question of why this then works. Can you give some reasoning of what the answer is telling us and why it works? – spacepickle Oct 01 '19 at 15:25