Удаленка для jenkins+selenide+selenoid+allure+docker спецов на 2-3 часа в день. 100% remote! Присоединиться к проекту

Selenide ищет элемент каждый раз при обращении к объекту

selenidelement
selenide
Теги: #<Tag:0x00007fedbfe350f8> #<Tag:0x00007fedbfe34ef0>

(Ivan Trechyokas) #1

Проблема (Вопрос) заключается в том, что создав объект, он его не запоминает и постоянно ищет его по указанному пути.

К примеру:
SelenideElement row = tableList.$(byText(ip)).parent();

После вызова в UI редактирования для этого элемента - там меняется само поле, по которому происходит поиск.

row.$(“button”).click() - отработал, текстове поле стало input.
row.$(“input[name=‘ip’]”).setValue() - уже не выполняется, так как объект не находится по тексту byText(ip) из-за того, что этого текста уже нет.

HTML пример

До нажатия Редактирования
<tbody>
   <tr> # сохраняет этот объект в объект row
      <td data-test="ip">${ip}</td>
      <td>
         <button>Edit</button>
      </td>
   </tr>
</tbody>


После нажатия
<tbody>
   <tr> # сохраняет этот объект в объект row
      <td>
         <input type="text"  name="ip" value="${ip}" placeholder="">
      </td>
      <td>
         <button>Edit</button>
      </td>
   </tr>
</tbody>

Вот и как так сделать, что бы работать с найденным родителем? Решил свой вопрос через нахождение его напрямую (при создании он всегда находится на первом месте), но что если нужно искать не конкретно его.


(Oleksandr Khotemskyi) #2

В таком случае не ищите по тексту, очевидно же

Вы заходите не с той стороны, берите все строки в таблице, фильтруйте по тексту, и кликайте по нужному элементу, а не ищите по тексту.


(Ivan Trechyokas) #3

А каким образом фильтер отфильтрует эти элементы?
tableList.$$("tr").filterBy(Condition.text("111.202.212.34")).get(0)

Возможно я чего-то не понимаю, но java соглашается со мной, возвращая

Element not found {<tbody>/tr.filter(text '111.202.212.34')}

Если же спускаться на уровень ниже и искать “tr td”, то происходит всё абсолютно также, только работать начинает раз в 10 медленнее =(

Element not found {<tbody>/tr td.filter(text '111.123.194.2')}

Дело тут в in-place-изменении, при редактировании эта строка меняет тип для

, содержащего текст с ip, на новый
<input … >
уже без текста. Но по идее, я определял родителя элемента, а не этот , но после этого - все операции начинают искать этот элемент каждый раз при обращении к нему.

В любом случае, ваш подход тоже не решил проблему.


(asolntsev) #4

Самое простое - я бы посоветовал добавить нормальные локаторы/атрибуты для строки:

<tr data-ip="${ip}">

И тогда строку можно будет искать по IP:

row = $(by("data-ip", "111.22.33.4444");


(Ivan Trechyokas) #5

да, это самое логично, но к сожалению с этим какие-то проблемы ( React + web-kit - это самописная библиотека элементов).

Проблема тут даже вот в чём, я переписал через WebElement - и поиск через xpath - работает как надо, сделал аналогично на SelenideElement - при повторном обращении к строке, которую уже нашёл и совершил действие, - теряет элемент из-за того, что поле, по которому элемент был найден изменилось. Вот тут как-то проблемно, на мой взгляд.


(Ivan Trechyokas) #6

Стало интересно и уже второй час переписываю код туда-сюда

    // tableList - приватный аттрибут класса, который определяется при инициализации страницы для объекта tbody
    public IPTablePage changeFirstRuleInTable(String text, IPTableRule rule) {
         WebElement row = tableList.findElement(By.xpath("//text()[contains(.,'"+text+"')]/../..")); // - работает, находит и продолжает работать с элементом после изменения
//        SelenideElement row = tableList.find(By.xpath("//text()[contains(.,'"+text+"')]/../..")); - не работает, теряет элемент после изменения
//        WebElement row = tableList.$(By.xpath("//text()[contains(.,'"+text+"')]/../..")); // - не работает, теряет элемент после изменения
//        WebElement row = tableList.$(byText(text)).parent(); // - не работает, теряет элемент 
        updateRule(row, rule);
        return clickSaveButton(row);
    }

    private IPTablePage clickEditButton(WebElement row){
        logger.info("Click edit button");
        row.findElement(byText("Edit")).click();
        return this;
    }

    private void updateRule(WebElement row, IPTableRule newRule){
        clickEditButton(row);
        row.findElement(By.cssSelector("input[name='addr']")).clear(); // теряет элемент на этой строке, пытаясь повторно найти row
        row.findElement(By.cssSelector("input[name='addr']")).sendKeys(newRule.ip);
        row.findElement(By.cssSelector("input[name='added_by_cause']")).clear();
        row.findElement(By.cssSelector("input[name='added_by_cause']")).sendKeys(newRule.reason);
        row.findElement(By.cssSelector("input[placeholder='Expired Date']")).clear();
        row.findElement(By.cssSelector("input[placeholder='Expired Date']")).sendKeys(formatter.format(newRule.expiredDate));
        row.findElement(By.cssSelector("[data-test='ip-edit-type'] span.sc-input__control")).click();
        selectValueFromDropDownListForEdit(newRule.listType.toString());
        row.findElement(By.cssSelector("[data-test='ip-edit-section'] span.sc-input__control")).click();
        selectValueFromDropDownListForEdit(newRule.actionType.toString());
    }

В общем, скорее всего это связано с обновлением элемента, что бы избежать StaleElementReferenceException или что-то в этом роде. А так как он не знает какой кусок DOM есть наш объект, он его повторно ищет. Интересен момент, что WebElement с findElement вполне себе справляются с этой задачей =(

Если я правильно понял, то в примере Андрея, ситуация повторится, когда в этой строке я поменяю ip => data-ip аттрибут тоже изменится и начнётся хаос.