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


82

Після завантаження сторінки у мене є код, який запускається, приховує та показує різні елементи на основі даних, повернутих xhr.

Мій інтеграційний тест виглядає приблизно так:

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

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

Так, я встановив відповідний :js => trueблок опису :)

Будь-які ідеї будуть вдячні! Я сподіваюся, що мені не доведеться навмисно затримувати тут, що відчуває себе нестабільним і сповільнює ситуацію.


1
Що таке драйвер? Який очікуваний HTML після закінчення XHR?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Відповіді:


132

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

Тут ви хотіли б, щоб Capybara дочекався появи видимого елемента, що має бути досяжним, вказавши visibleопцію:

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

Я не пробував, але ignore_hidden_elementsопція конфігурації також може бути тут корисною, якщо ви хочете findзавжди чекати видимих ​​елементів.


6
у випадку, якщо хтось спочатку пропустив примітку @ Кевіна (як я), ви повинні мати js:trueна блоці, що містить, щоб це працювало.
Кріс Бек,

3
Це круто. Це допомогло мені дістатися до: expect(page).to have_selector('#flash-message', visible: false, text: "Signed in Successfully")- спасибі за розміщення цієї відповіді
Чак Бержерон

Параметр видимості не вплинув на мене при тестуванні видимості елемента слайда jquery. Мені довелося використовувати awa (find ('# blah'). Visible?). To be_falsey.
trueinViso

Я хочу щось на зразок is_visible? тоді робіть це ще робіть щось інше
user1735921

37

Це ще один спосіб зробити це, який для мене прекрасно працює:

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

Особливо для більш складних знахідок, таких як

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

що може стверджувати, що елемент прихований.


1
should_not be_visibleЧи не виглядає добре для мене , як Capybara перспектива , wait_until { base.visible? }коли елемент # видимі? викликається.
Phương Nguyễn

1
@ phng-nguyn, #wait_until було видалено з останніх версій Capybara.
solidcell

3
Це насправді кращий варіант, ніж "page.should have_selector ...", оскільки у випадку, якщо текст, що не вдається, це буде сказати, що елемент насправді явно невидимий, тоді як згаданий варіант просто викликає помилку "не було збігів" , це трохи засмучує.
installero

Це не те саме, що прийняте рішення. Для цього коду Capybara буде лише чекати, поки елемент опиниться в DOM, а потім негайно перевірити видимість. Якщо ви очікуєте, що видимість зміниться, це може додати специфікації умову перегонів.
johncip

1
Хтось знає, чи .should_not be_visibleобкладинки display: noneвстановлені jQuery? Здається, це не працює для мене.
Антрикший

20

Якщо ви хочете перевірити, чи є елемент на сторінці, але його не видно, 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)

1
Не можна використовувати should_notз капібарою через аякс
Марк-Андре Лафортун

@ Marc-AndréLafortune, для тестування ajax за допомогою капібари використовуйте Capybara.javascript_driver.
Zubin

1
з javascript_drive, have_cssбуде чекати весь час вашого очікування, перш ніж відмовлятись, оскільки він очікує знайти елемент. Наприклад, ви повинні використовувати should have_no_contentзамість should_not have_content.
Marc-André Lafortune

1
expect(page).not_to have_selector("#some_element", visible: true)добре працював у мене javascript_driver, не чекаючи весь час очікування.
Jason Swett

1
Власне, з мого коментаря це було змінено, і ви можете (і повинні) використовувати should_notзараз, вибачте!
Marc-André Lafortune

9

Використання:

 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();

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

Я намагався перевірити, що елемент, що має ідентифікатор: message_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 утвердження атрибутів елемента, яке показало, як перевірити атрибут елемента в необробленому вигляді.

Також я знайшов у документації 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 елемента

Я придумав наступне:

 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 має подібну поведінку, але він може мати справу з внутрішніми style.displayманіпуляціями CSS та Js :

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 .


1
Чудова відповідь - дякую за ваші зусилля, які ви доклали до цього. Тестування видимості елементів у наборі за допомогою декількох драйверів є нетривіальним.
Енді Триггс,

1
"раніше воно було помилковим (бачить як видимі, так і невидимі елементи), в даний час є істинним і управляється параметром Capybara.ignore_hidden_elements." Перегляньте цю публікацію в блозі для отримання додаткової інформації: elabs.se/blog/60-introducing-capybara-2-1
rizidoro

5

Можливо, ви захочете подивитися цю публікацію , в якій наведено зразок методу очікування, поки не будуть завершені всі запити ajax:

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

5
Це рішення не сумісне в майбутньому, оскільки його wait_untilбуло видалено з Capybara 2 .
parhamr

1
ВикористанняTimeout.timeout
Ian Vaughan

Краще використанняSelenium::WebDriver::Wait
Накілон

якщо ви використовуєте лише селен
Микола Кондратенко

2

Прийнята відповідь трохи застаріла, оскільки синтаксис "повинен" є застарілим. У ці дні вам було б краще зробити щось подібнеexpect(page).not_to have_css('#blah', visible: :hidden)


1

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.