Add with_count support to have_tag #3

Merged
merged 4 commits into from Mar 24, 2012
@@ -130,9 +130,10 @@ def negative_failure_message
# @return [Boolean]
def matches?(rendered)
@rendered = rendered
- Nokogiri::HTML::Document.parse(@rendered.to_s).css(@name).select do |element|
+ matches = Nokogiri::HTML::Document.parse(@rendered.to_s).css(@name).select do |element|
matches_attributes?(element) && matches_criteria?(element)
- end.length > 0
+ end
+ return matches_count?(matches)
end
# Adds a constraint that the matched elements must match certain attributes. The +attributes+
@@ -174,6 +175,19 @@ def with_criteria(method = nil, &block)
self
end
+ # Adds a constraint that the matched elements appear a given number of times. The criteria must be a Fixnum
+ #
+ # @example
+ # have_div.with_count(2)
+ #
+ # @param [Fixnum] method The name of the method to be called.
+ #
+ # @return [self]
+ def with_count(count)
+ @count = count
+ self
+ end
+
protected
# Tests with +attribute+ matches +expected+ according the the attribute matching rules described
@@ -240,11 +254,20 @@ def matches_criteria?(element)
end
end
+ # Answers whether or not +element+ appears the number of times set by {#with_count}.
+ #
+ # @param [[Nokogiri::XML::Node]] matches The matched elements to be tested.
+ #
+ # @return [Boolean]
+ def matches_count?(matches)
+ true if (@count.nil? && matches.length > 0) || matches.length == @count
+ end
+
# Provides extra description that can be appended to the basic description.
#
# @return [String]
def extra_description
- attributes_description
+ attributes_description + count_description
end
# Returns a description of the attribute criteria. For example, the description of an attribute
@@ -272,7 +295,7 @@ def attributes_description
)
end
- # Provides a prefix that can be used before a list of attribute criteria. Possible oututs are
+ # Provides a prefix that can be used before a list of attribute criteria. Possible outputs are
# <tt>"with attribute"</tt>, <tt>"with attributes"</tt>, <tt>"without attribute"</tt>, and
# <tt>"without attributes"</tt>.
#
@@ -319,5 +342,18 @@ def attribute_description(key, value)
"#{key}=#{value.inspect}"
end
end
+
+ # Returns a string describing the number of times the element must be matched.
+ # For example, the description of an attribute criteria of <tt>with_count(2)</tt> will look like
+ # <tt>'2 times'</tt>.
+ #
+ #
+ # @return [String]
+ def count_description
+ if @count
+ return "#{@count} times"
+ end
+ ""
+ end
end
end
@@ -292,6 +292,15 @@
end
end
+ describe "count matching" do
+ context "with count matcher" do
+ subject { have_tag(:foo).with_count(2) }
+ it { should match("<foo></foo><foo></foo>") }
+ it { should_not match("<foo></foo>") }
+ it { should_not match("<foo></foo><foo></foo><foo></foo>") }
+ end
+ end
+
describe "#description" do
context "for simple matchers" do
context "have_tag(:foo)" do
@@ -346,6 +355,11 @@
its(:description) { should == 'have "foo" tag with attribute bar=anything and without attribute baz' }
end
end
+
+ context "for matchers with count criteria" do
+ subject { have_tag(:foo).with_count(2) }
+ its(:description) { should == 'have "foo" tag 2 times'}
+ end
end
describe "#failure_message" do