Restore support for nested have_xpath, etc. with blocks

This commit is contained in:
Bryan Helmkamp 2008-11-08 21:34:46 -05:00
parent 055bd568f5
commit 0aad32d38a
5 changed files with 119 additions and 25 deletions

View File

@ -30,8 +30,8 @@ module Webrat
# HaveSelector:: A new have selector matcher. # HaveSelector:: A new have selector matcher.
# --- # ---
# @api public # @api public
def have_selector(expected) def have_selector(expected, &block)
HaveSelector.new(expected) HaveSelector.new(expected, &block)
end end
alias_method :match_selector, :have_selector alias_method :match_selector, :have_selector

View File

@ -49,8 +49,8 @@ module Webrat
end end
def have_tag(name, attributes = {}) def have_tag(name, attributes = {}, &block)
HaveTag.new([name, attributes]) HaveTag.new([name, attributes], &block)
end end
alias_method :match_tag, :have_tag alias_method :match_tag, :have_tag

View File

@ -16,17 +16,31 @@ module Webrat
end end
def matches_rexml?(stringlike) def matches_rexml?(stringlike)
@query = query
@document = rexml_document(stringlike) @document = rexml_document(stringlike)
query.all? do |q| matched = @query.map do |q|
matched = REXML::XPath.match(@document, q) if @document.is_a?(Array)
matched.any? && (!block_given? || matched.all?(&@block)) @document.map { |d| REXML::XPath.match(d, q) }
else
REXML::XPath.match(@document, q)
end end
end.flatten.compact
matched.any? && (!@block || @block.call(matched))
end end
def matches_nokogiri?(stringlike) def matches_nokogiri?(stringlike)
if Nokogiri::XML::NodeSet === stringlike
@query = query.map { |q| q.gsub(%r'//', './') }
else
@query = query
end
@document = Webrat.nokogiri_document(stringlike) @document = Webrat.nokogiri_document(stringlike)
@document.xpath(*query).any? matched = @document.xpath(*@query)
matched.any? && (!@block || @block.call(matched))
end end
def rexml_document(stringlike) def rexml_document(stringlike)
@ -35,9 +49,10 @@ module Webrat
case stringlike case stringlike
when REXML::Document when REXML::Document
stringlike.root stringlike.root
when REXML::Node when REXML::Node, Array
@query = query.map { |q| q.gsub(%r'//', './') }
stringlike stringlike
when StringIO, String else
begin begin
REXML::Document.new(stringlike.to_s).root REXML::Document.new(stringlike.to_s).root
rescue REXML::ParseException => e rescue REXML::ParseException => e
@ -76,8 +91,8 @@ module Webrat
# HaveXpath:: A new have xpath matcher. # HaveXpath:: A new have xpath matcher.
# --- # ---
# @api public # @api public
def have_xpath(expected) def have_xpath(expected, &block)
HaveXpath.new(expected) HaveXpath.new(expected, &block)
end end
alias_method :match_xpath, :have_xpath alias_method :match_xpath, :have_xpath

View File

@ -5,9 +5,11 @@ module Webrat
def self.nokogiri_document(stringlike) #:nodoc: def self.nokogiri_document(stringlike) #:nodoc:
return stringlike.dom if stringlike.respond_to?(:dom) return stringlike.dom if stringlike.respond_to?(:dom)
if stringlike === Nokogiri::HTML::Document || stringlike === Nokogiri::XML::NodeSet if Nokogiri::HTML::Document === stringlike
stringlike stringlike
elsif stringlike === StringIO elsif Nokogiri::XML::NodeSet === stringlike
stringlike
elsif StringIO === stringlike
Nokogiri::HTML(stringlike.string) Nokogiri::HTML(stringlike.string)
elsif stringlike.respond_to?(:body) elsif stringlike.respond_to?(:body)
Nokogiri::HTML(stringlike.body.to_s) Nokogiri::HTML(stringlike.body.to_s)

View File

