Skip to content

Commit

Permalink
Add section about custom selectors to README
Browse files Browse the repository at this point in the history
  • Loading branch information
jnicklas committed Aug 27, 2010
1 parent d995bfb commit fed2c5b
Showing 1 changed file with 32 additions and 5 deletions.
37 changes: 32 additions & 5 deletions README.rdoc
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ For ultimate control, you can instantiate and use a session manually.
end end
session.click_link 'Sign in' 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, 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 if you want to use XPath with your 'within' declarations for example, you'll need
Expand All @@ -379,24 +379,51 @@ Alternatively you can set the default selector to XPath:
Capybara.default_selector = :xpath Capybara.default_selector = :xpath
find('//ul/li').text 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 == Beware the XPath // trap


In XPath the expression // means something very specific, and it might not be what 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 you think. Contrary to common belief, // means "anywhere in the document" not "anywhere
in the current context". As an example: 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 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 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": 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: The same thing goes for within:


within('//body') do within(:xpath, '//body') do
page.find('.//script') page.find(:xpath, './/script')
within(:xpath, './/table/tbody') do
...
end
end end


== Gotchas: == Gotchas:
Expand Down

0 comments on commit fed2c5b

Please sign in to comment.