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,667 @@
1
+ require 'appium_lib'
2
+ require 'json'
3
+ require 'net/http'
4
+ require 'net/https'
5
+ require 'uri'
6
+
7
+
8
+ module TestCentricity
9
+ module AppiumConnect
10
+ attr_accessor :driver
11
+ attr_accessor :running
12
+ attr_accessor :endpoint
13
+ attr_accessor :capabilities
14
+ attr_accessor :global_scope
15
+
16
+ # Create a new driver instance with capabilities specified in the options parameter, or via Environment Variables.
17
+ # Refer to the `Connecting to a Mobile Simulator or Device` section of the ruby docs for this gem.
18
+ #
19
+ def self.initialize_appium(options = nil)
20
+ @endpoint = nil
21
+ @capabilities = nil
22
+ @running = false
23
+ @global_scope = false
24
+ Environ.driver_name = nil
25
+ Environ.device_orientation = nil
26
+ Environ.platform = :mobile
27
+ Environ.device = :simulator
28
+
29
+ if options.is_a?(Hash)
30
+ @endpoint = options[:endpoint] if options.key?(:endpoint)
31
+ @capabilities = options[:capabilities] if options.key?(:capabilities)
32
+ @global_scope = options[:global_driver] if options.key?(:global_driver)
33
+ Environ.driver = options[:driver] if options.key?(:driver)
34
+ Environ.driver_name = options[:driver_name] if options.key?(:driver_name)
35
+ Environ.device_type = options[:device_type] if options.key?(:device_type)
36
+ end
37
+ if @capabilities.nil?
38
+ Environ.driver = ENV['DRIVER'].downcase.to_sym if ENV['DRIVER']
39
+ Environ.device_type = ENV['DEVICE_TYPE'] if ENV['DEVICE_TYPE']
40
+ Environ.device_orientation = ENV['ORIENTATION'] if ENV['ORIENTATION']
41
+ else
42
+ raise ':browserName is specified in capabilities' if @capabilities[:browserName]
43
+ end
44
+
45
+ raise 'You must specify a driver' if Environ.driver.nil?
46
+ raise 'You must specify a device type - :phone or :tablet' if Environ.device_type.nil?
47
+
48
+ driver_caps = case Environ.driver
49
+ when :appium
50
+ appium_local_capabilities
51
+ when :custom
52
+ raise 'User-defined cloud driver requires that you define options' if options.nil?
53
+ custom_capabilities
54
+ when :browserstack
55
+ browserstack_capabilities
56
+ when :testingbot
57
+ testingbot_capabilities
58
+ # :nocov:
59
+ when :saucelabs
60
+ sauce_capabilities
61
+ else
62
+ raise "#{Environ.driver} is not a supported driver"
63
+ # :nocov:
64
+ end
65
+ driver_opts = {
66
+ caps: driver_caps,
67
+ appium_lib: { server_url: @endpoint }
68
+ }
69
+ @driver = Appium::Driver.new(driver_opts, global_driver = @global_scope)
70
+ @driver.start_driver
71
+ Environ.appium_driver = @driver
72
+ @running = true
73
+ Appium.promote_appium_methods(TestCentricity::ScreenObject, driver = @driver)
74
+ Appium.promote_appium_methods(TestCentricity::ScreenSection, driver = @driver)
75
+ Appium.promote_appium_methods(TestCentricity::AppElements::AppUIElement, driver = @driver)
76
+
77
+ Environ.screen_size = window_size
78
+ unless Environ.driver_name
79
+ Environ.driver_name = "#{Environ.driver}_#{Environ.device_os}_#{Environ.device_type}".downcase.to_sym
80
+ end
81
+ Environ.session_state = :running
82
+ end
83
+
84
+ # Quit the running driver instance. Sets Environ.session_state to :quit.
85
+ #
86
+ def self.quit_driver
87
+ if @running
88
+ driver.driver_quit
89
+ @running = false
90
+ end
91
+ Environ.session_state = :quit
92
+ end
93
+
94
+ # Return a reference to last created Appium driver
95
+ #
96
+ def self.driver
97
+ @driver
98
+ end
99
+
100
+ # Save a screenshot in .png format to the specified file path.
101
+ #
102
+ # @param png_save_path [String] path to save the screenshot
103
+ # @example
104
+ # AppiumConnect.take_screenshot('reports/screenshots/login_screen.png')
105
+ #
106
+ def self.take_screenshot(png_save_path)
107
+ FileUtils.mkdir_p(File.dirname(png_save_path))
108
+ driver.driver.save_screenshot(png_save_path)
109
+ end
110
+
111
+ # Install app on device. If bundle_id is not specified, then bundle id will be retrieved from Environ.current.ios_bundle_id
112
+ # or Environ.current.android_app_id dependent on which platform is being tested.
113
+ #
114
+ # @param bundle_id [String] OPTIONAL bundle id of app
115
+ # @example
116
+ # AppiumConnect.install_app('com.saucelabs.mydemoapp.rn')
117
+ #
118
+ def self.install_app(app_path)
119
+ driver.install_app(app_path)
120
+ end
121
+
122
+ # Remove app from device. If bundle_id is not specified, then bundle id will be retrieved from Environ.current.ios_bundle_id
123
+ # or Environ.current.android_app_id dependent on which platform is being tested.
124
+ #
125
+ # @param bundle_id [String] OPTIONAL bundle id of app
126
+ # @example
127
+ # AppiumConnect.remove_app('com.saucelabs.mydemoapp.rn')
128
+ #
129
+ def self.remove_app(bundle_id = nil)
130
+ driver.remove_app(get_app_id(bundle_id))
131
+ end
132
+
133
+ # Is the app installed? If bundle_id is not specified, then bundle id will be retrieved from Environ.current.ios_bundle_id
134
+ # or Environ.current.android_app_id dependent on which platform is being tested.
135
+ #
136
+ # @param bundle_id [String] OPTIONAL bundle id of app
137
+ # @return [Boolean] TRUE if app is installed
138
+ # @example
139
+ # AppiumConnect.app_installed?('com.saucelabs.mydemoapp.rn')
140
+ #
141
+ def self.app_installed?(bundle_id = nil)
142
+ driver.app_installed?(get_app_id(bundle_id))
143
+ end
144
+
145
+ # Backgrounds the app for a specified number of seconds.
146
+ #
147
+ # @param duration [Integer] number of seconds to background the app for
148
+ # @example
149
+ # AppiumConnect.background_app(20)
150
+ #
151
+ def self.background_app(duration = 0)
152
+ driver.background_app(duration)
153
+ end
154
+
155
+ # Launch the app. If bundle_id is not specified, then bundle id will be retrieved from Environ.current.ios_bundle_id,
156
+ # Environ.current.android_app_id, or Environ.current.mac_bundle_id dependent on which platform is being tested.
157
+ #
158
+ # @param bundle_id [String] OPTIONAL bundle id of app
159
+ # @example
160
+ # AppiumConnect.activate_app('com.saucelabs.mydemoapp.rn')
161
+ #
162
+ def self.activate_app(bundle_id = nil)
163
+ if Environ.is_macos?
164
+ @driver.execute_script('macos: activateApp', { bundleId: get_app_id(bundle_id) })
165
+ else
166
+ driver.activate_app(get_app_id(bundle_id))
167
+ if Environ.is_android?
168
+ sleep(1.5) if app_state == :running_in_foreground
169
+ end
170
+ end
171
+ Environ.new_app_session
172
+ end
173
+
174
+ # Get status of app. If bundle_id is not specified, then bundle id will be retrieved from Environ.current.ios_bundle_id,
175
+ # Environ.current.android_app_id, or Environ.current.mac_bundle_id dependent on which platform is being tested. Returns
176
+ # the following statuses:
177
+ # :not_installed - The current application state cannot be determined/is unknown
178
+ # :not_running - The application is not running
179
+ # :running_in_background_suspended - The application is running in the background and is suspended
180
+ # :running_in_background - The application is running in the background and is not suspended
181
+ # :running_in_foreground - The application is running in the foreground
182
+ #
183
+ # @param bundle_id [String] OPTIONAL bundle id of app
184
+ # @return [Symbol] status of app
185
+ # @example
186
+ # AppiumConnect.app_state('com.saucelabs.mydemoapp.rn')
187
+ #
188
+ def self.app_state(bundle_id = nil)
189
+ if Environ.is_macos?
190
+ state = @driver.execute_script('macos: queryAppState', { bundleId: get_app_id(bundle_id) })
191
+ case state
192
+ when 0
193
+ :not_installed
194
+ when 1
195
+ :not_running
196
+ when 2
197
+ :running_in_background_suspended
198
+ when 3
199
+ :running_in_background
200
+ when 4
201
+ :running_in_foreground
202
+ end
203
+ else
204
+ driver.app_state(get_app_id(bundle_id))
205
+ end
206
+ end
207
+
208
+ # Terminate the app. If bundle_id is not specified, then bundle id will be retrieved from Environ.current.ios_bundle_id,
209
+ # Environ.current.android_app_id, or Environ.current.mac_bundle_id dependent on which platform is being tested.
210
+ #
211
+ # @param bundle_id [String] OPTIONAL bundle id of app
212
+ # @example
213
+ # AppiumConnect.terminate_app('com.saucelabs.mydemoapp.rn')
214
+ #
215
+ def self.terminate_app(bundle_id = nil)
216
+ if Environ.is_macos?
217
+ @driver.execute_script('macos: terminateApp', { bundleId: get_app_id(bundle_id) })
218
+ else
219
+ driver.terminate_app(get_app_id(bundle_id))
220
+ end
221
+ end
222
+
223
+ # Set the amount of time the driver should wait when searching for elements.
224
+ #
225
+ # @param timeout [Integer] number of seconds to wait
226
+ #
227
+ def self.implicit_wait(timeout)
228
+ driver.manage.timeouts.implicit_wait = timeout
229
+ end
230
+
231
+ # Hide the onscreen keyboard
232
+ #
233
+ def self.hide_keyboard
234
+ driver.hide_keyboard
235
+ end
236
+
237
+ # Is onscreen keyboard displayed?
238
+ #
239
+ # @return [Boolean] TRUE if keyboard is shown. Return false if keyboard is hidden.
240
+ #
241
+ def self.keyboard_shown?
242
+ @driver.execute_script('mobile: isKeyboardShown')
243
+ end
244
+
245
+ # Get the current screen orientation
246
+ #
247
+ # @return [Symbol] :landscape or :portrait
248
+ #
249
+ def self.orientation
250
+ driver.driver.orientation
251
+ end
252
+
253
+ # Change the screen orientation
254
+ #
255
+ # @param orientation [Symbol or String] :landscape or :portrait
256
+ #
257
+ def self.rotation(orientation)
258
+ orientation.downcase.to_sym if orientation.is_a?(String)
259
+ driver.driver.rotation = orientation
260
+ end
261
+
262
+ # Get the device's window size.
263
+ #
264
+ # @return [Array] window size as [width, height]
265
+ #
266
+ def self.window_size
267
+ size = driver.window_size
268
+ [size.width, size.height]
269
+ end
270
+
271
+ # Get the device's window rectangle.
272
+ #
273
+ # @return (Selenium::WebDriver::Rectangle)
274
+ #
275
+ def self.window_rect
276
+ driver.window_rect
277
+ end
278
+
279
+ def self.geolocation
280
+ driver.driver.location
281
+ end
282
+
283
+ def self.set_geolocation(location_data)
284
+ driver.set_location(location_data)
285
+ end
286
+
287
+ def self.current_context
288
+ driver.current_context
289
+ end
290
+
291
+ def self.set_context(context)
292
+ driver.set_context(context)
293
+ end
294
+
295
+ def self.available_contexts
296
+ driver.available_contexts
297
+ end
298
+
299
+ def self.is_webview?
300
+ driver.current_context.start_with?('WEBVIEW')
301
+ end
302
+
303
+ def self.is_native_app?
304
+ driver.current_context.start_with?('NATIVE_APP')
305
+ end
306
+
307
+ def self.webview_context
308
+ contexts = driver.available_contexts
309
+ puts "Contexts = #{contexts}" if ENV['DEBUG']
310
+ set_context(contexts.last)
311
+ puts "Current context = #{driver.current_context}" if ENV['DEBUG']
312
+ end
313
+
314
+ def self.is_biometric_enrolled?
315
+ if Environ.is_ios?
316
+ @driver.execute_script('mobile: isBiometricEnrolled')
317
+ else
318
+ puts 'biometric_enrollment is not supported for this platform'
319
+ end
320
+ end
321
+
322
+ def self.set_biometric_enrollment(state)
323
+ if Environ.is_ios?
324
+ @driver.execute_script('mobile: enrollBiometric', { isEnabled: state })
325
+ else
326
+ puts 'biometric_enrollment is not supported for this platform'
327
+ end
328
+ end
329
+
330
+ def self.biometric_match(type, match)
331
+ if Environ.is_ios?
332
+ @driver.execute_script('mobile: sendBiometricMatch', { type: type, match: match })
333
+ else
334
+ raise 'biometric_match is not supported for this platform'
335
+ end
336
+ end
337
+
338
+ # :nocov:
339
+ def self.upload_app(service)
340
+ # determine app custom test id (if specified)
341
+ custom_id = if ENV['APP_ID']
342
+ ENV['APP_ID']
343
+ else
344
+ Environ.is_android? ? Environ.current.android_test_id : Environ.current.ios_test_id
345
+ end
346
+ # determine endpoint url, user id, and auth key for specified cloud service provider
347
+ case service
348
+ when :browserstack
349
+ url = 'https://api-cloud.browserstack.com/app-automate/upload'
350
+ user_id = ENV['BS_USERNAME']
351
+ auth_key = ENV['BS_AUTHKEY']
352
+ when :testingbot
353
+ url = 'https://api.testingbot.com/v1/storage'
354
+ url = "#{url}/#{custom_id}" unless custom_id.nil?
355
+ user_id = ENV['TB_USERNAME']
356
+ auth_key = ENV['TB_AUTHKEY']
357
+ else
358
+ raise "#{service} is not supported"
359
+ end
360
+ # determine file path of app to be uploaded to cloud service
361
+ file_path = if Environ.is_android?
362
+ Environ.current.android_apk_path
363
+ elsif Environ.is_ios?
364
+ Environ.is_device? ? Environ.current.ios_ipa_path : Environ.current.ios_app_path
365
+ end
366
+
367
+ request = Net::HTTP::Post.new(url)
368
+ boundary = "WebAppBoundary"
369
+ post_body = []
370
+ post_body << "--#{boundary}\r\n"
371
+ post_body << "Content-Disposition: form-data; name=\"file\"; filename=\"#{file_path}\"\r\n"
372
+ post_body << "\r\n"
373
+ post_body << File.open(file_path) {|io| io.read}
374
+ # add custom id form data to post body if a custom test id has been provided
375
+ if !custom_id.nil? && service == :browserstack
376
+ post_body << "\r\n--#{boundary}\r\n"
377
+ post_body << "Content-Disposition: form-data; name=\"custom_id\"\r\n"
378
+ post_body << "\r\n"
379
+ post_body << "#{custom_id}"
380
+ end
381
+ post_body << "\r\n--#{boundary}--\r\n"
382
+ request.body = post_body.join
383
+ request["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
384
+ request.basic_auth(user_id, auth_key)
385
+ # send the request to upload to cloud service provider
386
+ uri = URI.parse(url)
387
+ conn = Net::HTTP.new(uri.host, uri.port)
388
+ if uri.scheme == 'https'
389
+ conn.use_ssl = true
390
+ conn.verify_mode = OpenSSL::SSL::VERIFY_NONE
391
+ end
392
+ response = conn.request(request)
393
+ result = JSON.parse(response.body)
394
+ if response.code.to_i > 202
395
+ raise "An error has occurred while attempting to upload #{file_path} to the #{service} service\n#{result}"
396
+ else
397
+ puts "Successfully uploaded #{file_path} to the #{service} service\n#{result}"
398
+ end
399
+ end
400
+ # :nocov:
401
+
402
+ private
403
+
404
+ def self.get_app_id(bundle_id = nil)
405
+ return bundle_id unless bundle_id.nil?
406
+ case
407
+ when Environ.is_ios?
408
+ Environ.current.ios_bundle_id
409
+ when Environ.is_android?
410
+ Environ.current.android_app_id
411
+ when Environ.is_macos?
412
+ Environ.current.mac_bundle_id
413
+ else
414
+ nil
415
+ end
416
+ end
417
+
418
+ def self.appium_local_capabilities
419
+ # specify endpoint url
420
+ if @endpoint.nil?
421
+ @endpoint = if ENV['APPIUM_SERVER_VERSION'] && ENV['APPIUM_SERVER_VERSION'].to_i == 1
422
+ 'http://127.0.0.1:4723/wd/hub'
423
+ else
424
+ 'http://127.0.0.1:4723'
425
+ end
426
+ end
427
+ # define local Appium capabilities
428
+ if @capabilities.nil?
429
+ Environ.device_name = ENV['APP_DEVICE']
430
+ Environ.device_os = ENV['APP_PLATFORM_NAME']
431
+ Environ.device_os_version = ENV['APP_VERSION']
432
+ Environ.device = ENV['UDID'] ? :device : :simulator
433
+
434
+ caps = {
435
+ platformName: ENV['APP_PLATFORM_NAME'],
436
+ 'appium:platformVersion': ENV['APP_VERSION'],
437
+ 'appium:deviceName': ENV['APP_DEVICE'],
438
+ 'appium:automationName': ENV['AUTOMATION_ENGINE']
439
+ }
440
+ caps[:'appium:avd'] = ENV['APP_DEVICE'] if ENV['APP_PLATFORM_NAME'].downcase.to_sym == :android
441
+ caps[:'appium:orientation'] = ENV['ORIENTATION'].upcase if ENV['ORIENTATION']
442
+ if ENV['LOCALE'] && ENV['LANGUAGE']
443
+ caps[:'appium:language'] = ENV['LANGUAGE']
444
+ caps[:'appium:locale'] = if Environ.is_android?
445
+ locale = ENV['LOCALE'].gsub('-', '_')
446
+ locale.split('_')[1]
447
+ else
448
+ ENV['LOCALE'].gsub('-', '_')
449
+ end
450
+ end
451
+ caps[:'appium:newCommandTimeout'] = ENV['NEW_COMMAND_TIMEOUT'] if ENV['NEW_COMMAND_TIMEOUT']
452
+ caps[:'appium:noReset'] = ENV['APP_NO_RESET'] if ENV['APP_NO_RESET']
453
+ caps[:'appium:fullReset'] = ENV['APP_FULL_RESET'] if ENV['APP_FULL_RESET']
454
+ caps[:'appium:autoLaunch'] = ENV['AUTO_LAUNCH'] if ENV['AUTO_LAUNCH']
455
+ caps[:'appium:webkitDebugProxyPort'] = ENV['WEBKIT_DEBUG_PROXY_PORT'] if ENV['WEBKIT_DEBUG_PROXY_PORT']
456
+ caps[:'appium:webDriverAgentUrl'] = ENV['WEBDRIVER_AGENT_URL'] if ENV['WEBDRIVER_AGENT_URL']
457
+ caps[:'appium:wdaLocalPort'] = ENV['WDA_LOCAL_PORT'] if ENV['WDA_LOCAL_PORT']
458
+ caps[:'appium:usePrebuiltWDA'] = ENV['USE_PREBUILT_WDA'] if ENV['USE_PREBUILT_WDA']
459
+ caps[:'appium:useNewWDA'] = ENV['USE_NEW_WDA'] if ENV['USE_NEW_WDA']
460
+ caps[:'appium:autoWebview'] = ENV['AUTO_WEBVIEW'] if ENV['AUTO_WEBVIEW']
461
+ caps[:'appium:chromedriverExecutable'] = ENV['CHROMEDRIVER_EXECUTABLE'] if ENV['CHROMEDRIVER_EXECUTABLE']
462
+ caps[:'appium:autoWebviewTimeout'] = ENV['AUTO_WEBVIEW_TIMEOUT'] if ENV['AUTO_WEBVIEW_TIMEOUT']
463
+ caps[:'appium:udid'] = ENV['UDID'] if ENV['UDID']
464
+ caps[:'appium:xcodeOrgId'] = ENV['TEAM_ID'] if ENV['TEAM_ID']
465
+ caps[:'appium:xcodeSigningId'] = ENV['TEAM_NAME'] if ENV['TEAM_NAME']
466
+ caps[:'appium:appActivity'] = ENV['APP_ACTIVITY'] if ENV['APP_ACTIVITY']
467
+ caps[:'appium:appPackage'] = ENV['APP_PACKAGE'] if ENV['APP_PACKAGE']
468
+ caps[:'appium:forceSimulatorSoftwareKeyboardPresence'] = ENV['SHOW_SIM_KEYBOARD'] if ENV['SHOW_SIM_KEYBOARD']
469
+ if Environ.is_ios?
470
+ caps[:'appium:webviewConnectTimeout'] = 90000
471
+ caps[:'appium:maxTypingFrequency'] = 15
472
+ caps[:'appium:respectSystemAlerts'] = true
473
+ end
474
+
475
+ if ENV['BUNDLE_ID']
476
+ caps[:'appium:bundleId'] = ENV['BUNDLE_ID']
477
+ else
478
+ app_id = get_app_id
479
+ caps[:'appium:bundleId'] = app_id unless app_id.nil?
480
+ end
481
+
482
+ caps[:'appium:app'] = if ENV['APP']
483
+ ENV['APP']
484
+ else
485
+ if Environ.is_android?
486
+ Environ.current.android_apk_path
487
+ elsif Environ.is_ios?
488
+ Environ.is_device? ?
489
+ Environ.current.ios_ipa_path :
490
+ Environ.current.ios_app_path
491
+ end
492
+ end
493
+ caps
494
+ else
495
+ Environ.device_os = @capabilities[:platformName]
496
+ Environ.device_name = @capabilities[:'appium:deviceName']
497
+ Environ.device_os_version = @capabilities[:'appium:platformVersion']
498
+ Environ.device_orientation = @capabilities[:'appium:orientation']
499
+ Environ.device = @capabilities[:'appium:udid'] ? :device : :simulator
500
+ @capabilities
501
+ end
502
+ end
503
+
504
+ def self.custom_capabilities
505
+ raise 'User-defined cloud driver requires that you provide capabilities' if @capabilities.nil?
506
+ raise 'User-defined cloud driver requires that you provide an endpoint' if @endpoint.nil?
507
+
508
+ Environ.device_os = @capabilities[:platformName]
509
+ Environ.device_name = @capabilities[:'appium:deviceName']
510
+ Environ.device_os_version = @capabilities[:'appium:platformVersion']
511
+ @capabilities
512
+ end
513
+
514
+ def self.browserstack_capabilities
515
+ # specify endpoint url
516
+ @endpoint = "https://#{ENV['BS_USERNAME']}:#{ENV['BS_AUTHKEY']}@hub-cloud.browserstack.com/wd/hub" if @endpoint.nil?
517
+ # define BrowserStack options
518
+ options = if @capabilities.nil?
519
+ Environ.device_name = ENV['BS_DEVICE']
520
+ Environ.device_os = ENV['BS_OS']
521
+ Environ.device_os_version = ENV['BS_OS_VERSION']
522
+ # define the required set of BrowserStack options
523
+ bs_options = {
524
+ userName: ENV['BS_USERNAME'],
525
+ accessKey: ENV['BS_AUTHKEY'],
526
+ sessionName: test_context_message
527
+ }
528
+ # define the optional BrowserStack options
529
+ bs_options[:projectName] = ENV['AUTOMATE_PROJECT'] if ENV['AUTOMATE_PROJECT']
530
+ bs_options[:buildName] = ENV['AUTOMATE_BUILD'] if ENV['AUTOMATE_BUILD']
531
+ bs_options[:geoLocation] = ENV['IP_GEOLOCATION'] if ENV['IP_GEOLOCATION']
532
+ bs_options[:timezone] = ENV['TIME_ZONE'] if ENV['TIME_ZONE']
533
+ bs_options[:video] = ENV['RECORD_VIDEO'] if ENV['RECORD_VIDEO']
534
+ bs_options[:debug] = ENV['SCREENSHOTS'] if ENV['SCREENSHOTS']
535
+ bs_options[:local] = ENV['TUNNELING'] if ENV['TUNNELING']
536
+ bs_options[:deviceOrientation] = ENV['ORIENTATION'] if ENV['ORIENTATION']
537
+ bs_options[:appiumLogs] = ENV['APPIUM_LOGS'] if ENV['APPIUM_LOGS']
538
+ bs_options[:networkLogs] = ENV['NETWORK_LOGS'] if ENV['NETWORK_LOGS']
539
+ bs_options[:deviceLogs] = ENV['DEVICE_LOGS'] if ENV['DEVICE_LOGS']
540
+ bs_options[:networkProfile] = ENV['NETWORK_PROFILE'] if ENV['NETWORK_PROFILE']
541
+ bs_options[:idleTimeout] = ENV['IDLE_TIMEOUT'] if ENV['IDLE_TIMEOUT']
542
+ bs_options[:resignApp] = ENV['RESIGN_APP'] if ENV['RESIGN_APP']
543
+ bs_options[:gpsLocation] = ENV['GPS_LOCATION'] if ENV['GPS_LOCATION']
544
+ bs_options[:acceptInsecureCerts] = ENV['ACCEPT_INSECURE_CERTS'] if ENV['ACCEPT_INSECURE_CERTS']
545
+ bs_options[:disableAnimations] = ENV['DISABLE_ANIMATION'] if ENV['DISABLE_ANIMATION']
546
+ bs_options[:appiumVersion] = ENV['APPIUM_VERSION'] ? ENV['APPIUM_VERSION'] : '2.4.1'
547
+
548
+ capabilities = {
549
+ platformName: ENV['BS_OS'],
550
+ 'appium:platformVersion': ENV['BS_OS_VERSION'],
551
+ 'appium:deviceName': ENV['BS_DEVICE'],
552
+ 'appium:automationName': ENV['AUTOMATION_ENGINE'],
553
+ 'appium:app': ENV['APP'],
554
+ 'bstack:options': bs_options
555
+ }
556
+ capabilities[:language] = ENV['LANGUAGE'] if ENV['LANGUAGE']
557
+ capabilities[:locale] = ENV['LOCALE'] if ENV['LOCALE']
558
+ capabilities
559
+ else
560
+ Environ.device_os = @capabilities[:platformName]
561
+ Environ.device_name = @capabilities[:'appium:deviceName']
562
+ Environ.device_os_version = @capabilities[:'appium:platformVersion']
563
+ @capabilities
564
+ end
565
+ # BrowserStack uses only real devices
566
+ Environ.device = :device
567
+ upload_app(:browserstack) if ENV['UPLOAD_APP']
568
+ options
569
+ end
570
+
571
+ # :nocov:
572
+ def self.testingbot_capabilities
573
+ Environ.device = :simulator
574
+ # specify endpoint url
575
+ @endpoint = "http://#{ENV['TB_USERNAME']}:#{ENV['TB_AUTHKEY']}@hub.testingbot.com/wd/hub" if @endpoint.nil?
576
+ # define TestingBot options
577
+ options = if @capabilities.nil?
578
+ Environ.device_name = ENV['TB_DEVICE']
579
+ Environ.device_os = ENV['TB_OS']
580
+ Environ.device_os_version = ENV['TB_OS_VERSION']
581
+ Environ.device = :device if ENV['REAL_DEVICE'] == 'true'
582
+ # define the required set of TestingBot options
583
+ tb_options = { build: test_context_message }
584
+ # define the optional TestingBot options
585
+ tb_options[:name] = ENV['AUTOMATE_PROJECT'] if ENV['AUTOMATE_PROJECT']
586
+ tb_options[:timeZone] = ENV['TIME_ZONE'] if ENV['TIME_ZONE']
587
+ tb_options['testingbot.geoCountryCode'] = ENV['IP_GEOLOCATION'] if ENV['IP_GEOLOCATION']
588
+ tb_options[:screenrecorder] = ENV['RECORD_VIDEO'] if ENV['RECORD_VIDEO']
589
+ tb_options[:screenshot] = ENV['SCREENSHOTS'] if ENV['SCREENSHOTS']
590
+ tb_options[:appiumVersion] = ENV['APPIUM_VERSION'] ? ENV['APPIUM_VERSION'] : '2.4.1'
591
+
592
+ capabilities = {
593
+ platformName: ENV['TB_OS'],
594
+ 'appium:platformVersion': ENV['TB_OS_VERSION'],
595
+ 'appium:deviceName': ENV['TB_DEVICE'],
596
+ 'appium:automationName': ENV['AUTOMATION_ENGINE'],
597
+ 'appium:app': ENV['APP'],
598
+ 'tb:options': tb_options
599
+ }
600
+ capabilities[:'appium:realDevice'] = ENV['REAL_DEVICE'] if ENV['REAL_DEVICE']
601
+ capabilities
602
+ else
603
+ Environ.device_os = @capabilities[:platformName]
604
+ Environ.device_name = @capabilities[:'appium:deviceName']
605
+ Environ.device_os_version = @capabilities[:'appium:platformVersion']
606
+ if @capabilities.key?(:'appium:realDevice') && @capabilities[:'appium:realDevice'] == true
607
+ Environ.device = :device
608
+ end
609
+ @capabilities
610
+ end
611
+
612
+ upload_app(:testingbot) if ENV['UPLOAD_APP']
613
+ options
614
+ end
615
+
616
+ def self.sauce_capabilities
617
+ # specify endpoint url
618
+ if @endpoint.nil?
619
+ @endpoint = "https://#{ENV['SL_USERNAME']}:#{ENV['SL_AUTHKEY']}@ondemand.#{ENV['SL_DATA_CENTER']}.saucelabs.com:443/wd/hub"
620
+ end
621
+ # define SauceLabs options
622
+ options = if @capabilities.nil?
623
+ Environ.device_name = ENV['SL_DEVICE']
624
+ Environ.device_os = ENV['SL_OS']
625
+ Environ.device_os_version = ENV['SL_OS_VERSION']
626
+ # define the required set of SauceLabs options
627
+ sl_options = { build: test_context_message }
628
+ # define the optional SauceLabs options
629
+ sl_options[:name] = ENV['AUTOMATE_PROJECT'] if ENV['AUTOMATE_PROJECT']
630
+ sl_options[:deviceOrientation] = ENV['ORIENTATION'].upcase if ENV['ORIENTATION']
631
+ sl_options[:recordVideo] = ENV['RECORD_VIDEO'] if ENV['RECORD_VIDEO']
632
+ sl_options[:recordScreenshots] = ENV['SCREENSHOTS'] if ENV['SCREENSHOTS']
633
+ sl_options[:appiumVersion] = ENV['APPIUM_VERSION'] ? ENV['APPIUM_VERSION'] : '2.1.3'
634
+ capabilities = {
635
+ platformName: ENV['SL_OS'],
636
+ 'appium:platformVersion': ENV['SL_OS_VERSION'],
637
+ 'appium:deviceName': ENV['SL_DEVICE'],
638
+ 'appium:automationName': ENV['AUTOMATION_ENGINE'],
639
+ 'appium:app': ENV['APP'],
640
+ 'sauce:options': sl_options
641
+ }
642
+ capabilities
643
+ else
644
+ Environ.device_os = @capabilities[:platformName]
645
+ Environ.device_name = @capabilities[:'appium:deviceName']
646
+ Environ.device_os_version = @capabilities[:'appium:platformVersion']
647
+ @capabilities
648
+ end
649
+ options
650
+ end
651
+
652
+ def self.test_context_message
653
+ context_message = if ENV['TEST_CONTEXT']
654
+ "#{Environ.test_environment.to_s.upcase} - #{ENV['TEST_CONTEXT']}"
655
+ else
656
+ Environ.test_environment.to_s.upcase
657
+ end
658
+ if ENV['PARALLEL']
659
+ thread_num = ENV['TEST_ENV_NUMBER']
660
+ thread_num = 1 if thread_num.blank?
661
+ context_message = "#{context_message} - Thread ##{thread_num}"
662
+ end
663
+ context_message
664
+ end
665
+ # :nocov:
666
+ end
667
+ end