it-swarm.com.ru

Как заставить Capybara проверять видимость после запуска JS?

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

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

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

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

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

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

78
Kevin Davis

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

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

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

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

124
Jon M

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

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

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

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

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

35
Björn Grossmann

Если вы хотите проверить, что элемент находится на странице, но не виден, 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)
20
Zubin

С помощью:

 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 ( cucumber-Rails gem со встроенной поддержкой Capybara )

Я пытался проверить, что элемент с идентификатором: tification_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>

что и следовало ожидать.

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

Также я нашел в документации по Capybara для видимых? метод ( 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.

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

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

 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')
9
Jignesh Gohel

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

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

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

Selenium ведет себя совершенно иначе: if считает пустой элемент невидимым и 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 .

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

def wait_for_ajax(timeout = Capybara.default_wait_time)
  page.wait_until(timeout) do
    page.evaluate_script 'jQuery.active == 0'
  end
end
5
smallsense

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

2
Alex Foxleigh

Другие ответы здесь - лучший способ "подождать" элемента. Однако я обнаружил, что это не работает для сайта, над которым я работаю. В основном элемент, который нужно было щелкнуть, был виден до полной загрузки функции, стоящей за ним. Это за доли секунды, но я обнаружил, что мой тест иногда проходил так быстро, что он нажимал кнопку, и ничего не происходило. Мне удалось обойти это, выполнив логическое выражение 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, но если он просто не работает, попробуйте это

1
Dono