diff --git a/lib/webrat/core/matchers/have_selector.rb b/lib/webrat/core/matchers/have_selector.rb
index dd6fff9..605b0d8 100644
--- a/lib/webrat/core/matchers/have_selector.rb
+++ b/lib/webrat/core/matchers/have_selector.rb
@@ -30,8 +30,8 @@ module Webrat
# HaveSelector:: A new have selector matcher.
# ---
# @api public
- def have_selector(expected)
- HaveSelector.new(expected)
+ def have_selector(expected, &block)
+ HaveSelector.new(expected, &block)
end
alias_method :match_selector, :have_selector
diff --git a/lib/webrat/core/matchers/have_tag.rb b/lib/webrat/core/matchers/have_tag.rb
index 752c85d..01a2017 100644
--- a/lib/webrat/core/matchers/have_tag.rb
+++ b/lib/webrat/core/matchers/have_tag.rb
@@ -49,8 +49,8 @@ module Webrat
end
- def have_tag(name, attributes = {})
- HaveTag.new([name, attributes])
+ def have_tag(name, attributes = {}, &block)
+ HaveTag.new([name, attributes], &block)
end
alias_method :match_tag, :have_tag
diff --git a/lib/webrat/core/matchers/have_xpath.rb b/lib/webrat/core/matchers/have_xpath.rb
index 4e9c238..e06bc41 100644
--- a/lib/webrat/core/matchers/have_xpath.rb
+++ b/lib/webrat/core/matchers/have_xpath.rb
@@ -16,17 +16,31 @@ module Webrat
end
def matches_rexml?(stringlike)
+ @query = query
+
@document = rexml_document(stringlike)
-
- query.all? do |q|
- matched = REXML::XPath.match(@document, q)
- matched.any? && (!block_given? || matched.all?(&@block))
- end
+
+ matched = @query.map do |q|
+ if @document.is_a?(Array)
+ @document.map { |d| REXML::XPath.match(d, q) }
+ else
+ REXML::XPath.match(@document, q)
+ end
+ end.flatten.compact
+
+ matched.any? && (!@block || @block.call(matched))
end
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.xpath(*query).any?
+ matched = @document.xpath(*@query)
+ matched.any? && (!@block || @block.call(matched))
end
def rexml_document(stringlike)
@@ -35,9 +49,10 @@ module Webrat
case stringlike
when REXML::Document
stringlike.root
- when REXML::Node
+ when REXML::Node, Array
+ @query = query.map { |q| q.gsub(%r'//', './') }
stringlike
- when StringIO, String
+ else
begin
REXML::Document.new(stringlike.to_s).root
rescue REXML::ParseException => e
@@ -76,8 +91,8 @@ module Webrat
# HaveXpath:: A new have xpath matcher.
# ---
# @api public
- def have_xpath(expected)
- HaveXpath.new(expected)
+ def have_xpath(expected, &block)
+ HaveXpath.new(expected, &block)
end
alias_method :match_xpath, :have_xpath
diff --git a/lib/webrat/core/nokogiri.rb b/lib/webrat/core/nokogiri.rb
index c9d7deb..51fe87d 100644
--- a/lib/webrat/core/nokogiri.rb
+++ b/lib/webrat/core/nokogiri.rb
@@ -5,9 +5,11 @@ module Webrat
def self.nokogiri_document(stringlike) #:nodoc:
return stringlike.dom if stringlike.respond_to?(:dom)
- if stringlike === Nokogiri::HTML::Document || stringlike === Nokogiri::XML::NodeSet
+ if Nokogiri::HTML::Document === stringlike
stringlike
- elsif stringlike === StringIO
+ elsif Nokogiri::XML::NodeSet === stringlike
+ stringlike
+ elsif StringIO === stringlike
Nokogiri::HTML(stringlike.string)
elsif stringlike.respond_to?(:body)
Nokogiri::HTML(stringlike.body.to_s)
diff --git a/spec/api/matchers_spec.rb b/spec/api/matchers_spec.rb
index 0a3ebc8..3d4daf7 100644
--- a/spec/api/matchers_spec.rb
+++ b/spec/api/matchers_spec.rb
@@ -8,10 +8,50 @@ describe Webrat::Matchers do
@body = <<-EOF
EOF
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
it "should be able to match a CSS selector" do
@@ -23,12 +63,22 @@ describe Webrat::Matchers do
end
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
it "should not match of any of the matchers in the block fail" do
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)
end
@@ -52,11 +102,38 @@ describe Webrat::Matchers do
@body.should have_tag("div", :class => "inner")
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
-
+
describe Webrat::Matchers::HasContent do
include Webrat::Matchers
-
+
before(:each) do
@body = <<-EOF
@@ -66,26 +143,26 @@ describe Webrat::Matchers do
end
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!")
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/)
end
end
-
+
describe "#failure_message" do
it "should include the content string" do
hc = Webrat::Matchers::HasContent.new("hello, world!")
- hc.matches?(@element)
+ hc.matches?(@body)
hc.failure_message.should include("\"hello, world!\"")
end
it "should include the content regular expresson" do
hc = Webrat::Matchers::HasContent.new(/hello,\sworld!/)
- hc.matches?(@element)
+ hc.matches?(@body)
hc.failure_message.should include("/hello,\\sworld!/")
end