diff --git a/History.txt b/History.txt index 55de196..a702bd8 100644 --- a/History.txt +++ b/History.txt @@ -1,11 +1,24 @@ -== Git +== 0.4.2 / 2009-02-24 +* Major enhancements + + * Significant improvements to have_selector. It now supports specifying + attributes in a hash and :count and :content options. See + have_selector_spec.rb for more. + * Add the same functionality mentioned above to have_xpath + * Minor enhancements - * Detect infinite redirects and raise a Webrat::InfiniteRedirectError (Daniel Lucraft) + * Squeeze extra whitespace out of failures messages from contain + matcher + * Detect infinite redirects and raise a Webrat::InfiniteRedirectError + (Daniel Lucraft) * Bug fixes + * Properly quote single and double quotes strings in XPath + * Fix warning caused by Nokogiri deprecating CSS::Parser.parse + (Aaron Patterson) * Accept do/end blocks in matchers. [#157] (Peter Jaros) * Quote --chdir option to mongrel_rails to support RAILS_ROOTs with spaces (T.J. VanSlyke) diff --git a/Rakefile b/Rakefile index 836711a..5106aa7 100644 --- a/Rakefile +++ b/Rakefile @@ -28,7 +28,7 @@ spec = Gem::Specification.new do |s| s.extra_rdoc_files = %w(README.rdoc MIT-LICENSE.txt) # Dependencies - s.add_dependency "nokogiri", ">= 1.1.0" + s.add_dependency "nokogiri", ">= 1.2.0" s.rubyforge_project = "webrat" end diff --git a/lib/webrat.rb b/lib/webrat.rb index 9fd5f74..000fa1f 100644 --- a/lib/webrat.rb +++ b/lib/webrat.rb @@ -7,7 +7,7 @@ module Webrat class WebratError < StandardError end - VERSION = '0.4.1' + VERSION = '0.4.2' def self.require_xml gem "nokogiri", ">= 1.0.6" diff --git a/lib/webrat/core/matchers/have_content.rb b/lib/webrat/core/matchers/have_content.rb index 8c1e3ff..7fc7481 100644 --- a/lib/webrat/core/matchers/have_content.rb +++ b/lib/webrat/core/matchers/have_content.rb @@ -26,15 +26,19 @@ module Webrat # ==== Returns # String:: The failure message. def failure_message - "expected the following element's content to #{content_message}:\n#{@element}" + "expected the following element's content to #{content_message}:\n#{squeeze_space(@element)}" end # ==== Returns # String:: The failure message to be displayed in negative matches. def negative_failure_message - "expected the following element's content to not #{content_message}:\n#{@element}" + "expected the following element's content to not #{content_message}:\n#{squeeze_space(@element)}" end - + + def squeeze_space(inner_text) + inner_text.gsub(/^\s*$/, "").squeeze("\n") + end + def content_message case @content when String diff --git a/lib/webrat/core/matchers/have_selector.rb b/lib/webrat/core/matchers/have_selector.rb index ea15d46..d79c8ad 100644 --- a/lib/webrat/core/matchers/have_selector.rb +++ b/lib/webrat/core/matchers/have_selector.rb @@ -1,24 +1,46 @@ +require "webrat/core/matchers/have_xpath" + module Webrat module Matchers class HaveSelector < HaveXpath #:nodoc: - # ==== Returns # String:: The failure message. def failure_message - "expected following text to match selector #{@expected}:\n#{@document}" + "expected following output to contain a #{tag_inspect} tag:\n#{@document}" end - + # ==== Returns # String:: The failure message to be displayed in negative matches. def negative_failure_message - "expected following text to not match selector #{@expected}:\n#{@document}" + "expected following output to omit a #{tag_inspect}:\n#{@document}" end - + + def tag_inspect + options = @options.dup + count = options.delete(:count) + content = options.delete(:content) + + html = "<#{@expected}" + options.each do |k,v| + html << " #{k}='#{v}'" + end + + if content + html << ">#{content}" + else + html << "/>" + end + + html + end + def query - Nokogiri::CSS::Parser.parse(*super).map { |ast| ast.to_xpath } + Nokogiri::CSS.parse(@expected.to_s).map do |ast| + ast.to_xpath + end.first end - + end # Matches HTML content against a CSS 3 selector. @@ -28,24 +50,24 @@ module Webrat # # ==== Returns # HaveSelector:: A new have selector matcher. - def have_selector(expected, &block) - HaveSelector.new(expected, &block) + def have_selector(name, attributes = {}, &block) + HaveSelector.new(name, attributes, &block) end alias_method :match_selector, :have_selector # Asserts that the body of the response contains # the supplied selector - def assert_have_selector(expected) - hs = HaveSelector.new(expected) - assert hs.matches?(response_body), hs.failure_message + def assert_have_selector(name, attributes = {}, &block) + matcher = HaveSelector.new(name, attributes, &block) + assert matcher.matches?(response_body), matcher.failure_message end # Asserts that the body of the response # does not contain the supplied string or regepx - def assert_have_no_selector(expected) - hs = HaveSelector.new(expected) - assert !hs.matches?(response_body), hs.negative_failure_message + def assert_have_no_selector(name, attributes = {}, &block) + matcher = HaveSelector.new(name, attributes, &block) + assert !matcher.matches?(response_body), matcher.negative_failure_message end end diff --git a/lib/webrat/core/matchers/have_tag.rb b/lib/webrat/core/matchers/have_tag.rb index 3f80952..d233a48 100644 --- a/lib/webrat/core/matchers/have_tag.rb +++ b/lib/webrat/core/matchers/have_tag.rb @@ -1,70 +1,20 @@ +require "webrat/core/matchers/have_selector" + module Webrat - module HaveTagMatcher - class HaveTag < ::Webrat::Matchers::HaveSelector #:nodoc: - # ==== Returns - # String:: The failure message. - def failure_message - "expected following output to contain a #{tag_inspect} tag:\n#{@document}" - end - - # ==== Returns - # String:: The failure message to be displayed in negative matches. - def negative_failure_message - "expected following output to omit a #{tag_inspect}:\n#{@document}" - end - - def tag_inspect - options = @expected.last.dup - content = options.delete(:content) - - html = "<#{@expected.first}" - options.each do |k,v| - html << " #{k}='#{v}'" - end - - if content - html << ">#{content}" - else - html << "/>" - end - - html - end - - def query - options = @expected.last.dup - selector = @expected.first.to_s - - selector << ":contains('#{options.delete(:content)}')" if options[:content] - - options.each do |key, value| - selector << "[#{key}='#{value}']" - end - - Nokogiri::CSS::Parser.parse(selector).map { |ast| ast.to_xpath } - end - end - - def have_tag(name, attributes = {}, &block) - HaveTag.new([name, attributes], &block) + def have_tag(*args, &block) + have_selector(*args, &block) end alias_method :match_tag, :have_tag - # Asserts that the body of the response contains - # the supplied tag with the associated selectors - def assert_have_tag(name, attributes = {}) - ht = HaveTag.new([name, attributes]) - assert ht.matches?(response_body), ht.failure_message + def assert_have_tag(*args, &block) + assert_have_selector(*args, &block) end - # Asserts that the body of the response - # does not contain the supplied string or regepx - def assert_have_no_tag(name, attributes = {}) - ht = HaveTag.new([name, attributes]) - assert !ht.matches?(response_body), ht.negative_failure_message + def assert_have_no_tag(*args, &block) + assert_have_no_selector(*args, &block) end end diff --git a/lib/webrat/core/matchers/have_xpath.rb b/lib/webrat/core/matchers/have_xpath.rb index bd3618f..c31fdd0 100644 --- a/lib/webrat/core/matchers/have_xpath.rb +++ b/lib/webrat/core/matchers/have_xpath.rb @@ -5,55 +5,90 @@ module Webrat module Matchers class HaveXpath #:nodoc: - def initialize(expected, &block) + def initialize(expected, options = {}, &block) @expected = expected + @options = options @block = block end def matches?(stringlike, &block) @block ||= block + matched = matches(stringlike) - if Webrat.configuration.parse_with_nokogiri? - matches_nokogiri?(stringlike) + if @options[:count] + matched.size == @options[:count] && (!@block || @block.call(matched)) else - matches_rexml?(stringlike) + matched.any? && (!@block || @block.call(matched)) + end + end + + def matches(stringlike) + if Webrat.configuration.parse_with_nokogiri? + nokogiri_matches(stringlike) + else + rexml_matches(stringlike) end end - def matches_rexml?(stringlike) + def rexml_matches(stringlike) if REXML::Node === stringlike || Array === stringlike @query = query.map { |q| q.gsub(%r'//', './') } else @query = query end + add_options_conditions_to(@query) + @document = Webrat.rexml_document(stringlike) - matched = @query.map do |q| + @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) + def nokogiri_matches(stringlike) if Nokogiri::XML::NodeSet === stringlike - @query = query.map { |q| q.gsub(%r'//', './') } + @query = query.gsub(%r'//', './') else @query = query end + add_options_conditions_to(@query) + @document = Webrat::XML.document(stringlike) - matched = @document.xpath(*@query) - matched.any? && (!@block || @block.call(matched)) + @document.xpath(*@query) + end + + def add_options_conditions_to(query) + add_attributes_conditions_to(query) + add_content_condition_to(query) + end + + def add_attributes_conditions_to(query) + 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 << "[#{attribute_conditions.join(' and ')}]" + end + end + + def add_content_condition_to(query) + if @options[:content] + query << "[contains(., #{xpath_escape(@options[:content])})]" + end end def query - [@expected].flatten.compact + @expected end # ==== Returns @@ -66,7 +101,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 @@ -76,18 +128,18 @@ module Webrat # # ==== Returns # HaveXpath:: A new have xpath matcher. - def have_xpath(expected, &block) - HaveXpath.new(expected, &block) + def have_xpath(expected, options = {}, &block) + HaveXpath.new(expected, options, &block) end alias_method :match_xpath, :have_xpath - def assert_have_xpath(expected, &block) - hs = HaveXpath.new(expected, &block) + def assert_have_xpath(expected, options = {}, &block) + hs = HaveXpath.new(expected, options, &block) assert hs.matches?(response_body), hs.failure_message end - def assert_have_no_xpath(expected, &block) - hs = HaveXpath.new(expected, &block) + def assert_have_no_xpath(expected, options = {}, &block) + hs = HaveXpath.new(expected, options, &block) assert !hs.matches?(response_body), hs.negative_failure_message end diff --git a/lib/webrat/selenium/matchers/have_tag.rb b/lib/webrat/selenium/matchers/have_tag.rb index a7c87ee..c95bc7b 100644 --- a/lib/webrat/selenium/matchers/have_tag.rb +++ b/lib/webrat/selenium/matchers/have_tag.rb @@ -43,7 +43,7 @@ module Webrat selector << "[#{key}='#{value}']" end - Nokogiri::CSS::Parser.parse(selector).map { |ast| ast.to_xpath } + Nokogiri::CSS.parse(selector).map { |ast| ast.to_xpath } end end diff --git a/spec/public/matchers/contain_spec.rb b/spec/public/matchers/contain_spec.rb new file mode 100644 index 0000000..78ebae1 --- /dev/null +++ b/spec/public/matchers/contain_spec.rb @@ -0,0 +1,114 @@ +require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper") + +describe "contain" do + include Webrat::Matchers + + before(:each) do + @body = <<-HTML +
+
hello, world!
+

Welcome "Bryan"

+

Welcome 'Bryan'

+

Welcome 'Bryan"

+ +
+ HTML + end + + before(:each) do + @body = <<-EOF +
+
hello, world!
+
+ EOF + end + + describe "#matches?" do + it "should call element#contains? when the argument is a string" do + @body.should contain("hello, world!") + end + + it "should call element#matches? when the argument is a regular expression" do + @body.should contain(/hello, world/) + end + end + + describe "asserts for contains," do + include Test::Unit::Assertions + + before(:each) do + should_receive(:response_body).and_return @body + require 'test/unit' + end + + describe "assert_contain" do + it "should pass when containing the text" do + assert_contain("hello, world") + end + + it "should pass when containing the regexp" do + assert_contain(/hello, world/) + end + + it "should throw an exception when the body doesnt contain the text" do + lambda { + assert_contain("monkeys") + }.should raise_error(Test::Unit::AssertionFailedError) + end + + it "should throw an exception when the body doesnt contain the regexp" do + lambda { + assert_contain(/monkeys/) + }.should raise_error(Test::Unit::AssertionFailedError) + end + end + + describe "assert_not_contain" do + it "should pass when not containing the text" do + assert_not_contain("monkeys") + end + + it "should pass when not containing the regexp" do + assert_not_contain(/monkeys/) + end + + it "should throw an exception when the body does contain the text" do + lambda { + assert_not_contain("hello, world") + }.should raise_error(Test::Unit::AssertionFailedError) + end + + it "should throw an exception when the body does contain the regexp" do + lambda { + assert_not_contain(/hello, world/) + }.should raise_error(Test::Unit::AssertionFailedError) + end + end + end + + describe "#failure_message" do + it "should include the content string" do + hc = Webrat::Matchers::HasContent.new("hello, world!") + 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?(@body) + + hc.failure_message.should include("/hello,\\sworld!/") + end + + it "should include the element's inner content" do + hc = Webrat::Matchers::HasContent.new(/hello,\sworld!/) + hc.matches?(@body) + + hc.failure_message.should include("hello, world!") + end + end +end diff --git a/spec/public/matchers/have_selector_spec.rb b/spec/public/matchers/have_selector_spec.rb new file mode 100644 index 0000000..3b6f3b5 --- /dev/null +++ b/spec/public/matchers/have_selector_spec.rb @@ -0,0 +1,135 @@ +require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper") + +describe "have_selector" do + include Webrat::Matchers + + before(:each) do + @body = <<-HTML +
+
hello, world!
+

Welcome "Bryan"

+

Welcome 'Bryan'

+

Welcome 'Bryan"

+ +
+ HTML + end + + it "should be able to match a CSS selector" do + @body.should have_selector("div") + end + + it "should not match a CSS selector that does not exist" do + @body.should_not have_selector("p") + end + + describe "specifying attributes" do + it "should be able to specify the attributes of the tag" do + @body.should have_selector("div", :class => "inner") + end + end + + describe "specifying content" do + it "should be able to specify the content of the tag" do + @body.should have_selector("div", :content => "hello, world!") + end + + it "should be able to specify the content of the tag with double quotes in it" do + @body.should have_selector("h2", :content => 'Welcome "Bryan"') + end + + it "should be able to specify the content of the tag with single quotes in it" do + @body.should have_selector("h3", :content => "Welcome 'Bryan'") + end + + it "should be able to specify the content of the tag with both kinds of quotes" do + @body.should have_selector("h4", :content => "Welcome 'Bryan\"") + end + end + + describe "specifying counts" do + it "should be able to specify the number of occurences of the tag" do + @body.should have_selector("li", :count => 2) + end + + it "should not match if the count is wrong" do + lambda { + @body.should have_selector("li", :count => 3) + }.should raise_error(Spec::Expectations::ExpectationNotMetError) + end + end + + describe "specifying nested elements" do + it "should be able to loop over all the matched elements" do + @body.should have_selector("div") do |node| + node.first.name.should == "div" + end + end + + it "should not match of any of the matchers in the block fail" do + lambda { + @body.should have_selector("div") do |node| + node.first.name.should == "p" + end + }.should raise_error(Spec::Expectations::ExpectationNotMetError) + end + + it "should be able to use #have_selector in the block" do + @body.should have_selector("#main") do |node| + node.should have_selector(".inner") + end + end + + it "should not match any parent tags in the block" do + lambda { + @body.should have_selector(".inner") do |node| + node.should have_selector("#main") + end + }.should raise_error(Spec::Expectations::ExpectationNotMetError) + end + + it "should work with items that have multiple child nodes" do + @body.should have_selector("ul") do |n| + n.should have_selector("li", :content => "First") + n.should have_selector("li", :content => "Second") + end + end + end + + describe "Test::Unit assertions" do + include Test::Unit::Assertions + + before(:each) do + require 'test/unit' + should_receive(:response_body).and_return @body + end + + describe "assert_have_selector" do + it "should pass when body contains the selection" do + assert_have_selector("div") + end + + it "should throw an exception when the body doesnt have matching selection" do + lambda { + assert_have_selector("p") + }.should raise_error(Test::Unit::AssertionFailedError) + end + end + + describe "assert_have_not_selector" do + it "should pass when the body doesn't contan the selection" do + assert_have_no_selector("p") + end + + it "should throw an exception when the body does contain the selection" do + lambda { + assert_have_no_selector("div") + }.should raise_error(Test::Unit::AssertionFailedError) + end + end + end + +end diff --git a/spec/public/matchers/have_tag_spec.rb b/spec/public/matchers/have_tag_spec.rb new file mode 100644 index 0000000..583e879 --- /dev/null +++ b/spec/public/matchers/have_tag_spec.rb @@ -0,0 +1,39 @@ +require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper") + +describe "have_tag" do + include Webrat::Matchers + include Webrat::HaveTagMatcher + + before(:each) do + @body = <<-HTML +
+
hello, world!
+
+ HTML + end + + it "should be an alias for have_selector" do + @body.should have_tag("div") + end + + describe "asserts for tags" do + include Test::Unit::Assertions + + before(:each) do + should_receive(:response_body).and_return @body + require 'test/unit' + end + + describe "assert_have_tag" do + it "should be an alias for assert_have_selector" do + assert_have_tag("div") + end + end + + describe "assert_have_no_tag" do + it "should be an alias for assert_have_no_selector" do + assert_have_no_tag("p") + end + end + end +end diff --git a/spec/public/matchers/have_xpath_spec.rb b/spec/public/matchers/have_xpath_spec.rb new file mode 100644 index 0000000..1a7942f --- /dev/null +++ b/spec/public/matchers/have_xpath_spec.rb @@ -0,0 +1,123 @@ +require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper") + +describe "have_xpath" do + include Webrat::Matchers + + before(:each) do + @body = <<-HTML +
+
hello, world!
+

Welcome "Bryan"

+

Welcome 'Bryan'

+

Welcome 'Bryan"

+ +
+ HTML + end + + it "should be able to match an 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 + + it "should be able to loop over all the matched elements" do + @body.should have_xpath("//div") do |node| + node.first.name.should == "div" + end + end + + it "should not match if any of the matchers in the block fail" do + lambda { + @body.should have_xpath("//div") do |node| + node.first.name.should == "p" + end + }.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']") do |node| + node.should have_xpath("./div[@class='inner']") + end + end + + it "should convert absolute paths to relative in the block" do + @body.should have_xpath("//div[@id='main']") do |node| + node.should have_xpath("//div[@class='inner']") + end + end + + it "should not match any parent tags in the block" do + lambda { + @body.should have_xpath("//div[@class='inner']") do |node| + node.should have_xpath("//div[@id='main']") + end + }.should raise_error(Spec::Expectations::ExpectationNotMetError) + end + + describe 'asserts for xpath' do + include Test::Unit::Assertions + + before(:each) do + should_receive(:response_body).and_return @body + require 'test/unit' + end + + describe "assert_have_xpath" do + it "should pass when body contains the selection" do + assert_have_xpath("//div") + end + + it "should throw an exception when the body doesnt have matching xpath" do + lambda { + assert_have_xpath("//p") + }.should raise_error(Test::Unit::AssertionFailedError) + end + end + + describe "assert_have_no_xpath" do + it "should pass when the body doesn't contan the xpath" do + assert_have_no_xpath("//p") + end + + it "should throw an exception when the body does contain the xpath" do + lambda { + assert_have_no_xpath("//div") + }.should raise_error(Test::Unit::AssertionFailedError) + end + end + end +end diff --git a/spec/public/matchers_spec.rb b/spec/public/matchers_spec.rb deleted file mode 100644 index 554708c..0000000 --- a/spec/public/matchers_spec.rb +++ /dev/null @@ -1,333 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + "/../spec_helper") - -describe Webrat::Matchers do - include Webrat::Matchers - include Webrat::HaveTagMatcher - - before(:each) do - @body = <<-HTML -
-
hello, world!
- -
- HTML - 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") do |node| - node.first.name.should == "div" - end - end - - it "should not match if any of the matchers in the block fail" do - lambda { - @body.should have_xpath("//div") do |node| - node.first.name.should == "p" - end - }.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 - - describe 'asserts for xpath' do - include Test::Unit::Assertions - before(:each) do - should_receive(:response_body).and_return @body - require 'test/unit' - end - describe "assert_have_xpath" do - it "should pass when body contains the selection" do - assert_have_xpath("//div") - end - - it "should throw an exception when the body doesnt have matching xpath" do - lambda {assert_have_xpath("//p")}.should raise_error(Test::Unit::AssertionFailedError) - end - - end - - describe "assert_have_no_xpath" do - it "should pass when the body doesn't contan the xpath" do - assert_have_no_xpath("//p") - end - - it "should throw an exception when the body does contain the xpath" do - lambda {assert_have_no_xpath("//div")}.should raise_error(Test::Unit::AssertionFailedError) - end - end - end - - end - - describe "#have_selector" do - - it "should be able to match a CSS selector" do - @body.should have_selector("div") - end - - it "should not match a CSS selector that does not exist" do - @body.should_not have_selector("p") - end - - it "should be able to loop over all the matched elements" do - @body.should have_selector("div") do |node| - node.first.name.should == "div" - end - end - - it "should not match of any of the matchers in the block fail" do - lambda { - @body.should have_selector("div") do |node| - node.first.name.should == "p" - end - }.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 - - describe "asserts for selector," do - include Test::Unit::Assertions - before(:each) do - should_receive(:response_body).and_return @body - require 'test/unit' - end - describe "assert_have_selector" do - it "should pass when body contains the selection" do - assert_have_selector("div") - end - - it "should throw an exception when the body doesnt have matching selection" do - lambda {assert_have_selector("p")}.should raise_error(Test::Unit::AssertionFailedError) - end - - end - - describe "assert_have_not_selector" do - it "should pass when the body doesn't contan the selection" do - assert_have_no_selector("p") - end - - it "should throw an exception when the body does contain the selection" do - lambda {assert_have_no_selector("div")}.should raise_error(Test::Unit::AssertionFailedError) - end - end - end - - end - - describe "#have_tag" do - - it "should be able to match a tag" do - @body.should have_tag("div") - end - - it "should not match the tag when it should not match" do - @body.should_not have_tag("p") - end - - it "should be able to specify the content of the tag" do - @body.should have_tag("div", :content => "hello, world!") - end - - it "should be able to specify the attributes of the tag" 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") do |node| - node.first.name.should == "div" - end - end - - it "should not match of any of the matchers in the block fail" do - lambda { - @body.should have_tag("div") do |node| - node.first.name.should == "p" - end - }.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 - - describe "asserts for tags," do - include Test::Unit::Assertions - before(:each) do - should_receive(:response_body).and_return @body - require 'test/unit' - end - describe "assert_have_tag" do - it "should pass when body contains the tag" do - assert_have_tag("div") - end - - it "should pass when finding with additional selectors" do - assert_have_tag("div", :class => "inner") - end - - - it "should throw an exception when the body doesnt have matching tag" do - lambda {assert_have_tag("p")}.should raise_error(Test::Unit::AssertionFailedError) - end - - it "should throw an exception when the body doens't have a tag matching the additional selector" do - lambda {assert_have_tag("div", :class => "nope")}.should raise_error(Test::Unit::AssertionFailedError) - end - end - - describe "assert_have_no_tag" do - it "should pass when the body doesn't contan the tag" do - assert_have_no_tag("p") - end - - it "should pass when the body doesn't contain the tag due to additional selectors missing" do - assert_have_no_tag("div", :class => "nope") - end - - it "should throw an exception when the body does contain the tag" do - lambda {assert_have_no_tag("div")}.should raise_error(Test::Unit::AssertionFailedError) - end - - it "should throw an exception when the body contains the tag with additional selectors" do - lambda {assert_have_no_tag("div", :class => "inner")}.should raise_error(Test::Unit::AssertionFailedError) - end - end - end - - end - - describe Webrat::Matchers::HasContent do - include Webrat::Matchers - - before(:each) do - @body = <<-EOF -
-
hello, world!
-
- EOF - end - - describe "#matches?" do - it "should call element#contains? when the argument is a string" do - @body.should contain("hello, world!") - end - - it "should call element#matches? when the argument is a regular expression" do - @body.should contain(/hello, world/) - end - end - - describe "asserts for contains," do - include Test::Unit::Assertions - before(:each) do - should_receive(:response_body).and_return @body - require 'test/unit' - end - describe "assert_contain" do - it "should pass when containing the text" do - assert_contain("hello, world") - end - - it "should pass when containing the regexp" do - assert_contain(/hello, world/) - end - - it "should throw an exception when the body doesnt contain the text" do - lambda {assert_contain("monkeys")}.should raise_error(Test::Unit::AssertionFailedError) - end - - it "should throw an exception when the body doesnt contain the regexp" do - lambda {assert_contain(/monkeys/)}.should raise_error(Test::Unit::AssertionFailedError) - end - end - - describe "assert_not_contain" do - it "should pass when not containing the text" do - assert_not_contain("monkeys") - end - - it "should pass when not containing the regexp" do - assert_not_contain(/monkeys/) - end - - it "should throw an exception when the body does contain the text" do - lambda {assert_not_contain("hello, world")}.should raise_error(Test::Unit::AssertionFailedError) - end - - it "should throw an exception when the body does contain the regexp" do - lambda {assert_not_contain(/hello, world/)}.should raise_error(Test::Unit::AssertionFailedError) - end - end - end - - describe "#failure_message" do - - it "should include the content string" do - hc = Webrat::Matchers::HasContent.new("hello, world!") - 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?(@body) - - hc.failure_message.should include("/hello,\\sworld!/") - end - - it "should include the element's inner content" do - hc = Webrat::Matchers::HasContent.new(/hello,\sworld!/) - hc.matches?(@body) - - hc.failure_message.should include("hello, world!") - end - end - end -end