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


85

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

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

?


Также мне будет очень полезно, если вы скажете, генерирует ли Capybara клики по элементам с помощью {display: hidden}, и есть ли способ найти элементы в некоторой области, где display! = Hidden?
Sandrew 01

Это отдельный вопрос, но он зависит от используемого вами драйвера. webrat с радостью найдет скрытые вещи, но селен не так рад нажимать на предметы, которые вы не видите.
jamuraa 01

Ответы:


111

Я действительно нашел ответ 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,".//..")вместо этого.


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

Другой способ рекурсивно найти определенный родительский узел - использовать селектор xpath-предка или себя. Проверьте это stackoverflow.com/questions/1362466/…
vrish88

25
Вам не нужно .//..искать родителя - ..достаточно, и это тоже никогда не будет двусмысленным.
Eamon Nerbonne 02

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

39

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

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

2
Когда я делаю аналогичный поиск xpath, я получаю сообщение об ошибке Nokogiri, в котором говорится, что выражение недействительно. Я добавил звездочку перед открытой квадратной скобкой в ​​выражении, чтобы исправить выражение: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

@hakunin Мне любопытно, какое ускорение вы видите? Значительное?
kross

Не могу сейчас проверить, но has_css, похоже, занял секунду, а сопоставление класса казалось немедленным.
hakunin

Capybara теперь имеет встроенный ancestor(selector)метод. См. Github.com/teamcapybara/capybara/commit/ ...
Тайлер Рик

-5

Вот

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

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


5
Это возвращает мне только документ верхнего уровня. Не уверен, проблема в драйвере или что-то в этом роде.
Nerdmaster

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