Skip to content

Commit

Permalink
merged jrun and gwynms merb changes into main webrat code
Browse files Browse the repository at this point in the history
  • Loading branch information
orangewolf committed Oct 11, 2008
2 parents 33fdf33 + 300880d commit dbb3883
Show file tree
Hide file tree
Showing 17 changed files with 516 additions and 20 deletions.
3 changes: 2 additions & 1 deletion .gitignore
@@ -1,5 +1,6 @@
coverage
.DS_Store
pkg
doc
ri
email.txt
email.txt
12 changes: 11 additions & 1 deletion README.txt
Expand Up @@ -65,7 +65,10 @@ A test written with Webrat can handle these changes to these without any modific
Install
-------

To install the latest release:
* 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)

sudo gem install webrat

Expand All @@ -75,6 +78,13 @@ 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:
Requirements
------------

Expand Down
127 changes: 127 additions & 0 deletions lib/boot_merb.rb
@@ -0,0 +1,127 @@
module Webrat
module MerbTest

#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.
#
#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

follow_redirect! while redirect?
status
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
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
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'
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")



39 changes: 39 additions & 0 deletions 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

125 changes: 125 additions & 0 deletions lib/merb_support/indifferent_access.rb
@@ -0,0 +1,125 @@
# 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


17 changes: 17 additions & 0 deletions 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
12 changes: 12 additions & 0 deletions 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

0 comments on commit dbb3883

Please sign in to comment.