[Selenide] Перестал работать обычный click()

Не знаю с чем связано, но последнее время в моих тестах не работает обычный клик на элемент, например на кнопку.
В консоли пишет ошибку is not clickable at point (77, 458)
Обхожу эту неприятность через использование JS,

executeJavaScript("arguments[0].click()", element);

Хотелось бы понять почему обычный клик не работает… Подозреваю что тут замешан сам браузер, chrome Версия 67.0.3396.99
Помогите пожалуйста, хочется писать тесты в обычном стиле, не использую JS.

Что-то перекрывает элемент в момент попытки клика.
Скорее всего какой-то лоадер.

вот html кнопки.
%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%BA%D0%BD%D0%BE%D0%BF%D0%BA%D0%B0
После загрузки формы кнопка видная и ясная, как божий день)
Но click() не срабатывает, ошибка та которую выше писал

Обычно такие ошибки сопровождаются еще и второй частью - “other element would receive a click” - c указанием конкретной ноды, по которой проходит клик, вместо заявленного элемента. Изучите, что за элемент получает фокус. Тогда и придет понимание того, как фиксить проблему.

По факту, что угодно может перекрывать элемент: от банального спинера до плавающих контролов. Соответственно, и подход к решению может отличаться. Возможно просто нужно подождать, пока перекрывающий элемент не исчезнет. Либо же дополнительно скроллить, чтобы вернуть фокус target компоненту.

То что Вы глазами после прогрузки видите, что кнопка сразу доступна - совсем не означает, что это на самом деле так.
Загораживающий элемент может появиться хоть на 1ms, и в этот момент не дать кликнуть. Глаза человека такое не увидят.

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

Либо, если не хотите заморачиваться, ожидайте доступности клика перед кликом (Enabled && Displayed).

Но, если там действительно закрался какой-то лоадер - то он может быть не только в этом месте.

3 лайка

Спасибо за направления в поиске, но нестандартность ситуации в том, что другой тест, который на той же форме кликает по той же строчке выпадающего списка проходит успешно… В методе где происходит клик есть условие ожидания waitUntil(visible, 5000) только в первом случае метод проходит успешно, в другом случае падает

Ожидание условия visible не гарантирует того, что по элементу можно произвести клик.

Другой тест может попадать на эту страницу через другие действия, которые могут запускать какие-то процессы пока страница грузится (например, подгрузка данных из БД).

Так что это не показатель.

Попробуйте для эксперимента хардкодно ждать выполнения условий в течении минуты:
element.Displayed && element.Enabled

Привет, я бы еще выше по иерархии посмотрел, может есть какой то елемент невидимый который накладывается на кнопку, и он получает клик а не ваша кнопка.
Как упомянул @ArtOfLife там должна быть вторая часть лога, то что какой то другой элемент получает клик, можете полные логи после клика сюда кинуть?
@Noksa прав в том что visible никак не поможет, кнопка будет видима, но не факт что вы можете на нее кликнуть.

Условия выполняются, элемент не нажимается.

Пишет, что это элемент label, с текстом “…”. Прикрепил скрин. Такого элемента на странице не нашёл. По-моему странно, что в качестве кликабельного элемента подсказывает label.

Эти условия фигня, они никак не влияют, т.к. элемент отображается (что соответствует isDisplayed) и то что элемен вообще есть в DOM (что соответствует isEnabled).
Если он так подсказывает то не с проста, возможно во время клика подгружается что то с этим label’ом и оно перекрывает как раз таки вашу кнопку, что я рекомендую, в консоле Chrome во вкладке Network поставить профиль на Slow 3g, воспроизвести заход на страницу с кнопкой как в тесте, и посмотреть, может вы сможете даже споймать этот элемент.
Screenshot_1

Потом можете написать custom waiter, что бы ждал пока этот элемент не исчезнет то не кликать.

По-моему странно, что в качестве кликабельного элемента подсказывает label.

