From 0aad32d38aac4fc62f5036a1f87c21c0e839f6b9 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 8 Nov 2008 21:34:46 -0500 Subject: [PATCH] Restore support for nested have_xpath, etc. with blocks --- lib/webrat/core/matchers/have_selector.rb | 4 +- lib/webrat/core/matchers/have_tag.rb | 4 +- lib/webrat/core/matchers/have_xpath.rb | 35 ++++++--- lib/webrat/core/nokogiri.rb | 6 +- spec/api/matchers_spec.rb | 95 ++++++++++++++++++++--- 5 files changed, 119 insertions(+), 25 deletions(-) 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
hello, world!
+
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