Various improvements, refinements, and bugfixes for select field usage.
Multiple select boxes are now handled a lot better. * You can now select more than one field (where as previously, the last one select would override previous selections) * You can now unselect a value. It works like select, takes the same params, but removes the selection value Issues regarding ampersands in values have been resolved. * Values are now unescaped when the to_param method is run on elements, to make assertions less complicated * Locating an option with ampersand values now works as expected (it will check for both escaped and unescaped occurrences) Bunch of new specs and 3 broken pending ones have now been fixed. [#145 status:resolved]
This commit is contained in:
parent
98efa54900
commit
a8d0cebde3
|
@ -38,7 +38,12 @@ module Webrat
|
|||
def self.field_class(element)
|
||||
case element.name
|
||||
when "button" then ButtonField
|
||||
when "select" then SelectField
|
||||
when "select"
|
||||
if element.attributes["multiple"].nil?
|
||||
SelectField
|
||||
else
|
||||
MultipleSelectField
|
||||
end
|
||||
when "textarea" then TextareaField
|
||||
else
|
||||
case element["type"]
|
||||
|
@ -82,14 +87,16 @@ module Webrat
|
|||
def to_param
|
||||
return nil if disabled?
|
||||
|
||||
case Webrat.configuration.mode
|
||||
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 }
|
||||
{ name => [*@value].first.to_s }
|
||||
end
|
||||
|
||||
unescape_params(params)
|
||||
end
|
||||
|
||||
def set(value)
|
||||
|
@ -135,6 +142,21 @@ module Webrat
|
|||
CGI.escape([*@value].first.to_s)
|
||||
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
|
||||
end
|
||||
|
||||
def labels
|
||||
@labels ||= label_elements.map do |element|
|
||||
Label.load(@session, element)
|
||||
|
@ -385,13 +407,17 @@ module Webrat
|
|||
class SelectField < Field #:nodoc:
|
||||
|
||||
def self.xpath_search
|
||||
[".//select"]
|
||||
[".//select[not(@multiple)]"]
|
||||
end
|
||||
|
||||
def options
|
||||
@options ||= SelectOption.load_all(@session, @element)
|
||||
end
|
||||
|
||||
def unset(value)
|
||||
@value = []
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def default_value
|
||||
|
@ -405,4 +431,53 @@ module Webrat
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
class MultipleSelectField < SelectField #:nodoc:
|
||||
|
||||
def self.xpath_search
|
||||
[".//select[@multiple='multiple']"]
|
||||
end
|
||||
|
||||
def set(value)
|
||||
@value << value
|
||||
end
|
||||
|
||||
def unset(value)
|
||||
@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
|
||||
# (mutliples don't select the first option unlike their non multiple versions)
|
||||
def default_value
|
||||
selected_options = @element.xpath(".//option[@selected = 'selected']")
|
||||
|
||||
selected_options.map do |option|
|
||||
return "" if option.nil?
|
||||
option["value"] || option.inner_html
|
||||
end.uniq
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -12,6 +12,11 @@ module Webrat
|
|||
select.set(value)
|
||||
end
|
||||
|
||||
def unchoose
|
||||
select.raise_error_if_disabled
|
||||
select.unset(value)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def select
|
||||
|
@ -31,5 +36,9 @@ module Webrat
|
|||
@element["value"] || @element.inner_html
|
||||
end
|
||||
|
||||
def label
|
||||
@element.inner_html
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,7 +21,7 @@ module Webrat
|
|||
if @option_text.is_a?(Regexp)
|
||||
o.element.inner_html =~ @option_text
|
||||
else
|
||||
o.element.inner_html == @option_text.to_s
|
||||
escaped_or_non_escaped_values.include?(o.element.inner_html)
|
||||
end
|
||||
end
|
||||
else
|
||||
|
@ -29,7 +29,7 @@ module Webrat
|
|||
if @option_text.is_a?(Regexp)
|
||||
o.inner_html =~ @option_text
|
||||
else
|
||||
o.inner_html == @option_text.to_s
|
||||
escaped_or_non_escaped_values.include?(o.inner_html)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -37,6 +37,10 @@ module Webrat
|
|||
end
|
||||
end
|
||||
|
||||
def escaped_or_non_escaped_values
|
||||
[@option_text.to_s, CGI.escapeHTML(@option_text.to_s)]
|
||||
end
|
||||
|
||||
def option_elements
|
||||
@dom.xpath(*SelectOption.xpath_search)
|
||||
end
|
||||
|
|
|
@ -39,6 +39,7 @@ module Webrat
|
|||
:unchecks, :uncheck,
|
||||
:chooses, :choose,
|
||||
:selects, :select,
|
||||
:unselects, :unselect,
|
||||
:attaches_file, :attach_file,
|
||||
:current_page,
|
||||
:current_url,
|
||||
|
|
|
@ -112,6 +112,21 @@ module Webrat
|
|||
|
||||
webrat_deprecate :selects, :select
|
||||
|
||||
# Verifies that a an option element exists on the current page with the specified
|
||||
# text. You can optionally restrict the search to a specific select list by
|
||||
# assigning <tt>options[:from]</tt> the value of the select list's name or
|
||||
# a label. Remove the option's value before the form is submitted.
|
||||
#
|
||||
# Examples:
|
||||
# unselect "January"
|
||||
# unselect "February", :from => "event_month"
|
||||
# unselect "February", :from => "Event Month"
|
||||
def unselect(option_text, options={})
|
||||
select_option(option_text, options[:from]).unchoose
|
||||
end
|
||||
|
||||
webrat_deprecate :unselects, :unselect
|
||||
|
||||
DATE_TIME_SUFFIXES = {
|
||||
:year => '1i',
|
||||
:month => '2i',
|
||||
|
|
|
@ -260,6 +260,7 @@ For example:
|
|||
def_delegators :current_scope, :uncheck, :unchecks
|
||||
def_delegators :current_scope, :choose, :chooses
|
||||
def_delegators :current_scope, :select, :selects
|
||||
def_delegators :current_scope, :unselect, :unselects
|
||||
def_delegators :current_scope, :select_datetime, :selects_datetime
|
||||
def_delegators :current_scope, :select_date, :selects_date
|
||||
def_delegators :current_scope, :select_time, :selects_time
|
||||
|
|
|
@ -331,18 +331,16 @@ describe "click_button" do
|
|||
end
|
||||
|
||||
it "should properly handle HTML entities in textarea default values" do
|
||||
pending "needs bug fix" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/posts">
|
||||
<textarea name="post[body]">Peanut butter & jelly</textarea>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/posts", "post" => {"body" => "Peanut butter & jelly"})
|
||||
click_button
|
||||
end
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/posts">
|
||||
<textarea name="post[body]">Peanut butter & jelly</textarea>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/posts", "post" => {"body" => "Peanut butter & jelly"})
|
||||
click_button
|
||||
end
|
||||
|
||||
it "should send default selected option value from select" do
|
||||
|
|
|
@ -201,7 +201,6 @@ describe "select" do
|
|||
end
|
||||
|
||||
it "should properly handle submitting HTML entities in select values" do
|
||||
pending "needs bug fix" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/login">
|
||||
|
@ -212,11 +211,9 @@ describe "select" do
|
|||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", "month" => "Peanut butter & jelly")
|
||||
click_button
|
||||
end
|
||||
end
|
||||
|
||||
it "should properly handle locating with HTML entities in select values" do
|
||||
pending "needs bug fix" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/login">
|
||||
|
@ -229,7 +226,6 @@ describe "select" do
|
|||
lambda {
|
||||
select "Peanut butter & jelly"
|
||||
}.should_not raise_error(Webrat::NotFoundError)
|
||||
end
|
||||
end
|
||||
|
||||
it "should submit duplicates selected options as a single value" do
|
||||
|
@ -246,4 +242,168 @@ describe "select" do
|
|||
click_button
|
||||
end
|
||||
|
||||
it "should allow fields to be unselected" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/login">
|
||||
<select name="clothes">
|
||||
<option value="tshirt" selected="selected">tshirt</option>
|
||||
<option value="pants">pants</option>
|
||||
</select>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
webrat_session.should_receive(:post).with("/login", {"clothes"=>""})
|
||||
unselect "tshirt"
|
||||
click_button
|
||||
end
|
||||
|
||||
#
|
||||
# Mutliple Selection Fields
|
||||
#
|
||||
|
||||
it "should not submit any values for multiples without any selected" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/login">
|
||||
<select name="clothes[]" multiple="multiple">
|
||||
<option value="tshirt">tshirt</option>
|
||||
<option value="pants">pants</option>
|
||||
</select>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
webrat_session.should_receive(:post).with("/login", {})
|
||||
click_button
|
||||
end
|
||||
|
||||
it "should submit with preselected values" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/login">
|
||||
<select name="clothes[]" multiple="multiple">
|
||||
<option value="tshirt" selected="selected">tshirt</option>
|
||||
<option value="pants" selected="selected">pants</option>
|
||||
</select>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
webrat_session.should_receive(:post).with("/login", "clothes" => ['tshirt', 'pants'])
|
||||
click_button
|
||||
end
|
||||
|
||||
it "should allow selection of multiple fields" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/login">
|
||||
<select name="clothes[]" multiple="multiple">
|
||||
<option value="tshirt">tshirt</option>
|
||||
<option value="pants">pants</option>
|
||||
</select>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
webrat_session.should_receive(:post).with("/login", "clothes" => ['pants'])
|
||||
select 'pants'
|
||||
click_button
|
||||
end
|
||||
|
||||
it "should not overwrite preselected multiples" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/login">
|
||||
<select name="clothes[]" multiple="multiple">
|
||||
<option value="tshirt" selected="selected">tshirt</option>
|
||||
<option value="pants">pants</option>
|
||||
</select>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
webrat_session.should_receive(:post).with("/login", "clothes" => ['tshirt', 'pants'])
|
||||
select 'pants'
|
||||
click_button
|
||||
end
|
||||
|
||||
it "should allow fields that exist to be selected or throw errors" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/login">
|
||||
<select name="clothes[]" multiple="multiple">
|
||||
<option value="top" selected="selected">shirt</option>
|
||||
<option value="pants">trousers</option>
|
||||
</select>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
lambda { select "shirt" }.should_not raise_error(Webrat::NotFoundError)
|
||||
lambda { select "trousers" }.should_not raise_error(Webrat::NotFoundError)
|
||||
lambda { select "shoes" }.should raise_error(Webrat::NotFoundError)
|
||||
end
|
||||
|
||||
it "should allow selected fields to be unselected" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/login">
|
||||
<select name="clothes[]" multiple="multiple">
|
||||
<option value="tshirt" selected="selected">tshirt</option>
|
||||
<option value="pants" selected="selected">pants</option>
|
||||
</select>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
webrat_session.should_receive(:post).with("/login", "clothes" => ['pants'])
|
||||
unselect 'tshirt'
|
||||
click_button
|
||||
end
|
||||
|
||||
it "should be able to select options with special characters" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/login">
|
||||
<select name="clothes[]" multiple="multiple">
|
||||
<option>tshirt & sweater</option>
|
||||
<option>pants & socks</option>
|
||||
</select>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
webrat_session.should_receive(:post).with("/login", "clothes" => ['pants & socks'])
|
||||
select 'pants & socks'
|
||||
click_button
|
||||
end
|
||||
|
||||
it "should be able to unselect options with special characters" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/login">
|
||||
<select name="clothes[]" multiple="multiple">
|
||||
<option selected="selected">tshirt & sweater</option>
|
||||
<option selected="selected">pants & socks</option>
|
||||
</select>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
webrat_session.should_receive(:post).with("/login", "clothes" => ['tshirt & sweater'])
|
||||
unselect 'pants & socks'
|
||||
click_button
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue