selects_time, selects_date, and selects_datetime added to API. Closes #36.

This commit is contained in:
Ben Mabey 2008-11-13 21:26:19 -07:00
parent 0dffbec8f4
commit 6cd76fa08e
11 changed files with 564 additions and 9 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ email.txt
log
.project
.loadpath
*.swp

View File

@ -1,5 +1,9 @@
== Trunk
* Major enhancements
* Added selects_time, selects_date, and selects_datetime to API. (Ben Mabey, Ticket #36)
* Minor enhancements
* Allow clicking links by id and id regexp (gaffo)

View File

@ -34,9 +34,17 @@ module Webrat
labels.first.text
end
def id
@element["id"]
end
def matches_id?(id)
if id.is_a?(Regexp)
@element["id"] =~ id
else
@element["id"] == id.to_s
end
end
def matches_name?(name)
@element["name"] == name.to_s
@ -83,10 +91,6 @@ module Webrat
protected
def id
@element["id"]
end
def name
@element["name"]
end

View File

@ -44,6 +44,10 @@ module Webrat
end
end
def labels
@labels ||= element.search("label").map { |element| Label.new(nil, element) }
end
def submit
@session.request_page(form_action, form_method, params)
end
@ -66,6 +70,10 @@ module Webrat
matching_fields.min { |a, b| a.label_text.length <=> b.label_text.length }
end
def label_matching(label_text)
labels.detect { |label| label.matches_text?(label_text) }
end
protected
def fields_by_type(field_types)

View File

@ -18,5 +18,9 @@ module Webrat
str
end
def for_id
@element['for']
end
end
end

View File

@ -88,5 +88,14 @@ module Webrat
end
end
def find_field_id_for_label(label_text)
label = forms.detect_mapped { |form| form.label_matching(label_text) }
if label
label.for_id
else
flunk("Could not find the label with text #{label_text}")
end
end
end
end

View File

@ -92,6 +92,114 @@ module Webrat
alias_method :select, :selects
DATE_TIME_SUFFIXES = {:rails => {:year => '1i', :month => '2i', :day => '3i',
:hour => '4i', :minute => '5i'},
:full_words => {:year => 'year', :month => 'month', :day => 'day',
:hour => 'hour', :minute => 'minute'}
}
# Verifies that date elements (year, month, day) exist on the current page
# with the specified values. You can optionally restrict the search to a specific
# date's elements by assigning <tt>options[:from]</tt> the value of the date's
# label. Selects all the date elements with date provided. The date provided may
# be a string or a Date/Time object.
#
# By default Rail's convention is used for detecting the date elements, but this
# may be overriden by assinging a <tt>options[:suffix_convention]</tt> or
# <tt>options[:suffixes]</tt>. In all cases all elements are assumed to have a
# shared prefix. For example, a birthday date on a form might have the following:
# 'birthday_Year', 'birthday_Month', 'birthday_Day'. You may also specify the
# prefix by assigning <tt>options[:id_prefix]</tt>.
#
# Examples:
# selects_date "January 23, 2004"
# selects_date "April 26, 1982", :from => "Birthday"
# selects_date Date.parse("December 25, 2000"), :from => "Event"
# selects_date "April 26, 1982", :suffix_convention => :full_words
# selects_date "April 26, 1982", :id_prefix => 'birthday',
# :suffixes => {:year => 'Year', :month => 'Mon', :day => 'Day'}
def selects_date(date_to_select, options ={})
date = date_to_select.is_a?(Date) || date_to_select.is_a?(Time) ?
date_to_select : Date.parse(date_to_select)
suffixes = extract_date_time_suffixes(options)
id_prefix = locate_id_prefix(options) do
year_field = find_field_with_id(/(.*?)_#{suffixes[:year]}$/)
flunk("No date fields were found") unless year_field && year_field.id =~ /(.*?)_1i/
$1
end
selects date.year, :from => "#{id_prefix}_#{suffixes[:year]}"
selects date.strftime('%B'), :from => "#{id_prefix}_#{suffixes[:month]}"
selects date.day, :from => "#{id_prefix}_#{suffixes[:day]}"
end
alias_method :select_date, :selects_date
# Verifies that time elements (hour, minute) exist on the current page
# with the specified values. You can optionally restrict the search to a specific
# time's elements by assigning <tt>options[:from]</tt> the value of the time's
# label. Selects all the time elements with date provided. The time provided may
# be a string or a Time object.
#
# By default Rail's convention is used for detecting the time elements, but this
# may be overriden by assinging a <tt>options[:suffix_convention]</tt> or
# <tt>options[:suffixes]</tt>. In all cases all elements are assumed to have a
# shared prefix. For example, an appointment time on a form might have the
# following: 'appt_time_hour', 'appt_time_min'. You may also specify the
# prefix by assigning <tt>options[:id_prefix]</tt>.
#
# Note: Just like Rails' time_select helper this assumes the form is using
# 24 hour select boxes, and not 12 hours with AM/PM.
#
# Examples:
# selects_time "9:30"
# selects_date "3:30PM", :from => "Party Time"
# selects_date Time.parse("10:00PM"), :from => "Event"
# selects_date "8:30", :suffix_convention => :full_words
# selects_date "10:30AM", :id_prefix => 'meeting',
# :suffixes => {:hour => 'Hour', :min => 'Min'}
def selects_time(time_to_select, options ={})
time = time_to_select.is_a?(Time) ? time_to_select : Time.parse(time_to_select)
suffixes = extract_date_time_suffixes(options)
id_prefix = locate_id_prefix(options) do
hour_field = find_field_with_id(/(.*?)_#{suffixes[:hour]}$/)
flunk("No time fields were found") unless hour_field && hour_field.id =~ /(.*?)_4i/
$1
end
selects time.hour.to_s.rjust(2,'0'), :from => "#{id_prefix}_#{suffixes[:hour]}"
selects time.min.to_s.rjust(2,'0'), :from => "#{id_prefix}_#{suffixes[:minute]}"
end
alias_method :select_time, :selects_time
# Verifies and selects all the date and time elements on the current page.
# See #selects_time and #selects_date for more details and available options.
#
# Examples:
# selects_datetime "January 23, 2004 10:30AM"
# selects_datetime "April 26, 1982 7:00PM", :from => "Birthday"
# selects_datetime Time.parse("December 25, 2000 15:30"), :from => "Event"
# selects_datetime "April 26, 1982 5:50PM", :suffix_convention => :full_words
# selects_datetime "April 26, 1982 5:50PM", :id_prefix => 'birthday',
# :suffixes => {:year => 'Year', :month => 'Mon', :day => 'Day',
# :hour => 'Hour', :minute => 'Min'}
def selects_datetime(time_to_select, options ={})
time = time_to_select.is_a?(Time) ? time_to_select : Time.parse(time_to_select)
options[:id_prefix] ||= (options[:from] ? find_field_with_id(options[:from]) : nil)
selects_date time, options
selects_time time, options
end
alias_method :select_datetime, :selects_datetime
# Verifies that an input file field exists on the current page and sets
# its value to the given +file+, so that the file will be uploaded
# along with the form. An optional <tt>content_type</tt> may be given.
@ -191,6 +299,17 @@ module Webrat
end
end
def locate_id_prefix(options, &location_strategy) #:nodoc:
return options[:id_prefix] if options[:id_prefix]
id_prefix = options[:from] ? find_field_id_for_label(options[:from]) : yield
end
def extract_date_time_suffixes(options) #:nodoc:
options[:suffixes] ||
DATE_TIME_SUFFIXES[options[:suffix_convention]] ||
DATE_TIME_SUFFIXES[:rails]
end
def areas #:nodoc:
Webrat::XML.css_search(dom, "area").map do |element|
Area.new(@session, element)

View File

@ -184,6 +184,9 @@ module Webrat
def_delegators :current_scope, :uncheck, :unchecks
def_delegators :current_scope, :choose, :chooses
def_delegators :current_scope, :select, :selects
def_delegators :current_scope, :select_datetime, :selects_datetime
def_delegators :current_scope, :select_date, :selects_date
def_delegators :current_scope, :select_time, :selects_time
def_delegators :current_scope, :attach_file, :attaches_file
def_delegators :current_scope, :click_area, :clicks_area
def_delegators :current_scope, :click_link, :clicks_link

View File

@ -0,0 +1,130 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "selects_date" do
before do
@session = Webrat::TestSession.new
end
it "should send the values for each individual date component" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<label for="appointment_date">Date</label><br />
<select id="appointment_date_1i" name="appointment[date(1i)]">
<option value="2003">2003</option>
</select>
<select id="appointment_date_2i" name="appointment[date(2i)]">
<option value="12">December</option>
</select>
<select id="appointment_date_3i" name="appointment[date(3i)]">
<option value="25">25</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"date(1i)" => '2003', "date(2i)" => "12", "date(3i)" => "25"})
@session.selects_date "December 25, 2003", :from => "Date"
@session.click_button
end
it "should select the date components with the suffix convention provided" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<label for="appointment_date">Date</label><br />
<select id="appointment_date_year" name="appointment[year]">
<option value="2003">2003</option>
</select>
<select id="appointment_date_month" name="appointment[month]">
<option value="12">December</option>
</select>
<select id="appointment_date_day" name="appointment[day]">
<option value="25">25</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"year" => '2003', "month" => "12", "day" => "25"})
@session.selects_date "December 25, 2003 9:30", :from => "Date", :suffix_convention => :full_words
@session.click_button
end
it "should select the date components with the suffixes provided" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<label for="appointment_date">Date</label><br />
<select id="appointment_date_y" name="appointment[y]">
<option value="2003">2003</option>
</select>
<select id="appointment_date_mo" name="appointment[mo]">
<option value="12">December</option>
</select>
<select id="appointment_date_d" name="appointment[d]">
<option value="25">25</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"y" => '2003', "mo" => "12", "d" => "25"})
@session.selects_date "December 25, 2003 9:30", :from => "Date",
:suffixes => {:year => 'y', :month => 'mo', :day => 'd'}
@session.click_button
end
it "should accept a date object" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<label for="appointment_date">date</label><br />
<select id="appointment_date_1i" name="appointment[date(1i)]">
<option value="2003">2003</option>
</select>
<select id="appointment_date_2i" name="appointment[date(2i)]">
<option value="12">December</option>
</select>
<select id="appointment_date_3i" name="appointment[date(3i)]">
<option value="25">25</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"date(1i)" => '2003', "date(2i)" => "12", "date(3i)" => "25"})
@session.selects_date Date.parse("December 25, 2003"), :from => "date"
@session.click_button
end
it "should work when no label is specified" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<select id="appointment_date_1i" name="appointment[date(1i)]">
<option value="2003">2003</option>
</select>
<select id="appointment_date_2i" name="appointment[date(2i)]">
<option value="12">December</option>
</select>
<select id="appointment_date_3i" name="appointment[date(3i)]">
<option value="25">25</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"date(1i)" => '2003', "date(2i)" => "12", "date(3i)" => "25"})
@session.selects_date "December 25, 2003"
@session.click_button
end
it "should fail if the specified label is not found" do
@session.response_body = <<-EOS
<form method="post" action="/appointments">
<select name="month"><option>January</option></select>
<input type="submit" />
</form>
EOS
lambda { @session.selects_date "December 25, 2003", :from => "date" }.should raise_error
end
end

View File

@ -0,0 +1,159 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "selects_datetime" do
before do
@session = Webrat::TestSession.new
end
it "should send the values for each individual date and time components" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<label for="appointment_time">Time</label><br />
<select id="appointment_time_1i" name="appointment[time(1i)]">
<option value="2003">2003</option>
</select>
<select id="appointment_time_2i" name="appointment[time(2i)]">
<option value="12">December</option>
</select>
<select id="appointment_time_3i" name="appointment[time(3i)]">
<option value="25">25</option>
</select>
<select id="appointment_time_4i" name="appointment[time(4i)]">
<option value="09">09</option>
</select>
: <select id="appointment_time_5i" name="appointment[time(5i)]">
<option value="30">30</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"time(1i)" => '2003', "time(2i)" => "12", "time(3i)" => "25", "time(4i)" => "09", "time(5i)" => "30"})
@session.selects_datetime "December 25, 2003 9:30", :from => "Time"
@session.click_button
end
it "should select the date and time components with the suffix convention provided" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<label for="appointment_time">Time</label><br />
<select id="appointment_time_year" name="appointment[year]">
<option value="2003">2003</option>
</select>
<select id="appointment_time_month" name="appointment[month]">
<option value="12">December</option>
</select>
<select id="appointment_time_day" name="appointment[day]">
<option value="25">25</option>
</select>
<select id="appointment_time_hour" name="appointment[hour]">
<option value="09">09</option>
</select>
: <select id="appointment_time_minute" name="appointment[minute]">
<option value="30">30</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"year" => '2003', "month" => "12", "day" => "25", "hour" => "09", "minute" => "30"})
@session.selects_datetime "December 25, 2003 9:30", :from => "Time", :suffix_convention => :full_words
@session.click_button
end
it "should select the date and time components with the suffixes provided" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<label for="appointment_time">Time</label><br />
<select id="appointment_time_y" name="appointment[y]">
<option value="2003">2003</option>
</select>
<select id="appointment_time_mo" name="appointment[mo]">
<option value="12">December</option>
</select>
<select id="appointment_time_d" name="appointment[d]">
<option value="25">25</option>
</select>
<select id="appointment_time_h" name="appointment[h]">
<option value="09">09</option>
</select>
: <select id="appointment_time_mi" name="appointment[mi]">
<option value="30">30</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"y" => '2003', "mo" => "12", "d" => "25", "h" => "09", "mi" => "30"})
@session.selects_datetime "December 25, 2003 9:30", :from => "Time",
:suffixes => {:year => 'y', :month => 'mo', :day => 'd', :hour => 'h', :minute => 'mi'}
@session.click_button
end
it "should accept a time object" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<label for="appointment_time">Time</label><br />
<select id="appointment_time_1i" name="appointment[time(1i)]">
<option value="2003">2003</option>
</select>
<select id="appointment_time_2i" name="appointment[time(2i)]">
<option value="12">December</option>
</select>
<select id="appointment_time_3i" name="appointment[time(3i)]">
<option value="25">25</option>
</select>
<select id="appointment_time_4i" name="appointment[time(4i)]">
<option value="09">09</option>
</select>
: <select id="appointment_time_5i" name="appointment[time(5i)]">
<option value="30">30</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"time(1i)" => '2003', "time(2i)" => "12", "time(3i)" => "25", "time(4i)" => "09", "time(5i)" => "30"})
@session.select_datetime Time.parse("December 25, 2003 9:30"), :from => "Time"
@session.click_button
end
it "should work when no label is specified" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<select id="appointment_time_1i" name="appointment[time(1i)]">
<option value="2003">2003</option>
</select>
<select id="appointment_time_2i" name="appointment[time(2i)]">
<option value="12">December</option>
</select>
<select id="appointment_time_3i" name="appointment[time(3i)]">
<option value="25">25</option>
</select>
<select id="appointment_time_4i" name="appointment[time(4i)]">
<option value="09">09</option>
</select>
: <select id="appointment_time_5i" name="appointment[time(5i)]">
<option value="30">30</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"time(1i)" => '2003', "time(2i)" => "12", "time(3i)" => "25", "time(4i)" => "09", "time(5i)" => "30"})
@session.selects_datetime "December 25, 2003 9:30"
@session.click_button
end
it "should fail if the specified label is not found" do
@session.response_body = <<-EOS
<form method="post" action="/appointments">
<select name="month"><option>January</option></select>
<input type="submit" />
</form>
EOS
lambda { @session.selects_datetime "December 25, 2003 9:30", :from => "Time" }.should raise_error
end
end

