Module: Appium::Device

Extended by:
Forwardable
Defined in:
lib/appium_lib/device/device.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.add_endpoint_method(method) ⇒ Object



393
394
395
396
397
398
# File 'lib/appium_lib/device/device.rb', line 393

def add_endpoint_method(method)
  block_given? ? create_bridge_command(method, &Proc.new) : create_bridge_command(method)

  delegate_driver_method method
  delegate_from_appium_driver method
end

.add_ime_actionsObject



488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
# File 'lib/appium_lib/device/device.rb', line 488

def add_ime_actions
  # Commands for IME are defined in the following commands.rb, but the driver have no bridge.
  # So, appium_lib define just bridge here.
  # https://github.com/SeleniumHQ/selenium/blob/selenium-3.0.1/rb/lib/selenium/webdriver/remote/commands.rb#L184-L192

  # @!method ime_activate
  #   Make an engine that is available active.
  #
  #   Android only.
  #   @param [String] The IME owning the activity [required]
  #
  #   ```ruby
  #   ime_activate engine: 'com.android.inputmethod.latin/.LatinIME'
  #   ```
  add_endpoint_method(:ime_activate) do
    def ime_activate(ime_name)
      execute :imeActivateEngine, {}, engine: ime_name
    end
  end

  # @!method ime_available_engines
  #   List all available input engines on the machine.
  #   Android only.
  #
  #   ```ruby
  #   ime_available_engines #=> Get the list of IME installed in the target device
  #   ```
  add_endpoint_method(:ime_available_engines) do
    def ime_available_engines
      execute :imeGetAvailableEngines
    end
  end

  # @!method ime_active_engine
  #   Get the name of the active IME engine.
  #   Android only.
  #
  #   ```ruby
  #   ime_active_engine #=> Get the current active IME such as 'com.android.inputmethod.latin/.LatinIME'
  #   ```
  add_endpoint_method(:ime_active_engine) do
    def ime_active_engine
      execute :imeGetActiveEngine
    end
  end

  # @!method ime_activated
  #   Indicates whether IME input is active at the moment (not if it is available).
  #   Android only.
  #
  #   ```ruby
  #   ime_activated #=> True if IME is activated
  #   ```
  add_endpoint_method(:ime_activated) do
    def ime_activated
      execute :imeIsActivated
    end
  end

  # @!method ime_deactivate
  #   De-activates the currently-active IME engine.
  #
  #   Android only.
  #
  #   ```ruby
  #   ime_deactivate #=> Deactivate current IME engine
  #   ```
  add_endpoint_method(:ime_deactivate) do
    def ime_deactivate
      execute :imeDeactivate, {}
    end
  end
end

.add_touch_actionsObject



465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
# File 'lib/appium_lib/device/device.rb', line 465

def add_touch_actions
  add_endpoint_method(:touch_actions) do
    def touch_actions(actions)
      actions = { actions: [actions].flatten }
      execute :touch_actions, {}, actions
    end
  end

  add_endpoint_method(:multi_touch) do
    def multi_touch(actions)
      execute :multi_touch, {}, actions: actions
    end
  end

  actions = Appium::TouchAction::COMPLEX_ACTIONS
  actions.each do |method|
    delegate_from_appium_driver(method, Appium::TouchAction)
  end

  delegate_from_appium_driver(:pinch, Appium::MultiTouch)
  delegate_from_appium_driver(:zoom, Appium::MultiTouch)
end

.create_bridge_command(method) ⇒ Object



420
421
422
423
424
# File 'lib/appium_lib/device/device.rb', line 420

def create_bridge_command(method)
  Selenium::WebDriver::Remote::Bridge.class_eval do
    block_given? ? class_eval(&Proc.new) : define_method(method) { execute method }
  end
end

.delegate_driver_method(method) ⇒ Object



409
410
411
412
# File 'lib/appium_lib/device/device.rb', line 409

def delegate_driver_method(method)
  return if Selenium::WebDriver::Driver.method_defined? method
  Selenium::WebDriver::Driver.class_eval { def_delegator :@bridge, method }
end

.delegate_from_appium_driver(method, delegation_target = :driver) ⇒ Object



415
416
417
# File 'lib/appium_lib/device/device.rb', line 415

def delegate_from_appium_driver(method, delegation_target = :driver)
  def_delegator delegation_target, method
