Selenium перестает работать после вызова FindElements

Иногда, когда я вызываю Selenium FindElements(By), он выдает исключение, и мой драйвер перестает работать. Параметр "BY" может быть проблемой: когда я использую другой by для поиска одних и тех же элементов, он работает.

Также я мог видеть, что даже если мой элемент существует или если этот же метод с тем же аргументом был вызван ранее, это не мешает методу генерировать исключение.

Мой метод:

    public IWebElement SafeFindElement(By by)
    {
        try
        {
            IWebElement element;
            if (_driver.FindElements(by).Any())
            {
                element = _driver.FindElements(by).First();
                return element;
            }

            return null;
        }
        catch (NoSuchElementException)
        {
            return null;
        }
        catch (Exception)
        {
            return null;
        }
    }

Пример значения BY, которое не работает постоянно (даже если оно существует на странице):

By.CssSelector("input[data-id-selenium='entrar']")

Исключение:

WebDriverException

HTTP-запрос к удаленному серверу WebDriver для URL-адреса http://localhost:46432/session/ef6cd2f1bf3ed5c924fe29d0f2c677cf/elements истекло через 60 секунд.

Я понятия не имею, что это может быть или что вызывает эту нестабильность. Есть кто-нибудь с любым предложением?

@РЕДАКТИРОВАТЬ

Я нашел временное решение.

Раньше я пытался найти элемент, используя:

var element = browser
    .FindElements(By.CssSelector("input[data-id-selenium='entrar']")
    .FirstOrDefault();

Or

var element = browser
    .FindElements(By.XPath("//input[@data-id-selenium='entrar']");
    .FirstOrDefault();

Теперь я использую:

var element = browser
    .FindElements(By.TagName("input"))
    .FirstOrDefault(x => x.GetAttribute("data-id-selenium") == "entrar");

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


person Striter Alfa    schedule 15.07.2015    source источник
comment
Эта ошибка не вызвана тем, как вы ищете элемент. Когда вы не можете найти элемент, вы получаете ElementNotFoundException   -  person BlackHatSamurai    schedule 15.07.2015
comment
Я думаю, что это происходит только с использованием FindElement. Когда я пытаюсь использовать FindElements (более одного вхождения), если селен не может найти никакого результата, он возвращает пустой список.   -  person Striter Alfa    schedule 15.07.2015


Ответы (2)


Это известная проблема для селена, сервер веб-драйвера имеет максимальное время ожидания 60 секунд для каждого запроса, и я не знаю, как это изменить, я предлагаю вам рассмотреть возможность использования явного ожидания перед использованием FindElement (), хотя эта проблема может возникнуть, есть обходной путь для этой проблемы, который сработал для меня, используя методы расширения, которые я реализовал, идея состоит в том, чтобы дождаться определенного условия, чтобы, если веб-драйвер выдал исключение, которое говорит, что он ждал для максимального ограничения в 60 секунд вы можете справиться с этим, пытаясь повторно дождаться определенного условия в течение определенного периода времени, каждый раз, когда вы выполняете цикл, на сервер веб-драйвера отправляется новый запрос.

    public static void WaitUntil(this IWebDriver webDriver, Func<IWebDriver, bool> predicate, TimeSpan timeout)
    {
        var dtStart = DateTime.Now;

        while (true)
        {
            try
            {
                if (!predicate(webDriver))
                    throw new Exception();

                break;
            }
            catch (Exception ex)
            {
                if (DateTime.Now.Subtract(dtStart) >= timeout)
                    throw ex;
            }

            Thread.Sleep(30000);
        }
    }
    public static void WaitUntil(this IWebDriver webDriver, Func<IWebDriver, IWebElement> predicate, TimeSpan timeout)
    {
        var dtStart = DateTime.Now;

        while (true)
        {
            try
            {
                predicate(webDriver);
                break;
            }
            catch (Exception ex)
            {
                if (DateTime.Now.Subtract(dtStart) >= timeout)
                    throw ex;
            }

            Thread.Sleep(30000);
        }
    }

вы могли бы, например, использовать методы расширения, подобные этому

webDriver.WaitUntil(w => w.Title == "title", TimeSpan.FromMinutes(2));

or

webDriver.WaitUntil(ExpectedConditions.TitleIs("title"), TimeSpan.FromMinutes(2));

or

webDriver.WaitUntil(ExpectedConditions.ElementIsVisible(By.Id("elementId")), TimeSpan.FromMinutes(2));

Обновить

После просмотра вашего последнего комментария вы сказали, что получили некоторые элементы, когда использовали FindElements(By.TagName("input"); это означает, что используемый вами селектор вызывает проблему, вы можете найти элементы по имени тега, а затем отфильтровать результаты по значению атрибута, или если вы уверены, что используемый вами селектор верен и ведет себя неправильно, попробуйте отладить проблему, а также, если есть какой-либо javascript, который отвечает за установку значения атрибута, убедитесь, что он запускается первым, используя неявное или явное ожидание перед вызовом FindElement().

person Khaled El Kholy    schedule 15.07.2015
comment
Привет, Халед Холи! Спасибо за ваш ответ, но это не сработало. То же исключение возникает, когда метод пытается выполнить предикат (webDriver), и мой webDriver снова перестает работать. Нет ошибки, чтобы проверить, действительно ли элемент существует на странице (я могу утверждать, что он существует, проверяя в консоли браузера с помощью селекторов), но что-то вроде того, когда драйвер пытается его найти, и даже браузер отображает элементы в страницу, и можно выбрать их в консоли (например, $(input[data-id-selenium='entrar'])), драйвер выдает такое же исключение. - person Striter Alfa; 15.07.2015
comment
Вы пробовали что-то еще, кроме этого примера $(input[data-id-selenium='entrar'])?, я имею в виду поиск элемента по идентификатору или имени тега, и как вы реализовали $(input[data- id-selenium='entrar']) с использованием селена? - person Khaled El Kholy; 15.07.2015
comment
Иногда, когда я меняю селектор, работает. В этом случае, даже используя класс, идентификатор или что-то еще, это не удается. Я начинаю свой запрос, используя свой собственный метод browser.HasElement(By.CssSelector("input[data-id-selenium='entrar']")) , и внутри метода HasElement я вызываю SafeFindElement как bool hasElement = SafeFindElement(@by) != null Вы можете увидеть мой метод SafeFindElement в посте. - person Striter Alfa; 15.07.2015
comment
Иногда, когда я меняю селектор, работает. Вы сталкиваетесь с той же проблемой, используя browser.HasElement(By.TagName(input)); ? - person Khaled El Kholy; 15.07.2015
comment
Используя browser.HasElement(By.TagName("input"));, Selenium находит некоторые элементы, но использование предыдущего селектора не работает. Кроме того, я пытался использовать селектор Xpath, например browser.HasElement(By.XPath("//input[@data-id-selenium='entrar']")), но он тоже не работает. Я думаю, что можно временно решить проблему, найдя элементы с помощью By.TagName("input") и отфильтровав их с помощью linq, чтобы проверить, существует ли мой желаемый ввод или нет. Как бы то ни было, я хочу решить проблему правильным способом. - person Striter Alfa; 16.07.2015
comment
Я обновил свой ответ, если этот ответ решил вашу проблему, примите его как ответ. - person Khaled El Kholy; 16.07.2015
comment
Я только не понимаю, почему Selenium выдает исключения, когда мой параметр является допустимым селектором. Если я всегда фильтрую свой результат с помощью linq, я не могу использовать общий метод для проверки элементов, поэтому для всех моих консультаций потребуется фильтр linq, а не действительный и многоразовый селектор css? Потому что это позволит мне использовать только оператор BY. Если я выполню в консоли $("input[data-id-selenium='entrar']"), он вернет ожидаемый результат, но этого не происходит в Selenium. Элемент всегда существует на странице, если нет необходимости, дождитесь изменения значения атрибута на желаемое - person Striter Alfa; 16.07.2015

Я нашел проблему. Я использую метод во всех своих тестовых костюмах, чтобы дождаться закрытия сообщения о загрузке. Но он пытается использовать jquery, и не все страницы в моем приложении используют его.

Таким образом, селен отказывается от попытки выполнить jquery через 60 секунд и возвращает ошибку тайм-аута, но эта ошибка не нарушает драйвер Selenium, только FindElements возвращает пустой список. И когда он пытается вернуть пустой список, весь диск сломался.

Оригинальный метод:

public void WaitLoadingMessage(int timeout)
{
    while (timeout > 0)
    {
        try
        {
            var loadingIsVisible = _js.ExecuteScript("return $('#loading-geral').is(':visible');").ToString();

            if (loadingIsVisible.ToLower() == "false")
                break;

            Thread.Sleep(1000);
            timeout -= 1000;
        }
        catch (Exception ex)
        {
            if (!ex.Message.ToLower().Contains("$ is not defined"))
                throw;
        }
    }
}

И поправка:

public void WaitLoadingMessage(int timeout)
{
    while (timeout > 0)
    {
        try
        {
            var loadingIsVisible = _js.ExecuteScript("return $('#loading-geral').is(':visible');").ToString();

            if (loadingIsVisible.ToLower() == "false")
                break;

            Thread.Sleep(1000);
            timeout -= 1000;
        }
        catch (Exception ex)
        {
            if (!ex.Message.ToLower().Contains("$ is not defined"))
                throw;

            break;
        }
    }
}
person Striter Alfa    schedule 03.09.2015