Webdriver and SVG embedded in an object tag

2,573 views
Skip to first unread message

bp

unread,
Sep 19, 2012, 4:25:12 PM9/19/12
to webd...@googlegroups.com
I can see tests like this,  http://code.google.com/p/selenium/source/browse/trunk/java/client/test/org/openqa/selenium/SvgElementTest.java?r=17611 which work with SVG embedded in the HTML doc itself, which looks like it works pretty well with webdriver.

however, if there is an object targ with the svg in its data field, I am seeing in Chrome that Chrome renders it as a new element called "#document" under the object tag. So, if I try to access the DOM of the xvg as children of the object tag, it does not work. the elements cannot be found.

Is there a way to test page that have SVG embedded in the object tag?

Simon Stewart

unread,
Sep 20, 2012, 7:12:12 AM9/20/12
to webd...@googlegroups.com
A reduced test case that demonstrates how you'd expect to work with
the object would be incredibly useful....

Simon
> --
> You received this message because you are subscribed to the Google Groups
> "webdriver" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/webdriver/-/SFZ7ibXjmMMJ.
> To post to this group, send email to webd...@googlegroups.com.
> To unsubscribe from this group, send email to
> webdriver+...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/webdriver?hl=en.

bp

unread,
Sep 20, 2012, 2:30:27 PM9/20/12
to webd...@googlegroups.com
Here is an example html page, made it as simple as it could get


<html>
<body>

    <object data="circle.svg" type="image/svg+xml"></object>

</body>
</html>



Here is the circle.svg file


<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <circle cx="100" cy="50" r="40" stroke="black"
  stroke-width="2" fill="red" />
</svg>


I would like to be able to access the <circle> element. If I place the svg text as inline int he HTML, I can get to the circle element with code that looks like this:

WebElement circle = driver.findElement(By.cssSelector("body svg circle"));

        System.out.println("Circle property cx is : "
                + circle.getAttribute("cx"));

However, if there is that object tag, I could not find a way to access the circle element,


I tried both of these:
WebElement circle = driver.findElement(By.cssSelector("body svg circle"));

WebElement circle = driver.findElement(By.cssSelector("body object svg circle"));


This returns a null. Chrome developer tools shows a "#document" element under the object, meaning it is probably rendering it in a different document object that I will need access to. Firefox too shows a frame element, and fails to get it too.

looks like i will need access to taht 'frame' or 'document' object under which I will have to issue the body svg circle query. Any clues how to do this?

darrell

unread,
Sep 21, 2012, 10:49:43 AM9/21/12
to webd...@googlegroups.com
I think the problem you are seeing here is that WebDriver sees an <OBJECT> tag and goes no further. To WebDriver, all the <OBJECT> elements are unknowns elements. You would be able to see the data attribute, I believe, but you won't be able to see anything inside the svg file, itself.

Darrell

bp

unread,
Oct 2, 2012, 4:53:05 PM10/2/12
to webd...@googlegroups.com
Does this mean the only option to test the SVG components with Selenium is to have the SVG inlined?

bp

unread,
Oct 4, 2012, 10:19:51 AM10/4/12
to webd...@googlegroups.com
Just found a link that indicates it might be possible to access the documentElement of an object tag,

http://stackoverflow.com/questions/2753732/how-to-access-svg-elements-with-javascript

Assuming this works, could Selenium route findElement calls to this document? May be support switching to this document using a switchto? Thoughts?

This may be a crazy idea, but maybe something like 

svgElem = driver.findElement(By.id("svgObject"));
driver.switchTo().someNewMethod(svgElem);
driver.findElement(By.id("g"));

Developers I work with are loading up svg in object tags because that seems to be the preferred method that provides most options for advanced features, and they don't have to paste large svg content into the page's dom directly. Plus the svg is coming from designers who use tools like Adobe Illustrator to design them, then hand off the svg to the devs.

bp

unread,
Oct 4, 2012, 10:51:59 AM10/4/12
to webd...@googlegroups.com
I also just confirmed that trying to use the approach to access the other document Elemetn driectly in webdriver throws an exception indicating a switchto is needed because the dom is a different frame than the current one

Ignoring the syntactic differences, here is what I am doing:

WebElement objectTag = findElement(By.id("anobject"));

        WebElement circle = (WebElement) ((JavascriptExecutor) driver)
                .executeScript(
                        "return arguments[0].contentDocument.getElementById('circleId')",
                        objectTag);
        assertThat(Integer.parseInt(circle.getAttribute("cx")), is(100));


This throws the following exception, meaning a sort of 'switchto' will be needed and I can't directly access this embedded document element. Alternatively, I will try using executeAsyncscript if it has any effect.