end

.extend_search_contextsObject



434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
# File 'lib/appium_lib/device/device.rb', line 434

def extend_search_contexts
  Selenium::WebDriver::SearchContext.class_eval do
    def find_element(*args)
      how, what = extract_args(args)
      by = _set_by_from_finders(how)
      begin
        bridge.find_element_by by, what.to_s, ref
      rescue Selenium::WebDriver::Error::TimeOutError
        raise Selenium::WebDriver::Error::NoSuchElementError
      end
    end

    def find_elements(*args)
      how, what = extract_args(args)
      by = _set_by_from_finders(how)
      begin
        bridge.find_elements_by by, what.to_s, ref
      rescue Selenium::WebDriver::Error::TimeOutError
        raise Selenium::WebDriver::Error::NoSuchElementError
      end
    end

    def _set_by_from_finders(how)
      finders = ::Selenium::WebDriver::SearchContext::FINDERS.merge ::Appium::Driver::SearchContext::FINDERS
      by = finders[how.to_sym]
      raise ArgumentError, "cannot find element by #{how.inspect}" unless by
      by
    end
  end
end

.extend_webdriver_with_forwardableObject



401
402
403
404
405
406
# File 'lib/appium_lib/device/device.rb', line 401

def extend_webdriver_with_forwardable
  return if Selenium::WebDriver::Driver.is_a? Forwardable
  Selenium::WebDriver::Driver.class_eval do
    extend Forwardable
  end
end

.extended(_mod) ⇒ Object



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
# File 'lib/appium_lib/device/device.rb', line 192

