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
Ruby SASS, Unable to Resolve Dependancies
Get SASS from Database (Compile Passed Data Instead of Reading from File)
How to Input Integer Value to an Array, Based Preceeding Row + Column Values
How to Make :Level Change Based on :Committed Days
How to Use Same Terminal Window After Using "Rails Server" Command
Cannot Click HTML Element with Watir
Understanding the Fibonacci Sequence
Bundler VS Rvm VS Gems VS Rubygems VS Gemsets VS System Ruby
Convert String to Symbol-Able in Ruby
Advantage of Tap Method in Ruby
Will Uuid as Primary Key in Postgresql Give Bad Index Performance
Having Trouble Installing Any Ruby 1.9.X (With Rbenv) on MAC Osx Due to Psych Yaml Parse Errors
Open_Id_Authentication - "Openidauthentication.Store Is Nil. Using In-Memory Store." Problem
Rails Email Error - 530-5.5.1 Authentication Required
How to Use Ruby Dbi's 'Select_All' VS 'Execute-Fetch/Each-Finish'