Элемент ошибки StaleElementReference не найден в кеше

Я использую Capybara 2.1 с Ruby 1.9.3, используя драйвер селена (с Minitest и Test Unit), чтобы протестировать веб-приложение.

Я борюсь с проблемой StaleElementReferenceException. Я видел довольно много обсуждений на эту тему, но я не смог найти решение проблемы, с которой столкнулся.

В общем, я пытаюсь найти все элементы разбиения на страницы на своей странице, используя этот код:

pagination_elements = page.all('.pagination a')

Затем я делаю некоторые утверждения для таких элементов, как:

pagination_elements.first.must_have_content('1')

После этих утверждений я продолжаю тест, нажимая ссылку «Следующая страница», чтобы убедиться, что моим будущим первым элементом разбиения на страницы будет «Предыдущая страница». Для этого я снова получаю элементы разбиения на страницы:

new_pagination_elements = page.all('.pagination a')

И здесь возникает Stale Error, потому что я достигаю элементов, которые я уже достиг. ( Вот ошибка)

Вы можете увидеть состояние ссылки здесь.

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


person Evers    schedule 27.08.2013    source источник
comment
Пожалуйста, загляните на github.com/jnicklas/capybara/issues/843.   -  person Rajarshi Das    schedule 27.08.2013
comment
@RajarshiDas Я уже читал эту тему и связанные с ней, но это действительно старая проблема из предыдущей версии Capybara, и она не помогает решить мою проблему.   -  person Evers    schedule 27.08.2013


Ответы (5)


Иногда у меня возникают проблемы с интенсивными страницами AJAX, в моем случае это решает этот обходной путь:

begin
  ...
rescue Selenium::WebDriver::Error::StaleElementReferenceError
  sleep 1
  retry
end
person ejosafat    schedule 27.08.2013

Я увидел основное сообщение в сути:

Element not found in the cache - 
perhaps the page has changed since it was looked up

У меня уже был подобный случай. Есть два решения:

  1. Добавьте page.reload перед проверкой того же материала на новой странице, если вы установили Capybara.automatic_reload = false в spec_helper

  2. find специальный элемент на новой странице, которого нет на предыдущей странице. Этот эффект эквивалентен ожиданию.

Другой метод заключается в использовании определенного селектора. Например, вместо

pagination_elements = page.all('.pagination a')

Использовать

pagination_elements = page.all('#post_123 .pagination a')

Добавьте к селектору область уникального идентификатора, и вы не столкнетесь с такой проблемой.

person Billy Chan    schedule 27.08.2013
comment
Я бы хотел избежать использования page.reload, потому что мои интеграционные тесты следуют пользовательскому потоку, и перезагрузка страницы не является его частью. - person Evers; 27.08.2013
comment
@Evers, здесь нет ничего плохого. Значение по умолчанию — true, поэтому каждое действие будет перезагружать контент, вы просто этого не заметили. Я всегда устанавливаю false, потому что часто использую Javascript для взаимодействия. Забудьте об этой части, если у вас нет такой настройки в spec_helper - person Billy Chan; 27.08.2013
comment
Но сила reload может помочь, если вы проверите одни и те же вещи дважды. Стоит попробовать. - person Billy Chan; 27.08.2013
comment
Спасибо! Теперь это работает очень хорошо! Добавление уникального идентификатора — лучший способ сделать это. Запуск этого конкретного теста 10 раз приводит только к одному неудачному тесту. Так что это все еще не 100% точно. - person Evers; 27.08.2013

Интересная ссылка об этой ошибке и о том, как ее исправить: http://stefan.haflidason.com/testing-with-rails-and-capybara-methods-that-wait-method-that-wont/

person Ben Colon    schedule 19.03.2015

Судя по всему, помимо условий гонки, эта ошибка появляется еще и из-за неправильного использования блоков within. Например:

within '.edit_form' do
  click '.edit_button'
  # The error will appear here if the 'edit_button' is not a
  # descendant of the 'edit_form'
end
person art-solopov    schedule 12.04.2016
comment
это мой случай! Я был заблокирован внутри блока within, который вызывал ложную ошибку на устаревшем объекте внутри него - устаревшим было не то, что я #find делал, а сам блок! - person igorsantos07; 26.04.2017

Пробовали ли вы использовать WebDriver напрямую, а не через Capybara? Это потенциально даст вам больше контроля над тем, когда следует кэшировать объекты, а когда нет.

например (Извините за синтаксис java, но идея должна быть понятна)

WebElement searchField = driver.findElement(By.CssSelector("input.foo"));

searchField.click();

searchField.sendKeys("foo foo");

System.out.println(searchField.getText());

//Do something elsewhere on the page which causes html to change (e.g. submit form)

.....
....

//This next line would throw stale object

System.out.println(searchField.getText());

//This line will not throw exception

searchField = driver.findElement(By.CssSelector("input.foo"));

System.out.println(searchField.getText());

Повторное присвоение «findElement» «searchField» означает, что мы повторно находим элемент. Знание того, когда переназначать, а когда нет, является ключом к решению, как кэшировать ваши веб-элементы.

Я не использовал Capybara, но я предполагаю, что она скрывает от вас стратегию кэширования?

person Robbie Wareham    schedule 27.08.2013
comment
Мы уже используем Capybara в других наших проектах и ​​не рассматриваем возможность отката к самому Webdriver. Капибара сэкономит нам много времени. Но вы правы, у капибары есть стратегии кеширования, среди многих других :) - person Evers; 27.08.2013
comment
Я собираюсь перейти на Ruby и пытаюсь решить, какую библиотеку использовать. Именно такие вещи заставляют думать, что я просто буду использовать Webdriver напрямую. Мне слишком нравится все контролировать, чтобы использовать что-то вроде Capybara. - person Robbie Wareham; 27.08.2013
comment
Я большой защитник Selenium Webdrivers, но я должен признать, что Capybara отлично подходит для ожидания элементов и т. Д. ... Позволяет вам сосредоточиться на своих тестах. - person Evers; 28.08.2013