Почему selenide пропускает индексы при клике на элемент из коллекции?

Всем привет! Строго не судите^^ :angel:

Имеется страница с ссылками(16 ссылок). Задача: поочередно кликнуть на каждую ссылку.

        String testElement = "a[class='node node__leaf']"; //css selector
        int numOfElements = $$(testElement).filter(Condition.visible).size(); //вычисляем сколько ссылок на странице(16)

        for (int i = 0; i < numOfElements; i++) {
            System.out.println(i + " - " + $$(testElement).filter(Condition.visible).get(i).getText()); //распечатываем i и кликаемую ссылку
            $$(testElement).filter(Condition.visible).get(i).click(); // собственно сам клик
            sleep(1); // Thread.sleep 1 сек для надежности
        }

На выходе получаю, что при клике - пропускается один элемент и кликается через одну ссылку.

Вот распечатка:

0 - #1
1 - #3
2 - #5
3 - #7
4 - #9
5 - #11
6 - #13
7 - #15

НО!

Если же закомментировать клик($$(testElement).filter(Condition.visible).get(i).click();) , то отрабатывает корректно:

0 - #1
1 - #2
2 - #3
3 - #4
4 - #5
5 - #6
6 - #7
7 - #8
8 - #9
9 - #10
10 - #11
11 - #12
12 - #13
13 - #14
14 - #15
15 - #16

Собственно вопрос, где мой косяк и как пофиксать ситуацию? Спасибо :slight_smile:

А что происходит после клика со страницей?
Возможно, фокус меняется, ваш слип вносит нестабильность.
Попробуйте тупо увеличить слип до 5 и посмотреть что будет, так не делали?

1 лайк

Думаю, проблема в том, что у вас на каждом шагу заново ищутся элементы через $$(testElement).filter(Condition.visible), а после клика, возможно, часть из них становится невидимой. Может быть чем-то закрываются, или совсем пропадают из dom.

2 лайка

Видимо не все ссылки видимые

1 лайк

А почему есть уверенность, что именно 16 находит, если судить по аутпуту то 8. Можно поставить System.out.println("links number " + numOfElements);, чтобы точно убедиться: 8 или 16.

1 лайк

После клика фокус меняется, вот пример страницы(всем известная allure) https://ci.qameta.io/job/allure2/job/master/Demo_Report/index.html#behaviors

Слип до 5 сек не помогает

Хороший вариант! Нужно заново искать элемент?

Потому что физически на моей странице 16 ссылок, что и загоняется в переменную(numOfElements = 16) (links number 16)
numOfElements по пути не меняется, оно служит выходом из цикла. По аутпуту 8, потому что при клике пропускается одна ссылка(вся суть проблемы). Как только selenide пытается кликнуть на 9ую ссылку - тест падает, потому что пропустились по одной ссылке(#2, #4, #6, #8)

Циклов = 16;
Элементов = 8; // потому что идет пропуск при клике

Если мое предположение верно, то нужно разобраться почему элементы становятся невидимыми. Возможно, после клика всплывает какой-то тултип поверх соседнего линка и скрывает его. Может быть нужно кликнуть куда-то в пустое место, чтобы тултип пропал.

1 лайк

С таким локатором всё заработает - div.tree__content > a.node.node__leaf

2 лайка

Да, все заработало! Спасибо! Объясните почему?

Негибкий локатор. Вы задали очень точный класс для a -элемента, когда на него кликаете ему ещё прибавляется ещё один класс (расскрытый) и он уже не подходит к вашему локатору. По моему локатору находятся все элементы, раскрытые или ещё нет.

3 лайка

Привет!
Вижу, что вам уже ответили, но хочу и от себя добавить пару комментариев по коду.

  1. Такой селектор слишком длинный и точный: $("a[class='node node__leaf']").
    Так проще и надёжнее: $("a.node.node__leaf").

  2. Вы внутри цикла каждый раз заново загружаете и фильтруете список, что делает код медленным. Лучше загрузить их один раз ДО цикла:

ElementCollection as = $$(testElement).filter(Condition.visible);
for (SelenideElement a : as) {
  a.click();
  sleep(1);
}
  1. sleep(1); - это не одна секунда, а одна миллисекунда. :slight_smile:
5 лайков

Спасибо, великий отец Selenide :innocent: очень полезная информация!

sleep(1) - кастомный метод, поэтому и указал в комментарии, что именно 1 сек :slightly_smiling_face:

Ясно :slight_smile:

В Selenide тоже есть метод sleep, только с миллисекундами.
Вариант с секундами плох тем, что рано или поздно кто-то захочет подождать полсекунды - и дико обломится.

2 лайка