Permalink
Browse files

adds filtering by custom criteria

  • Loading branch information...
1 parent 24ea982 commit d5140b4c47c983bacd213daad00774e7c51d7303 @dcuddeback committed Nov 12, 2011
Showing with 133 additions and 14 deletions.
  1. +38 −14 lib/rspec/tag_matchers/has_tag.rb
  2. +95 −0 spec/lib/rspec/tag_matchers/has_tag_spec.rb
@@ -9,24 +9,12 @@ class HasTag
def initialize(name)
@name = name.to_s
@attributes = {}
+ @criteria = []
end
def matches?(rendered)
Nokogiri::HTML::Document.parse(rendered).css(@name).select do |element|
- @attributes.all? do |key, value|
- case value
- when String
- element[key] == value
- when Symbol
- element[key] =~ /^#{value}$/i
- when Regexp
- element[key] =~ value
- when true
- !element[key].nil?
- when false
- element[key].nil?
- end
- end
+ matches_attributes?(element) && matches_criteria?(element)
end.length > 0
end
@@ -35,5 +23,41 @@ def with_attribute(attributes)
self
end
alias :with_attributes :with_attribute
+
+ def with_criteria(method = nil, &block)
+ @criteria << method unless method.nil?
+ @criteria << block if block_given?
+ self
+ end
+
+ private
+
+ def matches_attributes?(element)
+ @attributes.all? do |key, value|
+ case value
+ when String
+ element[key] == value
+ when Symbol
+ element[key] =~ /^#{value}$/i
+ when Regexp
+ element[key] =~ value
+ when true
+ !element[key].nil?
+ when false
+ element[key].nil?
+ end
+ end
+ end
+
+ def matches_criteria?(element)
+ @criteria.all? do |method|
+ case method
+ when Symbol
+ send(method, element)
+ when Proc
+ method.call(element)
+ end
+ end
+ end
end
end
@@ -176,4 +176,99 @@
end
end
end
+
+ describe "extra criteria" do
+ context "as symbol" do
+ context "have_tag(:foo).with_criteria(:custom_filter)" do
+ subject { have_tag(:foo).with_criteria(:custom_filter) }
+
+ it "should call custom_filter with Nokogiri::XML::Element as argument" do
+ HasTag.any_instance.should_receive(:custom_filter).with(an_instance_of(Nokogiri::XML::Element))
+ subject.matches?("<foo></foo>")
+ end
+
+ context "when custom_filter returns true" do
+ before { HasTag.any_instance.stub(:custom_filter) { true } }
+ it { should match("<foo></foo>") }
+ it { should_not match("<bar></bar>") }
+ end
+
+ context "when custom_filter returns false" do
+ before { HasTag.any_instance.stub(:custom_filter) { false } }
+ it { should_not match("<foo></foo>") }
+ it { should_not match("<bar></bar>") }
+ end
+ end
+ end
+
+ context "as block" do
+ context "have_tag(:foo).with_criteria { |element| ... }" do
+ let(:block) { Proc.new { |element| true } }
+ subject { have_tag(:foo).with_criteria(&block) }
+
+ it "should call the block with Nokogiri::XML::Element as argument" do
+ block.should_receive(:call).with(an_instance_of(Nokogiri::XML::Element))
+ subject.matches?("<foo></foo>")
+ end
+
+ context "when block returns true" do
+ before { block.stub(:call) { true } }
+ it { should match("<foo></foo>") }
+ it { should_not match("<bar></bar>") }
+ end
+
+ context "when block returns false" do
+ before { block.stub(:call) { false } }
+ it { should_not match("<foo></foo>") }
+ it { should_not match("<bar></bar>") }
+ end
+ end
+ end
+
+ context "multiple criteria" do
+ context "have_tag(:foo).with_criteria(:filter_1).with_criteria(:filter_2)" do
+ subject { have_tag(:foo).with_criteria(:filter_1).with_criteria(:filter_2) }
+
+ context "both filters return true" do
+ before do
+ HasTag.any_instance.stub(:filter_1) { true }
+ HasTag.any_instance.stub(:filter_2) { true }
+ end
+
+ it { should match("<foo></foo>") }
+ it { should_not match("<bar></bar>") }
+ end
+
+ context "filter_1 returns false" do
+ before do
+ HasTag.any_instance.stub(:filter_1) { false }
+ HasTag.any_instance.stub(:filter_2) { true }
+ end
+
+ it { should_not match("<foo></foo>") }
+ it { should_not match("<bar></bar>") }
+ end
+
+ context "filter_2 returns false" do
+ before do
+ HasTag.any_instance.stub(:filter_1) { true }
+ HasTag.any_instance.stub(:filter_2) { false }
+ end
+
+ it { should_not match("<foo></foo>") }
+ it { should_not match("<bar></bar>") }
+ end
+
+ context "both filters return false" do
+ before do
+ HasTag.any_instance.stub(:filter_1) { false }
+ HasTag.any_instance.stub(:filter_2) { false }
+ end
+
+ it { should_not match("<foo></foo>") }
+ it { should_not match("<bar></bar>") }
+ end
+ end
+ end
+ end
end

0 comments on commit d5140b4

Please sign in to comment.