Ничего странного в этом нет, Selenium click() так и работает, он не кликает как человек, он старается кликнуть на элемент B, но если элемент A загораживает элемент B тогда он выдаст ошибку, что я хочу кликнуть по B, но клик получит A.
А JS click как раз таки позволяет это обходить, т.к. он кликает по элементу в DOM, т.е. минуя все элементы что загораживают его, поэтому у вас сейчас и работает только JS click.
Еще забыл спросить, вы не пробывали через Actions кликнуть?

Только что вспомнил, вот что я вам еще предлогаю, обернить этот клик в try/catch и поставьте breakpoint в catch блоке, и запустите в дебаге тест ваш.

Не вводите людей в заблуждение.

Если элемента вообще не будет в DOM, то у вас выбросится исключение NoSuchElementException или StaleElementException (в зависимости от ситуации) и до вызова IsEnabled дело даже не дойдет.

А метод/свойство IsEnabled отвечает как раз за то, что с элементом возможно произвести какие-то действия (Enabled = возможность взаимодействия).

Вот вам код из селениума, как пример:

public static Func<IWebDriver, IWebElement> ElementToBeClickable(IWebElement element)
        {
            return (driver) =>
            {
                try
                {
                    if (element != null && element.Displayed && element.Enabled)
                    {
                        return element;
                    }
                    else
                    {
                        return null;
                    }
                }
                catch (StaleElementReferenceException)
                {
                    return null;
                }
            };
        }

Потому что когда вы туда смотрите, этот элемент, скорее всего, уже исчез из DOM.
Убедиться в этом можно, подождав на брэйкпоинте перед кликом секунд 10-15, и потом попробовать кликнуть.
Если клик пройдет, значит ваш label - динамический элемент, что-то вроде лоадера.
Чудес не бывает.

В данном контексте это никак не влият клик, даже если он enabled и displayed это не означает что он может быть clicable без припятсвий, да, этот код верно работает, он просто проверяет две вещи, но он никак не проверяет что элемент действительно может быть кликнут, вот что я имел ввиду. И в данном случае, ставь любые условия, они никак не повлияют. Тут только нужно подождать пока этот элемент исчезнет.

Почему то не отлавливается org.openqa.selenium.WebDriverException …

Выбрал slow 3G, но к сожалению не увидел какого-то элемента, перекрывающего мне нужный.

Ждал пол минуты на брейкпоинте, клик на кнопку не получился(

Не совсем понял, т.е. тест падает но ошибку не можете отловить или что? Поставьте тогда общий exception тогда, что бы все ловились.

Получилось отловить исключение только через Throwable. В блоке catch ждал на точке остановки, ещё раз кликнул по кнопке - всё равно не кликнулось.

Что за выпадающий список? Кнопка является его частью?
Как выглядит DOM дерево на уровень выше / ниже кнопки?

Как искали?

Вам советовали использовать breakpoints в самом хроме, а не в java коде. К примеру, так:

image

И вообще, не лишним будет внимательно изучить дерево, включая расположение и размеры соседних элементов. Опять-таки, с помощью встроенных средств хрома.

Еще более полезным будет запуск этого теста на другой версии / типе браузера. Дабы исключить сторонние факторы. Благо, тот же Selenoid позволяет это сделать совершенно безболезненно.

Вы не понимаете зачем нужен try/catch в этом случае, он нужен для того что бы найти тот элемент что блокирует вашу кнопку, поэтому когда зайдет в catch блок, то сделайте evaluate (alt + f8) сделайте там клик, и посмотрите на лог сообщения, в логе будет явно указан элемент что блокирует, просто копируете его, идете в браузер, открываете панель разработчика или firebug (что там у вас) и ищите его, все, никакой магии.
Либо используйте breakpointы в браузере (тут я не особо компетентен).
@ArtOfLife в правильном направлении вас толкает, что бы вы всю иерархию посмотрели, может там какой нибудь parent или sibling невидимый блокирует его.

        try {
            webElement.click();
        } catch (Exception e) {
            e.printStackTrace();
        }

Самый обычный блок, всегда отлично у меня все отлавливал.