testcentricity_mobile 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,634 @@
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
+ # or Environ.current.android_app_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
+ driver.activate_app(get_app_id(bundle_id))
164
+ if Environ.is_android?
165
+ sleep(1.5) if app_state == :running_in_foreground
166
+ end
167
+ Environ.new_app_session
168
+ end
169
+
170
+ # Get status of app. If bundle_id is not specified, then bundle id will be retrieved from Environ.current.ios_bundle_id
171
+ # or Environ.current.android_app_id dependent on which platform is being tested. Returns the following statuses:
172
+ # :not_installed - The current application state cannot be determined/is unknown
173
+ # :not_running - The application is not running
174
+ # :running_in_background_suspended - The application is running in the background and is suspended
175
+ # :running_in_background - The application is running in the background and is not suspended
176
+ # :running_in_foreground - The application is running in the foreground
177
+ #
178
+ # @param bundle_id [String] OPTIONAL bundle id of app
179
+ # @return [Symbol] status of app
180
+ # @example
181
+ # AppiumConnect.app_state('com.saucelabs.mydemoapp.rn')
182
+ #
183
+ def self.app_state(bundle_id = nil)
184
+ driver.app_state(get_app_id(bundle_id))
185
+ end
186
+
187
+ # Terminate the app. If bundle_id is not specified, then bundle id will be retrieved from Environ.current.ios_bundle_id
188
+ # or Environ.current.android_app_id dependent on which platform is being tested.
189
+ #
190
+ # @param bundle_id [String] OPTIONAL bundle id of app
191
+ # @example
192
+ # AppiumConnect.terminate_app('com.saucelabs.mydemoapp.rn')
193
+ #
194
+ def self.terminate_app(bundle_id = nil)
195
+ driver.terminate_app(get_app_id(bundle_id))
196
+ end
197
+
198
+ # Set the amount of time the driver should wait when searching for elements.
199
+ #
200
+ # @param timeout [Integer] number of seconds to wait
201
+ #
202
+ def self.implicit_wait(timeout)
203
+ driver.manage.timeouts.implicit_wait = timeout
204
+ end
205
+
206
+ # Hide the onscreen keyboard
207
+ #
208
+ def self.hide_keyboard
209
+ driver.hide_keyboard
210
+ end
211
+
212
+ # Is onscreen keyboard displayed?
213
+ #
214
+ # @return [Boolean] TRUE if keyboard is shown. Return false if keyboard is hidden.
215
+ #
216
+ def self.keyboard_shown?
217
+ driver.driver.keyboard_shown?
218
+ end
219
+
220
+ # Get the current screen orientation
221
+ #
222
+ # @return [Symbol] :landscape or :portrait
223
+ #
224
+ def self.orientation
225
+ driver.driver.orientation
226
+ end
227
+
228
+ # Change the screen orientation
229
+ #
230
+ # @param orientation [Symbol or String] :landscape or :portrait
231
+ #
232
+ def self.rotation(orientation)
233
+ orientation.downcase.to_sym if orientation.is_a?(String)
234
+ driver.driver.rotation = orientation
235
+ end
236
+
237
+ # Get the device's window size.
238
+ #
239
+ # @return [Array] window size as [width, height]
240
+ #
241
+ def self.window_size
242
+ size = driver.window_size
243
+ [size.width, size.height]
244
+ end
245
+
246
+ # Get the device's window rectangle.
247
+ #
248
+ # @return (Selenium::WebDriver::Rectangle)
249
+ #
250
+ def self.window_rect
251
+ driver.window_rect
252
+ end
253
+
254
+ def self.geolocation
255
+ driver.driver.location
256
+ end
257
+
258
+ def self.set_geolocation(location_data)
259
+ driver.set_location(location_data)
260
+ end
261
+
262
+ def self.current_context
263
+ driver.current_context
264
+ end
265
+
266
+ def self.set_context(context)
267
+ driver.set_context(context)
268
+ end
269
+
270
+ def self.available_contexts
271
+ driver.available_contexts
272
+ end
273
+
274
+ def self.is_webview?
275
+ driver.current_context.start_with?('WEBVIEW')
276
+ end
277
+
278
+ def self.is_native_app?
279
+ driver.current_context.start_with?('NATIVE_APP')
280
+ end
281
+
282
+ def self.webview_context
283
+ contexts = driver.available_contexts
284
+ puts "Contexts = #{contexts}" if ENV['DEBUG']
285
+ set_context(contexts.last)
286
+ puts "Current context = #{driver.current_context}" if ENV['DEBUG']
287
+ end
288
+
289
+ def self.is_biometric_enrolled?
290
+ if Environ.is_ios?
291
+ @driver.execute_script('mobile: isBiometricEnrolled')
292
+ else
293
+ puts 'biometric_enrollment is not supported for Android'
294
+ end
295
+ end
296
+
297
+ def self.set_biometric_enrollment(state)
298
+ if Environ.is_ios?
299
+ @driver.execute_script('mobile: enrollBiometric', { isEnabled: state })
300
+ else
301
+ puts 'biometric_enrollment is not supported for Android'
302
+ end
303
+ end
304
+
305
+ def self.biometric_match(type, match)
306
+ if Environ.is_ios?
307
+ @driver.execute_script('mobile: sendBiometricMatch', { type: type, match: match })
308
+ else
309
+ raise 'biometric_match is not supported for Android'
310
+ end
311
+ end
312
+
313
+ # :nocov:
314
+ def self.upload_app(service)
315
+ # determine app custom test id (if specified)
316
+ custom_id = if ENV['APP_ID']
317
+ ENV['APP_ID']
318
+ else
319
+ Environ.is_android? ? Environ.current.android_test_id : Environ.current.ios_test_id
320
+ end
321
+ # determine endpoint url, user id, and auth key for specified cloud service provider
322
+ case service
323
+ when :browserstack
324
+ url = 'https://api-cloud.browserstack.com/app-automate/upload'
325
+ user_id = ENV['BS_USERNAME']
326
+ auth_key = ENV['BS_AUTHKEY']
327
+ when :testingbot
328
+ url = 'https://api.testingbot.com/v1/storage'
329
+ url = "#{url}/#{custom_id}" unless custom_id.nil?
330
+ user_id = ENV['TB_USERNAME']
331
+ auth_key = ENV['TB_AUTHKEY']
332
+ else
333
+ raise "#{service} is not supported"
334
+ end
335
+ # determine file path of app to be uploaded to cloud service
336
+ file_path = if Environ.is_android?
337
+ Environ.current.android_apk_path
338
+ elsif Environ.is_ios?
339
+ Environ.is_device? ? Environ.current.ios_ipa_path : Environ.current.ios_app_path
340
+ end
341
+
342
+ request = Net::HTTP::Post.new(url)
343
+ boundary = "WebAppBoundary"
344
+ post_body = []
345
+ post_body << "--#{boundary}\r\n"
346
+ post_body << "Content-Disposition: form-data; name=\"file\"; filename=\"#{file_path}\"\r\n"
347
+ post_body << "\r\n"
348
+ post_body << File.open(file_path) {|io| io.read}
349
+ # add custom id form data to post body if a custom test id has been provided
350
+ if !custom_id.nil? && service == :browserstack
351
+ post_body << "\r\n--#{boundary}\r\n"
352
+ post_body << "Content-Disposition: form-data; name=\"custom_id\"\r\n"
353
+ post_body << "\r\n"
354
+ post_body << "#{custom_id}"
355
+ end
356
+ post_body << "\r\n--#{boundary}--\r\n"
357
+ request.body = post_body.join
358
+ request["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
359
+ request.basic_auth(user_id, auth_key)
360
+ # send the request to upload to cloud service provider
361
+ uri = URI.parse(url)
362
+ conn = Net::HTTP.new(uri.host, uri.port)
363
+ if uri.scheme == 'https'
364
+ conn.use_ssl = true
365
+ conn.verify_mode = OpenSSL::SSL::VERIFY_NONE
366
+ end
367
+ response = conn.request(request)
368
+ result = JSON.parse(response.body)
369
+ if response.code.to_i > 202
370
+ raise "An error has occurred while attempting to upload #{file_path} to the #{service} service\n#{result}"
371
+ else
372
+ puts "Successfully uploaded #{file_path} to the #{service} service\n#{result}"
373
+ end
374
+ end
375
+ # :nocov:
376
+
377
+ private
378
+
379
+ def self.get_app_id(bundle_id = nil)
380
+ return bundle_id unless bundle_id.nil?
381
+
382
+ if Environ.is_ios?
383
+ Environ.current.ios_bundle_id
384
+ elsif Environ.is_android?
385
+ Environ.current.android_app_id
386
+ else
387
+ nil
388
+ end
389
+ end
390
+
391
+ def self.appium_local_capabilities
392
+ # specify endpoint url
393
+ @endpoint = 'http://127.0.0.1:4723/wd/hub' if @endpoint.nil?
394
+ # define local Appium capabilities
395
+ if @capabilities.nil?
396
+ Environ.device_name = ENV['APP_DEVICE']
397
+ Environ.device_os = ENV['APP_PLATFORM_NAME']
398
+ Environ.device_os_version = ENV['APP_VERSION']
399
+ Environ.device = ENV['UDID'] ? :device : :simulator
400
+
401
+ caps = {
402
+ platformName: ENV['APP_PLATFORM_NAME'],
403
+ 'appium:platformVersion': ENV['APP_VERSION'],
404
+ 'appium:deviceName': ENV['APP_DEVICE'],
405
+ 'appium:automationName': ENV['AUTOMATION_ENGINE']
406
+ }
407
+ caps[:'appium:avd'] = ENV['APP_DEVICE'] if ENV['APP_PLATFORM_NAME'].downcase.to_sym == :android
408
+ caps[:'appium:orientation'] = ENV['ORIENTATION'].upcase if ENV['ORIENTATION']
409
+ if ENV['LOCALE'] && ENV['LANGUAGE']
410
+ caps[:'appium:language'] = ENV['LANGUAGE']
411
+ caps[:'appium:locale'] = if Environ.is_android?
412
+ locale = ENV['LOCALE'].gsub('-', '_')
413
+ locale.split('_')[1]
414
+ else
415
+ ENV['LOCALE'].gsub('-', '_')
416
+ end
417
+ end
418
+ caps[:'appium:newCommandTimeout'] = ENV['NEW_COMMAND_TIMEOUT'] if ENV['NEW_COMMAND_TIMEOUT']
419
+ caps[:'appium:noReset'] = ENV['APP_NO_RESET'] if ENV['APP_NO_RESET']
420
+ caps[:'appium:fullReset'] = ENV['APP_FULL_RESET'] if ENV['APP_FULL_RESET']
421
+ caps[:'appium:autoLaunch'] = ENV['AUTO_LAUNCH'] if ENV['AUTO_LAUNCH']
422
+ caps[:'appium:webkitDebugProxyPort'] = ENV['WEBKIT_DEBUG_PROXY_PORT'] if ENV['WEBKIT_DEBUG_PROXY_PORT']
423
+ caps[:'appium:webDriverAgentUrl'] = ENV['WEBDRIVER_AGENT_URL'] if ENV['WEBDRIVER_AGENT_URL']
424
+ caps[:'appium:wdaLocalPort'] = ENV['WDA_LOCAL_PORT'] if ENV['WDA_LOCAL_PORT']
425
+ caps[:'appium:usePrebuiltWDA'] = ENV['USE_PREBUILT_WDA'] if ENV['USE_PREBUILT_WDA']
426
+ caps[:'appium:useNewWDA'] = ENV['USE_NEW_WDA'] if ENV['USE_NEW_WDA']
427
+ caps[:'appium:autoWebview'] = ENV['AUTO_WEBVIEW'] if ENV['AUTO_WEBVIEW']
428
+ caps[:'appium:chromedriverExecutable'] = ENV['CHROMEDRIVER_EXECUTABLE'] if ENV['CHROMEDRIVER_EXECUTABLE']
429
+ caps[:'appium:autoWebviewTimeout'] = ENV['AUTO_WEBVIEW_TIMEOUT'] if ENV['AUTO_WEBVIEW_TIMEOUT']
430
+ caps[:'appium:udid'] = ENV['UDID'] if ENV['UDID']
431
+ caps[:'appium:xcodeOrgId'] = ENV['TEAM_ID'] if ENV['TEAM_ID']
432
+ caps[:'appium:xcodeSigningId'] = ENV['TEAM_NAME'] if ENV['TEAM_NAME']
433
+ caps[:'appium:appActivity'] = ENV['APP_ACTIVITY'] if ENV['APP_ACTIVITY']
434
+ caps[:'appium:appPackage'] = ENV['APP_PACKAGE'] if ENV['APP_PACKAGE']
435
+ caps[:'appium:forceSimulatorSoftwareKeyboardPresence'] = ENV['SHOW_SIM_KEYBOARD'] if ENV['SHOW_SIM_KEYBOARD']
436
+ caps[:'appium:webviewConnectTimeout'] = '90000'
437
+
438
+ if ENV['BUNDLE_ID']
439
+ caps[:'appium:bundleId'] = ENV['BUNDLE_ID']
440
+ else
441
+ app_id = get_app_id
442
+ caps[:'appium:bundleId'] = app_id unless app_id.nil?
443
+ end
444
+
445
+ caps[:'appium:app'] = if ENV['APP']
446
+ ENV['APP']
447
+ else
448
+ if Environ.is_android?
449
+ Environ.current.android_apk_path
450
+ elsif Environ.is_ios?
451
+ Environ.is_device? ?
452
+ Environ.current.ios_ipa_path :
453
+ Environ.current.ios_app_path
454
+ end
455
+ end
456
+ caps
457
+ else
458
+ Environ.device_os = @capabilities[:platformName]
459
+ Environ.device_name = @capabilities[:'appium:deviceName']
460
+ Environ.device_os_version = @capabilities[:'appium:platformVersion']
461
+ Environ.device_orientation = @capabilities[:'appium:orientation']
462
+ Environ.device = if @capabilities[:'appium:udid']
463
+ :device
464
+ else
465
+ :simulator
466
+ end
467
+ @capabilities
468
+ end
469
+ end
470
+
471
+ def self.custom_capabilities
472
+ raise 'User-defined cloud driver requires that you provide capabilities' if @capabilities.nil?
473
+ raise 'User-defined cloud driver requires that you provide an endpoint' if @endpoint.nil?
474
+
475
+ Environ.device_os = @capabilities[:platformName]
476
+ Environ.device_name = @capabilities[:'appium:deviceName']
477
+ Environ.device_os_version = @capabilities[:'appium:platformVersion']
478
+ @capabilities
479
+ end
480
+
481
+ def self.browserstack_capabilities
482
+ # specify endpoint url
483
+ @endpoint = "https://#{ENV['BS_USERNAME']}:#{ENV['BS_AUTHKEY']}@hub-cloud.browserstack.com/wd/hub" if @endpoint.nil?
484
+ # define BrowserStack options
485
+ options = if @capabilities.nil?
486
+ Environ.device_name = ENV['BS_DEVICE']
487
+ Environ.device_os = ENV['BS_OS']
488
+ Environ.device_os_version = ENV['BS_OS_VERSION']
489
+ # define the required set of BrowserStack options
490
+ bs_options = {
491
+ userName: ENV['BS_USERNAME'],
492
+ accessKey: ENV['BS_AUTHKEY'],
493
+ sessionName: test_context_message
494
+ }
495
+ # define the optional BrowserStack options
496
+ bs_options[:projectName] = ENV['AUTOMATE_PROJECT'] if ENV['AUTOMATE_PROJECT']
497
+ bs_options[:buildName] = ENV['AUTOMATE_BUILD'] if ENV['AUTOMATE_BUILD']
498
+ bs_options[:geoLocation] = ENV['IP_GEOLOCATION'] if ENV['IP_GEOLOCATION']
499
+ bs_options[:timezone] = ENV['TIME_ZONE'] if ENV['TIME_ZONE']
500
+ bs_options[:video] = ENV['RECORD_VIDEO'] if ENV['RECORD_VIDEO']
501
+ bs_options[:debug] = ENV['SCREENSHOTS'] if ENV['SCREENSHOTS']
502
+ bs_options[:local] = ENV['TUNNELING'] if ENV['TUNNELING']
503
+ bs_options[:deviceOrientation] = ENV['ORIENTATION'] if ENV['ORIENTATION']
504
+ bs_options[:appiumLogs] = ENV['APPIUM_LOGS'] if ENV['APPIUM_LOGS']
505
+ bs_options[:networkLogs] = ENV['NETWORK_LOGS'] if ENV['NETWORK_LOGS']
506
+ bs_options[:deviceLogs] = ENV['DEVICE_LOGS'] if ENV['DEVICE_LOGS']
507
+ bs_options[:networkProfile] = ENV['NETWORK_PROFILE'] if ENV['NETWORK_PROFILE']
508
+ bs_options[:idleTimeout] = ENV['IDLE_TIMEOUT'] if ENV['IDLE_TIMEOUT']
509
+ bs_options[:resignApp] = ENV['RESIGN_APP'] if ENV['RESIGN_APP']
510
+ bs_options[:gpsLocation] = ENV['GPS_LOCATION'] if ENV['GPS_LOCATION']
511
+ bs_options[:acceptInsecureCerts] = ENV['ACCEPT_INSECURE_CERTS'] if ENV['ACCEPT_INSECURE_CERTS']
512
+ bs_options[:disableAnimations] = ENV['DISABLE_ANIMATION'] if ENV['DISABLE_ANIMATION']
513
+ bs_options[:appiumVersion] = ENV['APPIUM_VERSION'] ? ENV['APPIUM_VERSION'] : '2.4.1'
514
+
515
+ capabilities = {
516
+ platformName: ENV['BS_OS'],
517
+ 'appium:platformVersion': ENV['BS_OS_VERSION'],
518
+ 'appium:deviceName': ENV['BS_DEVICE'],
519
+ 'appium:automationName': ENV['AUTOMATION_ENGINE'],
520
+ 'appium:app': ENV['APP'],
521
+ 'bstack:options': bs_options
522
+ }
523
+ capabilities[:language] = ENV['LANGUAGE'] if ENV['LANGUAGE']
524
+ capabilities[:locale] = ENV['LOCALE'] if ENV['LOCALE']
525
+ capabilities
526
+ else
527
+ Environ.device_os = @capabilities[:platformName]
528
+ Environ.device_name = @capabilities[:'appium:deviceName']
529
+ Environ.device_os_version = @capabilities[:'appium:platformVersion']
530
+ @capabilities
531
+ end
532
+ # BrowserStack uses only real devices
533
+ Environ.device = :device
534
+ upload_app(:browserstack) if ENV['UPLOAD_APP']
535
+ options
536
+ end
537
+
538
+ # :nocov:
539
+ def self.testingbot_capabilities
540
+ Environ.device = :simulator
541
+ # specify endpoint url
542
+ @endpoint = "http://#{ENV['TB_USERNAME']}:#{ENV['TB_AUTHKEY']}@hub.testingbot.com/wd/hub" if @endpoint.nil?
543
+ # define TestingBot options
544
+ options = if @capabilities.nil?
545
+ Environ.device_name = ENV['TB_DEVICE']
546
+ Environ.device_os = ENV['TB_OS']
547
+ Environ.device_os_version = ENV['TB_OS_VERSION']
548
+ Environ.device = :device if ENV['REAL_DEVICE'] == 'true'
549
+ # define the required set of TestingBot options
550
+ tb_options = { build: test_context_message }
551
+ # define the optional TestingBot options
552
+ tb_options[:name] = ENV['AUTOMATE_PROJECT'] if ENV['AUTOMATE_PROJECT']
553
+ tb_options[:timeZone] = ENV['TIME_ZONE'] if ENV['TIME_ZONE']
554
+ tb_options['testingbot.geoCountryCode'] = ENV['IP_GEOLOCATION'] if ENV['IP_GEOLOCATION']
555
+ tb_options[:screenrecorder] = ENV['RECORD_VIDEO'] if ENV['RECORD_VIDEO']
556
+ tb_options[:screenshot] = ENV['SCREENSHOTS'] if ENV['SCREENSHOTS']
557
+ tb_options[:appiumVersion] = ENV['APPIUM_VERSION'] ? ENV['APPIUM_VERSION'] : '2.4.1'
558
+
559
+ capabilities = {
560
+ platformName: ENV['TB_OS'],
561
+ 'appium:platformVersion': ENV['TB_OS_VERSION'],
562
+ 'appium:deviceName': ENV['TB_DEVICE'],
563
+ 'appium:automationName': ENV['AUTOMATION_ENGINE'],
564
+ 'appium:app': ENV['APP'],
565
+ 'tb:options': tb_options
566
+ }
567
+ capabilities[:'appium:realDevice'] = ENV['REAL_DEVICE'] if ENV['REAL_DEVICE']
568
+ capabilities
569
+ else
570
+ Environ.device_os = @capabilities[:platformName]
571
+ Environ.device_name = @capabilities[:'appium:deviceName']
572
+ Environ.device_os_version = @capabilities[:'appium:platformVersion']
573
+ if @capabilities.key?(:'appium:realDevice') && @capabilities[:'appium:realDevice'] == true
574
+ Environ.device = :device
575
+ end
576
+ @capabilities
577
+ end
578
+
579
+ upload_app(:testingbot) if ENV['UPLOAD_APP']
580
+ options
581
+ end
582
+
583
+ def self.sauce_capabilities
584
+ # specify endpoint url
585
+ if @endpoint.nil?
586
+ @endpoint = "https://#{ENV['SL_USERNAME']}:#{ENV['SL_AUTHKEY']}@ondemand.#{ENV['SL_DATA_CENTER']}.saucelabs.com:443/wd/hub"
587
+ end
588
+ # define SauceLabs options
589
+ options = if @capabilities.nil?
590
+ Environ.device_name = ENV['SL_DEVICE']
591
+ Environ.device_os = ENV['SL_OS']
592
+ Environ.device_os_version = ENV['SL_OS_VERSION']
593
+ # define the required set of SauceLabs options
594
+ sl_options = { build: test_context_message }
595
+ # define the optional SauceLabs options
596
+ sl_options[:name] = ENV['AUTOMATE_PROJECT'] if ENV['AUTOMATE_PROJECT']
597
+ sl_options[:deviceOrientation] = ENV['ORIENTATION'].upcase if ENV['ORIENTATION']
598
+ sl_options[:recordVideo] = ENV['RECORD_VIDEO'] if ENV['RECORD_VIDEO']
599
+ sl_options[:recordScreenshots] = ENV['SCREENSHOTS'] if ENV['SCREENSHOTS']
600
+ sl_options[:appiumVersion] = ENV['APPIUM_VERSION'] ? ENV['APPIUM_VERSION'] : '2.1.3'
601
+ capabilities = {
602
+ platformName: ENV['SL_OS'],
603
+ 'appium:platformVersion': ENV['SL_OS_VERSION'],
604
+ 'appium:deviceName': ENV['SL_DEVICE'],
605
+ 'appium:automationName': ENV['AUTOMATION_ENGINE'],
606
+ 'appium:app': ENV['APP'],
607
+ 'sauce:options': sl_options
608
+ }
609
+ capabilities
610
+ else
611
+ Environ.device_os = @capabilities[:platformName]
612
+ Environ.device_name = @capabilities[:'appium:deviceName']
613
+ Environ.device_os_version = @capabilities[:'appium:platformVersion']
614
+ @capabilities
615
+ end
616
+ options
617
+ end
618
+
619
+ def self.test_context_message
620
+ context_message = if ENV['TEST_CONTEXT']
621
+ "#{Environ.test_environment.to_s.upcase} - #{ENV['TEST_CONTEXT']}"
622
+ else
623
+ Environ.test_environment.to_s.upcase
624
+ end
625
+ if ENV['PARALLEL']
626
+ thread_num = ENV['TEST_ENV_NUMBER']
627
+ thread_num = 1 if thread_num.blank?
628
+ context_message = "#{context_message} - Thread ##{thread_num}"
629
+ end
630
+ context_message
631
+ end
632
+ # :nocov:
633
+ end
634
+ end