From cdafd2ec0ff481d5676e808e46a1f1108fafeea1 Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Wed, 16 Apr 2008 10:54:37 +0100 Subject: [PATCH 01/19] Added Merb support. --- Manifest.txt | 28 +--- lib/boot_merb.rb | 84 ++++++++++++ lib/boot_rails.rb | 39 ++++++ lib/merb_support/indifferent_access.rb | 138 ++++++++++++++++++++ lib/merb_support/param_parser.rb | 17 +++ lib/merb_support/url_encoded_pair_parser.rb | 93 +++++++++++++ lib/webrat.rb | 42 +----- lib/webrat/field.rb | 10 +- lib/webrat/logging.rb | 4 +- test/fills_in_test.rb | 12 ++ 10 files changed, 401 insertions(+), 66 deletions(-) create mode 100644 lib/boot_merb.rb create mode 100644 lib/boot_rails.rb create mode 100644 lib/merb_support/indifferent_access.rb create mode 100644 lib/merb_support/param_parser.rb create mode 100644 lib/merb_support/url_encoded_pair_parser.rb diff --git a/Manifest.txt b/Manifest.txt index 55ecc1f..abdb8ef 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -1,26 +1,3 @@ -.git/HEAD -.git/config -.git/description -.git/hooks/applypatch-msg -.git/hooks/commit-msg -.git/hooks/post-commit -.git/hooks/post-receive -.git/hooks/post-update -.git/hooks/pre-applypatch -.git/hooks/pre-commit -.git/hooks/pre-rebase -.git/hooks/update -.git/index -.git/info/exclude -.git/logs/HEAD -.git/logs/refs/heads/master -.git/logs/refs/remotes/origin/master -.git/objects/pack/pack-3243faf8e8f6f0e226adf39a2c2e8c19c18da6c4.idx -.git/objects/pack/pack-3243faf8e8f6f0e226adf39a2c2e8c19c18da6c4.pack -.git/refs/heads/master -.git/refs/remotes/origin/HEAD -.git/refs/remotes/origin/master -.gitignore History.txt MIT-LICENSE.txt Manifest.txt @@ -38,6 +15,11 @@ lib/webrat/logging.rb lib/webrat/page.rb lib/webrat/redirect_actions.rb lib/webrat/select_option.rb +lib/boot_merb.rb +lib/boot_rails.rb +lib/merb_support/indifferent_access.rb +lib/merb_support/param_parser.rb +lib/merb_support/url_encoded_pair_parser.rb test/checks_test.rb test/chooses_test.rb test/clicks_button_test.rb diff --git a/lib/boot_merb.rb b/lib/boot_merb.rb new file mode 100644 index 0000000..21c4a9b --- /dev/null +++ b/lib/boot_merb.rb @@ -0,0 +1,84 @@ +#In Merb, we have an RspecStory instead of an integration Session. +class Merb::Test::RspecStory + + #Our own redirect actions defined below, to deal with the fact that we need to store + #a controller reference. + + def current_page + @current_page ||= Webrat::Page.new(self) + end + + def current_page=(new_page) + @current_page = new_page + end + + # Issues a GET request for a page, follows any redirects, and verifies the final page + # load was successful. + # + # Example: + # visits "/" + def visits(*args) + @current_page = Webrat::Page.new(self, *args) + end + + def save_and_open_page + current_page.save_and_open + end + + [:reloads, :fills_in, :clicks_button, :selects, :chooses, :checks, :unchecks, :clicks_link, :clicks_link_within, :clicks_put_link, :clicks_get_link, :clicks_post_link, :clicks_delete_link].each do |method_name| + define_method(method_name) do |*args| + current_page.send(method_name, *args) + end + end + + #Session defines the following (used by webrat), but RspecStory doesn't. Merb's get/put/delete return a controller, + #which is where we get our status and response from. + def get_via_redirect(path, parameters = {}, headers = {}) + @controller=get path, parameters, headers + follow_redirect! while redirect? + status + end + def put_via_redirect(path, parameters = {}, headers = {}) + @controller=put path, parameters, headers + follow_redirect! while redirect? + status + end + def delete_via_redirect(path, parameters = {}, headers = {}) + @controller=delete path, parameters, headers + follow_redirect! while redirect? + status + end + + def follow_redirect! + @controller=get @controller.headers["Location"] + end + + def redirect? + [307, *(300..305)].include?(status) + end + + def status + @controller.status + end + + def response + @controller #things like @controller.body will work. + end + + def assert_response(resp) + if resp == :success + response.should be_successful + else + raise "assert_response #{resp.inspect} is not supported" + end + end +end + +#Other utilities used by Webrat that are present in Rails but not Merb. We can require heavy dependencies +#here because we're only loaded in Test mode. +require 'strscan' +require 'cgi' +require File.join(File.dirname(__FILE__), "merb_support", "param_parser.rb") +require File.join(File.dirname(__FILE__), "merb_support", "url_encoded_pair_parser.rb") +require File.join(File.dirname(__FILE__), "merb_support", "indifferent_access.rb") + diff --git a/lib/boot_rails.rb b/lib/boot_rails.rb new file mode 100644 index 0000000..1954ca7 --- /dev/null +++ b/lib/boot_rails.rb @@ -0,0 +1,39 @@ +module ActionController + module Integration + class Session + + unless instance_methods.include?("put_via_redirect") + include Webrat::RedirectActions + end + + def current_page + @current_page ||= Webrat::Page.new(self) + end + + def current_page=(new_page) + @current_page = new_page + end + + # Issues a GET request for a page, follows any redirects, and verifies the final page + # load was successful. + # + # Example: + # visits "/" + def visits(*args) + @current_page = Webrat::Page.new(self, *args) + end + + def save_and_open_page + current_page.save_and_open + end + + [:reloads, :fills_in, :clicks_button, :selects, :chooses, :checks, :unchecks, :clicks_link, :clicks_link_within, :clicks_put_link, :clicks_get_link, :clicks_post_link, :clicks_delete_link].each do |method_name| + define_method(method_name) do |*args| + current_page.send(method_name, *args) + end + end + + end + end +end + diff --git a/lib/merb_support/indifferent_access.rb b/lib/merb_support/indifferent_access.rb new file mode 100644 index 0000000..2213b09 --- /dev/null +++ b/lib/merb_support/indifferent_access.rb @@ -0,0 +1,138 @@ +# This class has dubious semantics and we only have it so that +# people can write params[:key] instead of params['key'] +# and they get the same value for both keys. + +class HashWithIndifferentAccess < Hash + def initialize(constructor = {}) + if constructor.is_a?(Hash) + super() + update(constructor) + else + super(constructor) + end + end + + def default(key = nil) + if key.is_a?(Symbol) && include?(key = key.to_s) + self[key] + else + super + end + end + + alias_method :regular_writer, :[]= unless method_defined?(:regular_writer) + alias_method :regular_update, :update unless method_defined?(:regular_update) + + # + # Assigns a new value to the hash. + # + # Example: + # + # hash = HashWithIndifferentAccess.new + # hash[:key] = "value" + # + def []=(key, value) + regular_writer(convert_key(key), convert_value(value)) + end + + # + # Updates the instantized hash with values from the second. + # + # Example: + # + # >> hash_1 = HashWithIndifferentAccess.new + # => {} + # + # >> hash_1[:key] = "value" + # => "value" + # + # >> hash_2 = HashWithIndifferentAccess.new + # => {} + # + # >> hash_2[:key] = "New Value!" + # => "New Value!" + # + # >> hash_1.update(hash_2) + # => {"key"=>"New Value!"} + # + def update(other_hash) + other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) } + self + end + + alias_method :merge!, :update + + # Checks the hash for a key matching the argument passed in + def key?(key) + super(convert_key(key)) + end + + alias_method :include?, :key? + alias_method :has_key?, :key? + alias_method :member?, :key? + + # Fetches the value for the specified key, same as doing hash[key] + def fetch(key, *extras) + super(convert_key(key), *extras) + end + + # Returns an array of the values at the specified indicies. + def values_at(*indices) + indices.collect {|key| self[convert_key(key)]} + end + + # Returns an exact copy of the hash. + def dup + HashWithIndifferentAccess.new(self) + end + + # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash + # Does not overwrite the existing hash. + def merge(hash) + self.dup.update(hash) + end + + # Removes a specified key from the hash. + def delete(key) + super(convert_key(key)) + end + + def stringify_keys!; self end + def symbolize_keys!; self end + def to_options!; self end + + # Convert to a Hash with String keys. + def to_hash + Hash.new(default).merge(self) + end + + protected + def convert_key(key) + key.kind_of?(Symbol) ? key.to_s : key + end + + def convert_value(value) + case value + when Hash + value.with_indifferent_access + when Array + value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e } + else + value + end + end +end + +module ActiveSupport #:nodoc: + module CoreExtensions #:nodoc: + module Hash #:nodoc: + module IndifferentAccess #:nodoc: + def with_indifferent_access + hash = HashWithIndifferentAccess.new(self) + hash.default = self.default + hash + end + end + end + end +end diff --git a/lib/merb_support/param_parser.rb b/lib/merb_support/param_parser.rb new file mode 100644 index 0000000..534e1ff --- /dev/null +++ b/lib/merb_support/param_parser.rb @@ -0,0 +1,17 @@ +module Webrat + class ParamParser + def self.parse_query_parameters(query_string) + return {} if query_string.blank? + + pairs = query_string.split('&').collect do |chunk| + next if chunk.empty? + key, value = chunk.split('=', 2) + next if key.empty? + value = value.nil? ? nil : CGI.unescape(value) + [ CGI.unescape(key), value ] + end.compact + + UrlEncodedPairParser.new(pairs).result + end + end +end \ No newline at end of file diff --git a/lib/merb_support/url_encoded_pair_parser.rb b/lib/merb_support/url_encoded_pair_parser.rb new file mode 100644 index 0000000..8e668c7 --- /dev/null +++ b/lib/merb_support/url_encoded_pair_parser.rb @@ -0,0 +1,93 @@ +class UrlEncodedPairParser < StringScanner #:nodoc: + attr_reader :top, :parent, :result + + def initialize(pairs = []) + super('') + @result = {} + pairs.each { |key, value| parse(key, value) } + end + + KEY_REGEXP = %r{([^\[\]=&]+)} + BRACKETED_KEY_REGEXP = %r{\[([^\[\]=&]+)\]} + + # Parse the query string + def parse(key, value) + self.string = key + @top, @parent = result, nil + + # First scan the bare key + key = scan(KEY_REGEXP) or return + key = post_key_check(key) + + # Then scan as many nestings as present + until eos? + r = scan(BRACKETED_KEY_REGEXP) or return + key = self[1] + key = post_key_check(key) + end + + bind(key, value) + end + + private + # After we see a key, we must look ahead to determine our next action. Cases: + # + # [] follows the key. Then the value must be an array. + # = follows the key. (A value comes next) + # & or the end of string follows the key. Then the key is a flag. + # otherwise, a hash follows the key. + def post_key_check(key) + if scan(/\[\]/) # a[b][] indicates that b is an array + container(key, Array) + nil + elsif check(/\[[^\]]/) # a[b] indicates that a is a hash + container(key, Hash) + nil + else # End of key? We do nothing. + key + end + end + + # Add a container to the stack. + def container(key, klass) + type_conflict! klass, top[key] if top.is_a?(Hash) && top.key?(key) && ! top[key].is_a?(klass) + value = bind(key, klass.new) + type_conflict! klass, value unless value.is_a?(klass) + push(value) + end + + # Push a value onto the 'stack', which is actually only the top 2 items. + def push(value) + @parent, @top = @top, value + end + + # Bind a key (which may be nil for items in an array) to the provided value. + def bind(key, value) + if top.is_a? Array + if key + if top[-1].is_a?(Hash) && ! top[-1].key?(key) + top[-1][key] = value + else + top << {key => value}.with_indifferent_access + push top.last + value = top[key] + end + else + top << value + end + elsif top.is_a? Hash + key = CGI.unescape(key) + parent << (@top = {}) if top.key?(key) && parent.is_a?(Array) + top[key] ||= value + return top[key] + else + raise ArgumentError, "Don't know what to do: top is #{top.inspect}" + end + + return value + end + + def type_conflict!(klass, value) + raise TypeError, "Conflicting types for parameter containers. Expected an instance of #{klass} but found an instance of #{value.class}. This can be caused by colliding Array and Hash parameters like qs[]=value&qs[key]=value. (The parameters received were #{value.inspect}.)" + end +end \ No newline at end of file diff --git a/lib/webrat.rb b/lib/webrat.rb index 4401f1a..744fe10 100644 --- a/lib/webrat.rb +++ b/lib/webrat.rb @@ -6,42 +6,8 @@ module Webrat VERSION = '0.2.1' end -module ActionController - module Integration - class Session - - unless instance_methods.include?("put_via_redirect") - include Webrat::RedirectActions - end - - def current_page - @current_page ||= Webrat::Page.new(self) - end - - def current_page=(new_page) - @current_page = new_page - end - - # Issues a GET request for a page, follows any redirects, and verifies the final page - # load was successful. - # - # Example: - # visits "/" - def visits(*args) - @current_page = Webrat::Page.new(self, *args) - end - - def save_and_open_page - current_page.save_and_open - end - - [:reloads, :fills_in, :clicks_button, :selects, :chooses, :checks, :unchecks, :clicks_link, :clicks_link_within, :clicks_put_link, :clicks_get_link, :clicks_post_link, :clicks_delete_link].each do |method_name| - define_method(method_name) do |*args| - current_page.send(method_name, *args) - end - end - - end - end +if defined?(Merb) + require File.join(File.dirname(__FILE__), "boot_merb.rb") +else + require File.join(File.dirname(__FILE__), "boot_rails.rb") end - diff --git a/lib/webrat/field.rb b/lib/webrat/field.rb index 34b70bd..7c28798 100644 --- a/lib/webrat/field.rb +++ b/lib/webrat/field.rb @@ -6,15 +6,15 @@ module Webrat if %w[submit image].include?(element["type"]) field_class = "button" else - field_class = element["type"] + field_class = element["type"] || "text" #default type; 'type' attribute is not mandatory end else field_class = element.name end Webrat.const_get("#{field_class.capitalize}Field") - rescue NameError - raise "Invalid field element: #{element.inspect}" + #rescue NameError + # raise "Invalid field element: #{element.inspect}" end def initialize(form, element) @@ -92,8 +92,10 @@ module Webrat def param_parser if defined?(CGIMethods) CGIMethods - else + elsif defined?(ActionController::AbstractRequest) ActionController::AbstractRequest + else + Webrat::ParamParser #used for Merb end end diff --git a/lib/webrat/logging.rb b/lib/webrat/logging.rb index 08e9870..a77b6fa 100644 --- a/lib/webrat/logging.rb +++ b/lib/webrat/logging.rb @@ -3,12 +3,14 @@ module Webrat def debug_log(message) # :nodoc: return unless logger - logger.debug + logger.debug message end def logger # :nodoc: if defined? RAILS_DEFAULT_LOGGER RAILS_DEFAULT_LOGGER + elsif defined? Merb + Merb.logger else nil end diff --git a/test/fills_in_test.rb b/test/fills_in_test.rb index 0ebb567..19daf3f 100644 --- a/test/fills_in_test.rb +++ b/test/fills_in_test.rb @@ -137,6 +137,18 @@ class FillsInTest < Test::Unit::TestCase @session.fills_in "user[email]", :with => "foo@example.com" @session.clicks_button end + + def test_should_work_without_input_type + @response.stubs(:body).returns(<<-EOS) +
+ + +
+ EOS + @session.expects(:post_via_redirect).with("/login", "user" => {"email" => "foo@example.com"}) + @session.fills_in "user[email]", :with => "foo@example.com" + @session.clicks_button + end def test_should_work_with_symbols @response.stubs(:body).returns(<<-EOS) From 44745f689164ca1b53b1af6277cb361395e42bd9 Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Wed, 16 Apr 2008 15:35:10 +0100 Subject: [PATCH 02/19] Fixed Webrat not finding

