Navigation Menu

Skip to content

Commit

Permalink
changed Selector API. Now more like RSpec matchers
Browse files Browse the repository at this point in the history
  • Loading branch information
jnicklas committed Oct 22, 2010
1 parent 8b4857d commit b13e4d3
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 21 deletions.
23 changes: 16 additions & 7 deletions README.rdoc
Expand Up @@ -382,19 +382,28 @@ Alternatively you can set the default selector to XPath:
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}]" }
Capybara.add_selector(:id) do
xpath { |id| XPath.descendant[XPath.attr(:id) == id.to_s] }
end

Capybara.add_selector(:row) do
xpath { |num| ".//tbody/tr[#{num}]" }
end

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:
The block given to xpath 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 ===:
You can specify an optional match option which will automatically use the
selector if it matches the argument:

Capybara::Selector.add(:id, :for => Symbol) { |id| XPath.descendant[XPath.attr(:id) == id.to_s] }
Capybara.add_selector(:id) do
xpath { |id| XPath.descendant[XPath.attr(:id) == id.to_s] }
match { |value| value.is_a?(Symbol) }
end

Now use it like this:

Expand Down
4 changes: 4 additions & 0 deletions lib/capybara.rb
Expand Up @@ -64,6 +64,10 @@ def register_driver(name, &block)
drivers[name] = block
end

def add_selector(name, &block)
Capybara::Selector.add(name, &block)
end

def drivers
@drivers ||= {}
end
Expand Down
40 changes: 29 additions & 11 deletions lib/capybara/selector.rb
@@ -1,14 +1,14 @@
module Capybara
class Selector
attr_reader :name, :options, :block
attr_reader :name

class << self
def all
@selectors ||= {}
end

def add(name, options={}, &block)
all[name.to_sym] = Capybara::Selector.new(name.to_sym, options, &block)
def add(name, &block)
all[name.to_sym] = Capybara::Selector.new(name.to_sym, &block)
end

def remove(name)
Expand All @@ -31,22 +31,40 @@ def normalize(name_or_locator, locator=nil)
end
end

def initialize(name, options={}, &block)
def initialize(name, &block)
@name = name
@options = options
@block = block
instance_eval(&block)
end

def xpath(&block)
@xpath = block if block
@xpath
end

def match(&block)
@match = block if block
@match
end

def call(locator)
@block.call(locator)
@xpath.call(locator)
end

def match?(locator)
@options[:for] and @options[:for] === locator
@match and @match.call(locator)
end
end
end

Capybara::Selector.add(:xpath) { |xpath| xpath }
Capybara::Selector.add(:css) { |css| XPath.css(css) }
Capybara::Selector.add(:id, :for => Symbol) { |id| XPath.descendant[XPath.attr(:id) == id.to_s] }
Capybara.add_selector(:xpath) do
xpath { |xpath| xpath }
end

Capybara.add_selector(:css) do
xpath { |css| XPath.css(css) }
end

Capybara.add_selector(:id) do
xpath { |id| XPath.descendant[XPath.attr(:id) == id.to_s] }
match { |value| value.is_a?(Symbol) }
end
11 changes: 8 additions & 3 deletions lib/capybara/spec/session/find_spec.rb
Expand Up @@ -64,15 +64,20 @@

context "with custom selector" do
it "should use the custom selector" do
Capybara::Selector.add(:monkey) { |name| ".//*[@id='#{name}_monkey']" }
Capybara.add_selector(:monkey) do
xpath { |name| ".//*[@id='#{name}_monkey']" }
end
@session.find(:monkey, 'john').text.should == 'Monkey John'
@session.find(:monkey, 'paul').text.should == 'Monkey Paul'
end
end

context "with custom selector with :for option" do
it "should use the selector when it matches the :for option" do
Capybara::Selector.add(:monkey, :for => Fixnum) { |num| ".//*[contains(@id, 'monkey')][#{num}]" }
Capybara.add_selector(:monkey) do
xpath { |num| ".//*[contains(@id, 'monkey')][#{num}]" }
match { |value| value.is_a?(Fixnum) }
end
@session.find(:monkey, '2').text.should == 'Monkey Paul'
@session.find(1).text.should == 'Monkey John'
@session.find(2).text.should == 'Monkey Paul'
Expand Down Expand Up @@ -115,7 +120,7 @@
it "should find the first element using the given locator" do
@session.within(:xpath, "//div[@id='for_bar']") do
@session.find('.//li').text.should =~ /With Simple HTML/
end
end
end
end
end
Expand Down

0 comments on commit b13e4d3

Please sign in to comment.