testcentricity_apps 4.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +3 -0
  3. data/CHANGELOG.md +193 -0
  4. data/LICENSE.md +27 -0
  5. data/README.md +2297 -0
  6. data/lib/testcentricity_apps/app_core/appium_connect_helper.rb +667 -0
  7. data/lib/testcentricity_apps/app_core/screen_object.rb +494 -0
  8. data/lib/testcentricity_apps/app_core/screen_objects_helper.rb +211 -0
  9. data/lib/testcentricity_apps/app_core/screen_section.rb +669 -0
  10. data/lib/testcentricity_apps/app_elements/alert.rb +152 -0
  11. data/lib/testcentricity_apps/app_elements/app_element.rb +728 -0
  12. data/lib/testcentricity_apps/app_elements/button.rb +10 -0
  13. data/lib/testcentricity_apps/app_elements/checkbox.rb +61 -0
  14. data/lib/testcentricity_apps/app_elements/image.rb +10 -0
  15. data/lib/testcentricity_apps/app_elements/label.rb +10 -0
  16. data/lib/testcentricity_apps/app_elements/list.rb +188 -0
  17. data/lib/testcentricity_apps/app_elements/menu.rb +159 -0
  18. data/lib/testcentricity_apps/app_elements/menubar.rb +78 -0
  19. data/lib/testcentricity_apps/app_elements/radio.rb +61 -0
  20. data/lib/testcentricity_apps/app_elements/selectlist.rb +126 -0
  21. data/lib/testcentricity_apps/app_elements/switch.rb +66 -0
  22. data/lib/testcentricity_apps/app_elements/textfield.rb +51 -0
  23. data/lib/testcentricity_apps/appium_server.rb +76 -0
  24. data/lib/testcentricity_apps/data_objects/data_objects_helper.rb +100 -0
  25. data/lib/testcentricity_apps/data_objects/environment.rb +423 -0
  26. data/lib/testcentricity_apps/exception_queue_helper.rb +160 -0
  27. data/lib/testcentricity_apps/utility_helpers.rb +48 -0
  28. data/lib/testcentricity_apps/version.rb +3 -0
  29. data/lib/testcentricity_apps/world_extensions.rb +61 -0
  30. data/lib/testcentricity_apps.rb +103 -0
  31. metadata +322 -0