+ + + EOS + @session.expects(:post_via_redirect) + @session.clicks_button + end + def test_should_not_explode_on_file_fields @response.stubs(:body).returns(<<-EOS)
From 04261e66d88f9e5272d00e828e49896dbcf0d6f3 Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Wed, 16 Apr 2008 15:37:47 +0100 Subject: [PATCH 03/19] Added missing post_via_redirect --- lib/boot_merb.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/boot_merb.rb b/lib/boot_merb.rb index 21c4a9b..d5c85f0 100644 --- a/lib/boot_merb.rb +++ b/lib/boot_merb.rb @@ -43,6 +43,11 @@ class Merb::Test::RspecStory follow_redirect! while redirect? status end + def post_via_redirect(path, parameters = {}, headers = {}) + @controller=post path, parameters, headers + follow_redirect! while redirect? + status + end def delete_via_redirect(path, parameters = {}, headers = {}) @controller=delete path, parameters, headers follow_redirect! while redirect? From f74037e4dac06f7c4a6f2f43a38296abbd749886 Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Wed, 16 Apr 2008 17:12:31 +0100 Subject: [PATCH 04/19] Preserve cookies, so that we don't lose the session between requests. Make sure you are using the memory session store. --- lib/boot_merb.rb | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/lib/boot_merb.rb b/lib/boot_merb.rb index d5c85f0..11120cb 100644 --- a/lib/boot_merb.rb +++ b/lib/boot_merb.rb @@ -33,29 +33,38 @@ class Merb::Test::RspecStory #Session defines the following (used by webrat), but RspecStory doesn't. Merb's get/put/delete return a controller, #which is where we get our status and response from. + # + #We have to preserve cookies like this, or the session is lost. + def request_via_redirect(method,path,parameters={},headers={}) + mycookies = @controller.cookies rescue nil #will be nil if no requests yet + @controller=self.send(method, path, parameters, headers) do |new_controller| + new_controller.cookies = mycookies + end + follow_redirect! while redirect? + status + end + def get_via_redirect(path, parameters = {}, headers = {}) - @controller=get path, parameters, headers - follow_redirect! while redirect? - status + request_via_redirect(:get,path,parameters,headers) end + def put_via_redirect(path, parameters = {}, headers = {}) - @controller=put path, parameters, headers - follow_redirect! while redirect? - status + request_via_redirect(:put,path,parameters,headers) end + def post_via_redirect(path, parameters = {}, headers = {}) - @controller=post path, parameters, headers - follow_redirect! while redirect? - status + request_via_redirect(:post,path,parameters,headers) end + def delete_via_redirect(path, parameters = {}, headers = {}) - @controller=delete path, parameters, headers - follow_redirect! while redirect? - status + request_via_redirect(:delete,path,parameters,headers) end def follow_redirect! - @controller=get @controller.headers["Location"] + mycookies = @controller.cookies rescue nil + @controller=get @controller.headers["Location"] do |new_controller| + new_controller.cookies=mycookies + end end def redirect? @@ -79,6 +88,13 @@ class Merb::Test::RspecStory end end +class Application < Merb::Controller + def cookies=(newcookies) + @_cookies = newcookies + end +end + + #Other utilities used by Webrat that are present in Rails but not Merb. We can require heavy dependencies #here because we're only loaded in Test mode. require 'strscan' From ede0073db409a379573bd5573f56e9794161ca0f Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Wed, 16 Apr 2008 17:14:23 +0100 Subject: [PATCH 05/19] Added note to readme file: use session_store = memory or lose your sessions. --- README.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.txt b/README.txt index ffbdf08..467385c 100644 --- a/README.txt +++ b/README.txt @@ -63,7 +63,7 @@ A test written with Webrat can handle these changes smoothly. == REQUIREMENTS: -* Rails >= 1.2.6 +* Rails >= 1.2.6 or Merb edge * Hpricot >= 0.6 * Rails integration tests in Test::Unit _or_ * RSpec stories (using an RSpec version >= revision 2997) @@ -76,6 +76,12 @@ In your stories/helper.rb: You could also unpack the gem into vendor/plugins. +To avoid losing sessions, you need this in environments/test.rb: + +Merb::Config.use do |c| + c[:session_store] = 'memory' +end + == HISTORY: See CHANGELOG in this directory. From 2e03051735e5fecb9270437a677ecf76c609a6de Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Thu, 17 Apr 2008 11:52:42 +0100 Subject: [PATCH 06/19] Wrap RAILS_ROOT to support Merb also --- lib/webrat.rb | 3 +++ lib/webrat/page.rb | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/webrat.rb b/lib/webrat.rb index 744fe10..2419dba 100644 --- a/lib/webrat.rb +++ b/lib/webrat.rb @@ -4,6 +4,9 @@ end module Webrat VERSION = '0.2.1' + def self.root + defined?(RAILS_ROOT) ? RAILS_ROOT : Merb.root + end end if defined?(Merb) diff --git a/lib/webrat/page.rb b/lib/webrat/page.rb index 65e5056..7887aa7 100644 --- a/lib/webrat/page.rb +++ b/lib/webrat/page.rb @@ -94,10 +94,10 @@ module Webrat # Example: # save_and_open def save_and_open - return unless File.exist?(RAILS_ROOT + "/tmp") + return unless File.exist?(Webrat.root + "/tmp") filename = "webrat-#{Time.now.to_i}.html" - File.open(RAILS_ROOT + "/tmp/#{filename}", "w") do |f| + File.open(Webrat.root + "/tmp/#{filename}", "w") do |f| f.write response.body end `open tmp/#{filename}` From a45d654bb8f44e30dc1c93f465fa63ac07102943 Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Fri, 18 Apr 2008 13:19:13 +0100 Subject: [PATCH 07/19] Basic test working --- test/helper.rb | 43 +++++++++++++++++++++++++++++++------------ test/visits_test.rb | 21 +++++++++++++++------ 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/test/helper.rb b/test/helper.rb index 9c0418e..35550ce 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -1,20 +1,39 @@ require "rubygems" require "test/unit" -# gem install redgreen for colored test output -begin require "redgreen" unless ENV['TM_CURRENT_LINE']; rescue LoadError; end require "mocha" -require "active_support" +# gem install redgreen for colored test output +begin require "redgreen" unless ENV['TM_CURRENT_LINE']; rescue LoadError; end -silence_warnings do - require "action_controller" - require "action_controller/integration" +if ENV["TEST_MODE"] == "rails" + require "active_support" + silence_warnings do + require "action_controller" + require "action_controller/integration" + end + + class ActionController::Integration::Session + def flunk(message) + raise message + end + end + +elsif ENV["TEST_MODE"] == "merb" + require 'merb-core' + require 'merb_stories' + #require 'spec' #makes mocha cry + module Merb + module Test + class RspecStory + include Merb::Test::ControllerHelper + include Merb::Test::RouteHelper + include Merb::Test::ViewHelper + end + end + end + +else + raise "Please set the environment variable TEST_MODE to either 'rails' or 'merb'." end require File.expand_path(File.dirname(__FILE__) + "/../lib/webrat") - -class ActionController::Integration::Session - def flunk(message) - raise message - end -end \ No newline at end of file diff --git a/test/visits_test.rb b/test/visits_test.rb index 0b89631..d497892 100644 --- a/test/visits_test.rb +++ b/test/visits_test.rb @@ -5,12 +5,21 @@ RAILS_ROOT = "." unless defined?(RAILS_ROOT) class VisitsTest < Test::Unit::TestCase def setup - @session = ActionController::Integration::Session.new - @session.stubs(:assert_response) - @session.stubs(:get_via_redirect) - @response = mock - @session.stubs(:response).returns(@response) - @response.stubs(:body).returns("") + if ENV["TEST_MODE"] == "rails" + @session = ActionController::Integration::Session.new + @session.stubs(:assert_response) + @session.stubs(:get_via_redirect) + @response = mock + @session.stubs(:response).returns(@response) + @response.stubs(:body).returns("") + elsif ENV["TEST_MODE"] == "merb" + @session = Merb::Test::RspecStory.new + @session.stubs(:assert_response) + @session.stubs(:get_via_redirect) + @response = mock + @session.stubs(:response).returns(@response) + @response.stubs(:body).returns("") + end end def test_should_use_get From b9f6affa3f44b766c3fe6f657d3e099b1592d87f Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Fri, 18 Apr 2008 13:37:03 +0100 Subject: [PATCH 08/19] All but 3 merb tests pass --- test/checks_test.rb | 4 ++-- test/chooses_test.rb | 2 +- test/clicks_button_test.rb | 2 +- test/clicks_link_test.rb | 2 +- test/fills_in_test.rb | 2 +- test/helper.rb | 37 +++++++++---------------------------- test/reloads_test.rb | 2 +- test/selects_test.rb | 2 +- test/visits_test.rb | 21 ++++++--------------- 9 files changed, 23 insertions(+), 51 deletions(-) diff --git a/test/checks_test.rb b/test/checks_test.rb index 7d3113b..56f4432 100644 --- a/test/checks_test.rb +++ b/test/checks_test.rb @@ -2,7 +2,7 @@ require File.dirname(__FILE__) + "/helper" class ChecksTest < Test::Unit::TestCase def setup - @session = ActionController::Integration::Session.new + @session = test_session @session.stubs(:assert_response) @session.stubs(:get_via_redirect) @session.stubs(:response).returns(@response=mock) @@ -72,7 +72,7 @@ end class UnchecksTest < Test::Unit::TestCase def setup - @session = ActionController::Integration::Session.new + @session = test_session @session.stubs(:assert_response) @session.stubs(:get_via_redirect) @session.stubs(:response).returns(@response=mock) diff --git a/test/chooses_test.rb b/test/chooses_test.rb index 6b9afa8..cd5097e 100644 --- a/test/chooses_test.rb +++ b/test/chooses_test.rb @@ -3,7 +3,7 @@ require File.dirname(__FILE__) + "/helper" class ChoosesTest < Test::Unit::TestCase def setup - @session = ActionController::Integration::Session.new + @session = test_session @session.stubs(:assert_response) @session.stubs(:get_via_redirect) @session.stubs(:response).returns(@response=mock) diff --git a/test/clicks_button_test.rb b/test/clicks_button_test.rb index 26a8b9a..4239b2e 100644 --- a/test/clicks_button_test.rb +++ b/test/clicks_button_test.rb @@ -2,7 +2,7 @@ require File.dirname(__FILE__) + "/helper" class ClicksButtonTest < Test::Unit::TestCase def setup - @session = ActionController::Integration::Session.new + @session = test_session @session.stubs(:assert_response) @session.stubs(:get_via_redirect) @page = Webrat::Page.new(@session) diff --git a/test/clicks_link_test.rb b/test/clicks_link_test.rb index 3b1c7e9..7ed2db6 100644 --- a/test/clicks_link_test.rb +++ b/test/clicks_link_test.rb @@ -2,7 +2,7 @@ require File.dirname(__FILE__) + "/helper" class ClicksLinkTest < Test::Unit::TestCase def setup - @session = ActionController::Integration::Session.new + @session = test_session @session.stubs(:assert_response) @session.stubs(:get_via_redirect) @session.stubs(:response).returns(@response=mock) diff --git a/test/fills_in_test.rb b/test/fills_in_test.rb index 19daf3f..aba64c8 100644 --- a/test/fills_in_test.rb +++ b/test/fills_in_test.rb @@ -2,7 +2,7 @@ require File.dirname(__FILE__) + "/helper" class FillsInTest < Test::Unit::TestCase def setup - @session = ActionController::Integration::Session.new + @session = test_session @session.stubs(:assert_response) @session.stubs(:get_via_redirect) @session.stubs(:response).returns(@response=mock) diff --git a/test/helper.rb b/test/helper.rb index 35550ce..8b6224b 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -5,35 +5,16 @@ require "mocha" # gem install redgreen for colored test output begin require "redgreen" unless ENV['TM_CURRENT_LINE']; rescue LoadError; end -if ENV["TEST_MODE"] == "rails" - require "active_support" - silence_warnings do - require "action_controller" - require "action_controller/integration" - end - - class ActionController::Integration::Session - def flunk(message) - raise message - end - end - -elsif ENV["TEST_MODE"] == "merb" - require 'merb-core' - require 'merb_stories' - #require 'spec' #makes mocha cry - module Merb - module Test - class RspecStory - include Merb::Test::ControllerHelper - include Merb::Test::RouteHelper - include Merb::Test::ViewHelper - end - end - end - +if ["rails","merb"].include?(ENV["TEST_MODE"]) + require File.join(File.dirname(__FILE__), "helper_#{ENV["TEST_MODE"]}.rb") else raise "Please set the environment variable TEST_MODE to either 'rails' or 'merb'." end - + require File.expand_path(File.dirname(__FILE__) + "/../lib/webrat") + +def test_session + return ActionController::Integration::Session.new if ENV["TEST_MODE"] == "rails" + return Merb::Test::RspecStory.new if ENV["TEST_MODE"] == "merb" + raise "Unknown test type #{ENV["TEST_MODE"]}" +end \ No newline at end of file diff --git a/test/reloads_test.rb b/test/reloads_test.rb index 1f3e1ff..a69c330 100644 --- a/test/reloads_test.rb +++ b/test/reloads_test.rb @@ -5,7 +5,7 @@ RAILS_ROOT = "." unless defined?(RAILS_ROOT) class ReloadsTest < Test::Unit::TestCase def setup - @session = ActionController::Integration::Session.new + @session = test_session @session.stubs(:assert_response) @session.stubs(:get_via_redirect) @response = mock diff --git a/test/selects_test.rb b/test/selects_test.rb index 05576c4..cc26f37 100644 --- a/test/selects_test.rb +++ b/test/selects_test.rb @@ -2,7 +2,7 @@ require File.dirname(__FILE__) + "/helper" class SelectsTest < Test::Unit::TestCase def setup - @session = ActionController::Integration::Session.new + @session = test_session @session.stubs(:assert_response) @session.stubs(:get_via_redirect) @session.stubs(:response).returns(@response=mock) diff --git a/test/visits_test.rb b/test/visits_test.rb index d497892..a17cf54 100644 --- a/test/visits_test.rb +++ b/test/visits_test.rb @@ -5,21 +5,12 @@ RAILS_ROOT = "." unless defined?(RAILS_ROOT) class VisitsTest < Test::Unit::TestCase def setup - if ENV["TEST_MODE"] == "rails" - @session = ActionController::Integration::Session.new - @session.stubs(:assert_response) - @session.stubs(:get_via_redirect) - @response = mock - @session.stubs(:response).returns(@response) - @response.stubs(:body).returns("") - elsif ENV["TEST_MODE"] == "merb" - @session = Merb::Test::RspecStory.new - @session.stubs(:assert_response) - @session.stubs(:get_via_redirect) - @response = mock - @session.stubs(:response).returns(@response) - @response.stubs(:body).returns("") - end + @session = test_session + @session.stubs(:assert_response) + @session.stubs(:get_via_redirect) + @response = mock + @session.stubs(:response).returns(@response) + @response.stubs(:body).returns("") end def test_should_use_get From aeb6aa056c2bab3b8ede8865bec7fac38ac8a5ee Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Fri, 18 Apr 2008 13:37:53 +0100 Subject: [PATCH 09/19] All but 3 merb tests pass --- lib/webrat.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/webrat.rb b/lib/webrat.rb index 2419dba..106288b 100644 --- a/lib/webrat.rb +++ b/lib/webrat.rb @@ -10,6 +10,7 @@ module Webrat end if defined?(Merb) + puts "************ Booting merb mode" require File.join(File.dirname(__FILE__), "boot_merb.rb") else require File.join(File.dirname(__FILE__), "boot_rails.rb") From c967a02ca01293738cf6d8b6bb2027a13de4193d Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Fri, 18 Apr 2008 16:39:28 +0100 Subject: [PATCH 10/19] All tests pass in merb --- lib/boot_merb.rb | 3 +++ lib/merb_support/indifferent_access.rb | 15 +-------------- lib/webrat.rb | 1 - lib/webrat/form.rb | 2 +- 4 files changed, 5 insertions(+), 16 deletions(-) diff --git a/lib/boot_merb.rb b/lib/boot_merb.rb index 11120cb..59fe2b2 100644 --- a/lib/boot_merb.rb +++ b/lib/boot_merb.rb @@ -102,4 +102,7 @@ require 'cgi' require File.join(File.dirname(__FILE__), "merb_support", "param_parser.rb") require File.join(File.dirname(__FILE__), "merb_support", "url_encoded_pair_parser.rb") require File.join(File.dirname(__FILE__), "merb_support", "indifferent_access.rb") +require File.join(File.dirname(__FILE__), "merb_support", "support.rb") + + diff --git a/lib/merb_support/indifferent_access.rb b/lib/merb_support/indifferent_access.rb index 2213b09..26e0814 100644 --- a/lib/merb_support/indifferent_access.rb +++ b/lib/merb_support/indifferent_access.rb @@ -1,7 +1,6 @@ # This class has dubious semantics and we only have it so that # people can write params[:key] instead of params['key'] # and they get the same value for both keys. - class HashWithIndifferentAccess < Hash def initialize(constructor = {}) if constructor.is_a?(Hash) @@ -123,16 +122,4 @@ class HashWithIndifferentAccess < Hash end end -module ActiveSupport #:nodoc: - module CoreExtensions #:nodoc: - module Hash #:nodoc: - module IndifferentAccess #:nodoc: - def with_indifferent_access - hash = HashWithIndifferentAccess.new(self) - hash.default = self.default - hash - end - end - end - end -end + diff --git a/lib/webrat.rb b/lib/webrat.rb index 106288b..2419dba 100644 --- a/lib/webrat.rb +++ b/lib/webrat.rb @@ -10,7 +10,6 @@ module Webrat end if defined?(Merb) - puts "************ Booting merb mode" require File.join(File.dirname(__FILE__), "boot_merb.rb") else require File.join(File.dirname(__FILE__), "boot_rails.rb") diff --git a/lib/webrat/form.rb b/lib/webrat/form.rb index 923e5c9..265b20c 100644 --- a/lib/webrat/form.rb +++ b/lib/webrat/form.rb @@ -123,7 +123,7 @@ module Webrat def merge_hash_values(a, b) # :nodoc: a.keys.each do |k| if b.has_key?(k) - case [a[k], b[k]].map(&:class) + case [a[k].class, b[k].class] when [Hash, Hash] a[k] = merge_hash_values(a[k], b[k]) b.delete(k) From e4e2de1206172231e6c35641a5cbc1a6e4493445 Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Fri, 18 Apr 2008 16:40:24 +0100 Subject: [PATCH 11/19] Missing files --- lib/merb_support/support.rb | 12 ++++++++++++ test/helper_merb.rb | 14 ++++++++++++++ test/helper_rails.rb | 11 +++++++++++ test/mocha_test.rb | 14 ++++++++++++++ 4 files changed, 51 insertions(+) create mode 100644 lib/merb_support/support.rb create mode 100644 test/helper_merb.rb create mode 100644 test/helper_rails.rb create mode 100644 test/mocha_test.rb diff --git a/lib/merb_support/support.rb b/lib/merb_support/support.rb new file mode 100644 index 0000000..f7c24ee --- /dev/null +++ b/lib/merb_support/support.rb @@ -0,0 +1,12 @@ +class Hash + def with_indifferent_access + hash = HashWithIndifferentAccess.new(self) + hash.default = self.default + hash + end +end +class NilClass + def to_param + nil + end +end diff --git a/test/helper_merb.rb b/test/helper_merb.rb new file mode 100644 index 0000000..cad48fd --- /dev/null +++ b/test/helper_merb.rb @@ -0,0 +1,14 @@ +require 'merb-core' +require 'merb_stories' +module Merb + module Test + class RspecStory + include Merb::Test::ControllerHelper + include Merb::Test::RouteHelper + include Merb::Test::ViewHelper + def flunk(message) + raise message + end + end + end +end diff --git a/test/helper_rails.rb b/test/helper_rails.rb new file mode 100644 index 0000000..8c0e9b4 --- /dev/null +++ b/test/helper_rails.rb @@ -0,0 +1,11 @@ +require "active_support" +silence_warnings do + require "action_controller" + require "action_controller/integration" +end + +class ActionController::Integration::Session + def flunk(message) + raise message + end +end \ No newline at end of file diff --git a/test/mocha_test.rb b/test/mocha_test.rb new file mode 100644 index 0000000..25185af --- /dev/null +++ b/test/mocha_test.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + "/helper" + +RAILS_ROOT = "." unless defined?(RAILS_ROOT) + +class FooThing +end + +class MochaTest < Test::Unit::TestCase + def test_mocha + @foo = FooThing.new + @foo.stubs(:bar).returns("bar") + assert_equal @foo.bar, "bar" + end +end From 87af3dbcc75b64ee5ab2a0db107f9b1174b89db9 Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Fri, 18 Apr 2008 16:46:57 +0100 Subject: [PATCH 12/19] Remove temporary test --- test/mocha_test.rb | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 test/mocha_test.rb diff --git a/test/mocha_test.rb b/test/mocha_test.rb deleted file mode 100644 index 25185af..0000000 --- a/test/mocha_test.rb +++ /dev/null @@ -1,14 +0,0 @@ -require File.dirname(__FILE__) + "/helper" - -RAILS_ROOT = "." unless defined?(RAILS_ROOT) - -class FooThing -end - -class MochaTest < Test::Unit::TestCase - def test_mocha - @foo = FooThing.new - @foo.stubs(:bar).returns("bar") - assert_equal @foo.bar, "bar" - end -end From 97c1f8de3c4a86f786d7a339e5aeb55a4f23d741 Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Fri, 18 Apr 2008 16:54:42 +0100 Subject: [PATCH 13/19] Tidy up: these helpers aren't needed by existing tests --- test/helper_merb.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/helper_merb.rb b/test/helper_merb.rb index cad48fd..82f54fe 100644 --- a/test/helper_merb.rb +++ b/test/helper_merb.rb @@ -3,9 +3,6 @@ require 'merb_stories' module Merb module Test class RspecStory - include Merb::Test::ControllerHelper - include Merb::Test::RouteHelper - include Merb::Test::ViewHelper def flunk(message) raise message end From 94f0086a55cec2250e226df37094b57149bd2bd1 Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Tue, 22 Apr 2008 11:25:21 +0100 Subject: [PATCH 14/19] Corrected manifest --- Manifest.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Manifest.txt b/Manifest.txt index abdb8ef..cf2fd87 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -20,6 +20,7 @@ lib/boot_rails.rb lib/merb_support/indifferent_access.rb lib/merb_support/param_parser.rb lib/merb_support/url_encoded_pair_parser.rb +lib/merb_support/support.rb test/checks_test.rb test/chooses_test.rb test/clicks_button_test.rb From 580a301984aef358bfaf22977c6ac4d25cea60aa Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Wed, 23 Apr 2008 10:41:34 +0100 Subject: [PATCH 15/19] Make sure that PUTS and DELETES are handled correctly in merb --- lib/boot_merb.rb | 7 ++++++- test/clicks_button_test.rb | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/boot_merb.rb b/lib/boot_merb.rb index 59fe2b2..e6f6e64 100644 --- a/lib/boot_merb.rb +++ b/lib/boot_merb.rb @@ -35,8 +35,13 @@ class Merb::Test::RspecStory #which is where we get our status and response from. # #We have to preserve cookies like this, or the session is lost. + # + #While (in a web application) a PUT is modelled as a POST with a parameter _method, + #this close to the metal we need to make sure that we actually hit the underlying 'put' method, + #so we rewrite 'method'. def request_via_redirect(method,path,parameters={},headers={}) - mycookies = @controller.cookies rescue nil #will be nil if no requests yet + method = parameters["_method"] if !parameters["_method"].blank? + mycookies = defined?(@controller) ? @controller.cookies : nil #will be nil if no requests yet @controller=self.send(method, path, parameters, headers) do |new_controller| new_controller.cookies = mycookies end diff --git a/test/clicks_button_test.rb b/test/clicks_button_test.rb index 4239b2e..23a297e 100644 --- a/test/clicks_button_test.rb +++ b/test/clicks_button_test.rb @@ -9,6 +9,8 @@ class ClicksButtonTest < Test::Unit::TestCase @session.stubs(:current_page).returns(@page) @response = mock @session.stubs(:response).returns(@response) + @controller = mock + @controller.stubs(:status).returns(200) end def test_should_fail_if_no_buttons @@ -349,4 +351,29 @@ class ClicksButtonTest < Test::Unit::TestCase @session.expects(:get_via_redirect).with("/login", "user" => {"email" => ""}) @session.clicks_button end + + def test_should_use_put_method_when_needed + @response.stubs(:body).returns(<<-EOS) + + + + + EOS + @session.stubs(:redirect?).returns(false) + @session.expects(:put).returns(@controller) + @session.clicks_button + end + + def test_should_use_delete_method_when_needed + @response.stubs(:body).returns(<<-EOS) +
+ + +
+ EOS + @session.stubs(:redirect?).returns(false) + @session.expects(:delete).returns(@controller) + @session.clicks_button + end + end From 2855b4382f7e6db9da68b7998b739567714a68ee Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Wed, 23 Apr 2008 14:33:05 +0100 Subject: [PATCH 16/19] Implemented Merb's magic exception handling in tests. This could be more robust. --- lib/boot_merb.rb | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/boot_merb.rb b/lib/boot_merb.rb index e6f6e64..f02c28d 100644 --- a/lib/boot_merb.rb +++ b/lib/boot_merb.rb @@ -42,9 +42,21 @@ class Merb::Test::RspecStory def request_via_redirect(method,path,parameters={},headers={}) method = parameters["_method"] if !parameters["_method"].blank? mycookies = defined?(@controller) ? @controller.cookies : nil #will be nil if no requests yet - @controller=self.send(method, path, parameters, headers) do |new_controller| - new_controller.cookies = mycookies + begin + @controller=self.send(method, path, parameters, headers) do |new_controller| + new_controller.cookies = mycookies + end + rescue => exception + raise unless exception.kind_of?(Merb::ControllerExceptions::Base) + #Now we want to go one level below 'post' to build the request ourselves, then send it to the controller + exception_klass = exception.class + klass = ::Exceptions rescue Merb::Controller + request = fake_request + request.params[:exception] = exception + request.params[:action] = exception_klass.name + @controller=dispatch_request(request, klass, exception_klass.name) end + follow_redirect! while redirect? status end From 20561b0c411c687cd755be381109937910fcda97 Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Tue, 29 Apr 2008 12:26:16 +0100 Subject: [PATCH 17/19] Also find buttons by caption, if no value has been specified. --- lib/webrat/field.rb | 4 ++++ lib/webrat/form.rb | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/lib/webrat/field.rb b/lib/webrat/field.rb index ee99d26..5d13f7f 100644 --- a/lib/webrat/field.rb +++ b/lib/webrat/field.rb @@ -105,6 +105,10 @@ module Webrat def matches_value?(value) @element["value"] =~ /^\W*#{Regexp.escape(value.to_s)}/i end + + def matches_caption?(value) + @element.innerHTML =~ /^\W*#{Regexp.escape(value.to_s)}/i + end def to_param return nil if @value.nil? diff --git a/lib/webrat/form.rb b/lib/webrat/form.rb index 265b20c..37d842d 100644 --- a/lib/webrat/form.rb +++ b/lib/webrat/form.rb @@ -37,6 +37,11 @@ module Webrat return possible_button if possible_button.matches_value?(value) end + #If nothing matched on value, try by name. + possible_buttons.each do |possible_button| + return possible_button if possible_button.matches_caption?(value) + end + nil end From 9e673539a5f8ed0f8aaec78dc8c5225612e8191e Mon Sep 17 00:00:00 2001 From: Gwyn Morfey Date: Mon, 7 Jul 2008 15:57:52 +0100 Subject: [PATCH 18/19] Now you can do clicks_button 'foo_123' (passing button ID, not value) --- lib/webrat/field.rb | 4 ++++ lib/webrat/form.rb | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/lib/webrat/field.rb b/lib/webrat/field.rb index 5d13f7f..5dec37e 100644 --- a/lib/webrat/field.rb +++ b/lib/webrat/field.rb @@ -106,6 +106,10 @@ module Webrat @element["value"] =~ /^\W*#{Regexp.escape(value.to_s)}/i end + def matches_id?(id) + @element["id"] =~ /^\W*#{Regexp.escape(id.to_s)}/i + end + def matches_caption?(value) @element.innerHTML =~ /^\W*#{Regexp.escape(value.to_s)}/i end diff --git a/lib/webrat/form.rb b/lib/webrat/form.rb index 37d842d..2b81fc4 100644 --- a/lib/webrat/form.rb +++ b/lib/webrat/form.rb @@ -33,6 +33,10 @@ module Webrat possible_buttons = fields_by_type([ButtonField]) + possible_buttons.each do |possible_button| + return possible_button if possible_button.matches_id?(value) + end + possible_buttons.each do |possible_button| return possible_button if possible_button.matches_value?(value) end From 300880db2f0d50a3e2d7b171eb9745cb50e1c534 Mon Sep 17 00:00:00 2001 From: Jeremy Burks Date: Sun, 5 Oct 2008 22:05:01 -0500 Subject: [PATCH 19/19] get webrat+cucumber+merb working i put this in env.rb require 'webrat' World do w = Object.new w.extend(Merb::Test::ViewHelper) w.extend(Merb::Test::RouteHelper) w.extend(Merb::Test::ControllerHelper) w.extend(Webrat::MerbTest) end --- lib/boot_merb.rb | 194 ++++++++++++++++++++++++----------------------- lib/webrat.rb | 2 +- 2 files changed, 99 insertions(+), 97 deletions(-) diff --git a/lib/boot_merb.rb b/lib/boot_merb.rb index f02c28d..b0500db 100644 --- a/lib/boot_merb.rb +++ b/lib/boot_merb.rb @@ -1,108 +1,110 @@ -#In Merb, we have an RspecStory instead of an integration Session. -class Merb::Test::RspecStory +module Webrat + module MerbTest - #Our own redirect actions defined below, to deal with the fact that we need to store - #a controller reference. + #Our own redirect actions defined below, to deal with the fact that we need to store + #a controller reference. - def current_page - @current_page ||= Webrat::Page.new(self) - end - - def current_page=(new_page) - @current_page = new_page - end - - # Issues a GET request for a page, follows any redirects, and verifies the final page - # load was successful. - # - # Example: - # visits "/" - def visits(*args) - @current_page = Webrat::Page.new(self, *args) - end - - def save_and_open_page - current_page.save_and_open - end - - [:reloads, :fills_in, :clicks_button, :selects, :chooses, :checks, :unchecks, :clicks_link, :clicks_link_within, :clicks_put_link, :clicks_get_link, :clicks_post_link, :clicks_delete_link].each do |method_name| - define_method(method_name) do |*args| - current_page.send(method_name, *args) + def current_page + @current_page ||= Webrat::Page.new(self) end - end - - #Session defines the following (used by webrat), but RspecStory doesn't. Merb's get/put/delete return a controller, - #which is where we get our status and response from. - # - #We have to preserve cookies like this, or the session is lost. - # - #While (in a web application) a PUT is modelled as a POST with a parameter _method, - #this close to the metal we need to make sure that we actually hit the underlying 'put' method, - #so we rewrite 'method'. - def request_via_redirect(method,path,parameters={},headers={}) - method = parameters["_method"] if !parameters["_method"].blank? - mycookies = defined?(@controller) ? @controller.cookies : nil #will be nil if no requests yet - begin - @controller=self.send(method, path, parameters, headers) do |new_controller| - new_controller.cookies = mycookies + + def current_page=(new_page) + @current_page = new_page + end + + # Issues a GET request for a page, follows any redirects, and verifies the final page + # load was successful. + # + # Example: + # visits "/" + def visits(*args) + @current_page = Webrat::Page.new(self, *args) + end + + def save_and_open_page + current_page.save_and_open + end + + [:reloads, :fills_in, :clicks_button, :selects, :chooses, :checks, :unchecks, :clicks_link, :clicks_link_within, :clicks_put_link, :clicks_get_link, :clicks_post_link, :clicks_delete_link].each do |method_name| + define_method(method_name) do |*args| + current_page.send(method_name, *args) end - rescue => exception - raise unless exception.kind_of?(Merb::ControllerExceptions::Base) - #Now we want to go one level below 'post' to build the request ourselves, then send it to the controller - exception_klass = exception.class - klass = ::Exceptions rescue Merb::Controller - request = fake_request - request.params[:exception] = exception - request.params[:action] = exception_klass.name - @controller=dispatch_request(request, klass, exception_klass.name) end - - follow_redirect! while redirect? - status - end + + #Session defines the following (used by webrat), but RspecStory doesn't. Merb's get/put/delete return a controller, + #which is where we get our status and response from. + # + #We have to preserve cookies like this, or the session is lost. + # + #While (in a web application) a PUT is modelled as a POST with a parameter _method, + #this close to the metal we need to make sure that we actually hit the underlying 'put' method, + #so we rewrite 'method'. + def request_via_redirect(method,path,parameters={},headers={}) + method = parameters["_method"] if !parameters["_method"].blank? + mycookies = defined?(@controller) ? @controller.cookies : nil #will be nil if no requests yet + begin + @controller=self.send(method, path, parameters, headers) do |new_controller| + new_controller.cookies = mycookies + end + rescue => exception + raise unless exception.kind_of?(Merb::ControllerExceptions::Base) + #Now we want to go one level below 'post' to build the request ourselves, then send it to the controller + exception_klass = exception.class + klass = ::Exceptions rescue Merb::Controller + request = fake_request + request.params[:exception] = exception + request.params[:action] = exception_klass.name + @controller=dispatch_request(request, klass, exception_klass.name) + end - def get_via_redirect(path, parameters = {}, headers = {}) - request_via_redirect(:get,path,parameters,headers) - end - - def put_via_redirect(path, parameters = {}, headers = {}) - request_via_redirect(:put,path,parameters,headers) - end - - def post_via_redirect(path, parameters = {}, headers = {}) - request_via_redirect(:post,path,parameters,headers) - end - - def delete_via_redirect(path, parameters = {}, headers = {}) - request_via_redirect(:delete,path,parameters,headers) - end - - def follow_redirect! - mycookies = @controller.cookies rescue nil - @controller=get @controller.headers["Location"] do |new_controller| - new_controller.cookies=mycookies + follow_redirect! while redirect? + status end - end - - def redirect? - [307, *(300..305)].include?(status) - end - - def status - @controller.status - end - - def response - @controller #things like @controller.body will work. - end - def assert_response(resp) - if resp == :success - response.should be_successful - else - raise "assert_response #{resp.inspect} is not supported" + def get_via_redirect(path, parameters = {}, headers = {}) + request_via_redirect(:get,path,parameters,headers) end - end + + def put_via_redirect(path, parameters = {}, headers = {}) + request_via_redirect(:put,path,parameters,headers) + end + + def post_via_redirect(path, parameters = {}, headers = {}) + request_via_redirect(:post,path,parameters,headers) + end + + def delete_via_redirect(path, parameters = {}, headers = {}) + request_via_redirect(:delete,path,parameters,headers) + end + + def follow_redirect! + mycookies = @controller.cookies rescue nil + @controller=get @controller.headers["Location"] do |new_controller| + new_controller.cookies=mycookies + end + end + + def redirect? + [307, *(300..305)].include?(status) + end + + def status + @controller.status + end + + def response + @controller #things like @controller.body will work. + end + + def assert_response(resp) + if resp == :success + response.should be_successful + else + raise "assert_response #{resp.inspect} is not supported" + end + end + + end end class Application < Merb::Controller diff --git a/lib/webrat.rb b/lib/webrat.rb index 2419dba..072145a 100644 --- a/lib/webrat.rb +++ b/lib/webrat.rb @@ -3,7 +3,7 @@ Dir[File.join(File.dirname(__FILE__), "webrat", "*.rb")].each do |file| end module Webrat - VERSION = '0.2.1' + VERSION = '0.2.2' def self.root defined?(RAILS_ROOT) ? RAILS_ROOT : Merb.root end