0

I am trying to automate a test using SVG Nodes. I need to click on a particular node.

I click on the element in Firefox, click F12 to get the console up, & type console.dir($0) to see the details. This is what the element looks like:

text
​
__data__: Object { height: 0, depth: 1, x: 0, … }
​
attributes: NamedNodeMap [ fill="#fff", font-size="36px", font-family="mapicons", … ]
​
baseURI: "https://fnord.co.uk/#/jobs/add/job?@=-702x6714391y19z&lf=1!19.73740"
​
childElementCount: 0
​
childNodes: NodeList [ #text ]
​
children: HTMLCollection []
​
classList: DOMTokenList []
​
className: SVGAnimatedString { baseVal: "", animVal: "" }
​
clientHeight: 0
​
clientLeft: 0
​
clientTop: 0
​
clientWidth: 0
​
dataset: DOMStringMap {  }
​
dx: SVGAnimatedLengthList { baseVal: SVGLengthList, animVal: SVGLengthList }
​
dy: SVGAnimatedLengthList { baseVal: SVGLengthList, animVal: SVGLengthList }
​
farthestViewportElement: <svg id="svgstruct" style="position: relative; overflow: visible; margin-top: 50px; margin-left: 20px; min-width: 100%;" width="100%" height="100%">
​
firstChild: #text ""
​
firstElementChild: null
​
id: ""
​
innerHTML: "\ue05e"
​
isConnected: true
​
lastChild: #text ""
​
lastElementChild: null
​
lengthAdjust: SVGAnimatedEnumeration { baseVal: 1, animVal: 1 }
​
localName: "text"
​
namespaceURI: "http://www.w3.org/2000/svg"
​
nearestViewportElement: <svg id="svgstruct" style="position: relative; overflow: visible; margin-top: 50px; margin-left: 20px; min-width: 100%;" width="100%" height="100%">
​
nextElementSibling: null
​
nextSibling: null
​
nodeName: "text"
​
nodeType: 1
​
nodeValue: null
​
onabort: null
​
onanimationcancel: null
​
onanimationend: null
​
onanimationiteration: null
​
onanimationstart: null
​
onauxclick: null
​
onblur: null
​
oncanplay: null
​
oncanplaythrough: null
​
onchange: null
​
onclick: null
​
onclose: null
​
oncontextmenu: null
​
oncopy: null
​
oncut: null
​
ondblclick: null
​
ondrag: null
​
ondragend: null
​
ondragenter: null
​
ondragexit: null
​
ondragleave: null
​
ondragover: null
​
ondragstart: null
​
ondrop: null
​
ondurationchange: null
​
onemptied: null
​
onended: null
​
onerror: null
​
onfocus: null
​
ongotpointercapture: null
​
oninput: null
​
oninvalid: null
​
onkeydown: null
​
onkeypress: null
​
onkeyup: null
​
onload: null
​
onloadeddata: null
​
onloadedmetadata: null
​
onloadend: null
​
onloadstart: null
​
onlostpointercapture: null
​
onmousedown: null
​
onmouseenter: null
​
onmouseleave: null
​
onmousemove: null
​
onmouseout: null
​
onmouseover: null
​
onmouseup: null
​
onmozfullscreenchange: null
​
onmozfullscreenerror: null
​
onpaste: null
​
onpause: null
​
onplay: null
​
onplaying: null
​
onpointercancel: null
​
onpointerdown: null
​
onpointerenter: null
​
onpointerleave: null
​
onpointermove: null
​
onpointerout: null
​
onpointerover: null
​
onpointerup: null
​
onprogress: null
​
onratechange: null
​
onreset: null
​
onresize: null
​
onscroll: null
​
onseeked: null
​
onseeking: null
​
onselect: null
​
onselectstart: null
​
onshow: null
​
onstalled: null
​
onsubmit: null
​
onsuspend: null
​
ontimeupdate: null
​
ontoggle: null
​
ontransitioncancel: null
​
ontransitionend: null
​
ontransitionrun: null
​
ontransitionstart: null
​
onvolumechange: null
​
onwaiting: null
​
onwebkitanimationend: null
​
onwebkitanimationiteration: null
​
onwebkitanimationstart: null
​
onwebkittransitionend: null
​
onwheel: null
​
outerHTML: "<text fill=\"#fff\" font-size=\"36px\" font-family=\"mapicons\" transform=\"translate(0,30)\">\ue05e</text>"
​
ownerDocument: HTMLDocument https://alloy-labs.yotta.co.uk/#/jobs/add/job?@=-702x6714391y19z&lf=1!19.73740
​
ownerSVGElement: <svg id="svgstruct" style="position: relative; overflow: visible; margin-top: 50px; margin-left: 20px; min-width: 100%;" width="100%" height="100%">
​
parentElement: <g class="node" cursor="pointer" transform="translate(30,110)">
​
parentNode: <g class="node" cursor="pointer" transform="translate(30,110)">
​
prefix: null
​
previousElementSibling: <path d="M0,0a30,30,0,1,0,0,60h0a30,30,0,1,0,0,-60Z" fill="#f5c041">
​
previousSibling: <path d="M0,0a30,30,0,1,0,0,60h0a30,30,0,1,0,0,-60Z" fill="#f5c041">
​
requiredExtensions: SVGStringList { length: 0, numberOfItems: 0 }
​
requiredFeatures: SVGStringList { length: 0, numberOfItems: 0 }
​
rotate: SVGAnimatedNumberList { baseVal: SVGNumberList, animVal: SVGNumberList }
​
scrollHeight: 0
​
scrollLeft: 0
​
scrollLeftMax: 0
​
scrollTop: 0
​
scrollTopMax: 0
​
scrollWidth: 0
​
style: CSS2Properties {  }
​
systemLanguage: SVGStringList { length: 0, numberOfItems: 0 }
​
tabIndex: -1
​
tagName: "text"
​
textContent: "\ue05e"
​
textLength: SVGAnimatedLength { baseVal: SVGLength, animVal: SVGLength }
​
transform: SVGAnimatedTransformList { baseVal: SVGTransformList […], animVal: SVGTransformList […] }
​
viewportElement: <svg id="svgstruct" style="position: relative; overflow: visible; margin-top: 50px; margin-left: 20px; min-width: 100%;" width="100%" height="100%">
​
x: SVGAnimatedLengthList { baseVal: SVGLengthList, animVal: SVGLengthList }
​
y: SVGAnimatedLengthList
​​
animVal: SVGLengthList { numberOfItems: 0, length: 0 }
​​
baseVal: SVGLengthList
​​​
length: 0
​​​
numberOfItems: 0
​​​
__proto__: SVGLengthListPrototype { clear: clear(), initialize: initialize(), getItem: getItem(), … }
​​
__proto__: SVGAnimatedLengthListPrototype { baseVal: Getter, animVal: Getter, … }
​
__proto__: SVGTextElementPrototype
​​
constructor: ()
​​​
length: 0
​​​
name: "SVGTextElement"
​​​
prototype: SVGTextElementPrototype { … }
​​​
Symbol(Symbol.hasInstance): undefined
​​​
__proto__: function ()
​​
__proto__: SVGTextPositioningElementPrototype

I tried finding it using find by classname, but that didn't work:

String className="SVGAnimatedString";
        List<WebElement> cardTitles = driver.findElements(By.className(className));

Evidently className does not mean this kind of className?

So I tried finding it using cssSelector. This works, but is less useful, as the CSS Selector changes each time screen loads. Having found my element , if I click it just using element.click, nothing happens. If I click on it using this Javascript, it throws an exception:

JavascriptExecutor executor = (JavascriptExecutor) driver;
            executor.executeScript("arguments[0].click();", element);

The exception message:

org.openqa.selenium.JavascriptException: TypeError: arguments[0].click is not a function

How do I get the click to work on this element?

This is NOT a duplicate of Selenium WebDriver [Java]: How to Click on elements within an SVG using XPath

Unlike that enquirer, I have managed to find my element.

My problem is with clicking that element.

Browser: Firefox Quantum 59.0.1 (64-bit) Geckodriver: 0.19.1 Selenium Jar: 3.8.1

Steve Staple
  • 2,983
  • 9
  • 38
  • 73

2 Answers2

1

I think your find by is wrong. There are also lots of things to add to this post to help debug.

  1. What version of firefox, webdriver (firefox, marionetter or gecko) and selenium jar are you using?
  2. Does it work in other browsers?

In response to:
Evidently className does not mean this kind of className

You can check your find syntax from the console so in your case type the following to find an element that has a class of SVGAnimatedString:

$('.SVGAnimatedString')

Click on the collapse arrow to see if anything was found.

From the properties you posted your element does not have any class values set:

classList: DOMTokenList []

At this website https://demos.telerik.com/kendo-ui/dragdrop/events
Click on the big circle and repeat

console.dir($0)  
classList: DOMTokenList [ "k-header" ]

And this is the element in the DOM

<div id="droptarget" class="k-header" data-role="droptarget">Drag the small circle here.</div>

Thus these CSS selectors work:

$('.k-header') ==> finds 6, class only
$('div.k-header')  ==> finds 4, element type and class
$('div.k-header[data-role="droptarget"]') ===> finds 1, as above with attribute and value

What CSS selector have you got to work?

I notice the properties posted also have:

clientHeight: 0
​clientLeft: 0
clientTop: 0
clientWidth: 0

​ So it looks like you've got a hidden element?

My advice would be to click on the element, show it in the DOM and try a couple of elements above or below the one you are working with, you may find the elements has stable properties that make it easier.

You can also use this code to double check where your webdriver and selenium think the element is (updating for creating the driver):

 WebDriver webDriver = new FireFoxDriver();
 Actions actions = new Actions(webDriver);
 webDriver.navigate().to("https://demos.telerik.com/kendo-ui/dragdrop/events");
 Thread.sleep(500);
 WebElement drop = webDriver.findElement(By.cssSelector("#droptarget"));
 //movetoelement should be center and is
 actions.moveToElement(drop).contextClick().perform();
 Thread.sleep(500);
 webDriver.quit();

I've worked with SVG elements and the normal .click() has worked fine: Firefox 57.0.2, 57.0.3, 58.0.2, 59.0 with geckodriver 0.18.0 and selenium-java:3.7.1

elworthy
  • 454
  • 4
  • 12
  • I tried typing $('.SVGAnimatedString') at the console. Got this response: $('.SVGAnimatedString') {…} ​ length: 0 ​ prevObject: Object [ HTMLDocument https://fnord.co.uk/#/jobs/add/job?@=-736x6714468y19z&lf=1!19.73740 ] ​ __proto__: Object { jquery: "3.1.1", constructor: r(), length: 0, … } – Steve Staple Mar 22 '18 at 12:43
  • Your bit of code has done a right-click on my element? actions.moveToElement(drop).contextClick().perform(); – Steve Staple Mar 22 '18 at 12:59
  • @SteveStaple For your first comment: The console check was just a quick way to confirm your element couldn't be found using your original class pattern - length:0 means nothing found. Did you try the https://demos.telerik.com/kendo-ui/dragdrop/events example in my answer above - so you get a better understanding of finding by class? As per answer, what are you now using to find the element? My example code is supposed to do a right click, it's designed to show where the mouse is when the right click event is triggered. Try replacing contextClick() with click(). – elworthy Mar 22 '18 at 13:11
  • I did that - replacing contextClick with click. It appeared to work (i.e: it went on to execute the next statement & did not throw an exception). – Steve Staple Mar 22 '18 at 13:52
  • @SteveStaple OK so you have a solution using an actions mouse click rather than the normal WebElement.click(). If you want to use the normal WebElement.click() then see my original suggestion above, explore the DOM elements above and below the one you have currently found, using the console search to double check what your selector returns (as you did with $('.SVGAnimatedString') and my examples for the kendo site). Other than if you are happy with the solution please consider accepting my answer. – elworthy Mar 22 '18 at 13:58
0

You could use something like this if the classname has something about it that never changes. A partial search would be a simple explanation:

targetElement.findElement(By.cssSelector("[className*='partialClassNameString']"));

The "*" indicates that you want to match on either this string or this string as a substring of any web element that has a className attribute.

As far as clicking on the element. Have you tried using submit? I'm grasping as straws here, but it doesn't hurt to try. instead of .click() you use .submit()

Mike Cook
  • 99
  • 5