Don't call #node on a Capybara element

Updated . Posted . Visible to the public.

Capybara allows you to select DOM elements, e.g. by using field, find_field(...) or field_labeled(...):

role_select = field_labeled('Role')

In the example above, role_select is now a Capybara::Driver::Node. You can call a number of methods on such a node, e. g. in order to click it or to make a selection on its descendants. These methods should be the same regardless of the driver Capybara is using (drivers are e.g. the headless Rack::Test or Selenium).

It is a stupid idea to call #node on such a Capybara node, as you see here:

selection = role_select.node.search(".//option[@selected = 'selected']")

Why is this stupid? Because #node returns the internal node representation used by the driver, e.g. instances Nokogiri::XML::Element if you are using Rack::Test, or of Selenium::WebDriver::Element if you are using Selenium. Because the API of these classes vary from driver to driver, the code above is now Rack::Test only and won't work with Selenium. Remember that the whole point of Capybara is to be able to switch out drivers without code changes.

If possible, don't call methods on #node and use the driver-independent Capybara API for everything. The example above should be written like this:

selection = role_select.find(:xpath, ".//option[@selected = 'selected']")

We're guilty of this in many of the step definitions we've posted. If you encounter such a piece of code, please rewrite it to be driver-neutral and update the note.

Henning Koch
Last edit
License
Source code in this card is licensed under the MIT License.
Posted by Henning Koch to makandra dev (2011-05-25 09:04)