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)
|
def self.field_class(element)
|
||||||
case element.name
|
case element.name
|
||||||
when "button" then ButtonField
|
when "button" then ButtonField
|
||||||
when "select" then SelectField
|
when "select"
|
||||||
|
if element.attributes["multiple"].nil?
|
||||||
|
SelectField
|
||||||
|
else
|
||||||
|
MultipleSelectField
|
||||||
|
end
|
||||||
when "textarea" then TextareaField
|
when "textarea" then TextareaField
|
||||||
else
|
else
|
||||||
case element["type"]
|
case element["type"]
|
||||||
@ -82,14 +87,16 @@ module Webrat
|
|||||||
def to_param
|
def to_param
|
||||||
return nil if disabled?
|
return nil if disabled?
|
||||||
|
|
||||||
case Webrat.configuration.mode
|
params = case Webrat.configuration.mode
|
||||||
when :rails
|
when :rails
|
||||||
parse_rails_request_params("#{name}=#{escaped_value}")
|
parse_rails_request_params("#{name}=#{escaped_value}")
|
||||||
when :merb
|
when :merb
|
||||||
::Merb::Parse.query("#{name}=#{escaped_value}")
|
::Merb::Parse.query("#{name}=#{escaped_value}")
|
||||||
else
|
else
|
||||||
{ name => value }
|
{ name => [*@value].first.to_s }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
unescape_params(params)
|
||||||
end
|
end
|
||||||
|
|
||||||
def set(value)
|
def set(value)
|
||||||
@ -135,6 +142,21 @@ module Webrat
|
|||||||
CGI.escape([*@value].first.to_s)
|
CGI.escape([*@value].first.to_s)
|
||||||
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
|
||||||
|
end
|
||||||
|
|
||||||
def labels
|
def labels
|
||||||
@labels ||= label_elements.map do |element|
|
@labels ||= label_elements.map do |element|
|
||||||
Label.load(@session, element)
|
Label.load(@session, element)
|
||||||
@ -385,13 +407,17 @@ module Webrat
|
|||||||
class SelectField < Field #:nodoc:
|
class SelectField < Field #:nodoc:
|
||||||
|
|
||||||
def self.xpath_search
|
def self.xpath_search
|
||||||
[".//select"]
|
[".//select[not(@multiple)]"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def options
|
def options
|
||||||
@options ||= SelectOption.load_all(@session, @element)
|
@options ||= SelectOption.load_all(@session, @element)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def unset(value)
|
||||||
|
@value = []
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def default_value
|
def default_value
|
||||||
@ -405,4 +431,53 @@ module Webrat
|
|||||||
end
|
end
|
||||||
|
|
||||||
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
|
end
|
||||||
|
@ -12,6 +12,11 @@ module Webrat
|
|||||||
select.set(value)
|
select.set(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def unchoose
|
||||||
|
select.raise_error_if_disabled
|
||||||
|
select.unset(value)
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def select
|
def select
|
||||||
@ -31,5 +36,9 @@ module Webrat
|
|||||||
@element["value"] || @element.inner_html
|
@element["value"] || @element.inner_html
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def label
|
||||||
|
@element.inner_html
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -21,7 +21,7 @@ module Webrat
|
|||||||
if @option_text.is_a?(Regexp)
|
if @option_text.is_a?(Regexp)
|
||||||
o.element.inner_html =~ @option_text
|
o.element.inner_html =~ @option_text
|
||||||
else
|
else
|
||||||
o.element.inner_html == @option_text.to_s
|
escaped_or_non_escaped_values.include?(o.element.inner_html)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -29,7 +29,7 @@ module Webrat
|
|||||||
if @option_text.is_a?(Regexp)
|
if @option_text.is_a?(Regexp)
|
||||||
o.inner_html =~ @option_text
|
o.inner_html =~ @option_text
|
||||||
else
|
else
|
||||||
o.inner_html == @option_text.to_s
|
escaped_or_non_escaped_values.include?(o.inner_html)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -37,6 +37,10 @@ module Webrat
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def escaped_or_non_escaped_values
|
||||||
|
[@option_text.to_s, CGI.escapeHTML(@option_text.to_s)]
|
||||||
|
end
|
||||||
|
|
||||||
def option_elements
|
def option_elements
|
||||||
@dom.xpath(*SelectOption.xpath_search)
|
@dom.xpath(*SelectOption.xpath_search)
|
||||||
end
|
end
|
||||||
|
@ -39,6 +39,7 @@ module Webrat
|
|||||||
:unchecks, :uncheck,
|
:unchecks, :uncheck,
|
||||||
:chooses, :choose,
|
:chooses, :choose,
|
||||||
:selects, :select,
|
:selects, :select,
|
||||||
|
:unselects, :unselect,
|
||||||
:attaches_file, :attach_file,
|
:attaches_file, :attach_file,
|
||||||
:current_page,
|
:current_page,
|
||||||
:current_url,
|
:current_url,
|
||||||
|
@ -112,6 +112,21 @@ module Webrat
|
|||||||
|
|
||||||
webrat_deprecate :selects, :select
|
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 = {
|
DATE_TIME_SUFFIXES = {
|
||||||
:year => '1i',
|
:year => '1i',
|
||||||
:month => '2i',
|
:month => '2i',
|
||||||
|
@ -260,6 +260,7 @@ For example:
|
|||||||
def_delegators :current_scope, :uncheck, :unchecks
|
def_delegators :current_scope, :uncheck, :unchecks
|
||||||
def_delegators :current_scope, :choose, :chooses
|
def_delegators :current_scope, :choose, :chooses
|
||||||
def_delegators :current_scope, :select, :selects
|
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_datetime, :selects_datetime
|
||||||
def_delegators :current_scope, :select_date, :selects_date
|
def_delegators :current_scope, :select_date, :selects_date
|
||||||
def_delegators :current_scope, :select_time, :selects_time
|
def_delegators :current_scope, :select_time, :selects_time
|
||||||
|
@ -331,18 +331,16 @@ describe "click_button" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "should properly handle HTML entities in textarea default values" do
|
it "should properly handle HTML entities in textarea default values" do
|
||||||
pending "needs bug fix" do
|
with_html <<-HTML
|
||||||
with_html <<-HTML
|
<html>
|
||||||
<html>
|
<form method="post" action="/posts">
|
||||||
<form method="post" action="/posts">
|
<textarea name="post[body]">Peanut butter & jelly</textarea>
|
||||||
<textarea name="post[body]">Peanut butter & jelly</textarea>
|
<input type="submit" />
|
||||||
<input type="submit" />
|
</form>
|
||||||
</form>
|
</html>
|
||||||
</html>
|
HTML
|
||||||
HTML
|
webrat_session.should_receive(:post).with("/posts", "post" => {"body" => "Peanut butter & jelly"})
|
||||||
webrat_session.should_receive(:post).with("/posts", "post" => {"body" => "Peanut butter & jelly"})
|
click_button
|
||||||
click_button
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should send default selected option value from select" do
|
it "should send default selected option value from select" do
|
||||||
|
@ -201,7 +201,6 @@ describe "select" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "should properly handle submitting HTML entities in select values" do
|
it "should properly handle submitting HTML entities in select values" do
|
||||||
pending "needs bug fix" do
|
|
||||||
with_html <<-HTML
|
with_html <<-HTML
|
||||||
<html>
|
<html>
|
||||||
<form method="post" action="/login">
|
<form method="post" action="/login">
|
||||||
@ -212,11 +211,9 @@ describe "select" do
|
|||||||
HTML
|
HTML
|
||||||
webrat_session.should_receive(:post).with("/login", "month" => "Peanut butter & jelly")
|
webrat_session.should_receive(:post).with("/login", "month" => "Peanut butter & jelly")
|
||||||
click_button
|
click_button
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should properly handle locating with HTML entities in select values" do
|
it "should properly handle locating with HTML entities in select values" do
|
||||||
pending "needs bug fix" do
|
|
||||||
with_html <<-HTML
|
with_html <<-HTML
|
||||||
<html>
|
<html>
|
||||||
<form method="post" action="/login">
|
<form method="post" action="/login">
|
||||||
@ -229,7 +226,6 @@ describe "select" do
|
|||||||
lambda {
|
lambda {
|
||||||
select "Peanut butter & jelly"
|
select "Peanut butter & jelly"
|
||||||
}.should_not raise_error(Webrat::NotFoundError)
|
}.should_not raise_error(Webrat::NotFoundError)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should submit duplicates selected options as a single value" do
|
it "should submit duplicates selected options as a single value" do
|
||||||
@ -246,4 +242,168 @@ describe "select" do
|
|||||||
click_button
|
click_button
|
||||||
end
|
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
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user