def extended(_mod)
  extend_webdriver_with_forwardable

  ::Appium::Driver::Commands::COMMAND_NO_ARG.each_key do |method|
    add_endpoint_method method
  end

  add_endpoint_method(:available_contexts) do
    def available_contexts
      # return empty array instead of nil on failure
      execute(:available_contexts, {}) || []
    end
  end

  add_endpoint_method(:app_strings) do
    def app_strings(language = nil)
      opts = language ? { language: language } : {}
      execute :app_strings, {}, opts
    end
  end

  add_endpoint_method(:lock) do
    def lock(duration)
      execute :lock, {}, seconds: duration
    end
  end

  add_endpoint_method(:install_app) do
    def install_app(path)
      execute :install_app, {}, appPath: path
    end
  end

  add_endpoint_method(:remove_app) do
    def remove_app(id)
      execute :remove_app, {}, appId: id
    end
  end

  add_endpoint_method(:app_installed?) do
    def app_installed?(app_id)
      execute :app_installed?, {}, bundleId: app_id
    end
  end

  add_endpoint_method(:background_app) do
    def background_app(duration = 0)
      # https://github.com/appium/ruby_lib/issues/500, https://github.com/appium/appium/issues/7741
      if $driver.automation_name_is_xcuitest? && $driver.appium_server_status['build']['version'] >= '1.6.4'
        duration_milli_sec = duration.nil? ? nil : duration * 1000
        execute :background_app, {}, seconds: { timeout: duration_milli_sec }
      else
        execute :background_app, {}, seconds: duration
      end
    end
  end

  add_endpoint_method(:start_activity) do
    def start_activity(opts)
      raise 'opts must be a hash' unless opts.is_a? Hash
      app_package = opts[:app_package]
      raise 'app_package is required' unless app_package
      app_activity = opts[:app_activity]
      raise 'app_activity is required' unless app_activity
      app_wait_package  = opts.fetch(:app_wait_package, '')
      app_wait_activity = opts.fetch(:app_wait_activity, '')

      unknown_opts = opts.keys - [:app_package, :app_activity, :app_wait_package, :app_wait_activity]
      raise "Unknown options #{unknown_opts}" unless unknown_opts.empty?

      execute :start_activity, {}, appPackage: app_package,
                                   appActivity: app_activity,
                                   appWaitPackage: app_wait_package,
                                   appWaitActivity: app_wait_activity
    end
  end

  add_endpoint_method(:set_context) do
    def set_context(context = null)
      execute :set_context, {}, name: context
    end
  end

  add_endpoint_method(:hide_keyboard) do
    def hide_keyboard(close_key = nil)
      # Android can only tapOutside.
      if $driver.device_is_android?
        return execute :hide_keyboard, {}, strategy: :tapOutside
      end

      close_key ||= 'Done' # default to Done key.
      if $driver.automation_name_is_xcuitest?
        # strategy is not implemented in the following
        # https://github.com/appium/appium-xcuitest-driver/blob/v2.2.0/lib/commands/general.js#L51
        execute :hide_keyboard, {}, strategy: :grouped, key: close_key
      else
        $driver.hide_ios_keyboard close_key
      end
    end
  end

  add_endpoint_method(:press_keycode) do
    def press_keycode(key, metastate = nil)
      args             = { keycode: key }
      args[:metastate] = metastate if metastate
      execute :press_keycode, {}, args
    end
  end

  add_endpoint_method(:long_press_keycode) do
    def long_press_keycode(key, metastate = nil)
      args             = { keycode: key }
      args[:metastate] = metastate if metastate
      execute :long_press_keycode, {}, args
    end
  end

  add_endpoint_method(:set_immediate_value) do
    def set_immediate_value(element, *value)
      keys = ::Selenium::WebDriver::Keys.encode(value)
      execute :set_immediate_value, { id: element.ref }, value: Array(keys)
    end
  end

  add_endpoint_method(:push_file) do
    def push_file(path, filedata)
      encoded_data = Base64.encode64 filedata
      execute :push_file, {}, path: path, data: encoded_data
    end
  end

  add_endpoint_method(:pull_file) do
    def pull_file(path)
      data = execute :pull_file, {}, path: path
      Base64.decode64 data
    end
  end

  # TODO: TEST ME
  add_endpoint_method(:pull_folder) do
    def pull_folder(path)
      data = execute :pull_folder, {}, path: path
      Base64.decode64 data
    end
  end

  # TODO: TEST ME
  add_endpoint_method(:touch_id) do
    def touch_id(match = true)
      execute :touch_id, {}, match: match
    end
  end

  # TODO: TEST ME
  add_endpoint_method(:toggle_touch_id_enrollment) do
    def toggle_touch_id_enrollment
      execute :toggle_touch_id_enrollment, {}
    end
  end

  # TODO: TEST ME
  add_endpoint_method(:end_coverage) do
    def end_coverage(path, intent)
      execute :end_coverage, {}, path: path, intent: intent
    end
  end

  add_endpoint_method(:get_settings) do
    def get_settings
      execute :get_settings, {}
    end
  end

  add_endpoint_method(:update_settings) do
    def update_settings(settings)
      execute :update_settings, {}, settings: settings
    end
  end

  add_endpoint_method(:set_network_connection) do
    def set_network_connection(mode)
      execute :set_network_connection, {}, type: mode
    end
  end

  add_endpoint_method(:get_performance_data) do
    def get_performance_data(package_name:, data_type:, data_read_timeout: 1000)
      execute :get_performance_data, {}, packageName: package_name,
                                         dataType: data_type,
                                         dataReadTimeout: data_read_timeout
    end
  end

  add_touch_actions
  add_ime_actions
  extend_search_contexts
end

.find_element_with_appiumObject



434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
# File 'lib/appium_lib/device/device.rb', line 434

def extend_search_contexts
  Selenium::WebDriver::SearchContext.class_eval do
    def find_element(*args)
      how, what = extract_args(args)
      by = _set_by_from_finders(how)
      begin
        bridge.find_element_by by, what.to_s, ref
      rescue Selenium::WebDriver::Error::TimeOutError
        raise Selenium::WebDriver::Error::NoSuchElementError
      end
    end

    def find_elements(*args)
      how, what = extract_args(args)
      by = _set_by_from_finders(how)
      begin
        bridge.find_elements_by by, what.to_s, ref
      rescue Selenium::WebDriver::Error::TimeOutError
        raise Selenium::WebDriver::Error::NoSuchElementError
      end
    end

    def _set_by_from_finders(how)
      finders = ::Selenium::WebDriver::SearchContext::FINDERS.merge ::Appium::Driver::SearchContext::FINDERS
      by = finders[how.to_sym]
      raise ArgumentError, "cannot find element by #{how.inspect}" unless by
      by
    end
  end
end

.find_elements_with_appiumObject

find_element/s_with_appium with their accessibility_id

“‘ruby

find_elements :accessibility_id, 'Animation'

“‘



434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
# File 'lib/appium_lib/device/device.rb', line 434

