Skip to content

Commit

Permalink
selects_time, selects_date, and selects_datetime added to API. Closes
Browse files Browse the repository at this point in the history
…#36.
  • Loading branch information
bmabey committed Nov 15, 2008
1 parent 0dffbec commit 6cd76fa
Show file tree
Hide file tree
Showing 11 changed files with 564 additions and 9 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -8,3 +8,4 @@ email.txt
log
.project
.loadpath
*.swp
4 changes: 4 additions & 0 deletions History.txt
@@ -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)
Expand Down
14 changes: 9 additions & 5 deletions lib/webrat/core/field.rb
Expand Up @@ -34,8 +34,16 @@ def label_text
labels.first.text
end

def id
@element["id"]
end

def matches_id?(id)
@element["id"] == id.to_s
if id.is_a?(Regexp)
@element["id"] =~ id
else
@element["id"] == id.to_s
end
end

def matches_name?(name)
Expand Down Expand Up @@ -83,10 +91,6 @@ def unset

protected

def id
@element["id"]
end

def name
@element["name"]
end
Expand Down
10 changes: 9 additions & 1 deletion lib/webrat/core/form.rb
Expand Up @@ -44,6 +44,10 @@ def fields
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
Expand All @@ -65,6 +69,10 @@ def field_labeled(label, *field_types)
end
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

Expand Down Expand Up @@ -127,4 +135,4 @@ def merge_hash_values(a, b) # :nodoc:
end

end
end
end
6 changes: 5 additions & 1 deletion lib/webrat/core/label.rb
Expand Up @@ -17,6 +17,10 @@ def text
str.squeeze!(" ")
str
end

def for_id
@element['for']
end

end
end
end
11 changes: 10 additions & 1 deletion lib/webrat/core/locators.rb
Expand Up @@ -87,6 +87,15 @@ def find_link(text_or_title_or_id) #:nodoc:
flunk("Could not find link with text or title or id #{text_or_title_or_id.inspect}")
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
end
121 changes: 120 additions & 1 deletion lib/webrat/core/scope.rb
Expand Up @@ -92,6 +92,114 @@ def selects(option_text, options = {})

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.
Expand Down Expand Up @@ -191,6 +299,17 @@ def locate_field(field_locator, *field_types) #:nodoc:
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)
Expand All @@ -212,4 +331,4 @@ def forms #:nodoc:
end

end
end
end
3 changes: 3 additions & 0 deletions lib/webrat/core/session.rb
Expand Up @@ -184,6 +184,9 @@ def page_scope #:nodoc:
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
Expand Down
130 changes: 130 additions & 0 deletions spec/api/selects_date_spec.rb
@@ -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

0 comments on commit 6cd76fa

Please sign in to comment.