Skip to content

Commit

Permalink
Restore support for nested have_xpath, etc. with blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
brynary committed Nov 9, 2008
1 parent 055bd56 commit 0aad32d
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 25 deletions.
4 changes: 2 additions & 2 deletions lib/webrat/core/matchers/have_selector.rb
Expand Up @@ -30,8 +30,8 @@ def query
# 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

Expand Down
4 changes: 2 additions & 2 deletions lib/webrat/core/matchers/have_tag.rb
Expand Up @@ -49,8 +49,8 @@ def query

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

Expand Down
35 changes: 25 additions & 10 deletions lib/webrat/core/matchers/have_xpath.rb
Expand Up @@ -16,17 +16,31 @@ def matches?(stringlike)
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)
Expand All @@ -35,9 +49,10 @@ def rexml_document(stringlike)
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
Expand Down Expand Up @@ -76,8 +91,8 @@ def negative_failure_message
# 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

Expand Down
6 changes: 4 additions & 2 deletions lib/webrat/core/nokogiri.rb
Expand Up @@ -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)
Expand Down
95 changes: 86 additions & 9 deletions spec/api/matchers_spec.rb
Expand Up @@ -8,10 +8,50 @@
@body = <<-EOF
<div id='main'>
<div class='inner'>hello, world!</div>
<ul>
<li>First</li>
<li>Second</li>
</ul>
</div>
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
Expand All @@ -23,12 +63,22 @@
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

Expand All @@ -52,11 +102,38 @@
@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
<div id='main'>
Expand All @@ -66,26 +143,26 @@
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
Expand Down

0 comments on commit 0aad32d

Please sign in to comment.