def extend_search_contexts
  Selenium::WebDriver::SearchContext.class_eval do
    def find_element(*args)
      how, what = extract_args(args)
      by = _set_by_from_finders(how)
      begin
        bridge.find_element_by by, what.to_s, ref
      rescue Selenium::WebDriver::Error::TimeOutError
        raise Selenium::WebDriver::Error::NoSuchElementError
      end
    end

    def find_elements(*args)
      how, what = extract_args(args)
      by = _set_by_from_finders(how)
      begin
        bridge.find_elements_by by, what.to_s, ref
      rescue Selenium::WebDriver::Error::TimeOutError
        raise Selenium::WebDriver::Error::NoSuchElementError
      end
    end

    def _set_by_from_finders(how)
      finders = ::Selenium::WebDriver::SearchContext::FINDERS.merge ::Appium::Driver::SearchContext::FINDERS
      by = finders[how.to_sym]
      raise ArgumentError, "cannot find element by #{how.inspect}" unless by
      by
    end
  end
end

Instance Method Details

#app_stringsObject

Return the hash of all localization strings. “‘ruby app_strings #=> “TransitionsTitle”=>“Transitions”, “WebTitle”=>“Web” “`



# File 'lib/appium_lib/device/device.rb', line 7


#available_contextsArray<String>

Returns All usable contexts, as an array of strings.

Returns:

  • (Array<String>)

    All usable contexts, as an array of strings.



# File 'lib/appium_lib/device/device.rb', line 574


#background_appObject

Backgrounds the app for a set number of seconds. This is a blocking application



# File 'lib/appium_lib/device/device.rb', line 13


#current_activityObject



# File 'lib/appium_lib/device/device.rb', line 24


#current_contextString

Returns The context currently being used.

Returns:

  • (String)

    The context currently being used.



# File 'lib/appium_lib/device/device.rb', line 571


#device_locked?Object



# File 'lib/appium_lib/device/device.rb', line 62


#end_coverageObject

Android only; Ends the test coverage and writes the results to the given path on device.

Parameters:

  • path (String)

    Path on the device to write too.

  • intent (String)

    Intent to broadcast when ending coverage.



# File 'lib/appium_lib/device/device.rb', line 120


#get_display_densityInteger

Get connected device’s density. “‘ruby get_display_density # 320 “`

Returns:

  • (Integer)

    The size of density



# File 'lib/appium_lib/device/device.rb', line 34


#get_network_connectionObject

Get the device network connection current status See set_network_connection method for return value



# File 'lib/appium_lib/device/device.rb', line 146


#get_performance_data_typesObject

Get the information type of the system state which is supported to read such as cpu, memory, network, battery via adb commands. github.com/appium/appium-base-driver/blob/be29aec2318316d12b5c3295e924a5ba8f09b0fb/lib/mjsonwp/routes.js#L300

“‘ruby get_performance_data_types #=> [“cpuinfo”, “batteryinfo”, “networkinfo”, “memoryinfo”] “`



# File 'lib/appium_lib/device/device.rb', line 172


#get_settingsObject

Get appium Settings for current test session



# File 'lib/appium_lib/device/device.rb', line 125


#get_system_barsString

Get system bar’s information “‘ruby get_system_bars “`

Returns:

  • (String)

    System bar



# File 'lib/appium_lib/device/device.rb', line 26


#hide_keyboardObject

Hide the onscreen keyboard

Parameters:

  • close_key (String)

    The name of the key which closes the keyboard. Defaults to ‘Done’.



# File 'lib/appium_lib/device/device.rb', line 64


#is_keyboard_shownBool

Get whether keyboard is displayed or not. “‘ruby is_keyboard_shown # false “`

Returns:

  • (Bool)

    Return true if keyboard is shown. Return false if keyboard is hidden.



# File 'lib/appium_lib/device/device.rb', line 42


#launch_appObject

Start the simulator and application configured with desired capabilities



# File 'lib/appium_lib/device/device.rb', line 50


#long_press_keycodeObject

Parameters:

  • key (integer)

    The key to long press.

  • metastate (String)

    The state the metakeys should be in when long pressing the key.



# File 'lib/appium_lib/device/device.rb', line 79


#press_keycodeObject

Parameters:

  • key (integer)

    The key to press.

  • metastate (String)

    The state the metakeys should be in when pressing the key.



