Pulling features up from have_tag into have_selector

This commit is contained in:
Bryan Helmkamp 2009-02-23 19:51:50 -05:00
parent d96899be8c
commit 2296cadb93
4 changed files with 148 additions and 234 deletions

View File

@ -1,22 +1,77 @@
require "webrat/core/matchers/have_xpath"
module Webrat module Webrat
module Matchers module Matchers
class HaveSelector < HaveXpath #:nodoc: class HaveSelector < HaveXpath #:nodoc:
# ==== Returns # ==== Returns
# String:: The failure message. # String:: The failure message.
def 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 end
# ==== Returns # ==== Returns
# String:: The failure message to be displayed in negative matches. # String:: The failure message to be displayed in negative matches.
def negative_failure_message 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 matches?(stringlike, &block)
@block ||= block
matched = matches(stringlike)
options = @expected.last.dup
if options[:count]
matched.size == options[:count] && (!@block || @block.call(matched))
else
matched.any? && (!@block || @block.call(matched))
end
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}</#{@expected.first}>"
else
html << "/>"
end
html
end end
def query def query
Nokogiri::CSS::Parser.parse(*super).map { |ast| ast.to_xpath } options = @expected.last.dup
selector = @expected.first.to_s
options.each do |key, value|
next if [:content, :count].include?(key)
selector << "[#{key}='#{value}']"
end
q = Nokogiri::CSS::Parser.parse(selector).map { |ast| ast.to_xpath }.first
if options[:content] && options[:content].include?("'") && options[:content].include?('"')
parts = options[:content].split("'").map do |part|
"'#{part}'"
end
string = "concat(" + parts.join(", \"'\", ") + ")"
q << "[contains(., #{string})]"
elsif options[:content] && options[:content].include?("'")
q << "[contains(., \"#{options[:content]}\")]"
elsif options[:content]
q << "[contains(., '#{options[:content]}')]"
end
q
end end
end end
@ -28,24 +83,24 @@ module Webrat
# #
# ==== Returns # ==== Returns
# HaveSelector:: A new have selector matcher. # HaveSelector:: A new have selector matcher.
def have_selector(expected, &block) def have_selector(name, attributes = {}, &block)
HaveSelector.new(expected, &block) HaveSelector.new([name, attributes], &block)
end end
alias_method :match_selector, :have_selector alias_method :match_selector, :have_selector
# Asserts that the body of the response contains # Asserts that the body of the response contains
# the supplied selector # the supplied selector
def assert_have_selector(expected) def assert_have_selector(name, attributes = {}, &block)
hs = HaveSelector.new(expected) matcher = HaveSelector.new([name, attributes], &block)
assert hs.matches?(response_body), hs.failure_message assert matcher.matches?(response_body), matcher.failure_message
end end
# Asserts that the body of the response # Asserts that the body of the response
# does not contain the supplied string or regepx # does not contain the supplied string or regepx
def assert_have_no_selector(expected) def assert_have_no_selector(name, attributes = {}, &block)
hs = HaveSelector.new(expected) matcher = HaveSelector.new([name, attributes], &block)
assert !hs.matches?(response_body), hs.negative_failure_message assert !matcher.matches?(response_body), matcher.negative_failure_message
end end
end end

View File

@ -1,97 +1,20 @@
module Webrat require "webrat/core/matchers/have_selector"
module Webrat
module HaveTagMatcher module HaveTagMatcher
class HaveTag < ::Webrat::Matchers::HaveSelector #:nodoc: def have_tag(*args, &block)
# ==== Returns have_selector(*args, &block)
# 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 matches?(stringlike, &block)
@block ||= block
matched = matches(stringlike)
options = @expected.last.dup
if options[:count]
matched.size == options[:count] && (!@block || @block.call(matched))
else
matched.any? && (!@block || @block.call(matched))
end
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}</#{@expected.first}>"
else
html << "/>"
end
html
end
def query
options = @expected.last.dup
selector = @expected.first.to_s
options.each do |key, value|
next if [:content, :count].include?(key)
selector << "[#{key}='#{value}']"
end
q = Nokogiri::CSS::Parser.parse(selector).map { |ast| ast.to_xpath }.first
if options[:content] && options[:content].include?("'") && options[:content].include?('"')
parts = options[:content].split("'").map do |part|
"'#{part}'"
end
string = "concat(" + parts.join(", \"'\", ") + ")"
q << "[contains(., #{string})]"
elsif options[:content] && options[:content].include?("'")
q << "[contains(., \"#{options[:content]}\")]"
elsif options[:content]
q << "[contains(., '#{options[:content]}')]"
end
q
end
end
def have_tag(name, attributes = {}, &block)
HaveTag.new([name, attributes], &block)
end end
alias_method :match_tag, :have_tag alias_method :match_tag, :have_tag
# Asserts that the body of the response contains def assert_have_tag(*args, &block)
# the supplied tag with the associated selectors assert_have_selector(*args, &block)
def assert_have_tag(name, attributes = {})
ht = HaveTag.new([name, attributes])
assert ht.matches?(response_body), ht.failure_message
end end
# Asserts that the body of the response def assert_have_no_tag(*args, &block)
# does not contain the supplied string or regepx assert_have_no_selector(*args, &block)
def assert_have_no_tag(name, attributes = {})
ht = HaveTag.new([name, attributes])
assert !ht.matches?(response_body), ht.negative_failure_message
end end
end end

