briar 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +29 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +36 -0
  5. data/README.md +25 -0
  6. data/Rakefile +12 -0
  7. data/briar.gemspec +26 -0
  8. data/dotirbc_briar_additions +31 -0
  9. data/features/step_definitions/alerts_and_sheets/action_sheet_steps.rb +8 -0
  10. data/features/step_definitions/alerts_and_sheets/alert_view_steps.rb +25 -0
  11. data/features/step_definitions/bars/navbar_steps.rb +95 -0
  12. data/features/step_definitions/bars/tabbar_steps.rb +32 -0
  13. data/features/step_definitions/bars/toolbar_steps.rb +17 -0
  14. data/features/step_definitions/briar_core_steps.rb +9 -0
  15. data/features/step_definitions/control/button_steps.rb +57 -0
  16. data/features/step_definitions/control/segmented_control_steps.rb +85 -0
  17. data/features/step_definitions/control/slider_steps.rb +9 -0
  18. data/features/step_definitions/email_steps.rb +59 -0
  19. data/features/step_definitions/image_view_steps.rb +9 -0
  20. data/features/step_definitions/keyboard_steps.rb +21 -0
  21. data/features/step_definitions/label_steps.rb +21 -0
  22. data/features/step_definitions/picker/date_picker_steps.rb +216 -0
  23. data/features/step_definitions/picker/picker_steps.rb +58 -0
  24. data/features/step_definitions/scroll_view_steps.rb +20 -0
  25. data/features/step_definitions/table_steps.rb +186 -0
  26. data/features/step_definitions/text_field_steps.rb +37 -0
  27. data/features/step_definitions/text_view_steps.rb +44 -0
  28. data/features/support/env.rb +0 -0
  29. data/features/support/hooks.rb +0 -0
  30. data/features/support/launch.rb +0 -0
  31. data/lib/briar.rb +72 -0
  32. data/lib/briar/alerts_and_sheets/alert_view.rb +16 -0
  33. data/lib/briar/bars/navbar.rb +104 -0
  34. data/lib/briar/bars/tabbar.rb +38 -0
  35. data/lib/briar/bars/toolbar.rb +36 -0
  36. data/lib/briar/briar_core.rb +56 -0
  37. data/lib/briar/briar_steps.rb +26 -0
  38. data/lib/briar/control/button.rb +47 -0
  39. data/lib/briar/control/segmented_control.rb +22 -0
  40. data/lib/briar/control/slider.rb +34 -0
  41. data/lib/briar/cucumber.rb +49 -0
  42. data/lib/briar/email.rb +58 -0
  43. data/lib/briar/gestalt.rb +80 -0
  44. data/lib/briar/image_view.rb +27 -0
  45. data/lib/briar/keyboard.rb +104 -0
  46. data/lib/briar/label.rb +34 -0
  47. data/lib/briar/picker/date_picker.rb +598 -0
  48. data/lib/briar/picker/picker.rb +32 -0
  49. data/lib/briar/picker/picker_shared.rb +34 -0
  50. data/lib/briar/scroll_view.rb +10 -0
  51. data/lib/briar/table.rb +237 -0
  52. data/lib/briar/text_field.rb +57 -0
  53. data/lib/briar/text_view.rb +21 -0
  54. data/lib/briar/version.rb +3 -0
  55. data/spec/briar/gestalt_spec.rb +62 -0
  56. data/spec/spec_helper.rb +17 -0
  57. metadata +164 -0
@@ -0,0 +1,27 @@
1
+ require 'calabash-cucumber'
2
+
3
+ module Briar
4
+ module ImageView
5
+ def image_view_exists? name
6
+ query_str = "imageView marked:'#{name}'"
7
+ exists = !query(query_str).empty?
8
+ if exists
9
+ alpha = query(query_str, :alpha).first.to_i
10
+ hidden = query(query_str, :isHidden).first.to_i
11
+ alpha > 0 and hidden == 0
12
+ end
13
+ end
14
+
15
+ def should_see_image_view name
16
+ unless image_view_exists? name
17
+ screenshot_and_raise "i should see image view with id '#{name}'"
18
+ end
19
+ end
20
+
21
+ def should_not_see_image_view name
22
+ if image_view_exists? name
23
+ screenshot_and_raise "i should not see an image view with id #{name}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,104 @@
1
+ require "calabash-cucumber"
2
+
3
+ module Briar
4
+ module Keyboard
5
+ UITextAutocapitalizationTypeNone = 0
6
+ UITextAutocapitalizationTypeWords = 1
7
+ UITextAutocapitalizationTypeSentences = 2
8
+ UITextAutocapitalizationTypeAllCharacters = 3
9
+
10
+ UITextAutocorrectionTypeNo = 1
11
+ UITextAutocorrectionTypeYes = 2
12
+
13
+ UITextSpellCheckingTypeNo = 1
14
+ UITextSpellCheckingTypeYes = 2
15
+
16
+
17
+ def should_see_keyboard
18
+ res = element_exists("keyboardAutomatic")
19
+ unless res
20
+ screenshot_and_raise "Expected keyboard to be visible."
21
+ end
22
+ end
23
+
24
+ def should_not_see_keyboard
25
+ res = element_exists("keyboardAutomatic")
26
+ if res
27
+ screenshot_and_raise "Expected keyboard to not be visible."
28
+ end
29
+ end
30
+
31
+ # is it possible to find what view the keyboard is responding to?
32
+ def autocapitalization_type ()
33
+ if !query("textView index:0").empty?
34
+ query("textView index:0", :autocapitalizationType).first.to_i
35
+ elsif !query("textField index:0").empty?
36
+ query("textField index:0", :autocapitalizationType).first.to_i
37
+ else
38
+ screenshot_and_raise "could not find a text view or text field"
39
+ end
40
+ end
41
+
42
+ def set_autocapitalization (type)
43
+ if !query("textView index:0").empty?
44
+ query("textView index:0", [{setAutocapitalizationType:type}])
45
+ elsif !query("textField index:0").empty?
46
+ query("textField index:0", [{setAutocapitalizationType:type}])
47
+ else
48
+ screenshot_and_raise "could not find a text view or text field"
49
+ end
50
+ end
51
+
52
+ def turn_autocapitalization_off
53
+ set_autocapitalization UITextAutocapitalizationTypeNone
54
+ end
55
+
56
+ def set_autocorrect (type)
57
+ if !query("textView index:0").empty?
58
+ query("textView index:0", [{setAutocorrectionType:type}])
59
+ elsif !query("textField index:0").empty?
60
+ query("textField index:0", [{setAutocorrectionType:type}])
61
+ else
62
+ screenshot_and_raise "could not find a text view or text field"
63
+ end
64
+ end
65
+
66
+ def turn_autocorrect_off
67
+ set_autocorrect UITextAutocorrectionTypeNo
68
+ end
69
+
70
+ def turn_spell_correct_off
71
+ if !query("textView index:0").empty?
72
+ query("textView index:0", [{setSpellCheckingType:UITextSpellCheckingTypeNo}])
73
+ elsif !query("textField index:0").empty?
74
+ query("textField index:0", [{setSpellCheckingType:UITextSpellCheckingTypeNo}])
75
+ else
76
+ screenshot_and_raise "could not find a text view or text field"
77
+ end
78
+ end
79
+
80
+ #def is_capitalize_none (cap_type)
81
+ # cap_type == UITextAutocapitalizationTypeNone
82
+ #end
83
+ #
84
+ #def is_capitalize_words (cap_type)
85
+ # cap_type == UITextAutocapitalizationTypeWords
86
+ #end
87
+ #
88
+ #def is_capitalize_sentences (cap_type)
89
+ # cap_type == UITextAutocapitalizationTypeSentences
90
+ #end
91
+ #
92
+ #def is_capitalize_all (cap_type)
93
+ # cap_type == UITextAutocapitalizationTypeAllCharacters
94
+ #end
95
+ #
96
+ #def is_autocorrect_on (state)
97
+ # state == UITextAutocorrectionTypeYes
98
+ #end
99
+ #
100
+ #def is_autocorrect_off (state)
101
+ # state == UITextAutocorrectionTypeNo
102
+ #end
103
+ end
104
+ end
@@ -0,0 +1,34 @@
1
+ require "calabash-cucumber"
2
+
3
+ module Briar
4
+ module Label
5
+ def label_exists? (name)
6
+ !query("label marked:'#{name}'").empty?
7
+ end
8
+
9
+ def should_see_label (name)
10
+ res = label_exists? (name)
11
+ unless res
12
+ screenshot_and_raise "i could not find label with access id #{name}"
13
+ end
14
+ end
15
+
16
+ def label_exists_with_text? (name, text)
17
+ actual = query("label marked:'#{name}'", :text).first
18
+ actual.eql? text
19
+ end
20
+
21
+ def should_see_label_with_text (name, text)
22
+ unless label_exists_with_text?(name, text)
23
+ actual = query("label marked:'#{name}'", :text).first
24
+ screenshot_and_raise "i expected to see '#{text}' in label named '#{name}' but found '#{actual}'"
25
+ end
26
+ end
27
+
28
+ def should_not_see_label_with_text (name, text)
29
+ if label_exists_with_text?(name, text)
30
+ screenshot_and_raise "i expected that i would not see '#{text}' in label named '#{name}'"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,598 @@
1
+ require 'date'
2
+ require 'calabash-cucumber'
3
+
4
+ module Briar
5
+ module Picker
6
+ module Date
7
+ include Briar::Picker_Shared
8
+ =begin
9
+ TODO use minute interval modes 5,10,15 etc. to test if date is reachable
10
+ TODO use the max/min dates to determine if a date is reachable
11
+ TODO when manually moving the picker wheels - speed things up by figuring out which direction to scroll the hour/minutes
12
+ =end
13
+
14
+
15
+ =begin
16
+
17
+ requires: picker_common_step.rb
18
+
19
+ examples
20
+
21
+ Then I should see that the date picker is in time mode
22
+ Then I should see that the time on the picker is now
23
+
24
+ Then I change the time on the picker to "1:45 PM"
25
+ Then I change the time on the picker to "13:45"
26
+
27
+ Then I change the date on the picker to "Sat Nov 17"
28
+ Then I change the date on the picker to "Sat 17 Nov"
29
+
30
+ Then I change the picker date to "Sat Nov 17" and the time to "0:00"
31
+ Then I change the picker date to "Sat 17 Nov" and the time to "12:00 AM"
32
+
33
+ Then I change the picker to 2 days ago at "9:30 PM"
34
+ Then I should see that the "checkin" row has the time I just entered in the "status" label
35
+
36
+
37
+ this file provides 2 ways to manipulate a date picker:
38
+
39
+ 1. AUTOMATIC <== setting the date directly using a UIDatePicker category method
40
+ 2. MANUAL <== setting the date by manipulating the picker wheels
41
+
42
+ there are pros and cons for each approach.
43
+
44
+ AUTOMATIC pros
45
+ 1. the date selection happens almost instantly
46
+ 2. there is very little parsing of date and time strings <== fewer errors
47
+ 3. it is accomplished in a small number of lines of code <== fewer errors
48
+
49
+ AUTOMATIC cons
50
+ 1. it does not really simulate the user interaction with the picker wheels.
51
+
52
+ this is actually very hard to do because there are cases where changing
53
+ one column will cause another column to change. for example: when in 12h
54
+ mode, if the user rotates the hour to 12, then the period column will change.
55
+ this change cannot be detected on the calabash side so either it has to be
56
+ guarded against (don't rotate past 12) or the AM/PM must be changed last.
57
+
58
+ 2. requires a category on UIDatePicker <== pollutes the application environment
59
+ 3. uses the query language to make changes to application state <== doesn't seem kosher
60
+
61
+ in my mind this is a little like the keyboard_enter_text because that method
62
+ enters text in a way that no user can (i.e. so fast)
63
+
64
+ MANUAL pros
65
+ 1. it directly simulates what a user does
66
+
67
+
68
+ MANUAL cons
69
+ 1. it is very slow <== long tests are a drag
70
+ 2. there is a lot of string <==> date parsing <== more errors
71
+ 3. lots of special case handling <== more errors
72
+
73
+
74
+ to use the automatic mode, include this category in your CALABASH target
75
+
76
+ === BEGIN ===
77
+ @interface UIDatePicker (CALABASH_ADDITIONS)
78
+ - (NSString *) hasCalabashAdditions:(NSString *) aSuccessIndicator;
79
+ - (BOOL) setDateWithString:(NSString *)aString
80
+ format:(NSString *) aFormat
81
+ animated:(BOOL) aAnimated;
82
+ @end
83
+
84
+
85
+ @implementation UIDatePicker (CALABASH_ADDITIONS)
86
+ - (NSString *) hasCalabashAdditions:(NSString *) aSuccessIndicator {
87
+ return aSuccessIndicator;
88
+ }
89
+
90
+ - (BOOL) setDateWithString:(NSString *)aString
91
+ format:(NSString *) aFormat
92
+ animated:(BOOL) aAnimated {
93
+ NSDateFormatter *df = [[NSDateFormatter alloc] init];
94
+ [df setDateFormat:aFormat];
95
+ NSDate *date = [df dateFromString:aString];
96
+ if (date == nil) return NO;
97
+ [self setDate:date animated:aAnimated];
98
+ return YES;
99
+ }
100
+ @end
101
+ === END ===
102
+
103
+ =end
104
+
105
+ # 0.2 is too fast because the picker does not pause at the date long enough for
106
+ # the date to change. 0.3 seems to work, but 0.4 is best i think.
107
+ PICKER_STEP_PAUSE = 0.4.to_f
108
+ PICKER_AM = "AM"
109
+ PICKER_PM = "PM"
110
+
111
+ # most locales and situations prefer _not_ to have leading zeros on hours in 24h
112
+ # see usage below to find out when and if the zeros are stripped
113
+ PICKER_24H_TIME_FMT = '%H:%M'
114
+ PICKER_12H_TIME_FMT = '%l:%M %p'
115
+ PICKER_ISO8601_TIME_FMT = '%H:%M'
116
+
117
+ PICKER_REMOVE_LEADING_ZERO_REGEX = /\A^0/
118
+
119
+ # 24h locales - Fri 16 Nov - 24h locales
120
+ PICKER_24H_DATE_FMT = '%a %e %b'
121
+ # common format for US Fri Nov 16
122
+ PICKER_12H_DATE_FMT = '%a %b %e'
123
+
124
+ # our canonical format for testing if two dates are the same
125
+ PICKER_ISO8601_DATE_FMT = '%Y-%m-%d'
126
+ PICKER_ISO8601_DATE_TIME_FMT = '%Y-%m-%d %H:%M'
127
+
128
+ # when we are using the date picker category, this is the format of the string
129
+ # we will send to setDateWithString:animated:
130
+ #
131
+ # ex. 2012_11_18_16_45
132
+ PICKER__RUBY___SET_PICKER_DATE__DATE_AND_TIME_FMT = '%Y_%m_%d_%H_%M_%z'
133
+ PICKER__OBJC___SET_PICKER_DATE__DATE_AND_TIME_FMT = 'yyyy_MM_dd_HH_mm_Z'
134
+
135
+ # iOS 5
136
+ PICKER_VIEW_CLASS_IOS5 = "datePickerView"
137
+ PICKER_VIEW_CLASS_IOS6 = "view:'_UIDatePickerView'"
138
+
139
+ # testing for existence
140
+ def should_see_date_picker (picker_id)
141
+ res = !query("datePicker marked:'#{picker_id}'").empty?
142
+ unless res
143
+ screenshot_and_raise "could not find date picker #{picker_id}"
144
+ end
145
+ end
146
+
147
+ # getting dates from the picker
148
+
149
+ def picker_date_time
150
+ res = query("datePicker", :date)
151
+ screenshot_and_raise "expected to see a date picker" if res.empty?
152
+ DateTime.parse(res.first)
153
+ end
154
+
155
+ # appledoc ==> The property is an NSDate object or nil (the default), which
156
+ # means no maximum date.
157
+ def picker_maximum_date_time
158
+ res = query("datePicker", :maximumDate)
159
+ screenshot_and_raise "expected to see a date picker" if res.empty?
160
+ res.first != nil ? DateTime.parse(res.first) : nil
161
+ end
162
+
163
+ # appledoc ==> The property is an NSDate object or nil (the default), which
164
+ # means no minimum date.
165
+ def picker_minimum_date_time
166
+ res = query("datePicker", :minimumDate)
167
+ screenshot_and_raise "expected to see a date picker" if res.empty?
168
+ res.first != nil ? DateTime.parse(res.first) : nil
169
+ end
170
+
171
+ # automatic date setting
172
+
173
+ # checking to see if the picker is visible and has the calabash category
174
+ # additions
175
+ def picker_has_calabash_additions
176
+ success_value = "1"
177
+ res = query("datePicker", [{hasCalabashAdditions:success_value}])
178
+ screenshot_and_raise "picker is not visible" if res.empty?
179
+ res.first.eql? success_value
180
+ end
181
+
182
+
183
+ def date_time_or_time_str_is_in_24h (date_time_or_time_str)
184
+ date_time_or_time_str[-1, 1].scan(/^[a-zA-Z]/).empty?
185
+ end
186
+
187
+ def date_str_is_in_24h (date_str)
188
+ !date_str[-1, 1].scan(/^[a-zA-Z]/).empty?
189
+ end
190
+
191
+ def date_str_to_send_to_picker_from_time_str (time_str)
192
+ time_in_24h = date_time_or_time_str_is_in_24h time_str
193
+ time_fmt = time_in_24h ? PICKER_24H_TIME_FMT : PICKER_12H_TIME_FMT
194
+ date_fmt = time_in_24h ? PICKER_24H_DATE_FMT : PICKER_12H_DATE_FMT
195
+ date_str = picker_date_time.strftime(date_fmt).squeeze(" ").strip
196
+
197
+ date_time_str = "#{date_str} #{time_str}"
198
+ date_time_fmt = "#{date_fmt} #{time_fmt}"
199
+
200
+ date_time = DateTime.strptime(date_time_str, date_time_fmt)
201
+ date_time.strftime(PICKER__RUBY___SET_PICKER_DATE__DATE_AND_TIME_FMT).squeeze(" ").strip
202
+ end
203
+
204
+
205
+ def date_str_to_send_to_picker_from_date_str (date_str)
206
+ date_in_24h = date_str_is_in_24h (date_str)
207
+ time_fmt = date_in_24h ? PICKER_24H_TIME_FMT : PICKER_12H_TIME_FMT
208
+ date_fmt = date_in_24h ? PICKER_24H_DATE_FMT : PICKER_12H_DATE_FMT
209
+ time_str = picker_date_time.strftime(time_fmt).squeeze(" ").strip
210
+ date_time_str = "#{date_str} #{time_str}"
211
+ date_time_fmt = "#{date_fmt} #{time_fmt}"
212
+ date_time = DateTime.strptime(date_time_str, date_time_fmt)
213
+ date_time.strftime(PICKER__RUBY___SET_PICKER_DATE__DATE_AND_TIME_FMT).squeeze(" ").strip
214
+ end
215
+
216
+
217
+ def set_picker_date_with_date_time_str (date_time_str, animated=1)
218
+ query("datePicker", [{respondsToSelector:"minuteInterval"}])
219
+
220
+
221
+ res = query("datePicker", [{setDateWithString:date_time_str},
222
+ {format:"#{PICKER__OBJC___SET_PICKER_DATE__DATE_AND_TIME_FMT}"},
223
+ {animated:animated.to_i}])
224
+ screenshot_and_raise "could not find a date picker to query" if res.empty?
225
+ if res.first.to_i == 0
226
+ screenshot_and_raise "could not set the picker date with '#{date_time_str}' and '#{PICKER__RUBY___SET_PICKER_DATE__DATE_AND_TIME_FMT}'"
227
+ end
228
+
229
+ # REQUIRED
230
+ sleep(PICKER_STEP_PAUSE)
231
+
232
+ # the query does not create a UIControlEventValueChanged event, so we have to
233
+ # to a touch event
234
+
235
+ # if the picker is in time mode, then we dont need to worry about min/max
236
+ # if the picker is date or date time mode, i think the first column is
237
+ # always scrollable up _and_ it sends an event even if the date is beyond
238
+ # the maximum date
239
+
240
+ #picker_max_date = picker_maximum_date_time
241
+ #picker_min_date = picker_minimum_date_time
242
+ #target_date = DateTime.strptime(date_time_str, PICKER__RUBY___SET_PICKER_DATE__DATE_AND_TIME_FMT)
243
+
244
+ #column_one_index = picker_current_index_for_column 0
245
+ #query("pickerTableView index:0", [{selectRow:column_one_index}, {animated:1}, {notify:1}])
246
+
247
+ picker_scroll_down_on_column 0
248
+ sleep(PICKER_STEP_PAUSE)
249
+ picker_scroll_up_on_column 0
250
+ sleep(PICKER_STEP_PAUSE)
251
+ #if (target_date + 1) > picker_max_date
252
+ # picker_scroll_down_on_column 0
253
+ # sleep(PICKER_STEP_PAUSE)
254
+ # picker_scroll_up_on_column 0
255
+ #elsif (target_date - 1) < picker_min_date
256
+ # picker_scroll_up_on_column 0
257
+ # sleep(PICKER_STEP_PAUSE)
258
+ # picker_scroll_down_on_column 0
259
+ #else
260
+ # screenshot_and_raise "could not figure out which way to rotate the day column to trigger an event"
261
+ #end
262
+
263
+ end
264
+
265
+ # apple docs
266
+ # You can use this property to set the interval displayed by the minutes wheel
267
+ # (for example, 15 minutes). The interval value must be evenly divided into 60;
268
+ # if it is not, the default value is used. The default and minimum values are 1;
269
+ # the maximum value is 30.
270
+ def picker_minute_interval
271
+ screenshot_and_raise "there is no minute in date mode" if picker_is_in_date_mode
272
+ screenshot_and_raise "nyi" if picker_is_in_countdown_mode
273
+ res = query("datePicker", :minuteInterval)
274
+ screenshot_and_raise "expected to see a date picker" if res.empty?
275
+ @picker_minute_interval = res.first
276
+ end
277
+
278
+ def time_hash_by_add_minutes_until_at_closest_interval (time_str, interval=picker_minute_interval())
279
+ screenshot_and_raise "interval '#{interval}' is not on (0, 59) which is not allowed" unless (0..59).member?(interval)
280
+ time = Time.parse(time_str)
281
+ # normalize to zero
282
+ time = time - time.sec
283
+ minute = time.min
284
+ count = 0
285
+ unless (minute % interval) == 0
286
+ begin
287
+ minute = (minute > 59) ? 0 : minute + 1
288
+ count = count + 1
289
+ end
290
+ end while ((minute % interval) != 0)
291
+ time = time + (count * 60)
292
+
293
+ {:h12 => time.strftime(PICKER_12H_TIME_FMT).squeeze(" ").strip,
294
+ :h24 => time.strftime(PICKER_24H_TIME_FMT).squeeze(" ").strip.sub(PICKER_REMOVE_LEADING_ZERO_REGEX,""),
295
+ :time => time}
296
+ end
297
+
298
+ # picker modes
299
+
300
+ UIDatePickerModeTime = 0
301
+ UIDatePickerModeDate = 1
302
+ UIDatePickerModeDateAndTime = 2
303
+ UIDatePickerModeCountDownTimer = 3
304
+
305
+ def picker_mode
306
+ res = query("datePicker", :datePickerMode)
307
+ screenshot_and_raise "expected to see a date picker" if res.empty?
308
+ res.first
309
+ end
310
+
311
+ def picker_is_in_time_mode
312
+ picker_mode == UIDatePickerModeTime
313
+ end
314
+
315
+ def picker_is_in_date_mode
316
+ picker_mode == UIDatePickerModeDate
317
+ end
318
+
319
+ def picker_is_in_date_and_time_mode
320
+ picker_mode == UIDatePickerModeDateAndTime
321
+ end
322
+
323
+ def picker_is_in_countdown_mode
324
+ picker_mode == UIDatePickerModeCountDownTimer
325
+ end
326
+
327
+ # columns for different modes
328
+
329
+ def picker_column_for_hour
330
+ screenshot_and_raise "there is no hour column in date mode" if picker_is_in_date_mode
331
+ screenshot_and_raise "nyi" if picker_is_in_countdown_mode
332
+ picker_is_in_time_mode ? 0 : 1
333
+ end
334
+
335
+ def picker_column_for_minute
336
+ screenshot_and_raise "there is no minute column in date mode" if picker_is_in_date_mode
337
+ screenshot_and_raise "nyi" if picker_is_in_countdown_mode
338
+ picker_is_in_time_mode ? 1 : 2
339
+ end
340
+
341
+ def picker_column_for_period
342
+ screenshot_and_raise "there is no period column in date mode" if picker_is_in_date_mode
343
+ screenshot_and_raise "nyi" if picker_is_in_countdown_mode
344
+ picker_is_in_time_mode ? 2 : 3
345
+ end
346
+
347
+ # 12h or 24h locale
348
+
349
+ def picker_is_in_12h_locale
350
+ screenshot_and_raise "12h/24h mode is not applicable to this mode" if picker_is_in_date_mode or picker_is_in_countdown_mode
351
+ column = picker_column_for_period
352
+ !query("pickerTableView index:#{column}").empty?
353
+ end
354
+
355
+ def picker_is_in_24h_locale
356
+ !picker_is_in_12h_locale
357
+ end
358
+
359
+ # dealing with the period (aka meridian) column
360
+
361
+ # this will cause problems with localizations - for example:
362
+ # pt (lisbon) - a.m./p.m.
363
+ # de - nach/vor
364
+ def picker_period
365
+ screenshot_and_raise "picker is not in 12h mode" if picker_is_in_24h_locale
366
+ date = picker_date_time
367
+ date_str = date.strftime(PICKER_12H_TIME_FMT)
368
+ tokens = date_str.split(" ")
369
+ tokens.last
370
+ end
371
+
372
+ def picker_period_is_am?
373
+ picker_period.eql?("AM")
374
+ end
375
+
376
+ def picker_period_is_pm?
377
+ picker_period.eql?("PM")
378
+ end
379
+
380
+ # weekday, month, day, etc
381
+
382
+ def picker_weekday
383
+ screenshot_and_raise "weekday is not applicable to this mode" if picker_is_in_time_mode or picker_is_in_countdown_mode
384
+ res = query("datePickerWeekMonthDayView", :weekdayLabel, :text)[2]
385
+ # need to guard against Today showing
386
+ res == nil ? Date.today.strftime('%a') : res
387
+ end
388
+
389
+ def picker_month_day
390
+ screenshot_and_raise "month/day is not applicable to this mode" if picker_is_in_time_mode or picker_is_in_countdown_mode
391
+ res = query("datePickerWeekMonthDayView", :dateLabel, :text)[2]
392
+ picker_iso = picker_date_time.strftime(PICKER_ISO8601_DATE_FMT).squeeze(" ").strip
393
+ today = Date.today
394
+ today_iso = today.strftime(PICKER_ISO8601_DATE_FMT).squeeze(" ").strip
395
+ fmt = picker_is_in_24h_locale ? '%e %b' : '%b %e'
396
+ (picker_iso.eql? today_iso) ? today.strftime(fmt) : res
397
+ end
398
+
399
+ def picker_date_str
400
+ "#{picker_weekday} #{picker_month_day}".strip.squeeze(" ")
401
+ end
402
+
403
+ def picker_weekday_month_day_is (weekday_month_day)
404
+ weekday_month_day.eql? picker_date_str
405
+ end
406
+
407
+ # dealing with time
408
+
409
+ def picker_hour_24h
410
+ screenshot_and_raise "hour is not applicable to this mode" if picker_is_in_countdown_mode or picker_is_in_date_mode
411
+ # query always returns as 24h
412
+ res_ios5 = query(PICKER_VIEW_CLASS_IOS5, :hour).first
413
+ res_ios6 = query(PICKER_VIEW_CLASS_IOS6, :hour).first
414
+ return res_ios5 != nil ? res_ios5 : res_ios6
415
+ #query("datePickerView", :hour).first
416
+ end
417
+
418
+ def picker_hour_24h_str
419
+ screenshot_and_raise "hour is not applicable to this mode" if picker_is_in_countdown_mode or picker_is_in_date_mode
420
+ "%02d" % picker_hour_24h
421
+ end
422
+
423
+ def picker_hour_12h
424
+ screenshot_and_raise "hour is not applicable to this mode" if picker_is_in_countdown_mode or picker_is_in_date_mode
425
+ hour_24h = picker_hour_24h
426
+ return 12 if hour_24h == 0
427
+ hour_24h > 12 ? hour_24h - 12 : hour_24h
428
+ end
429
+
430
+ def picker_hour_12h_str
431
+ screenshot_and_raise "hour is not applicable to this mode" if picker_is_in_countdown_mode or picker_is_in_date_mode
432
+ "#{picker_hour_12h}"
433
+ end
434
+
435
+ def picker_hour_24h_is (target_hour)
436
+ target_hour == picker_hour_24h
437
+ end
438
+
439
+ def picker_hour_12h_is (target_hour)
440
+ target_hour == picker_hour_12h
441
+ end
442
+
443
+ def picker_hour_is (target_hour)
444
+ picker_is_in_24h_locale ? picker_hour_24h_is(target_hour) : picker_hour_12h_is(target_hour)
445
+ end
446
+
447
+ def picker_minute
448
+ screenshot_and_raise "hour is not applicable to this mode" if picker_is_in_countdown_mode or picker_is_in_date_mode
449
+ res_ios5 = query(PICKER_VIEW_CLASS_IOS5, :minute).first
450
+ res_ios6 = query(PICKER_VIEW_CLASS_IOS6, :minute).first
451
+ return res_ios5 != nil ? res_ios5 : res_ios6
452
+ #query("datePickerView", :minute).first
453
+ end
454
+
455
+ def picker_minute_str
456
+ screenshot_and_raise "hour is not applicable to this mode" if picker_is_in_countdown_mode or picker_is_in_date_mode
457
+ "%02d" % picker_minute
458
+ #"%02d" % query("datePickerView", :minute).first
459
+ end
460
+
461
+ def picker_minute_is (target_minute)
462
+ target_minute == picker_minute
463
+ end
464
+
465
+ def picker_time_24h_str
466
+ screenshot_and_raise "the time is not applicable for this mode" if picker_is_in_date_mode or picker_is_in_countdown_mode
467
+ "#{picker_hour_24h_str}:#{picker_minute_str}".strip.sub(PICKER_REMOVE_LEADING_ZERO_REGEX, "")
468
+ end
469
+
470
+ def picker_time_12h_str
471
+ screenshot_and_raise "the time is not applicable for this mode" if picker_is_in_date_mode or picker_is_in_countdown_mode
472
+ "#{picker_hour_12h_str}:#{picker_minute_str} #{picker_period}"
473
+ end
474
+
475
+ def picker_time_str
476
+ screenshot_and_raise "the time is not applicable for this mode" if picker_is_in_date_mode or picker_is_in_countdown_mode
477
+ picker_is_in_24h_locale ? picker_time_24h_str : picker_time_12h_str
478
+ end
479
+
480
+ def picker_time_for_other_locale
481
+ time_str = picker_is_in_24h_locale ? picker_time_24h_str : picker_time_12h_str
482
+ fmt_str = picker_is_in_24h_locale ? PICKER_12H_TIME_FMT : PICKER_24H_TIME_FMT
483
+ Time.parse(time_str).strftime(fmt_str).squeeze(" ").strip.sub(PICKER_REMOVE_LEADING_ZERO_REGEX,"")
484
+ end
485
+
486
+ # date and time
487
+
488
+ def picker_date_and_time_str_24h
489
+ screenshot_and_raise "the time is not applicable for this mode" if picker_is_in_date_mode or picker_is_in_countdown_mode
490
+ "#{picker_date_str} #{picker_time_24h_str}"
491
+ end
492
+
493
+ def picker_date_and_time_str_12h
494
+ screenshot_and_raise "the time is not applicable for this mode" if picker_is_in_date_mode or picker_is_in_countdown_mode
495
+ "#{picker_date_str} #{picker_time_12h_str}"
496
+ end
497
+
498
+ def picker_date_and_time_str
499
+ "#{picker_date_str} #{picker_time_str}"
500
+ end
501
+
502
+ def picker_date_and_time_str_for_other_locale
503
+ "#{picker_date_str} #{picker_time_for_other_locale}"
504
+ end
505
+
506
+ # useful
507
+
508
+ def now_times_map
509
+ now = Time.new
510
+ {:h12 => now.strftime(PICKER_12H_TIME_FMT).squeeze(" ").strip,
511
+ :h24 => now.strftime(PICKER_24H_TIME_FMT).squeeze(" ").strip.sub(PICKER_REMOVE_LEADING_ZERO_REGEX,""),
512
+ :time => now}
513
+ end
514
+
515
+ def now_time_24h_locale
516
+ now_times_map[:h24]
517
+ end
518
+
519
+ def now_time_12h_locale
520
+ now_times_map[:h12]
521
+ end
522
+
523
+ # scrolling picker
524
+
525
+ def picker_scroll_to_hour (target_hour_int_24h_notation)
526
+ screenshot_and_raise "nyi" if picker_is_in_countdown_mode
527
+ column = picker_column_for_hour
528
+ limit = 25
529
+ count = 0
530
+ unless picker_hour_24h_is target_hour_int_24h_notation
531
+ begin
532
+ picker_scroll_up_on_column(column)
533
+ sleep(PICKER_STEP_PAUSE)
534
+ count = count + 1
535
+ end while (not picker_hour_24h_is target_hour_int_24h_notation) and count < limit
536
+ end
537
+ unless picker_hour_24h_is target_hour_int_24h_notation
538
+ screenshot_and_raise "scrolled '#{limit}' but could not change hour to '#{target_hour_int_24h_notation}'"
539
+ end
540
+ end
541
+
542
+ def picker_scroll_to_minute (target_minute_int)
543
+ screenshot_and_raise "nyi" if picker_is_in_countdown_mode
544
+ column = picker_column_for_minute
545
+ limit = 61
546
+ count = 0
547
+ unless picker_minute_is target_minute_int
548
+ begin
549
+ picker_scroll_up_on_column(column)
550
+ sleep(PICKER_STEP_PAUSE)
551
+ count = count + 1
552
+ end while (not picker_minute_is target_minute_int) and count < limit
553
+ end
554
+ unless picker_minute_is target_minute_int
555
+ screenshot_and_raise "scrolled '#{limit}' but could not change minute to '#{target_minute_int}'"
556
+ end
557
+ end
558
+
559
+ def picker_scroll_to_period(target_period_str)
560
+ screenshot_and_raise "nyi" if picker_is_in_countdown_mode
561
+ screenshot_and_raise "period is not applicable to 24h locale" if picker_is_in_24h_locale
562
+ column = picker_column_for_period
563
+ limit = 3
564
+ count = 0
565
+ unless picker_period.eql? target_period_str
566
+ begin
567
+ if picker_period_is_am?
568
+ scroll_to_row("pickerTableView index:#{column}", 1)
569
+ else
570
+ scroll_to_row("pickerTableView index:#{column}", 0)
571
+ end
572
+ sleep(PICKER_STEP_PAUSE)
573
+ count = count + 1
574
+ end while (not picker_period.eql? target_period_str) and count < limit
575
+ end
576
+ unless picker_period.eql? target_period_str
577
+ screenshot_and_raise "scrolled '#{limit}' but could not change period to '#{target_period_str}'"
578
+ end
579
+ end
580
+
581
+
582
+ # utility
583
+
584
+ def time_strings_are_equivalent (a, b)
585
+ a_iso_str = Time.parse(a).strftime(PICKER_ISO8601_TIME_FMT)
586
+ b_iso_str = Time.parse(b).strftime(PICKER_ISO8601_TIME_FMT)
587
+ a_iso_str.eql? b_iso_str
588
+ end
589
+
590
+ def date_time_strings_are_equivalent (a, b)
591
+ a_iso_str = Date.parse(a).strftime(PICKER_ISO8601_DATE_TIME_FMT)
592
+ b_iso_str = Date.parse(b).strftime(PICKER_ISO8601_DATE_TIME_FMT)
593
+ a_iso_str.eql? b_iso_str
594
+ end
595
+
596
+ end
597
+ end
598
+ end