diff --git a/lib/webrat/core/matchers/have_selector.rb b/lib/webrat/core/matchers/have_selector.rb index 28f6c24..d02dceb 100644 --- a/lib/webrat/core/matchers/have_selector.rb +++ b/lib/webrat/core/matchers/have_selector.rb @@ -18,6 +18,7 @@ module Webrat def tag_inspect options = @options.dup + count = options.delete(:count) content = options.delete(:content) html = "<#{@expected}" @@ -35,29 +36,7 @@ module Webrat end def query - options = @options.dup - selector = @expected.to_s - - options.each do |key, value| - next if [:content, :count].include?(key) - selector << "[#{key}='#{value}']" - end - - Nokogiri::CSS::Parser.parse(selector).map { |ast| ast.to_xpath }.first - end - - def xpath_escape(string) - if string.include?("'") && string.include?('"') - parts = string.split("'").map do |part| - "'#{part}'" - end - - "concat(" + parts.join(", \"'\", ") + ")" - elsif string.include?("'") - "\"#{string}\"" - else - "'#{string}'" - end + Nokogiri::CSS::Parser.parse(@expected.to_s).map { |ast| ast.to_xpath }.first end end diff --git a/lib/webrat/core/matchers/have_xpath.rb b/lib/webrat/core/matchers/have_xpath.rb index 8cdd9be..75bf698 100644 --- a/lib/webrat/core/matchers/have_xpath.rb +++ b/lib/webrat/core/matchers/have_xpath.rb @@ -37,6 +37,21 @@ module Webrat @query = query end + attribute_conditions = [] + + @options.each do |key, value| + next if [:content, :count].include?(key) + attribute_conditions << "@#{key} = #{xpath_escape(value)}" + end + + if attribute_conditions.any? + @query.first << "[#{attribute_conditions.join(' and ')}]" + end + + if @options[:content] + @query.first << "[contains(., #{xpath_escape(@options[:content])})]" + end + @document = Webrat.rexml_document(stringlike) @query.map do |q| @@ -55,8 +70,19 @@ module Webrat @query = query end + attribute_conditions = [] + + @options.each do |key, value| + next if [:content, :count].include?(key) + attribute_conditions << "@#{key} = #{xpath_escape(value)}" + end + + if attribute_conditions.any? + @query.first << "[#{attribute_conditions.join(' and ')}]" + end + if @options[:content] - query << "[contains(., #{xpath_escape(@options[:content])})]" + @query.first << "[contains(., #{xpath_escape(@options[:content])})]" end @document = Webrat::XML.document(stringlike) @@ -77,7 +103,24 @@ module Webrat # String:: The failure message to be displayed in negative matches. def negative_failure_message "expected following text to not match xpath #{@expected}:\n#{@document}" - end + end + + protected + + def xpath_escape(string) + if string.include?("'") && string.include?('"') + parts = string.split("'").map do |part| + "'#{part}'" + end + + "concat(" + parts.join(", \"'\", ") + ")" + elsif string.include?("'") + "\"#{string}\"" + else + "'#{string}'" + end + end + end # Matches HTML content against an XPath query diff --git a/spec/public/matchers/have_xpath_spec.rb b/spec/public/matchers/have_xpath_spec.rb index 7f06205..1a7942f 100644 --- a/spec/public/matchers/have_xpath_spec.rb +++ b/spec/public/matchers/have_xpath_spec.rb @@ -22,6 +22,34 @@ describe "have_xpath" do @body.should have_xpath("//div") end + it "should be able to match an XPATH with attributes" do + @body.should have_xpath("//div", :class => "inner") + end + + it "should be able to match an XPATH with content" do + @body.should have_xpath("//div", :content => "hello, world!") + end + + it "should not match an XPATH without content" do + @body.should_not have_xpath("//div", :content => "not present") + end + + it "should be able to match an XPATH with content and class" do + @body.should have_xpath("//div", :class => "inner", :content => "hello, world!") + end + + it "should not match an XPATH with content and wrong class" do + @body.should_not have_xpath("//div", :class => "outer", :content => "hello, world!") + end + + it "should not match an XPATH with wrong content and class" do + @body.should_not have_xpath("//div", :class => "inner", :content => "wrong") + end + + it "should not match an XPATH with wrong content and wrong class" do + @body.should_not have_xpath("//div", :class => "outer", :content => "wrong") + end + it "should not match a XPATH that does not exist" do @body.should_not have_xpath("//p") end