build querystring with all form elements and then parse to get query params
* Basically Field#to_param was replaced for Field#to_query_string and some methods related to build params were moved to Form class. Before this commit the params hash was made by parsing each element querystring to param and then merge, now we build the whole querystring first and then parse it to get params with Rack or Rails depending of the configure mode.
This commit is contained in:
parent
2f12422ae8
commit
fa881a88c8
|
@ -1,6 +1,7 @@
|
|||
require "cgi"
|
||||
require "digest/md5"
|
||||
require "webrat/core_extensions/blank"
|
||||
require "webrat/core_extensions/nil_to_param"
|
||||
require "webrat/core_extensions/nil_to_query_string"
|
||||
|
||||
require "webrat/core/elements/element"
|
||||
|
||||
|
@ -13,7 +14,7 @@ module Webrat
|
|||
attr_reader :value
|
||||
|
||||
def self.xpath_search
|
||||
[".//button", ".//input", ".//textarea", ".//select"]
|
||||
".//button|.//input|.//textarea|.//select"
|
||||
end
|
||||
|
||||
def self.xpath_search_excluding_hidden
|
||||
|
@ -84,19 +85,17 @@ module Webrat
|
|||
raise DisabledFieldError.new("Cannot interact with disabled form element (#{self})")
|
||||
end
|
||||
|
||||
def to_param
|
||||
def to_query_string
|
||||
return nil if disabled?
|
||||
|
||||
params = case Webrat.configuration.mode
|
||||
when :rails
|
||||
parse_rails_request_params("#{name}=#{escaped_value}")
|
||||
when :merb
|
||||
::Merb::Parse.query("#{name}=#{escaped_value}")
|
||||
else
|
||||
{ name => [*@value].first.to_s }
|
||||
query_string = case Webrat.configuration.mode
|
||||
when :rails, :merb, :rack, :sinatra
|
||||
build_query_string
|
||||
when :mechanize
|
||||
build_query_string(false)
|
||||
end
|
||||
|
||||
unescape_params(params)
|
||||
query_string
|
||||
end
|
||||
|
||||
def set(value)
|
||||
|
@ -109,18 +108,6 @@ module Webrat
|
|||
|
||||
protected
|
||||
|
||||
def parse_rails_request_params(params)
|
||||
if defined?(ActionController::AbstractRequest)
|
||||
ActionController::AbstractRequest.parse_query_parameters(params)
|
||||
elsif defined?(ActionController::UrlEncodedPairParser)
|
||||
# For Rails > 2.2
|
||||
ActionController::UrlEncodedPairParser.parse_query_parameters(params)
|
||||
else
|
||||
# For Rails > 2.3
|
||||
Rack::Utils.parse_nested_query(params)
|
||||
end
|
||||
end
|
||||
|
||||
def form
|
||||
Form.load(@session, form_element)
|
||||
end
|
||||
|
@ -138,23 +125,20 @@ module Webrat
|
|||
@element["name"]
|
||||
end
|
||||
|
||||
def escaped_value
|
||||
CGI.escape(@value.to_s)
|
||||
def build_query_string(escape_value=true)
|
||||
if @value.is_a?(Array)
|
||||
@value.collect {|value| "#{name}=#{ escape_value ? escape(value) : value }" }.join("&")
|
||||
else
|
||||
"#{name}=#{ escape_value ? escape(value) : value }"
|
||||
end
|
||||
end
|
||||
|
||||
# Because we have to escape it before sending it to the above case statement,
|
||||
# we have to make sure we unescape each value when it gets back so assertions
|
||||
# involving characters like <, >, and & work as expected
|
||||
def unescape_params(params)
|
||||
case params.class.name
|
||||
when 'Hash', 'Mash'
|
||||
params.each { |key,value| params[key] = unescape_params(value) }
|
||||
params
|
||||
when 'Array'
|
||||
params.collect { |value| unescape_params(value) }
|
||||
else
|
||||
CGI.unescapeHTML(params)
|
||||
end
|
||||
def escape(value)
|
||||
CGI.escape(value.to_s)
|
||||
end
|
||||
|
||||
def escaped_value
|
||||
CGI.escape(@value.to_s)
|
||||
end
|
||||
|
||||
def labels
|
||||
|
@ -186,22 +170,6 @@ module Webrat
|
|||
def default_value
|
||||
@element["value"]
|
||||
end
|
||||
|
||||
def replace_param_value(params, oval, nval)
|
||||
output = Hash.new
|
||||
params.each do |key, value|
|
||||
case value
|
||||
when Hash
|
||||
value = replace_param_value(value, oval, nval)
|
||||
when Array
|
||||
value = value.map { |o| o == oval ? nval : oval }
|
||||
when oval
|
||||
value = nval
|
||||
end
|
||||
output[key] = value
|
||||
end
|
||||
output
|
||||
end
|
||||
end
|
||||
|
||||
class ButtonField < Field #:nodoc:
|
||||
|
@ -210,7 +178,7 @@ module Webrat
|
|||
[".//button", ".//input[@type = 'submit']", ".//input[@type = 'button']", ".//input[@type = 'image']"]
|
||||
end
|
||||
|
||||
def to_param
|
||||
def to_query_string
|
||||
return nil if @value.nil?
|
||||
super
|
||||
end
|
||||
|
@ -233,13 +201,13 @@ module Webrat
|
|||
".//input[@type = 'hidden']"
|
||||
end
|
||||
|
||||
def to_param
|
||||
def to_query_string
|
||||
if collection_name?
|
||||
super
|
||||
else
|
||||
checkbox_with_same_name = form.field_named(name, CheckboxField)
|
||||
|
||||
if checkbox_with_same_name.to_param.blank?
|
||||
if checkbox_with_same_name.to_query_string.blank?
|
||||
super
|
||||
else
|
||||
nil
|
||||
|
@ -261,7 +229,7 @@ module Webrat
|
|||
".//input[@type = 'checkbox']"
|
||||
end
|
||||
|
||||
def to_param
|
||||
def to_query_string
|
||||
return nil if @value.nil?
|
||||
super
|
||||
end
|
||||
|
@ -306,7 +274,7 @@ module Webrat
|
|||
".//input[@type = 'radio']"
|
||||
end
|
||||
|
||||
def to_param
|
||||
def to_query_string
|
||||
return nil if @value.nil?
|
||||
super
|
||||
end
|
||||
|
@ -363,30 +331,32 @@ module Webrat
|
|||
attr_accessor :content_type
|
||||
|
||||
def set(value, content_type = nil)
|
||||
@original_value = @value
|
||||
@content_type ||= content_type
|
||||
super(value)
|
||||
@content_type = content_type
|
||||
end
|
||||
|
||||
def to_param
|
||||
if @value.nil?
|
||||
super
|
||||
else
|
||||
replace_param_value(super, @value, test_uploaded_file)
|
||||
end
|
||||
def digest_value
|
||||
@value ? Digest::MD5.hexdigest(self.object_id.to_s) : ""
|
||||
end
|
||||
|
||||
protected
|
||||
def to_query_string
|
||||
@value.nil? ? set("") : set(digest_value)
|
||||
super
|
||||
end
|
||||
|
||||
def test_uploaded_file
|
||||
return "" if @original_value.blank?
|
||||
|
||||
case Webrat.configuration.mode
|
||||
when :rails
|
||||
if content_type
|
||||
ActionController::TestUploadedFile.new(@value, content_type)
|
||||
ActionController::TestUploadedFile.new(@original_value, content_type)
|
||||
else
|
||||
ActionController::TestUploadedFile.new(@value)
|
||||
ActionController::TestUploadedFile.new(@original_value)
|
||||
end
|
||||
when :rack, :merb
|
||||
Rack::Test::UploadedFile.new(@value, content_type)
|
||||
Rack::Test::UploadedFile.new(@original_value, content_type)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -450,25 +420,6 @@ module Webrat
|
|||
@value.delete(value)
|
||||
end
|
||||
|
||||
# We have to overide how the uri string is formed when dealing with multiples
|
||||
# Where normally a select field might produce name=value with a multiple,
|
||||
# we need to form something like name[]=value1&name[]=value2
|
||||
def to_param
|
||||
return nil if disabled?
|
||||
|
||||
uri_string = @value.collect {|value| "#{name}=#{CGI.escape(value)}"}.join("&")
|
||||
params = case Webrat.configuration.mode
|
||||
when :rails
|
||||
parse_rails_request_params(uri_string)
|
||||
when :merb
|
||||
::Merb::Parse.query(uri_string)
|
||||
else
|
||||
{ name => @value }
|
||||
end
|
||||
|
||||
unescape_params(params)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Overwrite SelectField definition because we don't want to select the first option
|
||||
|
|
|
@ -38,15 +38,24 @@ module Webrat
|
|||
end
|
||||
end
|
||||
|
||||
# iterate over all form fields to build a request querystring to get params from it,
|
||||
# for file_field we made a work around to pass a digest as value to later replace it
|
||||
# in params hash with the real file.
|
||||
def params
|
||||
all_params = {}
|
||||
query_string = []
|
||||
replaces = {}
|
||||
|
||||
fields.each do |field|
|
||||
next if field.to_param.nil?
|
||||
merge(all_params, field.to_param)
|
||||
next if field.to_query_string.nil?
|
||||
replaces.merge!({field.digest_value => field.test_uploaded_file}) if field.is_a?(FileField)
|
||||
query_string << field.to_query_string
|
||||
end
|
||||
|
||||
all_params
|
||||
query_params = Form.query_string_to_params(query_string.join('&'))
|
||||
|
||||
query_params = Form.replace_params_values(query_params, replaces)
|
||||
|
||||
Form.unescape_params(query_params)
|
||||
end
|
||||
|
||||
def form_method
|
||||
|
@ -57,47 +66,64 @@ module Webrat
|
|||
@element["action"].blank? ? @session.current_url : @element["action"]
|
||||
end
|
||||
|
||||
def merge(all_params, new_param)
|
||||
new_param.each do |key, value|
|
||||
case all_params[key]
|
||||
when *hash_classes
|
||||
merge_hash_values(all_params[key], value)
|
||||
protected
|
||||
|
||||
def self.replace_param_value(params, oval, nval)
|
||||
output = Hash.new
|
||||
params.each do |key, value|
|
||||
case value
|
||||
when Hash
|
||||
value = replace_param_value(value, oval, nval)
|
||||
when Array
|
||||
all_params[key] += value
|
||||
else
|
||||
all_params[key] = value
|
||||
value = value.map { |o| o == oval ? nval : o }
|
||||
when oval
|
||||
value = nval
|
||||
end
|
||||
output[key] = value
|
||||
end
|
||||
output
|
||||
end
|
||||
|
||||
def self.replace_params_values(params, values)
|
||||
values.each do |key, value|
|
||||
params = replace_param_value(params, key, value)
|
||||
end
|
||||
params
|
||||
end
|
||||
|
||||
def self.unescape_params(params)
|
||||
case params.class.name
|
||||
when 'Hash', 'Mash'
|
||||
params.each { |key,value| params[key] = unescape_params(value) }
|
||||
params
|
||||
when 'Array'
|
||||
params.collect { |value| unescape_params(value) }
|
||||
else
|
||||
params.is_a?(String) ? CGI.unescapeHTML(params) : params
|
||||
end
|
||||
end
|
||||
|
||||
def merge_hash_values(a, b) # :nodoc:
|
||||
a.keys.each do |k|
|
||||
if b.has_key?(k)
|
||||
case [a[k], b[k]].map{|value| value.class}
|
||||
when *hash_classes.zip(hash_classes)
|
||||
a[k] = merge_hash_values(a[k], b[k])
|
||||
b.delete(k)
|
||||
when [Array, Array]
|
||||
a[k] += b[k]
|
||||
b.delete(k)
|
||||
end
|
||||
end
|
||||
end
|
||||
a.merge!(b)
|
||||
end
|
||||
|
||||
def hash_classes
|
||||
klasses = [Hash]
|
||||
|
||||
def self.query_string_to_params(query_string)
|
||||
case Webrat.configuration.mode
|
||||
when :rails
|
||||
klasses << HashWithIndifferentAccess
|
||||
parse_rails_request_params(query_string)
|
||||
when :merb
|
||||
klasses << Mash
|
||||
::Merb::Parse.query(query_string)
|
||||
when :rack, :sinatra
|
||||
Rack::Utils.parse_nested_query(query_string)
|
||||
else
|
||||
query_string.split('&').map {|query| { query.split('=').first => query.split('=').last }}
|
||||
end
|
||||
|
||||
klasses
|
||||
end
|
||||
|
||||
def self.parse_rails_request_params(query_string)
|
||||
if defined?(ActionController::AbstractRequest)
|
||||
ActionController::AbstractRequest.parse_query_parameters(query_string)
|
||||
elsif defined?(ActionController::UrlEncodedPairParser)
|
||||
ActionController::UrlEncodedPairParser.parse_query_parameters(query_string)
|
||||
else
|
||||
Rack::Utils.parse_nested_query(query_string)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class NilClass #:nodoc:
|
||||
def to_param
|
||||
def to_query_string
|
||||
nil
|
||||
end
|
||||
end
|
|
@ -77,7 +77,7 @@ module Webrat
|
|||
|
||||
element = Webrat::XML.document(html).css('input').first
|
||||
text_field = TextField.new(nil, element)
|
||||
text_field.to_param.should == { 'email' => 'user@example.com' }
|
||||
text_field.to_query_string.should == 'email=user@example.com'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
||||
|
||||
describe "Multiple nested params" do
|
||||
it "should be corretly posted" do
|
||||
Webrat.configuration.mode = :rails
|
||||
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/family">
|
||||
<div class="couple">
|
||||
<div class="parent">
|
||||
<select name="user[family][parents][0][][gender]">
|
||||
<option selected="selected" value="Mother">Mother</option>
|
||||
<option value="Father">Father</option>
|
||||
</select>
|
||||
<input type="text" value="Alice" name="user[family][parents][0][][name]" />
|
||||
</div>
|
||||
<div class="parent">
|
||||
<select name="user[family][parents][0][][gender]">
|
||||
<option value="Mother">Mother</option>
|
||||
<option selected="selected" value="Father">Father</option>
|
||||
</select>
|
||||
<input type="text" value="Michael" name="user[family][parents][0][][name]" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="couple">
|
||||
<div class="parent">
|
||||
<select name="user[family][parents][1][][gender]">
|
||||
<option selected="selected" value="Mother">Mother</option>
|
||||
<option value="Father">Father</option>
|
||||
</select>
|
||||
<input type="text" value="Jenny" name="user[family][parents][1][][name]" />
|
||||
</div>
|
||||
</div>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
params = { "user" => { "family" => { "parents" => {
|
||||
"0" => [ {"name" => "Alice", "gender"=>"Mother"}, {"name" => "Michael", "gender"=>"Father"} ],
|
||||
"1" => [ {"name" => "Jenny", "gender"=>"Mother"} ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
webrat_session.should_receive(:post).with("/family", params)
|
||||
click_button
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue