Перейти к содержимому

Фотография

Борьба со "StaleElementReferenceException: Element is no longer at


  • Авторизуйтесь для ответа в теме
Сообщений в теме: 10

#1 Marisya

Marisya

    Новый участник

  • Members
  • Pip
  • 10 сообщений
  • ФИО:Мария
  • Город:Санкт-Петербург

Отправлено 17 февраля 2012 - 13:28

Есть код (описывает выбор значения в выпадающем списке):
new Select( driver.findElement( By.name( "folderList" ) )).selectByVisibleText( folderName );

При выполнении выпадает ошибка:
org.openqa.selenium.StaleElementReferenceException: Element is no longer attached to the DOM

Причем если разнести вот так:
WebElement folderList = driver.findElement( By.name( "folderList" ) );
new Select( folderList ).selectByVisibleText( folderName ); 
То становится понятно, что ошибка обнаруживается только тогда, когда мы начинаем работать с элементом (выбирать в списке какие-то значения).

На текущий момент проблему решили созданием ожидания:
Boolean until = new WebDriverWait( login.getDriver(), 30 ).until( new ExpectedCondition<Boolean>()
        {
            public Boolean apply( WebDriver webDriver )
            {
                try
                {
                    new Select( driver.findElement( By.name( "folderList" ) )).selectByVisibleText( folderName ); 
                }
                catch( StaleElementReferenceException e )
                {
                    log.debug( "Select failed! Try again..." );
                    return false;
                }
                log.debug( "test found!" );
                return true;
            }
        } );

Хотелось бы вытащить эту "ожидалку" в отдельный метод (какой-нибудь "waitElementExist"), который поможет работать с AJAX'ом (будет ждять до тех пор, пока объект не окажется в DOM'е), а для этого надо отделелить "driver.findElement( By.name( "folderList" ))" - сделать его не завернутым в Select. Т.е. в итоге получить конструкцию вида:
driver.findElement( By.name( "folderList" ) ).click()
Т.е. штуку, которой все равно с каким элементом она работает - выпадающий список или что-то еще.

Можете посоветовать как так разделить? Как будет выглядеть этот хитрый метод?
  • 2

#2 LeshaL

LeshaL

    Профессионал

  • Members
  • PipPipPipPipPipPip
  • 1 094 сообщений
  • ФИО:Алексей Лянгузов
  • Город:Saint-Petersburg


Отправлено 17 февраля 2012 - 15:32

Попытайтесь неявное ожидание использовать:
Long timeout = 10;
driver.manage().timeouts().implicitlyWait(timeout, TimeUnit.SECONDS);

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

У меня есть 2 таймаута короткий и длинный. Длинный я использую только в определенных местах. А короткий - установлен по умолчанию. Т.е. после длинного ожиания я сбрасываю значение обратно в короткое ожидание, чтобы тесты быстрее падали в случае ошибки. В случае, если элемент есть сразу, то разницы нет никакой, driver делает опрос каждые 500мсек, пока не найдет или пока не вывалится по таймауту.
  • 0
Regards,
Alexey

#3 barancev

barancev

    Администратор

  • Admin
  • PipPipPipPipPipPip
  • 6 872 сообщений
  • ФИО:Алексей Баранцев
  • Город:Россия, Москва


Отправлено 19 февраля 2012 - 13:46

Мария, Вы всё сделали правильно.
Именно так и нужно бороться с исключением StaleElementReferenceException - пробовать выполнить действие несколько раз.
  • 0
Алексей Баранцев
Тренинги для тестировщиков (тестирование производительности, защищенности, тест-дизайн, автоматизация):
Линейка тренингов по Selenium

#4 sospectra

sospectra

    Новый участник

  • Members
  • Pip
  • 5 сообщений
  • ФИО:Милютина Спектра Петровна


Отправлено 04 февраля 2015 - 14:10

Спасибо за тему! Мне помогли ваши советы найти решение для обхода этой проблемы. предлагаю свой вариант для тех, кто тоже с этим столкнется:

        public bool WaitForElement(Action testMethod)
        {
            try
            {
                testMethod();
            }
            catch (StaleElementReferenceException)
            {
                testMethod();
            }
            catch (ElementNotVisibleException)
            {
                return false;
            }
            catch (NoSuchElementException)
            {
                return false;
            }
            return true;
        }
webDriver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(15));
           
var a = false;
short j = 0;
do
 {
  _Page.SelectCity.Click();
  var b = _Page.WaitForElement(() =>
    {
      _Page.SetCityToSelect("Москва");
      _Page.SelectThisCity.Click();
     });
   a = b;
   j++;
  } while (!a && j < 100);
            
webDriver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(5));

Assert.IsTrue(a);

Где:

_Page.SelectCity.Click(); 

- Открытие выпадающего списка с перечнем городов.

_Page.SetCityToSelect("Москва");

- Установка атрибута на строчку списка с названием "Москва" для дальнейшего поиска по нему вот таким образом:

WebDriver.ExecuteJavaScript<string>("$('" + csspath + "').attr('autId','cityToSelect'); return '0';");
public IWebElement SelectThisCity
        {
            get
            {
                return WebDriver.FindElement(By.CssSelector("[autId='cityToSelect']"));
            }
        }

А без кастомного атрибута элемент не получается найти - особенность реализации подгружаемого списка.

 

Клик по элементу выпадающего списка:

_Page.SelectThisCity.Click();

В чем была моя проблема:

  1. Вебдрайвер кликал на выпадающий список.
  2. Пока искал город, чтобы проставить атрибут, список почему-то закрывался.
  3. Если не кликнуть на выпадающий список еще раз, то найденный элемент с проставленным атрибутом становился скрытым, и выбрать его было невозможно (ElementNotVisibleException).
  4. А если кликнуть, то список перезагружался, проставленный атрибут стирался, и элемент нельзя было найти по нему (NoSuchElementException).
  5. Увеличение ImplicitlyWait позволило вызывать StaleElementReferenceException, но успех был через раз. Кстати, на StackOverFlow советуют возвращать обратно на маленькое значение, чтобы другие тесты не стали проходить медленнее.
  6. Без повторов операции по счетчику метод не срабатывает - потому что у меня могут возникнуть все три вида исключений, а задать последовательность операций для всех случаев было сложнее, чем сделать такой цикл.

Итог: Код, которым я поделилась, работает.

 

Если есть альтернативные, более оптимальные пути решения проблемы - буду рада советам.


  • 0

#5 Boltick

Boltick

    Специалист

  • Members
  • PipPipPipPipPip
  • 596 сообщений
  • ФИО:Алексей
  • Город:планета Земля

Отправлено 12 февраля 2015 - 23:16

Мария, Вы всё сделали правильно.
Именно так и нужно бороться с исключением StaleElementReferenceException - пробовать выполнить действие несколько раз.

 

А почему бы не игнорировать StaleElementReferenceException? Скажем типа:

new WebDriverWait(driver, 30).ignoring(StaleElementReferenceException.class).until(new ExpectedCondition<Boolean>()
...

  • 0
Алексей Булат
Про Тестинг

#6 barancev

barancev

    Администратор

  • Admin
  • PipPipPipPipPipPip
  • 6 872 сообщений
  • ФИО:Алексей Баранцев
  • Город:Россия, Москва


Отправлено 13 февраля 2015 - 11:25

Игнорировать при помощи WebDriverWait это исключение нельзя, потому что оно возникает во время выполнения некоторого действия (click, sendKeys, getText).

Тут требуется не механизм "ожиданий", а механизм "попыток".


  • 0
Алексей Баранцев
Тренинги для тестировщиков (тестирование производительности, защищенности, тест-дизайн, автоматизация):
Линейка тренингов по Selenium

#7 Boltick

Boltick

    Специалист

  • Members
  • PipPipPipPipPip
  • 596 сообщений
  • ФИО:Алексей
  • Город:планета Земля

Отправлено 15 февраля 2015 - 20:25

Игнорировать при помощи WebDriverWait это исключение нельзя, потому что оно возникает во время выполнения некоторого действия (click, sendKeys, getText).

Тут требуется не механизм "ожиданий", а механизм "попыток".

Не спорю, идеологически это разные операции, однако интересно, что именно реализуя механизм "попыток" и выполнен механизм "ожиданий". По существу, будет повторяться выполнение "некоторого действия (click, sendKeys, getText)" с игнорированием StaleElementReferenceException, пока либо оно не выполнится, либо не произойдет таймаут.


  • 0
Алексей Булат
Про Тестинг

#8 Ivis

Ivis

    Новый участник

  • Members
  • Pip
  • 53 сообщений
  • Город:Одесса


Отправлено 19 августа 2017 - 14:19

Здравствуйте.

У меня такая же проблема, и почему-то решение отлавливания этой ошибки не срабатывает.

 

Есть два метода: метод ожидания элемента и метод проверки видимости элемента с отлавливанием ошибок.

        public IWebElement WaitForElement(IWebElement webElement)
        {
            bool isFound = false;


            for (int i = 0; i < 30; i++)
            {
                if (IsElementPresentAndVisible(webElement))
                {
                    isFound = true;
                    break;
                }
                else
                {
                    System.Threading.Thread.Sleep(1000);
                }
            }


            if (isFound)
            {
                return webElement;
            }
            else
            {
                Assert.Fail("ERROR! It's impossible to detect web-element" + webElement.ToString() + ".");
                return null;
            }
        }


        public bool IsElementPresentAndVisible(IWebElement webElement)
        {
            try
            {
                if (webElement.Displayed)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (NoSuchElementException)
            {
                return false;
            }
            catch (ElementNotVisibleException)
            {
                return false;
            }
            catch (StaleElementReferenceException)
            {
                return false;
            }
        }

Т.е. я тут пытаюсь отлавливать ошибку "StaleElementReferenceException".
Но, тем не менее, мои тесты периодически падают в этом месте с сообщением
"System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.

  ----> OpenQA.Selenium.StaleElementReferenceException : The element reference is stale. Either the element is no longer attached to the DOM or the page has been refreshed."

Что не так у меня с кодом?


  • 0

#9 Alex

Alex

    Постоянный участник

  • Members
  • PipPipPip
  • 237 сообщений
  • ФИО:Алексей

Отправлено 21 августа 2017 - 07:01

Здравствуйте.

У меня такая же проблема, и почему-то решение отлавливания этой ошибки не срабатывает.

 

Есть два метода: метод ожидания элемента и метод проверки видимости элемента с отлавливанием ошибок.

        public IWebElement WaitForElement(IWebElement webElement)
        {
            bool isFound = false;


            for (int i = 0; i < 30; i++)
            {
                if (IsElementPresentAndVisible(webElement))
                {
                    isFound = true;
                    break;
                }
                else
                {
                    System.Threading.Thread.Sleep(1000);
                }
            }


            if (isFound)
            {
                return webElement;
            }
            else
            {
                Assert.Fail("ERROR! It's impossible to detect web-element" + webElement.ToString() + ".");
                return null;
            }
        }


        public bool IsElementPresentAndVisible(IWebElement webElement)
        {
            try
            {
                if (webElement.Displayed)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (NoSuchElementException)
            {
                return false;
            }
            catch (ElementNotVisibleException)
            {
                return false;
            }
            catch (StaleElementReferenceException)
            {
                return false;
            }
        }

Т.е. я тут пытаюсь отлавливать ошибку "StaleElementReferenceException".
Но, тем не менее, мои тесты периодически падают в этом месте с сообщением
"System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.

  ----> OpenQA.Selenium.StaleElementReferenceException : The element reference is stale. Either the element is no longer attached to the DOM or the page has been refreshed."

Что не так у меня с кодом?

Вообще, конкретно по Select, похоже, что у вас при попытке выбрать что-либо в списке, этот список обновляется или вообще используется другой (на одном проекте встречал подобное). Вам нужно детальнее посмотреть, что у вас происходит в DOM при работе с этим select. И решить каких именно событий ожидать, чтобы гарантированно дождаться обновления списка. Это может быть также наличие тех или иных опций в списке.


  • 0

#10 Ivis

Ivis

    Новый участник

  • Members
  • Pip
  • 53 сообщений
  • Город:Одесса


Отправлено 21 августа 2017 - 07:33

 

Здравствуйте.

У меня такая же проблема, и почему-то решение отлавливания этой ошибки не срабатывает.

 

Есть два метода: метод ожидания элемента и метод проверки видимости элемента с отлавливанием ошибок.

        public IWebElement WaitForElement(IWebElement webElement)
        {
            bool isFound = false;


            for (int i = 0; i < 30; i++)
            {
                if (IsElementPresentAndVisible(webElement))
                {
                    isFound = true;
                    break;
                }
                else
                {
                    System.Threading.Thread.Sleep(1000);
                }
            }


            if (isFound)
            {
                return webElement;
            }
            else
            {
                Assert.Fail("ERROR! It's impossible to detect web-element" + webElement.ToString() + ".");
                return null;
            }
        }


        public bool IsElementPresentAndVisible(IWebElement webElement)
        {
            try
            {
                if (webElement.Displayed)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (NoSuchElementException)
            {
                return false;
            }
            catch (ElementNotVisibleException)
            {
                return false;
            }
            catch (StaleElementReferenceException)
            {
                return false;
            }
        }

Т.е. я тут пытаюсь отлавливать ошибку "StaleElementReferenceException".
Но, тем не менее, мои тесты периодически падают в этом месте с сообщением
"System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.

  ----> OpenQA.Selenium.StaleElementReferenceException : The element reference is stale. Either the element is no longer attached to the DOM or the page has been refreshed."

Что не так у меня с кодом?

Вообще, конкретно по Select, похоже, что у вас при попытке выбрать что-либо в списке, этот список обновляется или вообще используется другой (на одном проекте встречал подобное). Вам нужно детальнее посмотреть, что у вас происходит в DOM при работе с этим select. И решить каких именно событий ожидать, чтобы гарантированно дождаться обновления списка. Это может быть также наличие тех или иных опций в списке.

 

 

Эмм... у меня тут вопрос не связан с select.
В моих тестах во многих местах используюется ожидание элемента (код выше), и на разных элементах тест падает с "StaleElementReferenceException".
Например, после логина я жду появление навигационного меню... и в этом ожидании тест часто падает.


  • 0

#11 Ivis

Ivis

    Новый участник

  • Members
  • Pip
  • 53 сообщений
  • Город:Одесса


Отправлено 21 августа 2017 - 13:39

В общем, разобрался, вроде.

 

Если переписать метод проверки видимости элемента следующим образом, то всё заработает.

        public bool IsElementPresentAndVisible(IWebElement webElement)
        {
            try
            {
                return webElement.Displayed;
            }
            catch (Exception ex)
            {
                if (ex is NoSuchElementException || ex is ElementNotVisibleException || ex is StaleElementReferenceException)
                {
                    return false;
                }
                else if (ex.InnerException != null && ex.InnerException is StaleElementReferenceException)
                {
                    return false;
                }


                throw ex;
            }
        }

Может кому пригодится...


  • 0


Количество пользователей, читающих эту тему: 1

0 пользователей, 1 гостей, 0 анонимных