@FindBy(xpath = "//th[@class='z-listheader z-listheader-sort' and not(@style)]/div")
private List<WebElement> headersFilter;
Прохожу по листу в цикле:
(внешний цикл условно обозначен как итерация по массиву объектов)
for (Object object : objects) {
for (int i = 0; i < headersFilter.size(); i++){
// Беру текст из элемента в листе по его индексу
String s = headersFilter.get(i).getText();
// Последующие операции с другими элементами в этой же форме
...
Беру текст из элемента в листе по его индексу и сохраняю в строку s, затем проделываю некую операцию в этой же форме, в котрой находятся данные элементы
Первая итерация по внешнему циклу срабатывает нормально, но вторая итерация затыкается на строчке:
String s = headersFilter.get(i).getText();
Выдается NullPointerException
Получается , что после того как я в первой итерации проделываю какую-то операцию - эти элементы пересоздаются что ли и не успевают загрузиться?.
Вот тут headersFilter.get(i).getText(); я обращуюсь к еще не загруженному элементу?
Внешний цикл нормально покажите, а не абстрактно. По какому именно списку вы там шагаете? Как он задан? Что за операции далее осуществляются в пределах формы? Влияют ли они на исходную выборку и наличие элементов на странице?
Вообще говоря NPE тут может означать как и отсутствие headersFilter, так и null-элемент, взятый по i-му индексу. Тут следует прежде всего сузить поиск и определить точное местоположение null. Разбейте операцию взятия текста на 2: получение элемента и вызов getText(). Посмотрите в дебаге, кто из них бросает NPE. Дальше уже будет более понятно, в чем может быть проблема.
Выяснил, что вводя в инпуты значения в этой форме и нажимая на Enter - форма перересовывалась.
То есть, если в этом месте input.sendKeys(condition[1]); добавить Keys.ENTER (input.sendKeys(condition[1] + Keys.ENTER); то форма перересуется и уже headersFilter будет новый
Поэтому вынес нажатие на ENTER, когда уже вышли из цикла (получается, что Keys.ENTER нажимаем в последнем заполненном инпуте и весь фильтр применяется)
Подскажите, как такие моменты обходить, когда юзаются элементы и вдруг перересовываются?
Чего и следовало ожидать. Шагать в цикле по динамическим компонентам - плохая практика. Вот вам и живой пример, где WebDriverWait + ExpectedConditions будет максимально эффективен.
И кстати, вы бы почитали о различных структурах данных в java. Зачем вам двумерный массив для задачи фильтрации? Исходя из предложенного формата, это чистейший Map. Но опять-таки, даже Map здесь лишний. Сам фильтр логичней было бы описать через enum, ввиду статичности его значений. Ну а компонент, в который необходимо ввести данные наверняка можно описать одним динамическим локатором, в который будет в runtime инжектиться какое-то значение.
П.С. Покажите, как выглядит ваш фильтр. Возможно это какой-нибудь Select2, где можно все сделать еще проще при помощи native api.
@ArtOfLife согласен насчет структуры данных. Вообще в таких случаях лучше использовать DTO классы, тогда код становится намного понятнее и устойчивее к изменениям.
После применения фильтра, что именно с фильтрами происходит? К ним добавляется style какой-то?
В любом случае после ввода значений надо нажать энтер или по другому подтвердить ввод. Сделай отдельной операцией внутри цикла безовсяких плюсов. Подтверждение операции всегда делай отдельной командой, а не составной с предыдущим заполнением/очищение/кликом/прочее.
Тут тебе нужно при каждой итерации фильтровать изменения на странице, типа если у вебэлемента появляется стайл какой-то, то пропускать его
Вроде бы ничего не поменялось, кроме того, что в инпуте параметр value стал равен 555.
Кстати, видимо в xpath описывающем хедеры, я ошибочно вставил not(@style), потому что их со стайлом вообще нет.
Вот вот, у меня подобное было с коллекцией элементов, решение простое, фильтрация новых/изменённых элементов на странице после перезагрузки, так и уходит заветный NullPointerExeption
Ну если у тебя новый элемент на странице применяет новое значение атрибута style или если применяется дополнительный класс - который визуально выделяет “Это новый/изменённый элемент на странице”
Например: есть локатор “div.addToCompare”, у которого есть только 1 класс: “addToCompare” и после клика и добавления товара к сравнению у этого локатора добавляется новый класс “added” или у тега появляется style: color=“33333f”
То в теле цикла сделай проверку чтобы, у элемента div.addToCompare есть стайл или класс тот, то не выполнять с ним манипуляций
Не надо, никогда не надо так делать - перебирать элементы, и в это время что-то выполнять на странице. Вы никогда не будете знать, как поменяется структура разметки.
Надо разбить:
Сначала перебираем элементы и запоминаем их уникальные признаки (например, текст).
Затем заново перебираем элементы, подставляя динамический локатор с этим текстом. То есть, каждый раз ищем элемент заново, и тогда уже с ним что-то делаем. (Просто не нужно фанатично привязываться к локаторам в аннотациях, их не всегда хватает)
К элементу с ленивой инициализацией ты не сможешь добавить дополнительный атрибут/приставку чтобы именно с этим дополнением искался элемент. Для этого делают типа так: public ProductsLineBlock findProductByIDInTags(String id, String tagName) { return $(String.format("%s[data-id='%s']", tagName, id));
это самый динамичный локатор который у меня есть, но универсальный
Но и это можно обойти, можно искать на странице [data-id] атрибут и отфильтровать по нужному тегу или/и id(переменчивый), но так дольше будет выполняться операция - не 100 миллисекунд, а уже целые 1.5 секунды. Потому что при поиске одного нужного элемента происходит поиск всех элементов с соответствующим идентификатором и из этой коллекции берётся нулевой, поэтому и будет занимать дольше времени поиск элемента
Поэтому идентификатор элемента следует делать по возможности наиуникальнейшим, так быстрее выполняется поиск его. Поэтому лучше для динамических элементов передавать локатор непосредственно в findElements как строку/перменную
Дополнительный минус ленивой инициализации, при первом обращении к объекту происходит более длинная задержка чем при последующих вызовах