Як отримати батьківський вузол у Capybara?


85

Я працюю з багатьма плагінами jQuery, які часто створюють елементи DOM без ідентифікатора чи інших властивостей ідентифікації, і єдиний спосіб отримати їх у Capybara (наприклад, для натискання) - це отримати спочатку свого сусіда (іншу дочку свого предка) . Але я ніде не знайшов, чи підтримує Капібара такі речі, наприклад:

find('#some_button').parent.fill_in "Name:", :with => name

?


Крім того, це буде дуже корисно для мене, якщо ви скажете, чи генерує Capybara клацання на елементи з {display: hidden}, і чи є спосіб знайти елементи в якомусь обсязі, де display! = Hidden?
sandrew

Це окреме питання, але це залежить від драйвера, який ви використовуєте. webrat з радістю знайде приховані речі, але селен не так радий натискати елементи, які ви не можете побачити.
jamuraa

Відповіді:


111

Я дійсно знайшов відповідь Jamuraa корисним, але проходження повного xpath дало мені страшний сон у моєму випадку, тому я із задоволенням скористався можливістю об'єднати знахідки в Capybara, дозволивши мені поєднати вибір css та xpath. Тоді ваш приклад виглядатиме так:

find('#some_button').find(:xpath,".//..").fill_in "Name:", :with => name

Оновлення Capybara 2.0 : find(:xpath,".//..")найімовірніше, призведе до Ambiguous matchпомилки. У такому випадку використовуйте first(:xpath,".//..")замість цього.


Дякую за цю ідею - я б ніколи про це не думав! Я робив el.parent для елемента td, який знайшов за допомогою find (: css), але з якихось причин я не розумію, el.parent повертав # <Capybara :: Document>. el.find (: xpath, ".// .."), з іншого боку, повертає # <Capybara :: Element tag = "tr">, що саме мені потрібно.
Тайлер Рік,

Інший спосіб рекурсивного пошуку певного батьківського вузла - за допомогою селектора xpath-предка або самостійно. Перевірте це stackoverflow.com/questions/1362466 / ...
vrish88

25
Вам не потрібно .//..знаходити батька - ..достатньо, і це теж ніколи не є двозначним.
Імон Нербонн

ти! Я знаю, що цей коментар трохи запізнився на вечірці, але я звів його до наступного після прочитання редакції та коментаря Імона: el.first (: xpath, '..')
aschyiel

39

Неможливо це зробити за допомогою капібари та CSS. Раніше я використовував XPath для досягнення цієї мети, яка має спосіб отримати батьківський елемент і підтримується Capybara:

find(:xpath, '//*[@id="some_button"]/..').fill_in "Name:", :with => name

2
Коли я роблю подібний пошук xpath, я отримую повідомлення про помилку Нокогірі, що вираз є недійсним. Я додав зірочку перед відкритим квадратним дужкою у вираз, щоб зафіксувати вираз:find(:xpath, '//*[@id="some_button"]/..')
Ендрю Ферк,

35

Я виявив наступне, що працює:

find(:xpath, '..')

Для підтримки цього оновлено програму Capybara.

https://github.com/jnicklas/capybara/pull/505


1
Мені здається, ви відповідаєте / заповнюєте попередню відповідь тут ("Це" що "не спрацювало"?). Було б краще, якби це була повна і незалежна відповідь. Тому я рекомендую вам відредагувати його. ;-)
helenov

Може підтвердити. З останньою версією Capybara 2.14.4 це правильний спосіб отримати батьківський вузол.
fny

10

Якщо ви натрапили на це, намагаючись зрозуміти, як знайти будь-який батьківський вузол (як у предка ) (як натякнуто в коментарі @ vrish88 до відповіді @Pascal Lindelauf):

find('#some_button').find(:xpath, 'ancestor::div[@id="some_div_id"]')

5

Ця відповідь стосується того, як маніпулювати елементом брата або сестри, на що, на мою думку, натякає вихідне питання

Гіпотеза вашого запитання працює з незначним допрацюванням. Якщо динамічно сформоване поле виглядає так і не має ідентифікатора:

<div>
  <input></input>
  <button>Test</button>
</div>

Тоді ваш запит буде таким:

find('button', text: 'Test').find(:xpath, "..").find('input').set('whatever')

Якщо динамічно згенерований вхід приєднується з елементом id (будьте обережні з ними, хоча, як і в angular, вони зазвичай не змінюються на основі додавання та видалення елементів), це буде приблизно так:

find('button', text: 'Test').find(:xpath, "..").fill_in('#input_1', with: 'whatever')

Сподіваюся, це допомагає.


4

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

find("<parent element>", text: "text within your #some_button").fill_in "Name:", with: name

Можливо, це корисно в подібній ситуації.


1
Це чудовий варіант. Поширення дії інтерфейсу користувача на частину сторінки, яка містить певний текст, є для мене звичним випадком використання.
clemensp

2

Мені потрібно було знайти предка з класом css, хоча він був невизначений, якщо у цільового предка був присутній один або кілька класів css, тому я не бачив способу зробити детермінований запит xpath. Я замість цього працював над цим:

def find_ancestor_with_class(field, cssClass)
  ancestor = field
  loop do
    ancestor = ancestor.find(:xpath, '..')
    break if ancestor.nil?

    break if ancestor.has_css? cssClass
  end

  ancestor
end

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


Прискорення: замініть свою другу перерву на break if ancestor[:class].split(" ").include?(css_class).
хакунін

@hakunin Мені цікаво, скільки прискорення ти бачиш? Значний?
kross

Не вдається перевірити зараз, але has_css, здається, зайняв секунду, тоді як збіг класу здався негайним.
хакунін

Capybara тепер має ancestor(selector)вбудований метод. Див. Github.com/teamcapybara/capybara/commit/…
Тайлер Рік,

-5

Ось

http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Base:parent

Існує батьківський метод;)


5
Це повертає лише документ верхнього рівня для мене. Не впевнений, чи це проблема драйвера, чи що.
Nerdmaster 28.03.13

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