Permalink
Browse files

Add section about custom selectors to README

  • Loading branch information...
1 parent d995bfb commit fed2c5ba9481e88c67e376093d1db999e4186e22 @jnicklas jnicklas committed Aug 27, 2010
Showing with 32 additions and 5 deletions.
  1. +32 −5 README.rdoc
View
@@ -364,7 +364,7 @@ For ultimate control, you can instantiate and use a session manually.
end
session.click_link 'Sign in'
-== XPath and CSS
+== XPath, CSS and selectors
Capybara does not try to guess what kind of selector you are going to give it,
if you want to use XPath with your 'within' declarations for example, you'll need
@@ -379,24 +379,51 @@ Alternatively you can set the default selector to XPath:
Capybara.default_selector = :xpath
find('//ul/li').text
+Capybara allows you to add custom selectors, which can be very useful if you
+find yourself using the same kinds of selectors very often:
+
+ Capybara::Selector.add(:id) { |id| XPath.descendant[XPath.attr(:id) == id.to_s] }
+ Capybara::Selector.add(:row) { |num| ".//tbody/tr[#{num}]" }
+
+These must always return an XPath expression as a String, or an XPath expression
+generated through the XPath gem. You can now use these selectors like this:
+
+ find(:id, 'post_123')
+ find(:row, 3)
+
+You can specify an optional :for option which will automatically use the
+selector if it matches the argument to find using ===:
+
+ Capybara::Selector.add(:id, :for => Symbol) { |id| XPath.descendant[XPath.attr(:id) == id.to_s] }
+
+Now use it like this:
+
+ find(:post_123)
+
+This :id selector is already built into Capybara by default, so you don't
+need to add it yourself.
+
== Beware the XPath // trap
In XPath the expression // means something very specific, and it might not be what
you think. Contrary to common belief, // means "anywhere in the document" not "anywhere
in the current context". As an example:
- page.find('//body').all('//script')
+ page.find(:xpath, '//body').all(:xpath, '//script')
You might expect this to find all script tags in the body, but actually, it finds all
script tags in the entire document, not only those in the body! What you're looking
for is the .// expression which means "any descendant of the current node":
- page.find('//body').all('.//script')
+ page.find(:xpath, '//body').all(:xpath, './/script')
The same thing goes for within:
- within('//body') do
- page.find('.//script')
+ within(:xpath, '//body') do
+ page.find(:xpath, './/script')
+ within(:xpath, './/table/tbody') do
+ ...
+ end
end
== Gotchas:

0 comments on commit fed2c5b

Please sign in to comment.