@@ -0,0 +1,66 @@
1
+ module TestCentricity
2
+ module AppElements
3
+ class AppSwitch < AppUIElement
4
+ def initialize(name, parent, locator, context)
5
+ super
6
+ @type = :switch
7
+ end
8
+
9
+ # Is switch in ON state?
10
+ #
11
+ # @return [Boolean]
12
+ # @example
13
+ # use_face_id_switch.on?
14
+ #
15
+ def on?
16
+ obj = element
17
+ object_not_found_exception(obj)
18
+
19
+ if Environ.is_ios?
20
+ state = obj.attribute(:value)
21
+ state.to_bool
22
+ else
23
+ state = obj.attribute(:checked)
24
+ state.boolean? ? state : state == 'true'
25
+ end
26
+ end
27
+
28
+ alias checked? on?
29
+ alias selected? on?
30
+
31
+ # Set the state of a switch object to ON.
32
+ #
33
+ # @example
34
+ # use_face_id_switch.on
35
+ #
36
+ def on
37
+ obj = element
38
+ object_not_found_exception(obj)
39
+ obj.click unless on?
40
+ end
41
+
42
+ # Set the state of a switch object to OFF.
43
+ #
44
+ # @example
45
+ # use_face_id_switch.off
46
+ #
47
+ def off
48
+ obj = element
49
+ object_not_found_exception(obj)
50
+ obj.click if on?
51
+ end
52
+
53
+ # Set the ON/OFF state of a switch object.
54
+ #
55
+ # @param state [Boolean] true = on / false = off
56
+ # @example
57
+ # use_face_id_switch.set_switch_state(true)
58
+ #
59
+ def set_switch_state(state)
60
+ obj = element
61
+ object_not_found_exception(obj)
62
+ state ? on : off
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,51 @@
1
+ module TestCentricity
2
+ module AppElements
3
+ class AppTextField < AppUIElement
4
+ def initialize(name, parent, locator, context)
5
+ super
6
+ @type = :textfield
7
+ end
8
+
9
+ # Is text field set to read-only?
10
+ #
11
+ # @return [Boolean]
12
+ # @example
13
+ # comments_field.read_only?
14
+ #
15
+ def read_only?
16
+ obj = element
17
+ object_not_found_exception(obj)
18
+ !!obj.attribute('readonly')
19
+ end
20
+
21
+ # Return maxlength character count of a text field.
22
+ #
23
+ # @return [Integer]
24
+ # @example
25
+ # max_num_chars = comments_field.get_max_length
26
+ #
27
+ def get_max_length
28
+ obj = element
29
+ object_not_found_exception(obj)
30
+ max_length = obj.attribute('maxlength')
31
+ max_length.to_i unless max_length.blank?
32
+ end
33
+
34
+ # Return placeholder text of a text field.
35
+ #
36
+ # @return [String]
37
+ # @example
38
+ # placeholder_message = username_field.get_placeholder
39
+ #
40
+ def get_placeholder
41
+ obj = element
42
+ object_not_found_exception(obj)
43
+ if AppiumConnect.is_webview?
44
+ obj.attribute('placeholder')
45
+ else
46
+ obj.text
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,76 @@
1
+ require 'childprocess'
2
+
3
+ #
4
+ # This class is designed to start and stop the Appium Server process. In order to use it you must have Appium
5
+ # and node installed on your computer. You can pass parameters to Appium at startup via the constructor.
6
+ #
7
+ module TestCentricity
8
+ class AppiumServer
9
+ attr_accessor :process
10
+
11
+ def initialize(params = {})
12
+ @params = params
13
+ end
14
+
15
+ #
16
+ # Start the Appium Server
17
+ #
18
+ def start
19
+ # terminate any currently running Appium Server
20
+ if running?
21
+ system('killall -9 node')
22
+ puts 'Terminating existing Appium Server'
23
+ sleep(5)
24
+ puts 'Appium Server is being restarted'
25
+ else
26
+ puts 'Appium Server is starting'
27
+ end
28
+ # start new Appium Server
29
+ @process = ChildProcess.build(*parameters)
30
+ process.start
31
+ # wait until confirmation that Appium Server is running
32
+ wait = Selenium::WebDriver::Wait.new(timeout: 30)
33
+ wait.until { running? }
34
+ puts "Appium Server is running - PID = #{process.pid}"
35
+ end
36
+
37
+ #
38
+ # Check to see if Appium Server is running
39
+ #
40
+ def running?
41
+ endpoint = if ENV['APPIUM_SERVER_VERSION'] && ENV['APPIUM_SERVER_VERSION'].to_i == 1
42
+ 'http://0.0.0.0:4723/wd/hub/sessions'
43
+ else
44
+ 'http://0.0.0.0:4723/sessions'
45
+ end
46
+ response = false
47
+ begin
48
+ response = Net::HTTP.get_response(URI(endpoint))
49
+ rescue
50
+ end
51
+ response && response.code_type == Net::HTTPOK
52
+ end
53
+
54
+ #
55
+ # Stop the Appium Server
56
+ #
57
+ def stop
58
+ process.stop
59
+ puts 'Appium Server has been terminated'
60
+ end
61
+
62
+ private
63
+
64
+ # :nocov:
65
+ def parameters
66
+ cmd = ['appium']
67
+ @params.each do |key, value|
68
+ cmd << '--' + key.to_s
69
+ cmd << value.to_s if not value.nil? and value.size > 0
70
+ end
71
+ cmd
72
+ end
73
+ # :nocov:
74
+ end
75
+ end
76
+
@@ -0,0 +1,100 @@
1
+ require 'yaml'
2
+ require 'json'
3
+ require 'virtus'
4
+ require 'time'
5
+ require 'chronic'
6
+ require 'faker'
7
+
8
+
9
+ module TestCentricity
10
+
11
+ PRIMARY_DATA_PATH ||= 'config/test_data/'
12
+ PRIMARY_DATA_FILE ||= "#{PRIMARY_DATA_PATH}data."
13
+ YML_PRIMARY_DATA_FILE ||= "#{PRIMARY_DATA_FILE}yml"
14
+ JSON_PRIMARY_DATA_FILE ||= "#{PRIMARY_DATA_FILE}json"
15
+
16
+
17
+ class DataObject
18
+ attr_accessor :current
19
+ attr_accessor :context
20
+ attr_accessor :hash_table
21
+
22
+ def initialize(data)
23
+ @hash_table = data
24
+ end
25
+
26
+ def self.current
27
+ @current
28
+ end
29
+
30
+ def self.current=(current)
31
+ @current = current
32
+ end
33
+ end
34
+
35
+
36
+ class DataPresenter
37
+ include Virtus.model
38
+
39
+ attr_accessor :current
40
+ attr_accessor :context
41
+
42
+ def initialize(data)
43
+ self.attributes = data unless data.nil?
44
+ end
45
+
46
+ def self.current
47
+ @current
48
+ end
49
+
50
+ def self.current=(current)
51
+ @current = current
52
+ end
53
+ end
54
+
55
+
56
+ # :nocov:
57
+ class DataSource
58
+ attr_accessor :file_path
59
+ attr_accessor :node
60
+
61
+ def read_yaml_node_data(file_name, node_name)
62
+ @file_path = "#{PRIMARY_DATA_PATH}#{file_name}"
63
+ @node = node_name
64
+ data = YAML.load_file(@file_path)
65
+ data[node_name]
66
+ end
67
+
68
+ def read_json_node_data(file_name, node_name)
69
+ @file_path = "#{PRIMARY_DATA_PATH}#{file_name}"
70
+ @node = node_name
71
+ raw_data = File.read(@file_path)
72
+ data = JSON.parse(raw_data)
73
+ data[node_name]
74
+ end
75
+
76
+ private
77
+
78
+ def self.calculate_dynamic_value(value)
79
+ test_value = value.split('!', 2)
80
+ parameter = test_value[1].split('.', 2)
81
+ case parameter[0]
82
+ when 'Date'
83
+ result = eval("Chronic.parse('#{parameter[1]}')")
84
+ when 'FormattedDate', 'FormatDate'
85
+ date_time_params = parameter[1].split(' format! ', 2)
86
+ date_time = eval("Chronic.parse('#{date_time_params[0].strip}')")
87
+ result = date_time.to_s.format_date_time("#{date_time_params[1].strip}")
88
+ else
89
+ result = if Faker.constants.include?(parameter[0].to_sym)
90
+ eval("Faker::#{parameter[0]}.#{parameter[1]}")
91
+ else
92
+ eval(test_value[1])
93
+ end
94
+ end
95
+ result.to_s
96
+ end
97
+ end
98
+ # :nocov:
99
+ end
100
+
@@ -0,0 +1,423 @@
1
+ module TestCentricity
2
+ class EnvironData < TestCentricity::DataSource
3
+ attr_accessor :current
4
+ attr_accessor :data_source_type
5
+ attr_accessor :generic_data
6
+ attr_accessor :environ_specific_data
7
+
8
+ def self.find_environ(environ_name, source_type = :yaml)
9
+ raise 'No environment specified' if environ_name.nil?
10
+
11
+ @data_source_type = source_type
12
+ data = case source_type
13
+ when :yaml
14
+ # read generic test data from data.yml file
15
+ @generic_data ||= YAML.load_file(YML_PRIMARY_DATA_FILE)
16
+ # read environment specific test data
17
+ data_file = "#{PRIMARY_DATA_PATH}#{environ_name}_data.yml"
18
+ @environ_specific_data = if File.exist?(data_file)
19
+ YAML.load_file(data_file)
20
+ else
21
+ {}
22
+ end
23
+ read('Environments', environ_name)
24
+ when :json
25
+ # read generic test data from data.json file
26
+ raw_data = File.read(JSON_PRIMARY_DATA_FILE)
27
+ @generic_data = JSON.parse(raw_data)
28
+ # read environment specific test data
29
+ data_file = "#{PRIMARY_DATA_PATH}#{environ_name}_data.json"
30
+ @environ_specific_data = if File.exist?(data_file)
31
+ raw_data = File.read(data_file)
32
+ JSON.parse(raw_data)
33
+ else
34
+ {}
35
+ end
36
+
37
+ read('Environments', environ_name)
38
+ else
39
+ raise "#{source_type} is not a supported data source type"
40
+ end
41
+ @current = Environ.new(data)
42
+ Environ.current = @current
43
+ end
44
+
45
+ def self.read(key_name, node_name)
46
+ if @environ_specific_data.key?(key_name) && @environ_specific_data[key_name].key?(node_name)
47
+ node_data = @environ_specific_data[key_name][node_name]
48
+ else
49
+ raise "No key named #{key_name} in generic and environment-specific data" unless @generic_data.key?(key_name)
50
+ raise "No node named #{node_name} in #{key_name} section of generic and environment-specific data" unless @generic_data[key_name].key?(node_name)
51
+
52
+ node_data = @generic_data[key_name][node_name]
53
+ end
54
+
55
+ if node_data.is_a?(Hash)
56
+ node_data.each do |key, value|
57
+ node_data[key] = calculate_dynamic_value(value) if value.to_s.start_with?('eval!')
58
+ end
59
+ end
60
+ node_data
61
+ end
62
+ end
63
+
64
+
65
+ class Environ < TestCentricity::DataObject
66
+ @session_id = Time.now.strftime('%d%H%M%S%L')
67
+ @session_time_stamp = Time.now.strftime('%Y%m%d%H%M%S')
68
+ @test_environment = ENV['TEST_ENVIRONMENT']
69
+ @a11y_standard = ENV['ACCESSIBILITY_STANDARD'] || 'best-practice'
70
+ @locale = ENV['LOCALE'] || 'en'
71
+ @language = ENV['LANGUAGE'] || 'English'
72
+ @screen_shots = []
73
+
74
+ attr_accessor :test_environment
75
+ attr_accessor :session_state
76
+ attr_accessor :session_code
77
+ attr_accessor :app_session_id
78
+ attr_accessor :os
79
+ attr_accessor :device
80
+ attr_accessor :device_name
81
+ attr_accessor :device_type
82
+ attr_accessor :device_os
83
+ attr_accessor :device_os_version
84
+ attr_accessor :device_orientation
85
+ attr_accessor :screen_size
86
+ attr_accessor :platform
87
+ attr_accessor :driver
88
+ attr_accessor :driver_name
89
+ attr_accessor :appium_driver
90
+ attr_accessor :tunneling
91
+ attr_accessor :locale
92
+ attr_accessor :language
93
+
94
+ attr_accessor :parallel
95
+ attr_accessor :process_num
96
+
97
+ attr_accessor :signed_in
98
+ attr_accessor :portal_status
99
+ attr_accessor :portal_context
100
+
101
+ attr_accessor :user_id
102
+ attr_accessor :password
103
+ attr_accessor :app_id
104
+ attr_accessor :api_key
105
+ attr_accessor :option1
106
+ attr_accessor :option2
107
+ attr_accessor :option3
108
+ attr_accessor :option4
109
+ attr_accessor :dns
110
+ attr_accessor :db_username
111
+ attr_accessor :db_password
112
+
113
+ attr_accessor :ios_app_path
114
+ attr_accessor :ios_ipa_path
115
+ attr_accessor :ios_bundle_id
116
+ attr_accessor :ios_test_id
117
+ attr_accessor :android_apk_path
118
+ attr_accessor :android_app_id
119
+ attr_accessor :android_test_id
120
+ attr_accessor :default_max_wait_time
121
+ attr_accessor :deep_link_prefix
122
+
123
+ attr_accessor :mac_bundle_id
124
+
125
+ def initialize(data)
126
+ @user_id = data['USER_ID']
127
+ @password = data['PASSWORD']
128
+ @app_id = data['APP_ID']
129
+ @api_key = data['API_KEY']
130
+ @option1 = data['OPTIONAL_1']
131
+ @option2 = data['OPTIONAL_2']
132
+ @option3 = data['OPTIONAL_3']
133
+ @option4 = data['OPTIONAL_4']
134
+ @dns = data['DNS']
135
+ @db_username = data['DB_USERNAME']
136
+ @db_password = data['DB_PASSWORD']
137
+ @ios_app_path = data['IOS_APP_PATH']
138
+ @ios_ipa_path = data['IOS_IPA_PATH']
139
+ @ios_bundle_id = data['IOS_BUNDLE_ID']
140
+ @ios_test_id = data['IOS_TEST_ID']
141
+ @android_apk_path = data['ANDROID_APK_PATH']
142
+ @android_app_id = data['ANDROID_APP_ID']
143
+ @android_test_id = data['ANDROID_TEST_ID']
144
+ @deep_link_prefix = data['DEEP_LINK_PREFIX']
145
+ @mac_bundle_id = data['MAC_BUNDLE_ID']
146
+
147
+ super
148
+ end
149
+
150
+ def self.new_app_session
151
+ @app_session_id = Time.now.strftime('%Y%m%d%H%M%S%L')
152
+ end
153
+
154
+ def self.app_session_id
155
+ @app_session_id
156
+ end
157
+
158
+ def self.session_code
159
+ if @session_code.nil?
160
+ characters = ('a'..'z').to_a
161
+ @session_code = (0..12).map { characters.sample }.join
162
+ end
163
+ @session_code
164
+ end
165
+
166
+ def self.session_id
167
+ @session_id
168
+ end
169
+
170
+ def self.session_time_stamp
171
+ @session_time_stamp
172
+ end
173
+
174
+ def self.parallel=(state)
175
+ @parallel = state
176
+ end
177
+
178
+ def self.parallel
179
+ @parallel
180
+ end
181
+
182
+ def self.process_num=(num)
183
+ @process_num = num
184
+ end
185
+
186
+ def self.process_num
187
+ @process_num
188
+ end
189
+
190
+ def self.test_environment
191
+ if @test_environment.blank?
192
+ nil
193
+ else
194
+ @test_environment.downcase.to_sym
195
+ end
196
+ end
197
+
198
+ def self.default_max_wait_time=(timeout)
199
+ @default_max_wait_time = timeout
200
+ end
201
+
202
+ def self.default_max_wait_time
203
+ @default_max_wait_time
204
+ end
205
+
206
+ def self.session_state=(session_state)
207
+ @session_state = session_state
208
+ end
209
+
210
+ def self.session_state
211
+ @session_state
212
+ end
213
+
214
+ def self.os=(os)
215
+ @os = os
216
+ end
217
+
218
+ def self.os
219
+ @os
220
+ end
221
+
222
+ def self.device=(device)
223
+ @device = device
224
+ end
225
+
226
+ def self.device
227
+ @device
228
+ end
229
+
230
+ def self.is_device?
231
+ @device == :device
232
+ end
233
+
234
+ def self.is_simulator?
235
+ @device == :simulator
236
+ end
237
+
238
+ def self.is_web?
239
+ @device == :web
240
+ end
241
+
242
+ def self.device_type=(type)
243
+ type = type.downcase.to_sym if type.is_a?(String)
244
+ @device_type = type
245
+ end
246
+
247
+ def self.device_type
248
+ @device_type
249
+ end
250
+
251
+ def self.device_name=(name)
252
+ @device_name = name
253
+ end
254
+
255
+ def self.device_name
256
+ @device_name
257
+ end
258
+
259
+ def self.device_os=(os)
260
+ @device_os = os.downcase.to_sym
261
+ end
262
+
263
+ def self.device_os
264
+ @device_os
265
+ end
266
+
267
+ def self.device_os_version=(version)
268
+ @device_os_version = version
269
+ end
270
+
271
+ def self.device_os_version
272
+ @device_os_version
273
+ end
274
+
275
+ def self.is_ios?
276
+ @device_os == :ios
277
+ end
278
+
279
+ def self.is_android?
280
+ @device_os == :android
281
+ end
282
+
283
+ def self.is_macos?
284
+ @device_os == :mac
285
+ end
286
+
287
+ def self.device_orientation=(orientation)
288
+ orientation = orientation.downcase.to_sym if orientation.is_a?(String)
289
+ @device_orientation = orientation
290
+ end
291
+
292
+ def self.device_orientation
293
+ @device_orientation
294
+ end
295
+
296
+ def self.screen_size=(size)
297
+ @screen_size = size
298
+ end
299
+
300
+ def self.screen_size
301
+ @screen_size
302
+ end
303
+
304
+ def self.driver=(type)
305
+ @driver = type
306
+ end
307
+
308
+ def self.driver
309
+ @driver
310
+ end
311
+
312
+ def self.driver_name=(name)
313
+ name = name.downcase.to_sym if name.is_a?(String)
314
+ @driver_name = name
315
+ end
316
+
317
+ def self.driver_name
318
+ @driver_name
319
+ end
320
+
321
+ def self.appium_driver=(driver_instance)
322
+ @appium_driver = driver_instance
323
+ end
324
+
325
+ def self.appium_driver
326
+ @appium_driver
327
+ end
328
+
329
+ def self.tunneling=(state)
330
+ @tunneling = state
331
+ end
332
+
333
+ def self.tunneling
334
+ @tunneling
335
+ end
336
+
337
+ def self.language=(language)
338
+ @language = language
339
+ end
340
+
341
+ def self.language
342
+ @language
343
+ end
344
+
345
+ def self.locale=(locale)
346
+ @locale = locale
347
+ end
348
+
349
+ def self.locale
350
+ @locale
351
+ end
352
+
353
+ def self.platform=(platform)
354
+ @platform = platform
355
+ end
356
+
357
+ def self.platform
358
+ @platform
359
+ end
360
+
361
+ def self.is_mobile?
362
+ @platform == :mobile
363
+ end
364
+
365
+ def self.set_signed_in(signed_in)
366
+ @signed_in = signed_in
367
+ end
368
+
369
+ def self.is_signed_in?
370
+ @signed_in
371
+ end
372
+
373
+ def self.portal_state=(portal_state)
374
+ @portal_status = portal_state
375
+ end
376
+
377
+ def self.portal_state
378
+ @portal_status
379
+ end
380
+
381
+ def self.portal_context=(portal_context)
382
+ @portal_context = portal_context
383
+ end
384
+
385
+ def self.portal_context
386
+ @portal_context
387
+ end
388
+
389
+ def self.set_external_page(state)
390
+ @external_page = state
391
+ end
392
+
393
+ def self.save_screen_shot(screen_shot)
394
+ @screen_shots.push(screen_shot)
395
+ end
396
+
397
+ def self.get_screen_shots
398
+ @screen_shots
399
+ end
400
+
401
+ def self.reset_contexts
402
+ @screen_shots = []
403
+ end
404
+
405
+ # :nocov:
406
+ def self.report_header
407
+ # build the Cucumber HTML report header
408
+ report_header = "\n<b><u>TEST ENVIRONMENT</u>:</b> #{ENV['TEST_ENVIRONMENT']}\n"
409
+ report_header = "#{report_header} <b>Driver:</b>\t #{Environ.driver}\n" if Environ.driver
410
+ report_header = "#{report_header} <b>Driver Name:</b>\t #{Environ.driver_name}\n" if Environ.driver_name
411
+ report_header = "#{report_header} <b>Platform:</b>\t #{Environ.platform}\n" if Environ.platform
412
+ report_header = "#{report_header} <b>Device:</b>\t #{Environ.device_name}\n" if Environ.device_name
413
+ report_header = "#{report_header} <b>Device OS:</b>\t #{Environ.device_os} #{Environ.device_os_version}\n" if Environ.device_os
414
+ report_header = "#{report_header} <b>Device type:</b>\t #{Environ.device_type}\n" if Environ.device_type
415
+ report_header = "#{report_header} <b>OS:</b>\t\t #{Environ.os}\n" if Environ.os
416
+ report_header = "#{report_header} <b>Locale:</b>\t #{Environ.locale}\n" if Environ.locale
417
+ report_header = "#{report_header} <b>Language:</b>\t #{Environ.language}\n" if Environ.language
418
+ report_header = "#{report_header} <b>Country:</b>\t #{ENV['COUNTRY']}\n" if ENV['COUNTRY']
419
+ "#{report_header}\n\n"
420
+ end
421
+ # :nocov:
422
+ end
423
+ end