View File

@ -26,6 +26,43 @@ describe "have_selector" do
@body.should_not have_selector("p") @body.should_not have_selector("p")
end 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 it "should be able to loop over all the matched elements" do
@body.should have_selector("div") do |node| @body.should have_selector("div") do |node|
node.first.name.should == "div" node.first.name.should == "div"
@ -54,12 +91,20 @@ describe "have_selector" do
}.should raise_error(Spec::Expectations::ExpectationNotMetError) }.should raise_error(Spec::Expectations::ExpectationNotMetError)
end end
describe "asserts for selector," do 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 include Test::Unit::Assertions
before(:each) do before(:each) do
should_receive(:response_body).and_return @body
require 'test/unit' require 'test/unit'
should_receive(:response_body).and_return @body
end end
describe "assert_have_selector" do describe "assert_have_selector" do

View File

@ -8,90 +8,14 @@ describe "have_tag" do
@body = <<-HTML @body = <<-HTML
<div id='main'> <div id='main'>
<div class='inner'>hello, world!</div> <div class='inner'>hello, world!</div>
<h2>Welcome "Bryan"</h2>
<h3>Welcome 'Bryan'</h3>
<h4>Welcome 'Bryan"</h4>
<ul>
<li>First</li>
<li>Second</li>
</ul>
</div> </div>
HTML HTML
end end
it "should be able to match a tag" do it "should be an alias for have_selector" do
@body.should have_tag("div") @body.should have_tag("div")
end 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 content of the tag with double quotes in it" do
@body.should have_tag("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_tag("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_tag("h4", :content => "Welcome 'Bryan\"")
end
it "should be able to specify the number of occurences of the tag" do
@body.should have_tag("li", :count => 2)
end
it "should not match if the count is wrong" do
lambda {
@body.should have_tag("li", :count => 3)
}.should raise_error(Spec::Expectations::ExpectationNotMetError)
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") do |node|
node.should have_tag("div", :class => "inner")
end
end
it "should not match any parent tags in the block" do
lambda {
@body.should have_tag("div", :class => "inner") do |node|
node.should have_tag("div", :id => "main")
end
}.should raise_error(Spec::Expectations::ExpectationNotMetError)
end
it "should work with items that have multiple child nodes" do
@body.should have_tag("ul") do |n|
n.should have_tag("li", :content => "First")
n.should have_tag("li", :content => "Second")
end
end
describe "asserts for tags" do describe "asserts for tags" do
include Test::Unit::Assertions include Test::Unit::Assertions
@ -101,48 +25,15 @@ describe "have_tag" do
end end
describe "assert_have_tag" do describe "assert_have_tag" do
it "should pass when body contains the tag" do it "should be an alias for assert_have_selector" do
assert_have_tag("div") assert_have_tag("div")
end 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 doesn't have matching tag" do
lambda {
assert_have_tag("p")
}.should raise_error(Test::Unit::AssertionFailedError)
end
it "should throw an exception when the body doesn't have a tag matching the attributes" do
lambda {
assert_have_tag("div", :class => "nope")
}.should raise_error(Test::Unit::AssertionFailedError)
end
end end
describe "assert_have_no_tag" do describe "assert_have_no_tag" do
it "should pass when the body doesn't contan the tag" do it "should be an alias for assert_have_no_selector" do
assert_have_no_tag("p") assert_have_no_tag("p")
end 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 end
end end