require 'date'
module Calabash
module Cucumber
module DatePicker
include Calabash::Cucumber::Core
# equivalent formats for ruby and objc
# we convert DateTime object to a string
# and pass the format that objc can use
# to convert the string into NSDate
RUBY_DATE_AND_TIME_FMT = '%Y_%m_%d_%H_%M'
OBJC_DATE_AND_TIME_FMT = 'yyyy_MM_dd_HH_mm'
# picker modes
UI_DATE_PICKER_MODE_TIME = 0
UI_DATE_PICKER_MODE_DATE = 1
UI_DATE_PICKER_MODE_DATE_AND_TIME = 2
UI_DATE_PICKER_MODE_COUNT_DOWN_TIMER = 3
def date_picker_mode(picker_id=nil)
query_str = should_see_date_picker picker_id
res = query(query_str, :datePickerMode)
if res.empty?
screenshot_and_raise "should be able to get mode from picker with query '#{query_str}'"
end
res.first
end
def time_mode?(picker_id=nil)
date_picker_mode(picker_id) == UI_DATE_PICKER_MODE_TIME
end
def date_mode?(picker_id=nil)
date_picker_mode(picker_id) == UI_DATE_PICKER_MODE_DATE
end
def date_and_time_mode?(picker_id=nil)
date_picker_mode(picker_id) == UI_DATE_PICKER_MODE_DATE_AND_TIME
end
def countdown_mode?(picker_id=nil)
date_picker_mode(picker_id) == UI_DATE_PICKER_MODE_COUNT_DOWN_TIMER
end
# ensuring picker is visible
def query_string_for_picker (picker_id = nil)
picker_id.nil? ? 'datePicker' : "datePicker marked:'#{picker_id}'"
end
def should_see_date_picker (picker_id=nil)
query_str = query_string_for_picker picker_id
if query(query_str).empty?
screenshot_and_raise "should see picker with query '#{query_str}'"
end
query_str
end
# minimum and maximum dates
# appledoc ==> The property is an NSDate object or nil (the default),
# which means no maximum date.
def maximum_date_time_from_picker (picker_id = nil)
if countdown_mode? picker_id
screenshot_and_raise 'method is not available for pickers that are not in date or date time mode'
end
query_str = should_see_date_picker picker_id
res = query(query_str, :maximumDate)
if res.empty?
screenshot_and_raise "should be able to get max date from picker with query '#{query_str}'"
end
return nil if res.first.nil?
DateTime.parse(res.first)
end
# appledoc ==> The property is an NSDate object or nil (the default),
# which means no minimum date.
def minimum_date_time_from_picker (picker_id = nil)
if countdown_mode? picker_id
screenshot_and_raise 'method is not available for pickers that are not in date or date time mode'
end
query_str = should_see_date_picker picker_id
res = query(query_str, :minimumDate)
if res.empty?
screenshot_and_raise "should be able to get min date from picker with query '#{query_str}'"
end
return nil if res.first.nil?
DateTime.parse(res.first)
end
# date time from picker
def date_time_from_picker (picker_id=nil)
if countdown_mode? picker_id
screenshot_and_raise 'method is not available for pickers that are not in date or date time mode'
end
query_str = query_string_for_picker picker_id
res = query(query_str, :date)
if res.empty?
screenshot_and_raise "should be able to get date from picker with query '#{query_str}'"
end
DateTime.parse(res.first)
end
# changing picker date time
def args_for_change_date_on_picker(options)
args = []
if options.has_key?(:notify_targets)
args << options[:notify_targets] ? 1 : 0
else
args << 1
end
if options.has_key?(:animate)
args << options[:animate] ? 1 : 0
else
args << 1
end
args
end
# sets the date and time on picker identified by options[:picker_id]
# using the DateTime +target_dt+
#
# valid options are:
#
# :animate - animate the change - default is +true+
# :picker_id - the id (or mark) of the date picker - default is +nil+ which
# will target the first visible date picker
# :notify_targets - notify all objc targets that the date picker has changed
# default is +true+
#
# when :notify_targets = true this operation iterates through the
# target/action pairs on the objc +UIDatePicker+ instance and calls
# performSelector: object: to simulate a +UIEvent+
#
# raises an error if
# * no UIDatePicker can be found
# * the target date is greater than the picker's maximum date
# * the target date is less than the picker's minimum date
# * the target date is not a DateTime object
def picker_set_date_time (target_dt, options = {:animate => true,
:picker_id => nil,
:notify_targets => true})
unless target_dt.is_a?(DateTime)
raise "target_dt must be a DateTime but found '#{target_dt.class}'"
end
picker_id = options == nil ? nil : options[:picker_id]
if time_mode?(picker_id) == UI_DATE_PICKER_MODE_COUNT_DOWN_TIMER
pending('picker is in count down mode which is not yet supported')
end
target_str = target_dt.strftime(RUBY_DATE_AND_TIME_FMT).squeeze(' ').strip
fmt_str = OBJC_DATE_AND_TIME_FMT
args = args_for_change_date_on_picker options
query_str = query_string_for_picker picker_id
views_touched = map(query_str, :changeDatePickerDate, target_str, fmt_str, *args)
msg = "could not change date on picker to '#{target_dt}' using query '#{query_str}' with options '#{options}'"
assert_map_results(views_touched,msg)
views_touched
end
end
end
end