Как получить родительский узел в Capybara?

Я работаю со многими плагинами jQuery, которые часто создают элементы DOM без идентификатора или других идентификационных свойств, и единственный способ получить их в Capybara (например, для щелчка) - это сначала получить их соседа (еще один ребенок его предка) . Но я нигде не нашел, поддерживает ли Capybara такие вещи, например:

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

?


person sandrew    schedule 01.02.2011    source источник
comment
Также мне будет очень полезно, если вы скажете, генерирует ли Capybara клик по элементам с { display: hidden }, и есть ли способ найти элементы в какой-то области видимости, где display != hidden ?   -  person sandrew    schedule 01.02.2011
comment
Это отдельный вопрос, но он зависит от используемого вами драйвера. webrat с радостью найдет спрятанные вещи, но селен не так рад нажимать на элементы, которые вы не видите.   -  person jamuraa    schedule 01.02.2011


Ответы (9)


Я действительно нашел ответ jamuraa полезным, но переход на полный xpath вызвал у меня кошмар со строкой в ​​моем случае, поэтому я с радостью воспользовался возможностью конкатенации find в Capybara, что позволило мне смешивать выбор css и xpath. Тогда ваш пример будет выглядеть так:

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

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

person Pascal Lindelauf    schedule 07.07.2011
comment
Спасибо за идею - я бы никогда не подумал об этом! Я делал el.parent для элемента td, который нашел с помощью find(:css), но по какой-то причине я не понимаю, el.parent возвращал #‹Capybara::Document›. el.find(:xpath,.//..), с другой стороны, возвращает #‹Capybara::Element tag=tr›, что мне и было нужно. - person Tyler Rick; 07.12.2011
comment
Другой способ рекурсивно найти определенный родительский узел — использовать селектор предка или себя в xpath. Проверьте это stackoverflow.com/questions/1362466/ - person vrish88; 08.05.2012
comment
Вам не нужно .//.., чтобы найти родителя — достаточно только .., и это также никогда не бывает двусмысленным. - person Eamon Nerbonne; 02.08.2013
comment
ты! Я знаю, что этот комментарий немного опоздал на вечеринку, но я сократил его до следующего после прочтения редактирования и комментария Имона: el.first(:xpath, '..') - person aschyiel; 05.09.2014

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

find(:xpath, '//*[@id="some_button"]/..').fill_in "Name:", :with => name
person jamuraa    schedule 01.02.2011
comment
Когда я делаю аналогичный поиск xpath, я получаю ошибку Nokogiri, говорящую, что выражение недействительно. Я добавил звездочку перед открытой квадратной скобкой в ​​выражении, чтобы исправить выражение: find(:xpath, '//*[@id="some_button"]/..') - person Andrew Ferk; 29.06.2012

Я нашел следующее, что работает:

find(:xpath, '..')

Capybara была обновлена, чтобы поддерживать это.

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

person B Seven    schedule 16.08.2012
comment
Мне кажется, что вы отвечаете/дополняете предыдущий ответ здесь (это то, что не сработало?). Лучше бы это был полный и независимый ответ. Так что рекомендую отредактировать. ;-) - person helenov; 19.10.2016
comment
Могу подтвердить. В последней версии Capybara 2.14.4 это правильный способ получить родительский узел. - person fny; 25.07.2017

Если вы наткнулись на это, пытаясь выяснить, как найти любой родительский (как в ancestor) узел (как намекается в комментарии @vrish88 к ответу @Pascal Lindelauf):

find('#some_button').find(:xpath, 'ancestor::div[@id="some_div_id"]')
person Ben Alavi    schedule 08.01.2014

Этот ответ относится к тому, как манипулировать родственным элементом, на что, как я полагаю, намекает исходный вопрос

Гипотеза вашего вопроса работает с небольшой поправкой. Если динамически сгенерированное поле выглядит так и не имеет идентификатора:

<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')

Надеюсь, это поможет.

person T. Slater    schedule 08.03.2016

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

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

Может быть, это полезно в похожей ситуации.

person Harm de Wit    schedule 25.04.2012
comment
Это отличный вариант. Распространение действия пользовательского интерфейса на часть страницы, содержащую определенный текст, является для меня распространенным вариантом использования. - person clemensp; 04.04.2016

Мне нужно было найти предка с классом 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

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

person kross    schedule 06.11.2014
comment
Ускорение: замените второй перерыв на break if ancestor[:class].split(" ").include?(css_class). - person hakunin; 12.11.2015
comment
@hakunin Мне любопытно, какое ускорение вы видите? Значительный? - person kross; 12.11.2015
comment
Не могу проверить сейчас, но has_css, казалось, занял секунду, в то время как сопоставление класса казалось немедленным. - person hakunin; 14.11.2015
comment
Capybara теперь имеет встроенный метод ancestor(selector). а> - person Tyler Rick; 17.07.2019

Как упоминалось в комментарии @Tyler Rick Capybara, в наши дни есть методы [ ancestor(selector) и sibling(selector)

person Foton    schedule 09.03.2021

Вот

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

Присутствует родительский метод;)

person Dmitriy Konovalov    schedule 30.01.2013
comment
Это возвращает мне только документ верхнего уровня. Не уверен, что это проблема с драйверами или что. - person Nerdmaster; 28.03.2013
comment
Читая документы, похоже, что это может означать родителя фрейма, а не родителя элемента? - person Nick; 02.09.2013