Как заставить Capybara проверять видимость после запуска JS? - PullRequest
78 голосов
/ 10 января 2012

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

Мой интеграционный тест выглядит примерно так:

it "should not show the blah" do
    page.find('#blah').visible?.should be_true
end 

Когда я вручную перехожу на страницу в контексте этого теста, #blah не виден, как я ожидал. Я подозреваю, что Capybara просматривает начальное состояние страницы (в данном случае невидимое), оценивает состояние DOM и не проходит тест до запуска JS.

Да, я установил :js => true в блоке описания:)

Любые идеи будут с благодарностью! Я надеюсь, что мне не нужно помещать здесь преднамеренную задержку, которая кажется ненадежной и замедлит процесс.

Ответы [ 8 ]

124 голосов
/ 11 января 2012

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

Здесь, вы бы хотели, чтобы Capybara ожидала появления видимого элемента, что должно быть достигнуто путем указания параметра visible:

expect(page).to have_selector('#blah', visible: true)

Я не пробовал, но параметр конфигурации ignore_hidden_elements можетздесь также будет полезно, если вы хотите, чтобы find всегда ожидал видимых элементов.

35 голосов
/ 17 октября 2012

Это еще один способ сделать это, который прекрасно работает для меня:

find(:css, "#some_element").should be_visible

Специально для более сложных находок, таких как

find(:css, "#comment_stream_list li[data-id='#{@id3}']").should_not be_visible

, который утверждал бы, что элемент был скрыт.

20 голосов
/ 06 сентября 2012

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

Вот как это сделать:

# assert element is present, regardless of visibility
page.should have_css('#some_element', :visible => false)
# assert visible element is not present
page.should have_no_css('#some_element', :visible => true)
9 голосов
/ 03 апреля 2013

Использование:

 Ruby:     ruby 1.9.3dev (2011-09-23 revision 33323) [i686-linux]
 Rails:    3.2.9
 Capybara: 2.0.3

У меня есть приложение Rails, в котором есть ссылка, при нажатии на которую следует отправить почтовый запрос AJAX и вернуть ответ JS.

Код ссылки:

 link_to("Send Notification", notification_path(user_id: user_id), remote: true, method: :post)

Ответ JS (файл .js.haml) должен переключать следующий скрытый div на странице, на которой существует ссылка:

 #notification_status(style='display:none')

Содержимое файла js.haml:

:plain
  var notificationStatusContainer = $('#notification_status');
  notificationStatusContainer.val("#{@notification_status_msg}");
  notificationStatusContainer.show();

Я тестировал свой сценарий отправки уведомления и отображения сообщения о статусе уведомления пользователю с помощью Cucumber ( огуречный рельс с встроенной поддержкой Capybara )

Я пытался проверить, что элемент с идентификатором: messages_status был виден при успешном ответе в моем определении шага. Для этого я попробовал следующие утверждения:

page.find('#notification_status').should be_visible
page.should have_selector('#notification_status', visible: true)
page.should have_css('#notification_status', visible: true)
page.find('#notification_status', visible: true)
page.find(:css, 'div#notification_status', visible: true)

Ни один из перечисленных вышесработал для меня и провалил мой шаг. Из приведенных выше 5 фрагментов последние 4 завершились с ошибкой:

'expected to find css "#notification_status" but there were no matches. Also found "", which matched the selector but not all filters. (Capybara::ExpectationNotMet)'

, что было странно, потому что следующее утверждение проходило правильно:

page.has_selector?('#notification_status')

И на самом деле я проверил источник страницы, используя

  print page.html

, который обнаружил

<div style='' id='notification_status'></div>

, что и ожидалось.

Наконец я нашел эту ссылку Capybara Assert атрибуты элемента , который показал, как проверять атрибут элемента в необработанном виде.

