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