@ -8,10 +8,50 @@ describe Webrat::Matchers do
@body = <<-EOF @body = <<-EOF
<div id='main'> <div id='main'>
<div class='inner'>hello, world!</div> <div class='inner'>hello, world!</div>
<ul>
<li>First</li>
<li>Second</li>
</ul>
</div> </div>
EOF EOF
end end
describe "#have_xpath" do
it "should be able to match an XPATH" do
@body.should have_xpath("//div")
end
it "should not match a XPATH that does not exist" do
@body.should_not have_xpath("//p")
end
it "should be able to loop over all the matched elements" do
@body.should have_xpath("//div") { |node| node.first.name.should == "div" }
end
it "should not match of any of the matchers in the block fail" do
lambda {
@body.should have_xpath("//div") { |node| node.first.name.should == "p" }
}.should raise_error(Spec::Expectations::ExpectationNotMetError)
end
it "should be able to use #have_xpath in the block" do
@body.should have_xpath("//div[@id='main']") { |node| node.should have_xpath("./div[@class='inner']") }
end
it "should convert absolute paths to relative in the block" do
@body.should have_xpath("//div[@id='main']") { |node| node.should have_xpath("//div[@class='inner']") }
end
it "should not match any parent tags in the block" do
lambda {
@body.should have_xpath("//div[@class='inner']") { |node| node.should have_xpath("//div[@id='main']") }
}.should raise_error(Spec::Expectations::ExpectationNotMetError)
end
end
describe "#have_selector" do describe "#have_selector" do
it "should be able to match a CSS selector" do it "should be able to match a CSS selector" do
@ -23,12 +63,22 @@ describe Webrat::Matchers do
end end
it "should be able to loop over all the matched elements" do it "should be able to loop over all the matched elements" do
@body.should have_selector("div") { |node| node.name.should == "div" } @body.should have_selector("div") { |node| node.first.name.should == "div" }
end end
it "should not match of any of the matchers in the block fail" do it "should not match of any of the matchers in the block fail" do
lambda { lambda {
@body.should_not have_selector("div") { |node| node.name.should == "p" } @body.should have_selector("div") { |node| node.first.name.should == "p" }
}.should raise_error(Spec::Expectations::ExpectationNotMetError)
end
it "should be able to use #have_selector in the block" do
@body.should have_selector("#main") { |node| node.should have_selector(".inner") }
end
it "should not match any parent tags in the block" do
lambda {
@body.should have_selector(".inner") { |node| node.should have_selector("#main") }
}.should raise_error(Spec::Expectations::ExpectationNotMetError) }.should raise_error(Spec::Expectations::ExpectationNotMetError)
end end
@ -52,6 +102,33 @@ describe Webrat::Matchers do
@body.should have_tag("div", :class => "inner") @body.should have_tag("div", :class => "inner")
end end
it "should be able to loop over all the matched elements" do
@body.should have_tag("div") { |node| node.first.name.should == "div" }
end
it "should not match of any of the matchers in the block fail" do
lambda {
@body.should have_tag("div") { |node| node.first.name.should == "p" }
}.should raise_error(Spec::Expectations::ExpectationNotMetError)
end
it "should be able to use #have_tag in the block" do
@body.should have_tag("div", :id => "main") { |node| node.should have_tag("div", :class => "inner") }
end
it "should not match any parent tags in the block" do
lambda {
@body.should have_tag("div", :class => "inner") { |node| node.should have_tag("div", :id => "main") }
}.should raise_error(Spec::Expectations::ExpectationNotMetError)
end
it "should work with items that have multiple child nodes" do
@body.should have_tag("ul") { |n|
n.should have_tag("li", :content => "First")
n.should have_tag("li", :content => "Second")
}
end
end end
describe Webrat::Matchers::HasContent do describe Webrat::Matchers::HasContent do
@ -66,11 +143,11 @@ describe Webrat::Matchers do
end end
describe "#matches?" do describe "#matches?" do
it "should call element#include? when the argument is a string" do it "should call element#contains? when the argument is a string" do
@body.should contain("hello, world!") @body.should contain("hello, world!")
end end
it "should call element#match when the argument is a regular expression" do it "should call element#matches? when the argument is a regular expression" do
@body.should contain(/hello, world/) @body.should contain(/hello, world/)
end end
end end
@ -78,14 +155,14 @@ describe Webrat::Matchers do
describe "#failure_message" do describe "#failure_message" do
it "should include the content string" do it "should include the content string" do
hc = Webrat::Matchers::HasContent.new("hello, world!") hc = Webrat::Matchers::HasContent.new("hello, world!")
hc.matches?(@element) hc.matches?(@body)
hc.failure_message.should include("\"hello, world!\"") hc.failure_message.should include("\"hello, world!\"")
end end
it "should include the content regular expresson" do it "should include the content regular expresson" do
hc = Webrat::Matchers::HasContent.new(/hello,\sworld!/) hc = Webrat::Matchers::HasContent.new(/hello,\sworld!/)
hc.matches?(@element) hc.matches?(@body)
hc.failure_message.should include("/hello,\\sworld!/") hc.failure_message.should include("/hello,\\sworld!/")
end end