sunomono 0.2.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +157 -0
- data/Rakefile +1 -0
- data/bin/suno +3 -0
- data/bin/sunomono +3 -0
- data/lib/aws/android/app_installation_hooks.rb +30 -0
- data/lib/aws/android/app_life_cycle_hooks.rb +13 -0
- data/lib/aws/ios/01_launch.rb +43 -0
- data/lib/helpers/sunomono_helpers.rb +136 -0
- data/lib/helpers/zip_helpers.rb +49 -0
- data/lib/skeleton/.gitignore +9 -0
- data/lib/skeleton/Gemfile +7 -0
- data/lib/skeleton/README.md +165 -0
- data/lib/skeleton/config/cucumber.yml +7 -0
- data/lib/skeleton/config/email/template.html +14 -0
- data/lib/skeleton/config/load_classes.rb +31 -0
- data/lib/skeleton/config/scripts/android/run_tests_all_devices.sh +41 -0
- data/lib/skeleton/config/scripts/android/start_emulators.sh +52 -0
- data/lib/skeleton/config/scripts/android/stop_emulators.sh +13 -0
- data/lib/skeleton/config/scripts/break_build_if_failed.sh +6 -0
- data/lib/skeleton/config/scripts/check_if_tests_failed.sh +11 -0
- data/lib/skeleton/config/scripts/ios/build_app.rb +71 -0
- data/lib/skeleton/config/scripts/ios/build_app.yml +13 -0
- data/lib/skeleton/config/scripts/ios/devices.txt +4 -0
- data/lib/skeleton/config/scripts/ios/run_tests_all_devices.sh +57 -0
- data/lib/skeleton/features/android/features/.gitkeep +0 -0
- data/lib/skeleton/features/android/screens/.gitkeep +0 -0
- data/lib/skeleton/features/android/step_definitions/.gitkeep +0 -0
- data/lib/skeleton/features/android/support/app_installation_hooks.rb +36 -0
- data/lib/skeleton/features/android/support/app_life_cycle_hooks.rb +11 -0
- data/lib/skeleton/features/android/support/hooks.rb +0 -0
- data/lib/skeleton/features/ios/features/.gitkeep +0 -0
- data/lib/skeleton/features/ios/screens/.gitkeep +0 -0
- data/lib/skeleton/features/ios/step_definitions/.gitkeep +0 -0
- data/lib/skeleton/features/ios/support/01_launch.rb +94 -0
- data/lib/skeleton/features/ios/support/02_pre_stop_hooks.rb +0 -0
- data/lib/skeleton/features/support/env.rb +5 -0
- data/lib/skeleton/features/support/exceptions.rb +11 -0
- data/lib/skeleton/screenshots/android/.gitkeep +0 -0
- data/lib/skeleton/screenshots/ios/.gitkeep +0 -0
- data/lib/sunomono.rb +238 -0
- data/lib/sunomono/locales/en.yml +27 -0
- data/lib/sunomono/locales/pt.yml +27 -0
- data/lib/sunomono/version.rb +3 -0
- data/lib/templates/android_screen_base.tt +186 -0
- data/lib/templates/base_steps.tt +48 -0
- data/lib/templates/feature.tt +8 -0
- data/lib/templates/ios_screen_base.tt +249 -0
- data/lib/templates/screen.tt +13 -0
- data/lib/templates/steps.tt +5 -0
- data/sunomono.gemspec +27 -0
- 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,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
|