appium_lib 9.6.1 → 9.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -2
  3. data/CHANGELOG.md +43 -0
  4. data/Rakefile +1 -1
  5. data/appium_lib.gemspec +1 -1
  6. data/docs/android_docs.md +440 -1295
  7. data/docs/docs.md +10 -103
  8. data/docs/index_paths.md +2 -0
  9. data/docs/ios_docs.md +725 -1674
  10. data/docs/migration.md +17 -0
  11. data/lib/appium_lib.rb +1 -2
  12. data/lib/appium_lib/android/android.rb +20 -0
  13. data/lib/appium_lib/android/{helper.rb → common/helper.rb} +1 -1
  14. data/lib/appium_lib/android/uiautomator2.rb +5 -4
  15. data/lib/appium_lib/android/uiautomator2/bridge.rb +16 -0
  16. data/lib/appium_lib/appium.rb +201 -0
  17. data/lib/appium_lib/common/helper.rb +18 -20
  18. data/lib/appium_lib/common/log.rb +24 -0
  19. data/lib/appium_lib/common/multi_touch.rb +89 -0
  20. data/lib/appium_lib/common/touch_actions.rb +48 -0
  21. data/lib/appium_lib/common/wait.rb +10 -49
  22. data/lib/appium_lib/core/android.rb +4 -0
  23. data/lib/appium_lib/core/android/device.rb +142 -0
  24. data/lib/appium_lib/core/android/search_context.rb +17 -0
  25. data/lib/appium_lib/core/android/uiautomator1/bridge.rb +16 -0
  26. data/lib/appium_lib/core/android/uiautomator2/bridge.rb +16 -0
  27. data/lib/appium_lib/core/android_uiautomator2.rb +4 -0
  28. data/lib/appium_lib/core/common.rb +6 -0
  29. data/lib/appium_lib/core/common/base.rb +8 -0
  30. data/lib/appium_lib/core/common/base/bridge.rb +47 -0
  31. data/lib/appium_lib/core/common/base/capabilities.rb +16 -0
  32. data/lib/appium_lib/core/common/base/command.rb +10 -0
  33. data/lib/appium_lib/core/common/base/driver.rb +40 -0
  34. data/lib/appium_lib/core/common/base/http_default.rb +12 -0
  35. data/lib/appium_lib/core/common/base/search_context.rb +89 -0
  36. data/lib/appium_lib/core/common/base/wait.rb +56 -0
  37. data/lib/appium_lib/{common → core/common}/command.rb +20 -16
  38. data/lib/appium_lib/core/common/device.rb +470 -0
  39. data/lib/appium_lib/core/common/error.rb +13 -0
  40. data/lib/appium_lib/core/common/log.rb +30 -0
  41. data/lib/appium_lib/{logger.rb → core/common/logger.rb} +2 -0
  42. data/lib/appium_lib/core/core.rb +38 -0
  43. data/lib/appium_lib/core/device/multi_touch.rb +213 -0
  44. data/lib/appium_lib/core/device/touch_actions.rb +206 -0
  45. data/lib/appium_lib/core/driver.rb +274 -0
  46. data/lib/appium_lib/core/ios.rb +6 -0
  47. data/lib/appium_lib/core/ios/device.rb +44 -0
  48. data/lib/appium_lib/core/ios/search_context.rb +27 -0
  49. data/lib/appium_lib/core/ios/uiautomation/bridge.rb +17 -0
  50. data/lib/appium_lib/core/ios/uiautomation/patch.rb +20 -0
  51. data/lib/appium_lib/core/ios/xcuitest/bridge.rb +18 -0
  52. data/lib/appium_lib/{ios → core/ios}/xcuitest/device.rb +5 -5
  53. data/lib/appium_lib/{ios → core/ios}/xcuitest/search_context.rb +13 -9
  54. data/lib/appium_lib/core/ios_xcuitest.rb +7 -0
  55. data/lib/appium_lib/core/patch.rb +56 -0
  56. data/lib/appium_lib/driver.rb +174 -446
  57. data/lib/appium_lib/ios/{errors.rb → common/errors.rb} +0 -0
  58. data/lib/appium_lib/ios/{helper.rb → common/helper.rb} +9 -110
  59. data/lib/appium_lib/ios/ios.rb +20 -0
  60. data/lib/appium_lib/ios/xcuitest.rb +1 -3
  61. data/lib/appium_lib/ios/xcuitest/bridge.rb +19 -0
  62. data/lib/appium_lib/ios/xcuitest/command.rb +4 -1
  63. data/lib/appium_lib/ios/xcuitest/{gestures.rb → command/gestures.rb} +1 -1
  64. data/lib/appium_lib/ios/xcuitest/element.rb +1 -18
  65. data/lib/appium_lib/ios/xcuitest/helper.rb +0 -6
  66. data/lib/appium_lib/sauce_labs.rb +29 -0
  67. data/lib/appium_lib/version.rb +5 -0
  68. data/release_notes.md +8 -0
  69. metadata +50 -25
  70. data/lib/appium_lib/android/client_xpath.rb +0 -51
  71. data/lib/appium_lib/android/device.rb +0 -39
  72. data/lib/appium_lib/android/mobile_methods.rb +0 -15
  73. data/lib/appium_lib/android/patch.rb +0 -16
  74. data/lib/appium_lib/capabilities.rb +0 -13
  75. data/lib/appium_lib/common/element/window.rb +0 -10
  76. data/lib/appium_lib/common/error.rb +0 -8
  77. data/lib/appium_lib/common/patch.rb +0 -190
  78. data/lib/appium_lib/common/search_context.rb +0 -10
  79. data/lib/appium_lib/common/version.rb +0 -5
  80. data/lib/appium_lib/device/device.rb +0 -611
  81. data/lib/appium_lib/device/multi_touch.rb +0 -225
  82. data/lib/appium_lib/device/touch_actions.rb +0 -230
  83. data/lib/appium_lib/ios/mobile_methods.rb +0 -25
  84. data/lib/appium_lib/ios/patch.rb +0 -22