Также я нашел в документации по Capybara для видимого?method (http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Element#visible%3F-instance_method) следующая информация:

 Not all drivers support CSS, so the result may be inaccurate.

Таким образом, я пришел к выводу, что при тестировании видимости элемента не следует полагаться на результаты метода visible? Capybara при использовании CSSСелектор и используя решение, предложенное в ссылке атрибуты asset capybara элемента

Я придумал следующее:

 module CustomMatchers
   def should_be_visible(css_selector)
    find(css_selector)['style'].should_not include('display:none', 'display: none')
   end
 end

 World(CustomMatchers)

Использование:

should_be_visible('#notification_status')
8 голосов

Что видимые средства не очевидны

Ошибка может быть вызвана неправильным пониманием того, что считается видимым или нет, поскольку оно неочевидно, не является переносимым драйвером и недостаточно документировано. Некоторые тесты:

HTML:

<div id="visible-empty"                                                                   ></div>
<div id="visible-empty-background"      style="width:10px; height:10px; background:black;"></div>
<div id="visible-empty-background-same" style="width:10px; height:10px; background:white;"></div>
<div id="visible-visibility-hidden"     style="visibility:hidden;"                        >a</div>
<div id="visible-display-none"          style="display:none;"                             >a</div>

Единственное, что тест Rack считает невидимым, это встроенный display: none (не внутренний CSS, поскольку он не выполняет селекторы):

!all('#visible-empty',                 visible: true).empty? or raise
!all('#visible-empty-background',      visible: true).empty? or raise
!all('#visible-empty-background-same', visible: true).empty? or raise
!all('#visible-visibiility-hidden',    visible: true).empty? or raise
 all('#visible-display-none',          visible: true).empty? or raise

Poltergeist имеет похожее поведение, но может иметь дело с внутренними CSS и Js style.display манипулирование:

Capybara.current_driver = :poltergeist
!all('#visible-empty',                 visible: true).empty? or raise
!all('#visible-empty-background',      visible: true).empty? or raise
!all('#visible-empty-background-same', visible: true).empty? or raise
!all('#visible-visibiility-hidden',    visible: true).empty? or raise
 all('#visible-display-none',          visible: true).empty? or raise

Селен ведет себя совершенно иначе: если считает пустой элемент невидимым и visibility-hidden, а также display: none:

Capybara.current_driver = :selenium
 all('#visible-empty',                 visible: true).empty? or raise
!all('#visible-empty-background',      visible: true).empty? or raise
!all('#visible-empty-background-same', visible: true).empty? or raise
 all('#visible-visibiility-hidden',    visible: true).empty? or raise
 all('#visible-display-none',          visible: true).empty? or raise

Другим распространенным уловом является значение по умолчанию visible:

  • Раньше было false (видит и видимых и невидимых элементов),
  • в настоящее время true
  • управляется опцией Capybara.ignore_hidden_elements.

Ссылка .

Полноценный тест на моем GitHub .

5 голосов
/ 28 июня 2012

Возможно, вы захотите посмотреть в этом посте , в котором приведен пример метода ожидания завершения всех запросов ajax:

def wait_for_ajax(timeout = Capybara.default_wait_time)
  page.wait_until(timeout) do
    page.evaluate_script 'jQuery.active == 0'
  end
end
2 голосов
/ 01 августа 2017

Принятый ответ немного устарел, так как синтаксис «следует» является устаревшим. В эти дни вам лучше делать что-то вроде expect(page).not_to have_css('#blah', visible: :hidden)

1 голос
/ 04 марта 2014

Другие ответы здесь - лучший способ «подождать» элемент.Однако я обнаружил, что это не работает для сайта, над которым я работаю.В основном элемент, который нужно было щелкнуть, был виден до полной загрузки функции, стоящей за ним.Это за доли секунды, но я обнаружил, что мой тест иногда проходил так быстро, что он нажимал кнопку, и ничего не происходило.Мне удалось обойти это, выполнив это логическое выражение make-shift:

if page.has_selector?('<css-that-appears-after-click>')
  puts ('<Some-message-you-want-printed-in-the-output>')
else
  find('<css-for-the-button-to-click-again>', :match == :first).trigger('click')
end

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

Снова я скажу, что сначала нужно попробовать метод should have_selector, но если он просто не работает, попробуйте это

...