Как заставить Selenium Java щелкнуть узел SVG в дереве SVG DOM?

Я пытаюсь автоматизировать тест с использованием узлов SVG. Мне нужно щелкнуть по конкретному узлу.

Я щелкаю элемент в Firefox, нажимаю F12, чтобы открыть консоль, и набираю console.dir ($ 0), чтобы увидеть подробности. Вот как выглядит элемент:

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

Я попытался найти его, используя команду find by classname, но это не сработало:

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

Очевидно, className не означает такого типа className?

Поэтому я попытался найти его с помощью cssSelector. Это работает, но менее полезно, поскольку селектор CSS изменяется при каждой загрузке экрана. Найдя свой элемент, если я щелкну его просто с помощью element.click, ничего не произойдет. Если я щелкну по нему с помощью этого Javascript, он выдаст исключение:

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

Сообщение об исключении:

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

Как заставить работать щелчок по этому элементу?

Это НЕ дубликат Selenium WebDriver [Java]: как нажимать на элементы в SVG с помощью XPath

В отличие от этого вопрошающего, мне удалось найти свою стихию.

Моя проблема в том, чтобы щелкнуть этот элемент.

Браузер: Firefox Quantum 59.0.1 (64-бит) Geckodriver: 0.19.1 Селеновая банка: 3.8.1

Я не понимаю, как @DebanjanB. Я не использую xpath для начинающих!

Steve Staple 21.03.2018 16:23

@DebanJanB. Совсем не тот вопрос!

Steve Staple 21.03.2018 16:25

@DebanjanB. Вы действительно читали мой вопрос?

Steve Staple 21.03.2018 16:26
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
4
612
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете использовать что-то подобное, если в имени класса есть что-то, что никогда не меняется. Частичный поиск был бы простым объяснением:

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

«*» Указывает, что вы хотите сопоставить либо эту строку, либо эту строку как подстроку любого веб-элемента, имеющего атрибут className.

Что касается нажатия на элемент. Вы пробовали использовать submit? Я тут как за соломинку хватаюсь, но попробовать не помешает. вместо .click () вы используете .submit ()

Ответ принят как подходящий

Я думаю, что ваша находка неверна. Также есть много вещей, которые можно добавить в этот пост, чтобы облегчить отладку.

  1. Какая версия firefox, webdriver (firefox, marionetter или gecko) а селеновую банку вы используете?
  2. Это работает в других браузерах?

В ответ:
Очевидно, className не означает такого типа className

Вы можете проверить свой синтаксис поиска с консоли, поэтому в вашем случае введите следующее, чтобы найти элемент, который имеет класс SVGAnimatedString:

$('.SVGAnimatedString')

Щелкните стрелку свертывания, чтобы увидеть, было ли что-то найдено.

Из свойств, которые вы разместили, ваш элемент не имеет установленных значений класса:

classList: DOMTokenList []

На этом сайте https://demos.telerik.com/kendo-ui/dragdrop/events
Нажмите на большой круг и повторите

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

И это элемент в DOM

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

Таким образом, эти селекторы CSS работают:

$('.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

Какой CSS-селектор у вас должен работать?

Я заметил, что в опубликованных свойствах также есть:

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

Взаимодействие с другими людьми Похоже, у вас есть скрытый элемент?

Я бы посоветовал щелкнуть элемент, показать его в DOM и попробовать несколько элементов выше или ниже того, с которым вы работаете, вы можете обнаружить, что элементы имеют стабильные свойства, которые упрощают задачу.

Вы также можете использовать этот код, чтобы дважды проверить, где ваш веб-драйвер и селен считают элемент (обновление для создания драйвера):

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

Я работал с элементами SVG, и нормальный .click () работал нормально: Firefox 57.0.2, 57.0.3, 58.0.2, 59.0 с geckodriver 0.18.0 и selenium-java: 3.7.1

Я попытался набрать $ ('. SVGAnimatedString') на консоли. Получил этот ответ: $ ('. SVGAnimatedString') {…} длина: 0 prevObject: Object [HTMLDocument fnord.co.uk/#/jobs/add/job?@=-736x6714468y19z&lf=1!19.73740] прото: Object {jquery: "3.1.1", конструктор: r (), length: 0,… }

Steve Staple 22.03.2018 13:43

Ваш фрагмент кода щелкнул правой кнопкой мыши мой элемент? actions.moveToElement (перетащить) .contextClick (). perform ();

Steve Staple 22.03.2018 13:59

@SteveStaple Для вашего первого комментария: проверка консоли была просто быстрым способом подтвердить, что ваш элемент не может быть найден с использованием вашего исходного шаблона класса - длина: 0 означает, что ничего не найдено. Вы пробовали пример demos.telerik.com/kendo-ui/dragdrop/events в моем ответе выше - чтобы вы лучше понимали поиск по классам? Согласно ответу, что вы сейчас используете, чтобы найти элемент? Мой примерный код должен делать щелчок правой кнопкой мыши, он предназначен для того, чтобы показать, где находится мышь, когда запускается событие щелчка правой кнопкой мыши. Попробуйте заменить contextClick () на click ().

elworthy 22.03.2018 14:11

Я так и сделал - заменив contextClick на click. Оказалось, что он сработал (то есть: он выполнил следующий оператор и не вызвал исключения).

Steve Staple 22.03.2018 14:52

@SteveStaple ОК, поэтому у вас есть решение, использующее щелчок мышью для действий, а не обычный WebElement.click (). Если вы хотите использовать обычный WebElement.click (), посмотрите мое исходное предложение выше, исследуйте элементы DOM выше и ниже того, который вы в настоящее время нашли, используя поиск в консоли, чтобы дважды проверить, что возвращает ваш селектор (как вы это делали с $ ('.SVGAnimatedString') и мои примеры для сайта кендо). Если вас не устраивает решение, подумайте о том, чтобы принять мой ответ.

elworthy 22.03.2018 14:58

Другие вопросы по теме