sunomono 0.2.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +9 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +157 -0
  6. data/Rakefile +1 -0
  7. data/bin/suno +3 -0
  8. data/bin/sunomono +3 -0
  9. data/lib/aws/android/app_installation_hooks.rb +30 -0
  10. data/lib/aws/android/app_life_cycle_hooks.rb +13 -0
  11. data/lib/aws/ios/01_launch.rb +43 -0
  12. data/lib/helpers/sunomono_helpers.rb +136 -0
  13. data/lib/helpers/zip_helpers.rb +49 -0
  14. data/lib/skeleton/.gitignore +9 -0
  15. data/lib/skeleton/Gemfile +7 -0
  16. data/lib/skeleton/README.md +165 -0
  17. data/lib/skeleton/config/cucumber.yml +7 -0
  18. data/lib/skeleton/config/email/template.html +14 -0
  19. data/lib/skeleton/config/load_classes.rb +31 -0
  20. data/lib/skeleton/config/scripts/android/run_tests_all_devices.sh +41 -0
  21. data/lib/skeleton/config/scripts/android/start_emulators.sh +52 -0
  22. data/lib/skeleton/config/scripts/android/stop_emulators.sh +13 -0
  23. data/lib/skeleton/config/scripts/break_build_if_failed.sh +6 -0
  24. data/lib/skeleton/config/scripts/check_if_tests_failed.sh +11 -0
  25. data/lib/skeleton/config/scripts/ios/build_app.rb +71 -0
  26. data/lib/skeleton/config/scripts/ios/build_app.yml +13 -0
  27. data/lib/skeleton/config/scripts/ios/devices.txt +4 -0
  28. data/lib/skeleton/config/scripts/ios/run_tests_all_devices.sh +57 -0
  29. data/lib/skeleton/features/android/features/.gitkeep +0 -0
  30. data/lib/skeleton/features/android/screens/.gitkeep +0 -0
  31. data/lib/skeleton/features/android/step_definitions/.gitkeep +0 -0
  32. data/lib/skeleton/features/android/support/app_installation_hooks.rb +36 -0
  33. data/lib/skeleton/features/android/support/app_life_cycle_hooks.rb +11 -0
  34. data/lib/skeleton/features/android/support/hooks.rb +0 -0
  35. data/lib/skeleton/features/ios/features/.gitkeep +0 -0
  36. data/lib/skeleton/features/ios/screens/.gitkeep +0 -0
  37. data/lib/skeleton/features/ios/step_definitions/.gitkeep +0 -0
  38. data/lib/skeleton/features/ios/support/01_launch.rb +94 -0
  39. data/lib/skeleton/features/ios/support/02_pre_stop_hooks.rb +0 -0
  40. data/lib/skeleton/features/support/env.rb +5 -0
  41. data/lib/skeleton/features/support/exceptions.rb +11 -0
  42. data/lib/skeleton/screenshots/android/.gitkeep +0 -0
  43. data/lib/skeleton/screenshots/ios/.gitkeep +0 -0
  44. data/lib/sunomono.rb +238 -0
  45. data/lib/sunomono/locales/en.yml +27 -0
  46. data/lib/sunomono/locales/pt.yml +27 -0
  47. data/lib/sunomono/version.rb +3 -0
  48. data/lib/templates/android_screen_base.tt +186 -0
  49. data/lib/templates/base_steps.tt +48 -0
  50. data/lib/templates/feature.tt +8 -0
  51. data/lib/templates/ios_screen_base.tt +249 -0
  52. data/lib/templates/screen.tt +13 -0
  53. data/lib/templates/steps.tt +5 -0
  54. data/sunomono.gemspec +27 -0
  55. metadata +184 -0
@@ -0,0 +1,27 @@
1
+ en:
2
+ android_only: "(Android Only)"
3
+ ios_only: "(iOS Only)"
4
+ first_scenario: "First Scenario"
5
+ comments:
6
+ trait: "The screen identificator"
7
+ insert_steps: "Insert steps"
8
+ elements: "Declare all the elements of this screen"
9
+ actions: "Declare all actions of this screen"
10
+ steps:
11
+ drag_until: 'I (?:drag|dragged) the screen (down|up|left|right) until I see the element "(.*?)"'
12
+ page_contains: "I am on a page that contains '(.*?)'"
13
+ drag_number_of_times: 'I drag the screen (left|right|down|up) (\d+) times'
14
+ touch_element: 'I (?:touch|touched) the "(.*?)" element'
15
+ drag_screen: "I drag the screen (down|up|left|right)"
16
+ wait_progress_bar: "I (?:wait|waited) for the progress bar to vanish"
17
+ should_see_page: "I should see the page '(.*?)'"
18
+ should_see_page_that_contains: "I should see a page that contains '(.*?)'"
19
+ take_print: "take picture"
20
+ been_in_page: "I am at (?:page|screen) '(.*?)'"
21
+ move_to_page: "I went to (?:page|screen) '(.*?)'"
22
+ restart_app: "I restart the app"
23
+ directions:
24
+ up: 'up'
25
+ down: 'down'
26
+ left: 'left'
27
+ right: 'right'
@@ -0,0 +1,27 @@
1
+ pt:
2
+ android_only: "(Somente Android)"
3
+ ios_only: "(Somente iOS)"
4
+ first_scenario: "Primeiro Cenario"
5
+ comments:
6
+ trait: "Identificador da tela"
7
+ insert_steps: "Insira os passos"
8
+ elements: "Declare todos os elementos da tela"
9
+ actions: "Declare todas as acoes da tela"
10
+ steps:
11
+ drag_until: 'que Eu (?:arrastei|arrasto) a tela para (baixo|cima|esquerda|direita) ate ver o elemento "(.*?)"'
12
+ page_contains: "que Eu estou em uma pagina que contem '(.*?)'"
13
+ drag_number_of_times: 'Eu arrasto a tela para (esquerda|direita|baixo|cima) (\d+) vezes'
14
+ touch_element: 'Eu (?:clico|cliquei) no elemento "(.*?)"'
15
+ drag_screen: "Eu arrasto a tela para (baixo|cima|esquerda|direita)"
16
+ wait_progress_bar: "Eu (?:espero|esperei) ate a barra de progresso sumir"
17
+ should_see_page: "Eu deveria ver a pagina '(.*?)'"
18
+ should_see_page_that_contains: "Eu deveria ver uma pagina que contem '(.*?)'"
19
+ take_print: "faco um print"
20
+ been_in_page: "que eu (?:estou|estava) na (?:pagina|tela)(?: de|) '(.*?)'"
21
+ move_to_page: "eu (?:devo|deveria) estar na (?:pagina|tela)(?: de|) '(.*?)'"
22
+ restart_app: "(?:Eu |)reiniciar o aplicativo"
23
+ directions:
24
+ up: 'cima'
25
+ down: 'baixo'
26
+ left: 'esquerda'
27
+ right: 'direita'
@@ -0,0 +1,3 @@
1
+ module Sunomono
2
+ VERSION = '0.2.0.pre'.freeze
3
+ end
@@ -0,0 +1,186 @@
1
+ require 'calabash-android/abase'
2
+
3
+ class AndroidScreenBase < Calabash::ABase
4
+ def self.element(element_name, &block)
5
+ define_method(element_name.to_s, *block)
6
+ end
7
+
8
+ class << self
9
+ alias_method :value, :element
10
+ alias_method :action, :element
11
+ alias_method :trait, :element
12
+ end
13
+
14
+ def restart_app
15
+ shutdown_test_server
16
+ start_test_server_in_background
17
+ end
18
+
19
+ def method_missing(method, *args)
20
+ if method.to_s.start_with?('touch_')
21
+ # If method name starts with touch_, executes the touch
22
+ # screen element method using the element name which is the
23
+ # method name without the first 'touch_' chars
24
+ touch_screen_element public_send(method.to_s.sub('touch_', ''))
25
+ elsif method.to_s.start_with?('enter_')
26
+ # If method starts with enter_, execute the enter method using
27
+ # the field name, which is the method name without the initial
28
+ # 'enter_' chars and appended '_field' chars
29
+ enter args[0], public_send("#{method.to_s.sub('enter_', '')}_field")
30
+ elsif method.to_s.end_with?('_visible?')
31
+ # If method ends with _visible?, executes the visible? method
32
+ # The field name is the method name without de ending
33
+ # '_visible? chars
34
+ visible? public_send(method.to_s.sub('_visible?', ''))
35
+ elsif method.to_s.end_with?('_visible!')
36
+ # Do the same as the method above, but throws an exception
37
+ # if the field is not visible
38
+ field_name = method.to_s.sub('_visible!', '')
39
+ .sub('_field', '')
40
+ .sub('_', ' ')
41
+ .capitalize
42
+ raise ElementNotFoundError, "ID: #{field_name}" unless
43
+ visible? public_send(method.to_s.sub('_visible!', ''))
44
+ else
45
+ super(method, args)
46
+ end
47
+ end
48
+
49
+ def visible?(id, query = nil)
50
+ query = "* id:'#{id}'" if query.nil?
51
+ begin
52
+ wait_for(timeout: 3) { element_exists query }
53
+ rescue
54
+ return false
55
+ end
56
+ true
57
+ end
58
+
59
+ element(:loading_screen) { 'insert_loading_view_id' }
60
+
61
+ # The progress bar of the application is a custom view
62
+ def wait_for_progress
63
+ sleep(2)
64
+ wait_for_element_does_not_exist("* id:'#{loading_screen}'",
65
+ timeout: 10)
66
+ end
67
+
68
+ def drag_to(direction)
69
+ positions = [0, 0, 0, 0] # [ 'from_x', 'to_x', 'from_y', 'to_y' ]
70
+
71
+ case(direction)
72
+ when :<%= (I18n.translate "directions.down").to_sym %>
73
+ positions = [30,30,60,30]
74
+ when :<%= (I18n.translate "directions.up").to_sym %>
75
+ positions = [80,80,60,90]
76
+ when :<%= (I18n.translate "directions.left").to_sym %>
77
+ positions = [90,20,80,80]
78
+ when :<%= (I18n.translate "directions.right").to_sym %>
79
+ positions = [20,90,80,80]
80
+ else
81
+ raise 'Direction not known!'
82
+ end
83
+
84
+ # perform_action( 'action', 'from_x', 'to_x', 'from_y', 'to_y',
85
+ # 'number of steps (in this case, velocity of drag' )
86
+ perform_action('drag', positions[0], positions[1],
87
+ positions[2], positions[3], 15)
88
+ sleep(1)
89
+ end
90
+
91
+ def drag_until_element_is_visible_with_special_query(direction, element)
92
+ drag_until_element_is_visible direction, element,
93
+ "* {text CONTAINS[c] '#{element}'}"
94
+ end
95
+
96
+ def drag_until_element_is_visible(direction, element, query = nil, limit = 15)
97
+ i = 0
98
+
99
+ element_query = ''
100
+ if query.nil?
101
+ element_query = "* marked:'#{element}'"
102
+ else
103
+ element_query = query
104
+ end
105
+
106
+ sleep(2)
107
+ while !element_exists(element_query) && i < limit
108
+ drag_to direction
109
+ i += 1
110
+ end
111
+
112
+ fail "Executed #{limit} moviments #{direction} and "\
113
+ "the element '#{element}' was not found on this view!" unless
114
+ i < limit
115
+ end
116
+
117
+ def drag_for_specified_number_of_times(direction, times)
118
+ times.times do
119
+ drag_to direction
120
+ end
121
+ end
122
+
123
+ # Negation indicates that we want a page that doesn't
124
+ # has the message passed as parameter
125
+ def is_on_page?(page_text, negation = '')
126
+ fail 'Error! Invalid query string!' if
127
+ page_text.to_s == ''
128
+
129
+ should_not_have_exception = false
130
+ should_have_exception = false
131
+ begin
132
+ wait_for(timeout: 5) { has_text? page_text }
133
+ # If negation is not nil, we should raise an error
134
+ # if this message was found on the view
135
+ should_not_have_exception = true unless negation == ''
136
+ rescue
137
+ # only raise exception if negation is nil,
138
+ # otherwise this is the expected behaviour
139
+ should_have_exception = true if negation == ''
140
+ end
141
+
142
+ fail "Unexpected Page. The page should not have: '#{page_text}'" if
143
+ should_not_have_exception
144
+
145
+ fail "Unexpected Page. Expected was: '#{page_text}'" if
146
+ should_have_exception
147
+ end
148
+
149
+ def enter(text, element, query = nil)
150
+ if query.nil?
151
+ query("* marked:'#{element}'", setText: text.to_s)
152
+ else
153
+ query(query, setText: text.to_s)
154
+ end
155
+ end
156
+
157
+ def touch_screen_element(element, query = nil)
158
+ query = "* id:'#{element}'" if query.nil?
159
+ begin
160
+ wait_for(timeout: 5) { element_exists(query) }
161
+ touch(query)
162
+ rescue => e
163
+ raise "Problem in touch screen element: '#{element}'\nError Message: #{e.message}"
164
+ end
165
+ end
166
+
167
+ def touch_element_by_index(id, index)
168
+ wait_for(timeout: 5) { element_exists("* id:'#{id}' index:#{index}") }
169
+ touch("* id:'#{id}' index:#{index}")
170
+ end
171
+
172
+ def clear_text_field(field)
173
+ clear_text_in("android.widget.EditText id:'#{field}'}")
174
+ end
175
+
176
+ def select_date_on_date_picker(date, date_picker_field_id)
177
+ # Touch the date picker field
178
+ touch "* id:'#{date_picker_field_id}'"
179
+
180
+ # Setting the date
181
+ set_date 'DatePicker', date.year, date.month, date.day
182
+
183
+ # Clicking in the Done button
184
+ touch "* id:'button1'"
185
+ end
186
+ end
@@ -0,0 +1,48 @@
1
+ ######### <%= I18n.translate( :given ).upcase %> #########
2
+ <%= I18n.translate( :given ).capitalize %>(/^<%= I18n.translate( "steps.drag_until" ) %>$/) do |direction, element|
3
+ @page.drag_until_element_is_visible_with_special_query direction.to_sym, element
4
+ end
5
+
6
+ <%= I18n.translate( :given ).capitalize %>(/^<%= I18n.translate( "steps.page_contains" ) %>$/) do |page_text|
7
+ @page.is_on_page? page_text
8
+ end
9
+
10
+ ######### <%= I18n.translate( :when ).upcase %> #########
11
+
12
+ <%= I18n.translate( :when ).capitalize %>(/^<%= I18n.translate( "steps.drag_number_of_times" ) %>$/) do |direction, times|
13
+ @page.drag_for_specified_number_of_times(direction.to_sym, times.to_i)
14
+ end
15
+
16
+ <%= I18n.translate( :when ).capitalize %>(/^<%= I18n.translate( "steps.touch_element" ) %>$/) do |element|
17
+ @page.touch_screen_element element
18
+ end
19
+
20
+ <%= I18n.translate( :when ).capitalize %>(/^<%= I18n.translate( "steps.drag_screen" ) %>$/) do |direction|
21
+ @page.drag_to direction.to_sym
22
+ end
23
+
24
+ <%= I18n.translate( :when ).capitalize %>(/^<%= I18n.translate( "steps.restart_app" ) %>$/) do
25
+ @page.restart_app
26
+ end
27
+
28
+ ######### <%= I18n.translate( :then ).upcase %> #########
29
+
30
+ <%= I18n.translate( :then ).capitalize %>(/^<%= I18n.translate "steps.wait_progress_bar" %>$/) do
31
+ # wait_for_progress is a method of the base class, so doesn't matter what is
32
+ # the value of the @page variable, because all screens will have this method
33
+ @page.wait_for_progress
34
+ end
35
+
36
+ <%= I18n.translate( :then ).capitalize %>(/^<%= I18n.translate "steps.should_see_page" %>$/) do |page_text|
37
+ @page.is_on_page? page_text
38
+ end
39
+
40
+ <%= I18n.translate( :then ).capitalize %>(/^<%= I18n.translate "steps.should_see_page_that_contains" %>$/) do |page_text|
41
+ @page.is_on_page? page_text
42
+ end
43
+ <% unless I18n.config.default_locale == :en %>
44
+
45
+ <%= I18n.translate( :then ).capitalize %>(/^<%= I18n.translate "steps.take_print" %>$/) do
46
+ screenshot_embed
47
+ end
48
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <%= "# language: #{options[:lang]}" %>
2
+ <%= I18n.translate( :feature ) %>: <%= config[:name] %> <%= !config[:platform].empty? ? I18n.translate( "#{config[:platform].downcase}_only") : "" %>
3
+
4
+ <%= I18n.translate( :background ) %>:
5
+ # <%= I18n.translate( "comments.insert_steps" ) %>
6
+
7
+ <%= I18n.translate( :scenario ) %>: <%= I18n.translate( :first_scenario ) %>
8
+ # <%= I18n.translate( "comments.insert_steps" ) %>
@@ -0,0 +1,249 @@
1
+ require 'calabash-cucumber/ibase'
2
+
3
+ class IOSScreenBase < Calabash::IBase
4
+ def self.element(element_name, &block)
5
+ define_method(element_name.to_s, *block)
6
+ end
7
+
8
+ class << self
9
+ alias_method :value, :element
10
+ alias_method :action, :element
11
+ alias_method :trait, :element
12
+ end
13
+
14
+ def restart_app
15
+ # Relaunch options
16
+ options = { timeout: 3000 }
17
+
18
+ launcher.relaunch(options)
19
+ launcher.calabash_notify(self)
20
+ end
21
+
22
+ def method_missing(method, *args)
23
+ if method.to_s.start_with?('touch_')
24
+ # If method name starts with touch_, executes the touch
25
+ # screen element method using the element name which is the
26
+ # method name without the first 'touch_' chars
27
+ touch_screen_element public_send(method.to_s.sub('touch_', ''))
28
+ elsif method.to_s.start_with?('enter_')
29
+ # If method starts with enter_, execute the enter method using
30
+ # the field name, which is the method name without the initial
31
+ # 'enter_' chars and appended '_field' chars
32
+ enter args[0], public_send("#{method.to_s.sub('enter_', '')}_field")
33
+ elsif method.to_s.end_with?('_visible?')
34
+ # If method ends with _visible?, executes the visible? method
35
+ # The field name is the method name without de ending
36
+ # '_visible? chars
37
+ visible? public_send(method.to_s.sub('_visible?', ''))
38
+ elsif method.to_s.end_with?('_visible!')
39
+ # Do the same as the method above, but throws an exception
40
+ # if the field is not visible
41
+ field_name = method.to_s.sub('_visible!', '')
42
+ .sub('_field', '')
43
+ .sub('_', ' ')
44
+ .capitalize
45
+ raise ElementNotFoundError, "ID: #{field_name}" unless
46
+ visible? public_send(method.to_s.sub('_visible!', ''))
47
+ else
48
+ super(method, args)
49
+ end
50
+ end
51
+
52
+ def visible?(id, query = nil)
53
+ query = "* id:'#{id}'" if query.nil?
54
+ begin
55
+ wait_for(timeout: 3) { element_exists query }
56
+ rescue
57
+ return false
58
+ end
59
+ true
60
+ end
61
+
62
+
63
+ element(:loading_screen) { 'LOADING' }
64
+
65
+ # The progress bar of the application is a custom view
66
+ def wait_for_progress
67
+ sleep(2)
68
+ wait_for(timeout: 10) { element_does_not_exist "* marked:'#{loading_screen}'" }
69
+ end
70
+
71
+ def has_text?(text)
72
+ !query("* {text CONTAINS[c] '#{text}'}").empty? ||
73
+ !query("* {accessibilityLabel CONTAINS[c] '#{text}'}").empty?
74
+ end
75
+
76
+ def drag_to(direction, element = nil)
77
+ element = 'scrollView' if element.nil?
78
+
79
+ case direction
80
+ when :<%= (I18n.translate "directions.down").to_sym %>
81
+ direction = { x: 0, y: -100 }
82
+ when :<%= (I18n.translate "directions.up").to_sym %>
83
+ direction = { x: 0, y: 100 }
84
+ when :<%= (I18n.translate "directions.left").to_sym %>
85
+ direction = { x: 100, y: 0 }
86
+ when :<%= (I18n.translate "directions.right").to_sym %>
87
+ direction = { x: -100, y: 0 }
88
+ else
89
+ raise 'Direction not known!'
90
+ end
91
+
92
+ flick(element, direction)
93
+ sleep(1)
94
+ end
95
+
96
+ # In the iOS, an element could be found from its text or its accessibilityLabel
97
+ # so this function looks for these two properties on the screen. When the query
98
+ # looks for just a part of the text (CONTAINS[c]) then we need to specify if
99
+ # we will look in accessibilityLabel or in any other propertie (marked)
100
+ def ios_element_exists?(query)
101
+ second_query = nil
102
+
103
+ if query.include? 'CONTAINS[c]'
104
+ if query.include? 'marked'
105
+ second_query = query.gsub('marked', 'accessibilityLabel')
106
+ end
107
+ if query.include? 'accessibilityLabel'
108
+ second_query = query.gsub('accessibilityLabel', 'marked')
109
+ end
110
+ end
111
+
112
+ if second_query.nil?
113
+ return element_exists(query)
114
+ else
115
+ element_exists(query) || element_exists(second_query)
116
+ end
117
+ end
118
+
119
+ def drag_until_element_is_visible_with_special_query(direction, element)
120
+ drag_until_element_is_visible direction, element,
121
+ "* {accessibilityLabel CONTAINS[c] '#{element}'}"
122
+ end
123
+
124
+ def drag_until_element_is_visible(direction, element, query = nil, limit = 15)
125
+ i = 0
126
+
127
+ query = "* marked:'#{element}'" if query.nil?
128
+
129
+ sleep(1)
130
+ while !ios_element_exists?(query) && i < limit
131
+ drag_to direction
132
+ i += 1
133
+ end
134
+
135
+ fail "Executed #{limit} moviments #{direction} and the "\
136
+ "element '#{element}' was not found on this view!" unless i < limit
137
+ end
138
+
139
+ def drag_for_specified_number_of_times(direction, times)
140
+ times.times do
141
+ drag_to direction
142
+ end
143
+ end
144
+
145
+ # Negation indicates that we want a page that doesn't has
146
+ # the message passed as parameter
147
+ def is_on_page?(page_text, negation = '')
148
+ fail 'Error! Invalid query string!' if
149
+ page_text.to_s == ''
150
+
151
+ should_not_have_exception = false
152
+ should_have_exception = false
153
+ begin
154
+ wait_for(timeout: 5) { has_text? page_text }
155
+ # If negation is not nil, we should raise an error
156
+ # if this message was found on the view
157
+ should_not_have_exception = true unless negation == ''
158
+ rescue
159
+ # only raise exception if negation is nil,
160
+ # otherwise this is the expected behaviour
161
+ should_have_exception = true if negation == ''
162
+ end
163
+
164
+ fail "Unexpected Page. The page should not have: '#{page_text}'" if
165
+ should_not_have_exception
166
+
167
+ fail "Unexpected Page. Expected was: '#{page_text}'" if
168
+ should_have_exception
169
+ end
170
+
171
+ def enter(text, element, query = nil)
172
+ query = "* marked:'#{element}'" if query.nil?
173
+
174
+ begin
175
+ wait_for(timeout: 5) { element_exists query }
176
+ rescue
177
+ # Just a better exception message
178
+ raise "Element '#{element}' not found on view!"
179
+ end
180
+
181
+ touch query
182
+ # Waits up to 20 seconds for the keyboard to show up
183
+ begin
184
+ wait_for(timeout: 10) { element_exists("view:'UIKeyboardAutomatic'") }
185
+ rescue
186
+ # If the keyboard didn't show up, tries another time
187
+ # before rainsing the error message
188
+ touch query
189
+ wait_for(timeout: 5) { element_exists("view:'UIKeyboardAutomatic'") }
190
+ end
191
+
192
+ keyboard_enter_text text
193
+ end
194
+
195
+ def touch_screen_element(element, query = nil)
196
+ query = "* marked:'#{element}'" if query.nil?
197
+ begin
198
+ wait_for(timeout: 5) { element_exists(query) }
199
+ touch query
200
+ rescue => e
201
+ raise "Problem in touch screen element: '#{element}'\nError Message: #{e.message}"
202
+ end
203
+ end
204
+
205
+ def touch_element_by_index(id, index)
206
+ query = "* marked:'#{id}' index:#{index}"
207
+ wait_for(timeout: 5) { element_exists(query) }
208
+ touch(query)
209
+ end
210
+
211
+ def clear_text_field(field)
212
+ clear_text("textField marked:'#{field}'")
213
+ end
214
+
215
+ def select_date_on_date_picker(date, date_picker_field_id)
216
+ # Touch the date picker element
217
+ touch_screen_element date_picker_field_id
218
+ # Waiting for the date picker to show up
219
+ wait_for(timeout: 5) { element_exists("view:'UIDatePicker'") }
220
+
221
+ # If date is today, then we have nothing to do
222
+ if date.year != DateTime.now.year ||
223
+ date.month != DateTime.now.month ||
224
+ date.day != DateTime.now.day
225
+ # Selecting 'date' on the date picker
226
+ picker_set_date_time date
227
+ end
228
+
229
+ # Touch the OK button
230
+ touch_screen_element 'Ok'
231
+ end
232
+
233
+ def touch_picker_item_by_index(index)
234
+ label = query('pickerView', :delegate,
235
+ [{ pickerView: nil }, { titleForRow: index },
236
+ { forComponent: 0 }])
237
+
238
+ # Exception if element no found
239
+ fail "Picker item index #{index} not found." if label.nil?
240
+ # Label is an array of 1 element. Just picking the first.
241
+ label = label.first
242
+
243
+ # Touching the first item using it's text and Javascript function
244
+ uia(%[uia.selectPickerValues('{0 "#{label}"}')])
245
+
246
+ # Touching the OK button to close the Picker
247
+ touch "* marked:'OK'"
248
+ end
249
+ end