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: # #
# People #
# # 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