org.openqa.selenium.StaleElementReferenceException: Element belongs to a different frame than the current one - switch to its containing frame to use it
Command duration or timeout: 18 milliseconds
For documentation on this error, please visit: http://seleniumhq.org/exceptions/stale_element_reference.html
Build info: version: '2.25.0', revision: '17482', time: '2012-07-18 22:18:01'
System info: os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.version: '1.6.0_21'
Driver info: driver.version: RemoteWebDriver
Session ID: f0a96365-ec86-4ab1-896b-968222caa753
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:188)
    at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:145)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:498)
    at org.openqa.selenium.remote.RemoteWebElement.execute(RemoteWebElement.java:244)
    at org.openqa.selenium.remote.RemoteWebElement.getAttribute(RemoteWebElement.java:120)
    at com.mathworks.test.tools.mwwebguitesttools.integration.TestSvgSupport.testSvgElementAccessInObjectTag(TestSvgSupport.java:78)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at com.mathworks.test.tools.mwwebguitesttools.junitextensions.BrowserSpecificRunner.runChild(BrowserSpecificRunner.java:137)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at com.mathworks.test.tools.mwwebguitesttools.junitextensions.BrowserRunBefores.evaluate(BrowserRunBefores.java:36)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:24)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.openqa.selenium.remote.ErrorHandler$UnknownServerException: Element belongs to a different frame than the current one - switch to its containing frame to use it
Build info: version: '2.25.0', revision: '17482', time: '2012-07-18 22:18:01'
System info: os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.version: '1.6.0_21'
Driver info: driver.version: unknown
    at <anonymous class>.<anonymous method>(resource://fxdriver/modules/web_element_cache.js:5671)
    at <anonymous class>.<anonymous method>(file:///C:/Users/auser/AppData/Local/Temp/anonymous7603687846920077736webdriver-profile/extensions/fxdr...@googlecode.com/components/command_processor.js:5282)
    at <anonymous class>.<anonymous method>(file:///C:/Users/auser/AppData/Local/Temp/anonymous7603687846920077736webdriver-profile/extensions/fxdr...@googlecode.com/components/command_processor.js:9569)
    at <anonymous class>.<anonymous method>(file:///C:/Users/auser/AppData/Local/Temp/anonymous7603687846920077736webdriver-profile/extensions/fxdr...@googlecode.com/components/command_processor.js:10131)
    at <anonymous class>.<anonymous method>(file:///C:/Users/auser/AppData/Local/Temp/anonymous7603687846920077736webdriver-profile/extensions/fxdr...@googlecode.com/components/command_processor.js:10136)
    at <anonymous class>.<anonymous method>(file:///C:/Users/auser/AppData/Local/Temp/anonymous7603687846920077736webdriver-profile/extensions/fxdr...@googlecode.com/components/command_processor.js:10074)

Vasu

unread,
Oct 5, 2012, 2:10:08 PM10/5/12
to webd...@googlegroups.com
Best option is to use CSS locators instead of XPath in such cases. I dealt with similar situation of dealing with tags embedded inside svg and using CSSlocators helped.  

Thanks,
Vasu

bp

unread,
Oct 8, 2012, 10:36:42 AM10/8/12
to webd...@googlegroups.com
I have created an issue report for enhancement at

http://code.google.com/p/selenium/issues/detail?id=4647

If Selenium developers can look at that, it will be great!

Aida Manna

unread,
Nov 26, 2013, 12:52:15 PM11/26/13
to webd...@googlegroups.com
Hi all,

I am reading this post and I have the same problem you are exaplaining, Did you manage to find a solution for that? Thanks in advance.


David

unread,
Nov 28, 2013, 5:34:32 PM11/28/13
to webd...@googlegroups.com
I wonder, for a workaround, what if instead of returning the nested element back via Javascript, which requires some switch to, you simply return the desired properties back. In such case the element stays manipulated in javascript and we only return back needed properties. As such, javascript manipulation of DOM is not (necessarily) subject to same restrictions of WebElements (stale elements, hidden not visible elements).

So in bp's example, perhaps do this instead

WebElement objectTag = findElement(By.id("anobject"));
int circleCx = (Integer) ((JavascriptExecutor) driver)
                .executeScript(
                        "return arguments[0].contentDocument.getElementById('circleId').getAttribute('cx')",
                        objectTag).intValue();
        assertThat(circleCx, is(100));

If it works it's a bit more work, but you are at least unblocked from testing. Also one can query by XPath/CSS in Javascript too, so if the elements inside the SVG are not well defined with IDs, names, etc. can query them using those techniques as well once you have the starting SVG object node to being from in the DOM in javascript.

    at <anonymous class>.<anonymous method>(file:///C:/Users/auser/AppData/Local/Temp/anonymous7603687846920077736webdriver-profile/extensions/fxdri...@googlecode.com/components/command_processor.js:5282)
    at <anonymous class>.<anonymous method>(file:///C:/Users/auser/AppData/Local/Temp/anonymous7603687846920077736webdriver-profile/extensions/fxdri...@googlecode.com/components/command_processor.js:9569)
    at <anonymous class>.<anonymous method>(file:///C:/Users/auser/AppData/Local/Temp/anonymous7603687846920077736webdriver-profile/extensions/fxdri...@googlecode.com/components/command_processor.js:10131)
    at <anonymous class>.<anonymous method>(file:///C:/Users/auser/AppData/Local/Temp/anonymous7603687846920077736webdriver-profile/extensions/fxdri...@googlecode.com/components/command_processor.js:10136)
    at <anonymous class>.<anonymous method>(file:///C:/Users/auser/AppData/Local/Temp/anonymous7603687846920077736webdriver-profile/extensions/fxdri...@googlecode.com/components/command_processor.js:10074)

Aida Manna

unread,
Dec 29, 2013, 10:58:14 AM12/29/13
to webd...@googlegroups.com
Thanks! The problem is that I need to click on the element :( it is not just verifying an attribute.
Reply all
Reply to author
Forward
0 new messages