# File 'lib/appium_lib/device/device.rb', line 73


#pull_fileObject

Retrieve a file from the device. This can retrieve an absolute path or a path relative to the installed app (iOS only). “‘ruby pull_file ’/local/data/some/path’ #=> Get the file at that path pull_file ‘Shenanigans.app/some/file’ #=> Get ‘some/file’ from the install location of Shenanigans.app “‘

Parameters:

  • path (String)

    Either an absolute path OR, for iOS devices, a path relative to the app, as described.



# File 'lib/appium_lib/device/device.rb', line 90


#pull_folderObject

Retrieve a folder from the device. “‘ruby pull_folder ’/data/local/tmp’ #=> Get the folder at that path “‘

Parameters:

  • path (String)

    absolute path to the folder



# File 'lib/appium_lib/device/device.rb', line 100


#push_fileObject

Place a file in a specific location on the device.

Parameters:

  • path (String)

    The absolute path on the device to store data at.

  • data (String)

    Raw file data to be sent to the device.



# File 'lib/appium_lib/device/device.rb', line 85


#resetObject

Reset the device, relaunching the application.



# File 'lib/appium_lib/device/device.rb', line 53


#set_contextObject

Change the context to the given context. “‘ruby set_context “NATIVE_APP” “`

Parameters:

  • The (String)

    context to change to



# File 'lib/appium_lib/device/device.rb', line 563


#set_immediate_valueObject

Set the value to element directly for iOS; setValue is called in XCUITest instead because XCUITest doesn’t provide set value directly. github.com/appium/appium-xcuitest-driver/blob/793cdc7d5e84bd553e375076e1c6dc7e242c9cde/lib/commands/element.js#L123

“‘ruby set_immediate_value element, ’hello’ “‘



# File 'lib/appium_lib/device/device.rb', line 163


#set_network_connectionObject

Set the device network connection mode Value (Alias) | Data | Wifi | Airplane Mode


1 (Airplane Mode) | 0 | 0 | 1 6 (All network on) | 1 | 1 | 0 4 (Data only) | 1 | 0 | 0 2 (Wifi only) | 0 | 1 | 0 0 (None) | 0 | 0 | 0

Parameters:

  • path (String)

    Bit mask that represent the network mode



# File 'lib/appium_lib/device/device.rb', line 150


#shakeObject

Cause the device to shake



# File 'lib/appium_lib/device/device.rb', line 56


#start_activityObject

Start a new activity within the current app or launch a new app and start the target activity.

Android only. “‘ruby start_activity app_package: ’io.appium.android.apis’,

app_activity: '.accessibility.AccessibilityNodeProviderActivity'

“‘



# File 'lib/appium_lib/device/device.rb', line 132


#switch_to_default_contextObject

Change to the default context. This is equivalent to ‘set_context nil`.



592
593
594
# File 'lib/appium_lib/device/device.rb', line 592

def switch_to_default_context
  set_context nil
end

#toggle_flight_modeObject

Toggle flight mode on or off



# File 'lib/appium_lib/device/device.rb', line 59


#toggle_touch_id_enrollmentObject

iOS Simulator only: Toggle touch id enrollment on an iOS Simulator.



# File 'lib/appium_lib/device/device.rb', line 117


#touch_idObject

iOS only; Simulate Touch ID with either valid (match == true) or invalid (match == false) fingerprint. “‘ruby touch_id true #=> Simulate valid fingerprint touch_id false #=> Simulate invalid fingerprint “`

Parameters:

  • match (Boolean)

    fingerprint validity Defaults to true.



# File 'lib/appium_lib/device/device.rb', line 108


#update_settingsObject

Update appium Settings for current test session

Parameters:

  • settings (Hash)

    Settings to update, keys are settings, values to value to set each setting to



# File 'lib/appium_lib/device/device.rb', line 128


#within_context(context) ⇒ Object

Perform a block within the given context, then switch back to the starting context. “‘ruby within_context(’NATIVE_APP’) do

find_element [:tag, "button"]

“‘

Parameters:

  • context (String)

    The context to switch to for the duration of the block.



584
585
586
587
588
589
# File 'lib/appium_lib/device/device.rb', line 584

def within_context(context)
  existing_context = current_context
  set_context context
  yield if block_given?
  set_context existing_context
end