How to Get Parent Node in Capybara

How to get parent node in Capybara?

I really found jamuraa's answer helpful, but going for full xpath gave me a nightmare of a string in my case, so I happily made use of the ability to concatenate find's in Capybara, allowing me to mix css and xpath selection. Your example would then look like this:

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

Capybara 2.0 update: find(:xpath,".//..") will most likely result in an Ambiguous match error. In that case, use first(:xpath,".//..") instead.

How to get parent node in Capybara?

I really found jamuraa's answer helpful, but going for full xpath gave me a nightmare of a string in my case, so I happily made use of the ability to concatenate find's in Capybara, allowing me to mix css and xpath selection. Your example would then look like this:

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

Capybara 2.0 update: find(:xpath,".//..") will most likely result in an Ambiguous match error. In that case, use first(:xpath,".//..") instead.

Capybara: Use find to find elements on first level

You can look for direct children > of the element

css: "#parentdiv > div"

Traverse the tree with Capybara

After having a bit of a play with capybara it looks as if the parent method returns the whole html document

e = find "table > thead"
=> #<Capybara::Element tag="thead">
e.parent
=> #<Capybara::Document>

The default selector type for capybara is CSS and that does not support the parent selector
It may be worth looking at XPath as with XPath you can perform a contains

e = find :xpath, "//table[thead]"
=> #<Capybara::Element tag="table">

e = find :xpath, "//table[thead]", text: "TOTAL"
=> #<Capybara::Element tag="table">

So looking at your code you could try this:

e = find :xpath, "//tr[td[contains(text(),'Bob Perkins')]]"
=> #<Capybara::Element tag="tr">

OR

e = find :xpath, "//tr[td]", text: 'Bob Perkins'
=> #<Capybara::Element tag="tr">

So you should get something like this

within find(:xpath, "//tr[td[contains(text(),'Bob Perkins')]]") do
click_link_or_button("Change Role")
end

Best of luck.

How can I find a certain element that comes right after another element with Capybara?

CSS

In CSS you could use a sibling selector. These allow you to select sibling elements; or those at the same nesting level and with the same parent element. There are two types of sibling selectors:

  • '+' the adjacent sibling selector
  • '~' the general sibling selector (adjacent or non-adjacent siblings)

It's usually ideal to avoid matching by text whenever possible. (This makes your specs easier to write and also means that textual changes are less likely to break your specs.) In that ideal world your 'h3' elements might have IDs on them and we could just:

find('h3#name2+table')

However, in your example they don't have IDs so let's connect a couple of queries to scope to what we want.

find('h3', text: 'Name2').find('+table')

First we found the correct 'h3' element (using text matching) and then with that query as a basis we request the sibling 'table' element.

You may also note that if you used the general sibling selector '~' you would get an ambiguous element error; Capybara found all the 'table' elements rather than just the adjacent one.

XPath

Sometimes XPath is actually easier to use if you're really forced to do textual element selection. So you could instead:

find(:xpath, "//h3[contains(text(),'Name2')]/following-sibling::table")

More difficult to read but does the same thing. First find an 'h3' with text 'Name2' and then select it's sibling 'table' element.

List child elements for a Capybara/Poltergeist element

I figured this out. The test was working fine, but I was missing an action step in my scenario.

However, I thought y'all might find it useful to know how I ended up getting the contents: executing jQuery on the page. I added a binding.pry to my test, and then in the binding.pry I console logged a jQuery result, e.g.:

# this gave me the expected contents and verified that button.delete was a child
page.execute_script("console.log($('#myform label.question').parent().html())");

# and this gave me the classes to demonstrate that it was the correct div
page.execute_script("console.log($('#myform label.question').parent().attr('class'))");

I took a shortcut with the selectors because I knew that the label I was looking for was the first one, but the selector doesn't matter, it's the idea of console.log()-ing jQuery in binding.pry that was useful.



Related Topics



Leave a reply



Submit