module Suhyo
module ViewMatchers
include Webrat::Matchers
# A simple wrapper around +have_selector+. Usage:
#
# response.should have_button(:text => 'Submit')
def have_button(options = {})
options[:type] = 'button'
options[:value] = options.delete(:text) if options.has_key?(:text)
have_selector('input', options)
end
class HaveOrderedContent < ::Webrat::Matchers::HasContent
def initialize(content, options = {})
@content = content
@options = options
end
def matches?(stringlike)
@document = Webrat::XML.document(stringlike)
@element = @document.inner_text
compacted = @element.gsub(/\s+/, ' ')
if index = compacted.index(@content)
if @options.has_key?(:before)
@other_content_index = compacted.index(@options[:before])
if @other_content_index.nil?
return false
else
return index < @other_content_index
end
elsif @options.has_key?(:after)
@other_content_index = compacted.index(@options[:after])
if @other_content_index.nil?
return false
else
return index > @other_content_index
end
else
return true
end
else
return nil
end
end
def failure_message
"expected the following element's content to #{content_message}#{order_message}:\n\n#{squeeze_space(@element)}"
end
def negative_failure_message
"expected the following element's content to not #{content_message}#{order_message}:\n\n#{squeeze_space(@element)}"
end
def order_message
if @options.has_key?(:before)
str = %Q{ before "#{@options[:before]}"}
if @other_content_index.nil?
str << %Q{ but "#{@options[:before]}" was not found}
end
return str
elsif @options.has_key?(:after)
str = %Q{ after "#{@options[:after]}"}
if @other_content_index.nil?
str << %Q{ but "#{@options[:after]}" was not found}
end
return str
else
return nil
end
end
end
# Like Webrat's +contain+ matcher, except it checks that one bit of text comes before or after another.
# Can be used to test sort order in an integration test. Usage:
#
# response.should contain_in_order('ABC', :before => 'DEF')
# response.should contain_in_order('DEF', :after => 'ABC')
def contain_in_order(content, options = {})
HaveOrderedContent.new(content, options)
end
# A simple wrapper around +have_selector+. Usage:
#
# response.should have_link(:url => people_url, :text => 'People', :ancestors => 'div#main')
#
# The above example would match the following:
#
#
#
# Options other than +:url+, +:text+, and +ancestors+ will be passed through
# to +have_selector+.
def have_link(options = {})
options[:href] = options.delete(:url) if options.has_key?(:url)
options[:content] = options.delete(:text) if options.has_key?(:text)
if ancestors = options.delete(:ancestors)
selector = ancestors + ' a'
else
selector = 'a'
end
have_selector(selector, options)
end
class HaveRestfulForm < ::Webrat::Matchers::HaveSelector
def initialize(method, options = {}, &block)
raise(ArgumentError, "Expected options to be a Hash, but got #{options.inspect}") unless options.is_a?(Hash)
@options = options
@method = method.to_s.downcase
unless @method == 'get' or @method == 'post' or @method == 'put' or @method == 'delete'
raise(ArgumentError, "Expected method to be 'get', 'post', 'put', or 'delete', but got #{method.inspect}")
end
# browser_method is the method the browser actually uses, either GET or POST
@browser_method = (method == 'get') ? 'get' : 'post'
if ancestors = @options.delete(:ancestors)
@expected = ancestors + ' form'
else
@expected = 'form'
end
@options.merge!(:method => @browser_method)
@block = block
end
def matches(stringlike)
# Cache it, because we're going to use it again in matches_hidden_field?
@matches ||= super(stringlike)
end
def matches?(stringlike, &block)
super(stringlike, &block) and matches_hidden_field?(stringlike)
end
def matches_hidden_field?(stringlike)
form = matches(stringlike)
case @method
when 'get', 'post'
!::Webrat::Matchers::HaveSelector.new('input', :name => '_method').matches?(form)
when 'put'
::Webrat::Matchers::HaveSelector.new('input', :name => '_method', :value => 'put').matches?(form)
when 'delete'
::Webrat::Matchers::HaveSelector.new('input', :name => '_method', :value => 'delete').matches?(form)
end
end
# Messages
def failure_message
"expected following output to contain a #{@method.upcase} form#{attributes_message}:\n\n#{@document}"
end
def negative_failure_message
"expected following output to omit a #{@method.upcase} form#{attributes_message}:\n\n#{@document}"
end
def attributes_message
attrs = @options.dup
attrs.delete(:method)
attrs.empty? ? nil : ' with attributes ' + attrs.inspect
end
end
# Wrapper around +have_selector+. Checks for a Rails-style form with the given HTTP method.
# You can also specify the +action+ and any other other attributes in the +options+ hash. Usage:
#
# response.should have_restful_form('put', :action => person_path(42), :class => 'edit_person', :ancestors => 'div#main')
#
# The above example would match the following:
#
#
#
#
#
# Options other than +ancestors+ will be passed through to +have_selector+.
def have_restful_form(method, options = {})
HaveRestfulForm.new(method, options)
end
end
end