Есть отличная удаленная работа для php+codeception+jenkins+allure+docker спецов. 100% remote! Присоединиться к проекту

Поиск элемента через WebElement


(Alex) #1

Когда мы ищем дочерний элемент в основном элементе, можно ли сочетать xpath и css?

driver.findElement(By.cssSelector("")).findElement(By.xpath()).click()


Selenide: не получается получить дочерний Selenide Element из родительского
Можно ли найти предка относительно элемента?
(vmaximv) #2

Можно


(Jane Tymoschuk) #3

главное чтобы xpath в этом случае начинался с точки

driver.findElement(By.cssSelector("bla bla")).findElement(By.xpath(".//*")).click()

Общие элементы для Popup и главной страницы
(Alex) #4

Не понимаю почему нельзя найти элемент с использованием ancestor? пишу следующее

WebElement element = driver.findElement(By.cssSelector("[id='row.name']"));

String text = element.findElement(By.xpath(".//ancestor::section[@class='form-group nav-item']/h3/a")).getText()

textначинает искать с самого начала DOM, а не относительно element Искать элемент можно только ниже относительно элемента?

P.S. локатор проверил через браузер.


(Sergey Korol) #5

ancestor:: — Возвращает множество предков.

Множество с локатором section[@class='form-group nav-item']/h3/a - это N элементов, судя по вашей верстке. Ввиду того, что вы используете findElement, а не findElements, на выходе получаете первый элемент из множества. Если выберете второй способ, увидите целую пачку нодов. Все логично.


(Alex) #6

Но я считал что будет выполняться поиск от конкретного элемента. Конечно когда я пишу:

//*[@id='row.name']/ancestor::section[@class='form-group nav-item']/h3/a

поиск выполняется относительно //*[@id='row.name']

В element.findElement я также пытаюсь найти относительно этого же элемента. Вот в этом и вопрос, почему он не находит относительно заданного локатора?


(Sergey Korol) #7

Ну вообще как бы есть разница между // и /.


(Alex) #8

Если я напишу один слеш, вообще ничего не находит. На скриншоте пример выполнения этой регулярки в браузере:


(Sergey Korol) #9

Начнем с того, что такое @id='row.name' и где оно на скрине?


(Alex) #10

Перепутал c row.descriptional, но не суть:


(vmaximv) #11

HTML:


<div id='main'>
    <div id='first'>
        <section>
            <h3>
                <a>first</a>
            </h3>
        </section>
    </div>
    <div id='second'>
        <section>
            <h3>
                <a>second</a>
            </h3>
        </section>
    </div>    
    <div id='third'>
        <section>
            <h3>
                <a>third</a>
            </h3>
            <div id='target'></div>
        </section>
    </div>    
</div>

Code:


WebDriver driver = new FirefoxDriver();
driver.get("http://jsfiddle.net/fcf0zvv1");
driver.switchTo().frame("result");
WebElement el1 = driver.findElement(By.cssSelector("[id='target']"));
WebElement el2 = el1.findElement(By.xpath(".//ancestor::section/h3/a"));
System.out.println(el2.getText());
driver.quit();

Output:

third

(Alex) #13

Такой способ я выше описал, он у меня не срабатывает. Игнорирует el1.


(vmaximv) #14

Ну я продемонстрировал, что ничего не игнорируется и данная конструкция вполне себе дееспособная.
Если у вас что-то “не срабатывает” - проблема на вашей стороне. Единственный действенный способ для вас - изолировать проблемное место и предоставить код, который бы мог запустить любой посетитель форума. Так как в таких случаях (“у всех работает, а у меня нет”) дебажить по скриншотам довольно затруднительно.


(Alex) #15

Понял. Спасибо


(Alex) #16

Хотел бы спросить вас по поводу точки. Почему локатор должен начинаться именно с точки? Дело в том что вы решили мне сейчас вопрос по вот этой теме. Обычно когда я ищу элемент в элементе, то не использовал точку и команды (click, isDisplayed…) выполнялись верно. Но когда я начал работу с Popup именно один из всех элементов не срабатывал из-за этой точки. Почему?


(vmaximv) #17

По спецификации.
http://www.w3.org/TR/xpath/

[quote]
// is short for /descendant-or-self::node()/. For example, //para is short for /descendant-or-self::node()/child::para and so will select any para element in the document (even a para element that is a document element will be selected by //para since the document element node is a child of the root node); div//para is short for div/descendant-or-self::node()/child::para and so will select all para descendants of div children.[/quote]

[quote]
A location step of . is short for self::node(). This is particularly useful in conjunction with //. For example, the location path .//para is short for self::node()/descendant-or-self::node()/child::para and so will select all para descendant elements of the context node.[/quote]


(Alex) #18

Я думал что в случае такого поиска элементов (//foo) он будет продолжать поиск от существующего элемента. Походу точка или self::node() говорит о том что поиск будет начинаться относительно предыдущего найденного элемента. Для примера продемонстрирую следующий скриншот:

На нем можно увидеть, что действительно в DOM находится 2 элемента. Поэтому когда я пытался искать элемент в элементе не используя точку, то локатор использовался относительно body а не последнего элемента:

public class Example{
...
public void testLocator(){

WebElement element = driver.findElement(By.xpath("//*[@additional-view][last()]//section[@name='row.__states.AvalabiltyOnVideoServers']"));

element.findElement(By.xpath("//td[normalize-space(.)='Московский']/input[@ng-model='row.__selected']")).click() // так как на странице 2 элемента с последним локатором, то найдет 2 элемента и выберет 1 который как видно на скриншоте находится за Popup. element учитываться не будет

element.findElement(By.xpath(".//td[normalize-space(.)='Московский']/input[@ng-model='row.__selected']")).click() // точка как я выше указал говорит нам что поиск локатора нужно начать относительно выше найденного элемента

}
...
}