View File

@ -0,0 +1,114 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "select_time" do
before do
@session = Webrat::TestSession.new
end
it "should send the values for each individual time component" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<label for="appointment_time">Time</label><br />
<select id="appointment_time_4i" name="appointment[time(4i)]">
<option value="09">09</option>
</select>
: <select id="appointment_time_5i" name="appointment[time(5i)]">
<option value="30">30</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"time(4i)" => "09", "time(5i)" => "30"})
@session.selects_time "9:30AM", :from => "Time"
@session.click_button
end
it "should select time components with the suffix convention provided" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<label for="appointment_time">Time</label><br />
<select id="appointment_time_hour" name="appointment[hour]">
<option value="09">09</option>
</select>
: <select id="appointment_time_minute" name="appointment[minute]">
<option value="30">30</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"hour" => "09", "minute" => "30"})
@session.selects_time "9:30", :from => "Time", :suffix_convention => :full_words
@session.click_button
end
it "should select the time components with the suffixes provided" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<label for="appointment_time">Time</label><br />
<select id="appointment_time_h" name="appointment[h]">
<option value="09">09</option>
</select>
: <select id="appointment_time_mi" name="appointment[mi]">
<option value="30">30</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"h" => "09", "mi" => "30"})
@session.selects_time "9:30", :from => "Time",
:suffixes => {:hour => 'h', :minute => 'mi'}
@session.click_button
end
it "should accept a time object" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<label for="appointment_time">Time</label><br />
<select id="appointment_time_4i" name="appointment[time(4i)]">
<option value="09">09</option>
</select>
: <select id="appointment_time_5i" name="appointment[time(5i)]">
<option value="30">30</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"time(4i)" => "09", "time(5i)" => "30"})
@session.select_time Time.parse("9:30AM"), :from => "Time"
@session.click_button
end
it "should work when no label is specified" do
@session.response_body = <<-EOS
<form action="/appointments" method="post">
<select id="appointment_time_4i" name="appointment[time(4i)]">
<option value="09">09</option>
</select>
: <select id="appointment_time_5i" name="appointment[time(5i)]">
<option value="30">30</option>
</select>
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/appointments",
"appointment" => {"time(4i)" => "09", "time(5i)" => "30"})
@session.select_time "9:30"
@session.click_button
end
it "should fail if the specified label is not found" do
@session.response_body = <<-EOS
<form method="post" action="/appointments">
<select name="month"><option>January</option></select>
<input type="submit" />
</form>
EOS
lambda { @session.select_time "9:30", :from => "Time" }.should raise_error
end
end