@@ -1,51 +0,0 @@
1
- require 'nokogiri'
2
-
3
- module Appium
4
- module Android
5
- def _nodeset_to_uiselector(opts = {})
6
- results = ''
7
-
8
- nodes = opts[:nodes]
9
- first = opts[:first]
10
-
11
- nodes = [nodes[0]] if first
12
-
13
- nodes.each do |node|
14
- results += %(new UiSelector().className("#{node.name}").instance(#{node.attr('instance')});)
15
- end
16
-
17
- results.strip
18
- end
19
-
20
- def _client_xpath(opts = {})
21
- root_node = Nokogiri::XML(get_source).children.first
22
-
23
- instance = Hash.new(-1)
24
-
25
- root_node.traverse do |node|
26
- number = instance[node.name] += 1
27
- node.set_attribute 'instance', number
28
- end
29
-
30
- nodes = root_node.xpath(opts[:xpath])
31
- first = opts[:first]
32
-
33
- _nodeset_to_uiselector nodes: nodes, first: first
34
- end
35
-
36
- # @deprecated Please use :uiautomator or :xpath strategy directly
37
- def client_xpath(xpath)
38
- warn '[DEPRECATION] client_xpath will be removed. Please use :uiautomator or :xpath strategy directly.'
39
- find_element :uiautomator, _client_xpath(xpath: xpath, first: true)
40
- end
41
-
42
- # @deprecated Please use :uiautomator or :xpath strategy directly
43
- def client_xpaths(xpath)
44
- warn '[DEPRECATION] client_xpaths will be removed. Please use :uiautomator or :xpath strategy directly.'
45
- find_elements :uiautomator, _client_xpath(xpath: xpath, first: false)
46
- end
47
- end
48
- end
49
-
50
- # http://stackoverflow.com/questions/9199415/getting-first-node-in-xpath-result-set
51
- # '(//android.widget.TextView)[1]' not '//android.widget.TextView[1]'
@@ -1,39 +0,0 @@
1
- require 'base64'
2
-
3
- module Appium
4
- module Android
5
- module Device
6
- extend Forwardable
7
-
8
- # @!method hide_keyboard
9
- # Hide the onscreen keyboard
10
- # @param [String] close_key The name of the key which closes the keyboard.
11
- # Defaults to 'Done' for iOS(except for XCUITest).
12
- # @param [Symbol] strategy The symbol of the strategy which closes the keyboard.
13
- # XCUITest ignore this argument.
14
- # Default for iOS is `:pressKey`. Default for Android is `:tapOutside`.
15
- # ```ruby
16
- # hide_keyboard # Close a keyboard with the 'Done' button
17
- # hide_keyboard('Finished') # Close a keyboard with the 'Finished' button
18
- # hide_keyboard(nil, :tapOutside) # Close a keyboard with tapping out side of keyboard
19
- # ```
20
-
21
- class << self
22
- def extended(_mod)
23
- ::Appium::Device.extend_webdriver_with_forwardable
24
-
25
- ::Appium::Device.add_endpoint_method(:hide_keyboard) do
26
- def hide_keyboard(close_key = nil, strategy = nil)
27
- option = {}
28
-
29
- option[:key] = close_key if close_key
30
- option[:strategy] = strategy || :tapOutside # default to pressKey
31
-
32
- execute :hide_keyboard, {}, option
33
- end
34
- end
35
- end
36
- end # class << self
37
- end # module Device
38
- end # module Android
39
- end # module Appium
@@ -1,15 +0,0 @@
1
- module Appium
2
- module Android
3
- class << self
4
- # @!method uiautomator_find
5
- # find_element/s can be used with a [UISelector](http://developer.android.com/tools/help/uiautomator/UiSelector.html).
6
- #
7
- # ```ruby
8
- # find_elements :uiautomator, 'new UiSelector().clickable(true)'
9
- # ```
10
- def extended(_mod)
11
- ::Appium::Driver::SearchContext::FINDERS[:uiautomator] = '-android uiautomator'
12
- end
13
- end # class << self
14
- end # module Android
15
- end # module Appium
@@ -1,16 +0,0 @@
1
- module Appium
2
- module Android
3
- # @private
4
- # class_eval inside a method because class Selenium::WebDriver::Element
5
- # will trigger as soon as the file is required. in contrast a method
6
- # will trigger only when invoked.
7
- def patch_webdriver_element
8
- Selenium::WebDriver::Element.class_eval do
9
- # Cross platform way of entering text into a textfield
10
- def type(text)
11
- send_keys text
12
- end
13
- end
14
- end
15
- end # Android
16
- end # Appium
@@ -1,13 +0,0 @@
1
- module Appium
2
- class Driver
3
- module Capabilities
4
- # @param [Hash] opts_caps Capabilities for Appium server. All capability keys are converted to lowerCamelCase when
5
- # this client sends capabilities to Appium server as JSON format.
6
- # @return [::Selenium::WebDriver::Remote::W3C::Capabilities] Return instance of Appium::Driver::Capabilities
7
- # inherited ::Selenium::WebDriver::Remote::W3C::Capabilities
8
- def self.init_caps_for_appium(opts_caps = {})
9
- ::Selenium::WebDriver::Remote::W3C::Capabilities.new(opts_caps)
10
- end
11
- end
12
- end
13
- end
@@ -1,10 +0,0 @@
1
- # UIAWindow methods
2
- module Appium
3
- module Common
4
- # Get the window's size
5
- def window_size
6
- return nil if @driver.nil?
7
- @driver.manage.window.size
8
- end
9
- end # module Common
10
- end # module Appium
@@ -1,8 +0,0 @@
1
- module Appium
2
- module Error
3
- class NotSupportedAppiumServer < RuntimeError; end
4
-
5
- # Server side error
6
- class ServerError; end
7
- end
8
- end
@@ -1,190 +0,0 @@
1
- require_relative 'version'
2
-
3
- module Appium
4
- module Common
5
- # Implement useful features for element.
6
- class Selenium::WebDriver::Element # rubocop:disable Style/ClassAndModuleChildren
7
- # Note: For testing .text should be used over value, and name.
8
-
9
- # Returns the value attribute
10
- #
11
- # Fixes NoMethodError: undefined method `value' for Selenium::WebDriver::Element
12
- def value
13
- attribute :value
14
- end
15
-
16
- # Returns the name attribute
17
- #
18
- # Fixes NoMethodError: undefined method `name' for Selenium::WebDriver::Element
19
- def name
20
- attribute :name
21
- end
22
-
23
- # For use with mobile tap.
24
- #
25
- # ```ruby
26
- # execute_script 'mobile: tap', :x => 0.0, :y => 0.98
27
- # ```
28
- #
29
- # @return [OpenStruct] the relative x, y in a struct. ex: { x: 0.50, y: 0.20 }
30
- def location_rel(driver = $driver)
31
- # TODO: Remove with 'refine Appium ruby binding'
32
- # https://github.com/appium/ruby_lib/issues/602
33
- if ::Appium.selenium_webdriver_version_more?('3.4.0')
34
- rect = self.rect
35
- location_x = rect.x.to_f
36
- location_y = rect.y.to_f
37
-
38
- size_width = rect.width.to_f
39
- size_height = rect.height.to_f
40
- else
41
- location = self.location
42
- location_x = location.x.to_f
43
- location_y = location.y.to_f
44
-
45
- size = self.size
46
- size_width = size.width.to_f
47
- size_height = size.height.to_f
48
- end
49
-
50
- center_x = location_x + (size_width / 2.0)
51
- center_y = location_y + (size_height / 2.0)
52
-
53
- w = driver.window_size
54
- OpenStruct.new(x: "#{center_x} / #{w.width.to_f}",
55
- y: "#{center_y} / #{w.height.to_f}")
56
- end
57
- end
58
- end # module Common
59
- end # module Appium
60
-
61
- # Print JSON posted to Appium. Not scoped to an Appium module.
62
- #
63
- # Requires from lib/selenium/webdriver/remote.rb
64
- require 'selenium/webdriver/remote/capabilities'
65
- require 'selenium/webdriver/remote/w3c/capabilities'
66
- require 'selenium/webdriver/remote/bridge'
67
- require 'selenium/webdriver/remote/oss/bridge'
68
- require 'selenium/webdriver/remote/w3c/bridge'
69
- require 'selenium/webdriver/remote/server_error'
70
- require 'selenium/webdriver/remote/response'
71
- require 'selenium/webdriver/remote/oss/commands'
72
- require 'selenium/webdriver/remote/w3c/commands'
73
- require 'selenium/webdriver/remote/http/common'
74
- require 'selenium/webdriver/remote/http/default'
75
-
76
- # @private
77
- # Show http calls to the Selenium server.
78
- #
79
- # Invaluable for debugging.
80
- def patch_webdriver_bridge
81
- Selenium::WebDriver::Remote::Bridge.class_eval do
82
- # Code from lib/selenium/webdriver/remote/bridge.rb
83
-
84
- def execute(command, opts = {}, command_hash = nil)
85
- verb, path = commands(command) || raise(ArgumentError, "unknown command: #{command.inspect}")
86
- path = path.dup
87
-
88
- path[':session_id'] = @session_id if path.include?(':session_id')
89
-
90
- begin
91
- opts.each do |key, value|
92
- path[key.inspect] = escaper.escape(value.to_s)
93
- end
94
- rescue IndexError
95
- raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
96
- end
97
-
98
- # convert /// into /
99
- path.gsub!(/\/+/, '/')
100
-
101
- # change path from session/efac972c-941a-499c-803c-d7d008749/execute
102
- # to /execute
103
- # path may be nil, session, or not have anything after the session_id.
104
- path_str = path
105
- path_str = '/' + path_str unless path_str.nil? || path_str.length <= 0 || path_str[0] == '/'
106
- path_match = path.match(/.*\h{8}-?\h{4}-?\h{4}-?\h{4}-?\h{12}/)
107
- path_str = path.sub(path_match[0], '') unless path_match.nil?
108
-
109
- Appium::Logger.info "#{verb} #{path_str}"
110
-
111
- # must check to see if command_hash is a hash. sometimes it's not.
112
- if command_hash.is_a?(Hash) && !command_hash.empty?
113
- print_command = command_hash.clone
114
-
115
- print_command.delete :args if print_command[:args] == []
116
-
117
- if print_command[:using] == '-android uiautomator'
118
- value = print_command[:value].split(';').map { |v| "#{v};" }
119
- print_command[:value] = value.length == 1 ? value[0] : value
120
-
121
- # avoid backslash escape quotes in strings. "\"a\"" => "a"
122
- Appium::Logger.info print_command.ai.gsub('\"', '"')
123
- else
124
- Appium::Logger.ap_info print_command
125
- end
126
- elsif command_hash
127
- # non-standard command hash
128
- # It's important to output this for debugging problems.
129
- # for example invalid JSON will not be a Hash
130
- Appium::Logger.ap_info command_hash
131
- end
132
-
133
- if !$driver.nil? && $driver.global_webdriver_http_sleep
134
- warn '[DEPRECATION] global_webdriver_http_sleep will be removed. Please arrange with timeout.'
135
-
136
- delay = $driver.global_webdriver_http_sleep
137
- sleep delay if delay > 0
138
- end
139
- # Appium::Logger.info "verb: #{verb}, path #{path}, command_hash #{command_hash.to_json}"
140
- http.call(verb, path, command_hash)
141
- end # def
142
- end # class
143
- end
144
-
145
- # Print Appium's origValue error messages.
146
- # rubocop:disable Style/ClassAndModuleChildren
147
- # rubocop:disable Style/AndOr
148
- class Selenium::WebDriver::Remote::Response
149
- # @private
150
- def error_message
151
- val = value
152
-
153
- case val
154
- when Hash
155
- msg = val['origValue'] || val['message'] or return 'unknown error'
156
- msg << ": #{val['alert']['text'].inspect}" if val['alert'].is_a?(Hash) && val['alert']['text']
157
- msg << " (#{val['class']})" if val['class']
158
- when String
159
- msg = val
160
- else
161
- msg = "unknown error, status=#{status}: #{val.inspect}"
162
- end
163
-
164
- msg
165
- end
166
- end
167
-
168
- class Selenium::WebDriver::Remote::Http::Common # rubocop:disable Style/ClassAndModuleChildren
169
- remove_const :DEFAULT_HEADERS if defined? DEFAULT_HEADERS
170
- DEFAULT_HEADERS = { 'Accept' => CONTENT_TYPE, 'User-Agent' => "appium/ruby_lib/#{::Appium::VERSION}" }.freeze
171
- end
172
-
173
- def patch_remote_driver_commands
174
- Selenium::WebDriver::Remote::OSS::Bridge.class_eval do
175
- def commands(command)
176
- ::Appium::Driver::Commands::COMMANDS_EXTEND_OSS[command]
177
- end
178
- end
179
-
180
- Selenium::WebDriver::Remote::W3C::Bridge.class_eval do
181
- def commands(command)
182
- case command
183
- when :status, :is_element_displayed
184
- ::Appium::Driver::Commands::COMMANDS_EXTEND_OSS[command]
185
- else
186
- ::Appium::Driver::Commands::COMMANDS_EXTEND_W3C[command]
187
- end
188
- end
189
- end
190
- end
@@ -1,10 +0,0 @@
1
- module Appium
2
- class Driver
3
- module SearchContext
4
- # rubocop:disable Style/MutableConstant
5
- FINDERS = {
6
- accessibility_id: 'accessibility id'
7
- }
8
- end
9
- end
10
- end
@@ -1,5 +0,0 @@
1
- module Appium
2
- # Version and Date are defined on the 'Appium' module, not 'Appium::Common'
3
- VERSION = '9.6.1'.freeze unless defined? ::Appium::VERSION
4
- DATE = '2017-08-27'.freeze unless defined? ::Appium::DATE
5
- end
@@ -1,611 +0,0 @@
1
- require 'base64'
2
-
3
- module Appium
4
- module Device
5
- extend Forwardable
6
-
7
- # @!method app_strings
8
- # Return the hash of all localization strings.
9
- # ```ruby
10
- # app_strings #=> "TransitionsTitle"=>"Transitions", "WebTitle"=>"Web"
11
- # ```
12
-
13
- # @!method background_app
14
- # Backgrounds the app for a set number of seconds.
15
- # This is a blocking application
16
- # @param [Integer] seconds How many seconds to background the app for.
17
- #
18
- # ```ruby
19
- # background_app
20
- # background_app(5)
21
- # background_app(-1) #=> the app never come back. https://github.com/appium/appium/issues/7741
22
- # ```
23
-
24
- # @!method current_activity
25
- # Get current activity name
26
- # @return [String] An activity name
27
- #
28
- # ```ruby
29
- # current_activity # '.ApiDemos'
30
- # ```
31
-
32
- # @!method current_package
33
- # Get current package name
34
- # @return [String] A package name
35
- #
36
- # ```ruby
37
- # current_package # 'com.example.android.apis'
38
- # ```
39
-
40
- # @!method get_system_bars
41
- # Get system bar's information
42
- # @return [String] System bar
43
- #
44
- # ```ruby
45
- # get_system_bars
46
- # ```
47
-
48
- # @!method get_display_density
49
- # Get connected device's density.
50
- # @return [Integer] The size of density
51
- #
52
- # ```ruby
53
- # get_display_density # 320
54
- # ```
55
-
56
- # @!method is_keyboard_shown
57
- # Get whether keyboard is displayed or not.
58
- # @return [Bool] Return true if keyboard is shown. Return false if keyboard is hidden.
59
- #
60
- # ```ruby
61
- # is_keyboard_shown # false
62
- # ```
63
-
64
- # @!method launch_app
65
- # Start the simulator and application configured with desired capabilities
66
-
67
- # @!method reset
68
- # Reset the device, relaunching the application.
69
-
70
- # @!method shake
71
- # Cause the device to shake
72
-
73
- # @!method toggle_flight_mode
74
- # Toggle flight mode on or off
75
-
76
- # @!method device_locked?
77
-
78
- # @!method hide_keyboard
79
- # Hide the onscreen keyboard
80
- # @param [String] close_key The name of the key which closes the keyboard.
81
- # Defaults to 'Done' for iOS(except for XCUITest).
82
- # @param [Symbol] strategy The symbol of the strategy which closes the keyboard.
83
- # XCUITest ignore this argument.
84
- # Default for iOS is `:pressKey`. Default for Android is `:tapOutside`.
85
- # ```ruby
86
- # hide_keyboard # Close a keyboard with the 'Done' button
87
- # hide_keyboard('Finished') # Close a keyboard with the 'Finished' button
88
- # hide_keyboard(nil, :tapOutside) # Close a keyboard with tapping out side of keyboard
89
- # ```
90
-
91
- # @!method press_keycode
92
- # Press keycode on the device.
93
- # http://developer.android.com/reference/android/view/KeyEvent.html
94
- # @param [integer] key The key to press.
95
- # @param [String] metastate The state the metakeys should be in when pressing the key.
96
-
97
- # @!method long_press_keycode
98
- # Long press keycode on the device.
99
- # http://developer.android.com/reference/android/view/KeyEvent.html
100
- # @param [integer] key The key to long press.
101
- # @param [String] metastate The state the metakeys should be in when long pressing the key.
102
-
103
- # @!method push_file
104
- # Place a file in a specific location on the device.
105
- # @param [String] path The absolute path on the device to store data at.
106
- # @param [String] data Raw file data to be sent to the device.
107
-
108
- # @!method pull_file
109
- # Retrieve a file from the device. This can retrieve an absolute path or
110
- # a path relative to the installed app (iOS only).
111
- # @param [String] path Either an absolute path OR, for iOS devices, a path relative to the app, as described.
112
- #
113
- # ```ruby
114
- # pull_file '/local/data/some/path' #=> Get the file at that path
115
- # pull_file 'Shenanigans.app/some/file' #=> Get 'some/file' from the install location of Shenanigans.app
116
- # ```
117
-
118
- # @!method pull_folder
119
- # Retrieve a folder from the device.
120
- # @param [String] path absolute path to the folder
121
- #
122
- # ```ruby
123
- # pull_folder '/data/local/tmp' #=> Get the folder at that path
124
- # ```
125
-
126
- # @!method touch_id
127
- # iOS only; Simulate Touch ID with either valid (match == true) or invalid (match == false) fingerprint.
128
- # @param [Boolean] match fingerprint validity
129
- # Defaults to true.
130
- # ```ruby
131
- # touch_id true #=> Simulate valid fingerprint
132
- # touch_id false #=> Simulate invalid fingerprint
133
- # ```
134
-
135
- # @!method toggle_touch_id_enrollment
136
- # iOS Simulator only: Toggle touch id enrollment on an iOS Simulator.
137
-
138
- # @!method end_coverage
139
- # Android only; Ends the test coverage and writes the results to the given path on device.
140
- # @param [String] path Path on the device to write too.
141
- # @param [String] intent Intent to broadcast when ending coverage.
142
-
143
- # @!method get_settings
144
- # Get appium Settings for current test session
145
-
146
- # @!method update_settings
147
- # Update appium Settings for current test session
148
- # @param [Hash] settings Settings to update, keys are settings, values to value to set each setting to
149
-
150
- # @!method start_activity
151
- # Start a new activity within the current app or launch a new app and start the target activity.
152
- #
153
- # Android only.
154
- # @option [String] The package owning the activity [required]
155
- # @option [String] The target activity [required]
156
- # @option opts [String] The package to start before the target package [optional]
157
- # @option opts [String] The activity to start before the target activity [optional]
158
- #
159
- # ```ruby
160
- # start_activity app_package: 'io.appium.android.apis',
161
- # app_activity: '.accessibility.AccessibilityNodeProviderActivity'
162
- # ```
163
-
164
- # @!method get_network_connection
165
- # Get the device network connection current status
166
- # See set_network_connection method for return value
167
-
168
- # @!method set_network_connection
169
- # Set the device network connection mode
170
- # @param [String] path Bit mask that represent the network mode
171
- #
172
- # Value (Alias) | Data | Wifi | Airplane Mode
173
- # -------------------------------------------------
174
- # 1 (Airplane Mode) | 0 | 0 | 1
175
- # 6 (All network on) | 1 | 1 | 0
176
- # 4 (Data only) | 1 | 0 | 0
177
- # 2 (Wifi only) | 0 | 1 | 0
178
- # 0 (None) | 0 | 0 | 0
179
- #
180
-
181
- # @!method set_immediate_value
182
- # Set the value to element directly
183
- # for iOS; setValue is called in XCUITest instead because XCUITest doesn't provide set value directly.
184
- # https://github.com/appium/appium-xcuitest-driver/blob/793cdc7d5e84bd553e375076e1c6dc7e242c9cde/lib/commands/element.js#L123
185
- #
186
- # ```ruby
187
- # set_immediate_value element, 'hello'
188
- # ```
189
-
190
- # @!method get_performance_data_types
191
- # Get the information type of the system state which is supported to read such as
192
- # cpu, memory, network, battery via adb commands.
193
- # https://github.com/appium/appium-base-driver/blob/be29aec2318316d12b5c3295e924a5ba8f09b0fb/lib/mjsonwp/routes.js#L300
194
- #
195
- # ```ruby
196
- # get_performance_data_types #=> ["cpuinfo", "batteryinfo", "networkinfo", "memoryinfo"]
197
- # ```
198
-
199
- # @!method get_performance_data
200
- # Get the resource usage information of the application.
201
- # https://github.com/appium/appium-base-driver/blob/be29aec2318316d12b5c3295e924a5ba8f09b0fb/lib/mjsonwp/routes.js#L303
202
- # @param [String] package_name Package name
203
- # @param [String] data_type Data type get with `get_performance_data_types`
204
- # @param [String] data_read_timeout Command timeout. Default is 2.
205
- #
206
- # ```ruby
207
- # get_performance_data package_name: package_name, data_type: data_type, data_read_timeout: 2
208
- # ```
209
- class << self
210
- def extended(_mod)
211
- extend_webdriver_with_forwardable
212
-
213
- ::Appium::Driver::Commands::COMMAND_NO_ARG.each_key do |method|
214
- add_endpoint_method method
215
- end
216
-
217
- add_endpoint_method(:available_contexts) do
218
- def available_contexts
219
- # return empty array instead of nil on failure
220
- execute(:available_contexts, {}) || []
221
- end
222
- end
223
-
224
- add_endpoint_method(:app_strings) do
225
- def app_strings(language = nil)
226
- opts = language ? { language: language } : {}
227
- execute :app_strings, {}, opts
228
- end
229
- end
230
-
231
- add_endpoint_method(:lock) do
232
- def lock(duration)
233
- execute :lock, {}, seconds: duration
234
- end
235
- end
236
-
237
- add_endpoint_method(:install_app) do
238
- def install_app(path)
239
- execute :install_app, {}, appPath: path
240
- end
241
- end
242
-
243
- add_endpoint_method(:remove_app) do
244
- def remove_app(id)
245
- execute :remove_app, {}, appId: id
246
- end
247
- end
248
-
249
- add_endpoint_method(:app_installed?) do
250
- def app_installed?(app_id)
251
- execute :app_installed?, {}, bundleId: app_id
252
- end
253
- end
254
-
255
- add_endpoint_method(:background_app) do
256
- def background_app(duration = 0)
257
- execute :background_app, {}, seconds: duration
258
- end
259
- end
260
-
261
- add_endpoint_method(:start_activity) do
262
- def start_activity(opts)
263
- raise 'opts must be a hash' unless opts.is_a? Hash
264
- app_package = opts[:app_package]
265
- raise 'app_package is required' unless app_package
266
- app_activity = opts[:app_activity]
267
- raise 'app_activity is required' unless app_activity
268
- app_wait_package = opts.fetch(:app_wait_package, '')
269
- app_wait_activity = opts.fetch(:app_wait_activity, '')
270
-
271
- unknown_opts = opts.keys - [:app_package, :app_activity, :app_wait_package, :app_wait_activity]
272
- raise "Unknown options #{unknown_opts}" unless unknown_opts.empty?
273
-
274
- execute :start_activity, {}, appPackage: app_package,
275
- appActivity: app_activity,
276
- appWaitPackage: app_wait_package,
277
- appWaitActivity: app_wait_activity
278
- end
279
- end
280
-
281
- add_endpoint_method(:set_context) do
282
- def set_context(context = null)
283
- execute :set_context, {}, name: context
284
- end
285
- end
286
-
287
- add_endpoint_method(:hide_keyboard) do
288
- def hide_keyboard(close_key = nil, strategy = nil)
289
- option = {}
290
-
291
- option[:key] = close_key || 'Done' # default to Done key.
292
- option[:strategy] = strategy || :pressKey # default to pressKey
293
-
294
- execute :hide_keyboard, {}, option
295
- end
296
- end
297
-
298
- add_endpoint_method(:press_keycode) do
299
- def press_keycode(key, metastate = nil)
300
- args = { keycode: key }
301
- args[:metastate] = metastate if metastate
302
- execute :press_keycode, {}, args
303
- end
304
- end
305
-
306
- add_endpoint_method(:long_press_keycode) do
307
- def long_press_keycode(key, metastate = nil)
308
- args = { keycode: key }
309
- args[:metastate] = metastate if metastate
310
- execute :long_press_keycode, {}, args
311
- end
312
- end
313
-
314
- add_endpoint_method(:set_immediate_value) do
315
- def set_immediate_value(element, *value)
316
- keys = ::Selenium::WebDriver::Keys.encode(value)
317
- execute :set_immediate_value, { id: element.ref }, value: Array(keys)
318
- end
319
- end
320
-
321
- add_endpoint_method(:push_file) do
322
- def push_file(path, filedata)
323
- encoded_data = Base64.encode64 filedata
324
- execute :push_file, {}, path: path, data: encoded_data
325
- end
326
- end
327
-
328
- add_endpoint_method(:pull_file) do
329
- def pull_file(path)
330
- data = execute :pull_file, {}, path: path
331
- Base64.decode64 data
332
- end
333
- end
334
-
335
- # TODO: TEST ME
336
- add_endpoint_method(:pull_folder) do
337
- def pull_folder(path)
338
- data = execute :pull_folder, {}, path: path
339
- Base64.decode64 data
340
- end
341
- end
342
-
343
- # TODO: TEST ME
344
- add_endpoint_method(:touch_id) do
345
- def touch_id(match = true)
346
- execute :touch_id, {}, match: match
347
- end
348
- end
349
-
350
- # TODO: TEST ME
351
- add_endpoint_method(:toggle_touch_id_enrollment) do
352
- def toggle_touch_id_enrollment
353
- execute :toggle_touch_id_enrollment, {}
354
- end
355
- end
356
-
357
- # TODO: TEST ME
358
- add_endpoint_method(:end_coverage) do
359
- def end_coverage(path, intent)
360
- execute :end_coverage, {}, path: path, intent: intent
361
- end
362
- end
363
-
364
- add_endpoint_method(:get_settings) do
365
- def get_settings
366
- execute :get_settings, {}
367
- end
368
- end
369
-
370
- add_endpoint_method(:update_settings) do
371
- def update_settings(settings)
372
- execute :update_settings, {}, settings: settings
373
- end
374
- end
375
-
376
- add_endpoint_method(:set_network_connection) do
377
- def set_network_connection(mode)
378
- execute :set_network_connection, {}, type: mode
379
- end
380
- end
381
-
382
- add_endpoint_method(:get_performance_data) do
383
- def get_performance_data(package_name:, data_type:, data_read_timeout: 1000)
384
- execute :get_performance_data, {}, packageName: package_name,
385
- dataType: data_type,
386
- dataReadTimeout: data_read_timeout
387
- end
388
- end
389
-
390
- add_touch_actions
391
- add_ime_actions
392
- extend_search_contexts
393
- end
394
-
395
- # def extended
396
-
397
- # @private
398
- def add_endpoint_method(method)
399
- block_given? ? create_bridge_command(method, &Proc.new) : create_bridge_command(method)
400
-
401
- delegate_driver_method method
402
- delegate_from_appium_driver method
403
- end
404
-
405
- # @private
406
- def extend_webdriver_with_forwardable
407
- return if Selenium::WebDriver::Driver.is_a? Forwardable
408
- Selenium::WebDriver::Driver.class_eval do
409
- extend Forwardable
410
- end
411
- end
412
-
413
- # @private
414
- def delegate_driver_method(method)
415
- return if Selenium::WebDriver::Driver.method_defined? method
416
- Selenium::WebDriver::Driver.class_eval { def_delegator :@bridge, method }
417
- end
418
-
419
- # @private
420
- def delegate_from_appium_driver(method, delegation_target = :driver)
421
- def_delegator delegation_target, method
422
- end
423
-
424
- # @private
425
- def create_bridge_command(method)
426
- Selenium::WebDriver::Remote::OSS::Bridge.class_eval do
427
- block_given? ? class_eval(&Proc.new) : define_method(method) { execute method }
428
- end
429
-
430
- Selenium::WebDriver::Remote::W3C::Bridge.class_eval do
431
- block_given? ? class_eval(&Proc.new) : define_method(method) { execute method }
432
- end
433
- end
434
-
435
- # @!method find_element_with_appium
436
- # @!method find_elements_with_appium
437
- #
438
- # find_element/s_with_appium with their accessibility_id
439
- #
440
- # ```ruby
441
- # find_elements :accessibility_id, 'Animation'
442
- # ```
443
- def extend_search_contexts
444
- Selenium::WebDriver::SearchContext.class_eval do
445
- def find_element(*args)
446
- how, what = extract_args(args)
447
- by = _set_by_from_finders(how)
448
- begin
449
- bridge.find_element_by by, what.to_s, ref
450
- rescue Selenium::WebDriver::Error::TimeOutError
451
- raise Selenium::WebDriver::Error::NoSuchElementError
452
- end
453
- end
454
-
455
- def find_elements(*args)
456
- how, what = extract_args(args)
457
- by = _set_by_from_finders(how)
458
- begin
459
- bridge.find_elements_by by, what.to_s, ref
460
- rescue Selenium::WebDriver::Error::TimeOutError
461
- raise Selenium::WebDriver::Error::NoSuchElementError
462
- end
463
- end
464
-
465
- def _set_by_from_finders(how)
466
- finders = ::Selenium::WebDriver::SearchContext::FINDERS.merge ::Appium::Driver::SearchContext::FINDERS
467
- by = finders[how.to_sym]
468
- raise ArgumentError, "cannot find element by #{how.inspect}" unless by
469
- by
470
- end
471
- end
472
- end
473
-
474
- def add_touch_actions
475
- add_endpoint_method(:touch_actions) do
476
- def touch_actions(actions)
477
- actions = { actions: [actions].flatten }
478
- execute :touch_actions, {}, actions
479
- end
480
- end
481
-
482
- add_endpoint_method(:multi_touch) do
483
- def multi_touch(actions)
484
- execute :multi_touch, {}, actions: actions
485
- end
486
- end
487
-
488
- actions = Appium::TouchAction::COMPLEX_ACTIONS
489
- actions.each do |method|
490
- delegate_from_appium_driver(method, Appium::TouchAction)
491
- end
492
-
493
- delegate_from_appium_driver(:pinch, Appium::MultiTouch)
494
- delegate_from_appium_driver(:zoom, Appium::MultiTouch)
495
- end
496
-
497
- def add_ime_actions
498
- # Commands for IME are defined in the following commands.rb, but the driver have no bridge.
499
- # So, appium_lib define just bridge here.
500
- # https://github.com/SeleniumHQ/selenium/blob/selenium-3.0.1/rb/lib/selenium/webdriver/remote/commands.rb#L184-L192
501
-
502
- # @!method ime_activate
503
- # Make an engine that is available active.
504
- #
505
- # Android only.
506
- # @param [String] The IME owning the activity [required]
507
- #
508
- # ```ruby
509
- # ime_activate engine: 'com.android.inputmethod.latin/.LatinIME'
510
- # ```
511
- add_endpoint_method(:ime_activate) do
512
- def ime_activate(ime_name)
513
- execute :ime_activate, {}, engine: ime_name
514
- end
515
- end
516
-
517
- # @!method ime_available_engines
518
- # List all available input engines on the machine.
519
- # Android only.
520
- #
521
- # ```ruby
522
- # ime_available_engines #=> Get the list of IME installed in the target device
523
- # ```
524
- add_endpoint_method(:ime_available_engines) do
525
- def ime_available_engines
526
- execute :get_ime_available_engines
527
- end
528
- end
529
-
530
- # @!method ime_active_engine
531
- # Get the name of the active IME engine.
532
- # Android only.
533
- #
534
- # ```ruby
535
- # ime_active_engine #=> Get the current active IME such as 'com.android.inputmethod.latin/.LatinIME'
536
- # ```
537
- add_endpoint_method(:ime_active_engine) do
538
- def ime_active_engine
539
- execute :get_ime_active_engine
540
- end
541
- end
542
-
543
- # @!method ime_activated
544
- # Indicates whether IME input is active at the moment (not if it is available).
545
- # Android only.
546
- #
547
- # ```ruby
548
- # ime_activated #=> True if IME is activated
549
- # ```
550
- add_endpoint_method(:ime_activated) do
551
- def ime_activated
552
- execute :get_ime_activated
553
- end
554
- end
555
-
556
- # @!method ime_deactivate
557
- # De-activates the currently-active IME engine.
558
- #
559
- # Android only.
560
- #
561
- # ```ruby
562
- # ime_deactivate #=> Deactivate current IME engine
563
- # ```
564
- add_endpoint_method(:ime_deactivate) do
565
- def ime_deactivate
566
- execute :ime_deactivate, {}
567
- end
568
- end
569
- end
570
- end # class << self
571
-
572
- # @!method set_context
573
- # Change the context to the given context.
574
- # @param [String] The context to change to
575
- #
576
- # ```ruby
577
- # set_context "NATIVE_APP"
578
- # ```
579
-
580
- # @!method current_context
581
- # @return [String] The context currently being used.
582
-
583
- # @!method available_contexts
584
- # @return [Array<String>] All usable contexts, as an array of strings.
585
-
586
- # Perform a block within the given context, then switch back to the starting context.
587
- # @param context (String) The context to switch to for the duration of the block.
588
- #
589
- # ```ruby
590
- # result = within_context('NATIVE_APP') do
591
- # find_element :tag, "button"
592
- # end # The result of `find_element :tag, "button"`
593
- # ```
594
- def within_context(context)
595
- existing_context = current_context
596
- set_context context
597
- if block_given?
598
- result = yield
599
- set_context existing_context
600
- result
601
- else
602
- set_context existing_context
603
- end
604
- end
605
-
606
- # Change to the default context. This is equivalent to `set_context nil`.
607
- def switch_to_default_context
608
- set_context nil
609
- end
610
- end # module Device
611
- end # module Appium