appium_lib 9.7.1 → 9.7.2

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.
@@ -75,6 +75,7 @@ module Appium
75
75
 
76
76
  data
77
77
  end
78
+ # @see load_settings
78
79
  alias load_appium_txt load_settings
79
80
 
80
81
  # @param [String] base_dir parent directory of loaded appium.txt (toml)
@@ -119,6 +120,9 @@ module Appium
119
120
  # if modules is a module instead of an array, then the constants of
120
121
  # that module are promoted on.
121
122
  # otherwise, the array of modules will be used as the promotion target.
123
+ #
124
+ # @param [Array<Module>] modules An array of modules
125
+ # @param [Driver] driver A driver to extend for
122
126
  def promote_singleton_appium_methods(modules, driver = $driver)
123
127
  raise 'Global $driver is nil' if driver.nil?
124
128
 
@@ -153,25 +157,27 @@ module Appium
153
157
  ##
154
158
  # Promote appium methods to class instance methods
155
159
  #
156
- # @param class_array [Array<Class>] An array of classes
160
+ # @param [Array<Class>] class_array An array of classes
161
+ # @param [Driver] driver A driver to extend for
157
162
  #
158
163
  # To promote methods to all classes:
159
164
  #
160
- # ```ruby
161
- # Appium.promote_appium_methods Object
162
- # ```
165
+ # @example
166
+ #
167
+ # Appium.promote_appium_methods Object
163
168
  #
164
169
  # It's better to promote on specific classes instead of Object
165
170
  #
166
- # ```ruby
167
- # # promote on rspec
168
- # Appium.promote_appium_methods RSpec::Core::ExampleGroup
169
- # ```
171
+ # @example
172
+ #
173
+ # # promote on rspec
174
+ # Appium.promote_appium_methods RSpec::Core::ExampleGroup
175
+ #
176
+ # @example
177
+ #
178
+ # # promote on minispec
179
+ # Appium.promote_appium_methods Minitest::Spec
170
180
  #
171
- # ```ruby
172
- # # promote on minispec
173
- # Appium.promote_appium_methods Minitest::Spec
174
- # ```
175
181
  def promote_appium_methods(class_array, driver = $driver)
176
182
  raise 'Driver is nil' if driver.nil?
177
183
  # Wrap single class into an array
@@ -198,5 +204,5 @@ module Appium
198
204
  end
199
205
  nil # return nil
200
206
  end
201
- end
202
- end
207
+ end # class << self
208
+ end # module Appium
@@ -1,5 +1,4 @@
1
- # Generic helper methods not specific
2
- # to a particular tag name
1
+ # Generic helper methods not specific to a particular tag name
3
2
  module Appium
4
3
  module Common
5
4
  # iOS .name returns the accessibility attribute if it's set. if not set, the string value is used.
@@ -26,6 +25,12 @@ module Appium
26
25
  end
27
26
 
28
27
  # For Sauce Labs reporting. Returns the current session id.
28
+ # @return [String]
29
+ #
30
+ # @example
31
+ #
32
+ # @driver.session_id #=> "some-session-ids"
33
+ #
29
34
  def session_id
30
35
  @driver.session_id
31
36
  end
@@ -81,6 +86,14 @@ module Appium
81
86
  end # class CountElements
82
87
 
83
88
  # Returns a string of class counts of visible elements.
89
+ # @return [String]
90
+ #
91
+ # @example
92
+ #
93
+ # get_page_class #=> "24x XCUIElementTypeStaticText\n12x XCUIElementTypeCell\n8x XCUIElementTypeOther\n
94
+ # # 2x XCUIElementTypeWindow\n1x XCUIElementTypeStatusBar\n1x XCUIElementTypeTable\n1
95
+ # # x XCUIElementTypeNavigationBar\n1x XCUIElementTypeApplication"
96
+ #
84
97
  def get_page_class
85
98
  parser = @count_elements_parser ||= Nokogiri::XML::SAX::Parser.new(CountElements.new)
86
99
 
@@ -92,6 +105,20 @@ module Appium
92
105
 
93
106
  # Count all classes on screen and print to stdout.
94
107
  # Useful for appium_console.
108
+ # @return [nil]
109
+ #
110
+ # @example
111
+ #
112
+ # page_class
113
+ # # 24x XCUIElementTypeStaticText
114
+ # # 12x XCUIElementTypeCell
115
+ # # 8x XCUIElementTypeOther
116
+ # # 2x XCUIElementTypeWindow
117
+ # # 1x XCUIElementTypeStatusBar
118
+ # # 1x XCUIElementTypeTable
119
+ # # 1x XCUIElementTypeNavigationBar
120
+ # # 1x XCUIElementTypeApplication
121
+ #
95
122
  def page_class
96
123
  puts get_page_class
97
124
  nil
@@ -99,9 +126,10 @@ module Appium
99
126
 
100
127
  # Converts pixel values to window relative values
101
128
  #
102
- # ```ruby
103
- # px_to_window_rel x: 50, y: 150
104
- # ```
129
+ # @example
130
+ #
131
+ # px_to_window_rel x: 50, y: 150 #=> #<OpenStruct x="50.0 / 375.0", y="150.0 / 667.0">
132
+ #
105
133
  def px_to_window_rel(opts = {}, driver = $driver)
106
134
  w = driver.window_size
107
135
  x = opts.fetch :x, 0
@@ -142,6 +170,7 @@ module Appium
142
170
  @strings_xml[id]
143
171
  end
144
172
 
173
+ # @private
145
174
  class HTMLElements < Nokogiri::XML::SAX::Document
146
175
  attr_reader :filter
147
176
 
@@ -4,6 +4,7 @@ require_relative '../version'
4
4
  module Appium
5
5
  module Http
6
6
  class Default < ::Appium::Core::Base::Http::Default
7
+ # Default HTTP client inherit Appium::Core::Base::Http::Default, but has different DEFAULT_HEADERS
7
8
  DEFAULT_HEADERS = { 'Accept' => CONTENT_TYPE, 'User-Agent' => "appium/ruby_lib/#{::Appium::VERSION}" }.freeze
8
9
  end
9
10
  end
@@ -4,6 +4,7 @@ module Appium
4
4
  # @return [[Selenium::WebDriver::LogEntry]] A list of logs data.
5
5
  #
6
6
  # @example
7
+ #
7
8
  # @driver.get_log("syslog") #=> [[Selenium::WebDriver::LogEntry]]
8
9
  # @driver.get_log(:syslog) #=> [[Selenium::WebDriver::LogEntry]]
9
10
  #
@@ -14,7 +15,9 @@ module Appium
14
15
  # Get a list of available log types
15
16
  #
16
17
  # @return [[String]] A list of available log types.
18
+ #
17
19
  # @example
20
+ #
18
21
  # @driver.get_available_log_types #=> [:syslog, :crashlog, :performance]
19
22
  #
20
23
  def get_available_log_types
@@ -6,25 +6,23 @@ module Appium
6
6
  # add to a new MultiTouch action. When ready, call `prepare()` and all
7
7
  # actions will be executed simultaneously.
8
8
  #
9
- # ```ruby
10
- # action_1 = TouchAction.new.press(x: 45, y: 100).wait(5).release
11
- # action_2 = TouchAction.new.tap(element: el, x: 50, y:5, count: 3)
9
+ # @example
12
10
  #
13
- # multi_touch_action = MultiTouch.new
14
- # multi_touch_action.add action_1
15
- # multi_touch_action.add action_2
16
- # multi_touch_action.perform
17
- # ```
11
+ # action_1 = TouchAction.new.press(x: 45, y: 100).wait(5).release
12
+ # action_2 = TouchAction.new.tap(element: el, x: 50, y:5, count: 3)
13
+ #
14
+ # multi_touch_action = MultiTouch.new
15
+ # multi_touch_action.add action_1
16
+ # multi_touch_action.add action_2
17
+ # multi_touch_action.perform
18
+ #
19
+ # # with an arbitrary driver
20
+ # driver = Appium::Driver.new(opts, false).start_driver
21
+ # multi_touch_action = MultiTouch.new(driver)
22
+ # multi_touch_action.add action_1
23
+ # multi_touch_action.add action_2
24
+ # multi_touch_action.perform
18
25
  #
19
- # ```
20
- # # with an arbitrary driver
21
- # driver = Appium::Driver.new(opts, false).start_driver
22
- # multi_touch_action = MultiTouch.new(driver)
23
- # multi_touch_action.add action_1
24
- # multi_touch_action.add action_2
25
- # multi_touch_action.perform
26
- # ```
27
-
28
26
  class MultiTouch < ::Appium::Core::MultiTouch
29
27
  class << self
30
28
  # Convenience method for pinching the screen.
@@ -33,23 +31,23 @@ module Appium
33
31
  # @param auto_perform (boolean) Whether to perform the action immediately (default true)
34
32
  # @param driver (Driver) Set a driver to conduct the action. DEfault is global driver($driver)
35
33
  #
36
- # ```ruby
37
- # pinch 75 #=> Pinch the screen from the top right and bottom left corners
38
- # ```
34
+ # @example
35
+ #
36
+ # pinch 75 #=> Pinch the screen from the top right and bottom left corners
39
37
  #
40
38
  # Without auto_perform
41
39
  #
42
- # ```ruby
43
- # action = pinch 75, false #=> Pinch the screen from the top right and bottom left corners
44
- # action.perform #=> to 25% of its size.
45
- # ```
40
+ # @example
41
+ #
42
+ # action = pinch 75, false #=> Pinch the screen from the top right and bottom left corners
43
+ # action.perform #=> to 25% of its size.
46
44
  #
47
45
  # With driver
48
46
  #
49
- # ```ruby
50
- # driver = Appium::Driver.new(opts, false).start_driver
51
- # pinch 75, true, driver #=> Pinch the screen from the top right and bottom left corners
52
- # ```
47
+ # @example
48
+ # driver = Appium::Driver.new(opts, false).start_driver
49
+ # pinch 75, true, driver #=> Pinch the screen from the top right and bottom left corners
50
+ #
53
51
  def pinch(percentage = 25, auto_perform = true, driver = $driver)
54
52
  ::Appium::Core::MultiTouch.pinch percentage: percentage, auto_perform: auto_perform, driver: driver
55
53
  end
@@ -60,23 +58,24 @@ module Appium
60
58
  # @param auto_perform (boolean) Whether to perform the action immediately (default true)
61
59
  # @param driver (Driver) Set a driver to conduct the action. DEfault is global driver($driver)
62
60
  #
63
- # ```ruby
64
- # action = zoom 200 #=> Zoom in the screen from the center until it doubles in size.
65
- # ```
61
+ # @example
62
+ #
63
+ # action = zoom 200 #=> Zoom in the screen from the center until it doubles in size.
66
64
  #
67
65
  # Without auto_perform
68
66
  #
69
- # ```ruby
70
- # action = zoom 200, false #=> Zoom in the screen from the center until it doubles in size.
71
- # action.perform #=> to 25% of its size.
72
- # ```
67
+ # @example
68
+ #
69
+ # action = zoom 200, false #=> Zoom in the screen from the center until it doubles in size.
70
+ # action.perform #=> to 25% of its size.
73
71
  #
74
72
  # With driver
75
73
  #
76
- # ```ruby
77
- # driver = Appium::Driver.new(opts, false).start_driver
78
- # pinch 200, true, driver #=> Zoom in the screen from the center until it doubles in size.
79
- # ```
74
+ # @example
75
+ #
76
+ # driver = Appium::Driver.new(opts, false).start_driver
77
+ # pinch 200, true, driver #=> Zoom in the screen from the center until it doubles in size.
78
+ #
80
79
  def zoom(percentage = 200, auto_perform = true, driver = $driver)
81
80
  ::Appium::Core::MultiTouch.zoom percentage: percentage, auto_perform: auto_perform, driver: driver
82
81
  end
@@ -4,28 +4,31 @@ module Appium
4
4
  #
5
5
  # Each method returns the object itself, so calls can be chained.
6
6
  #
7
- # ```ruby
8
- # action = TouchAction.new.press(x: 45, y: 100).wait(5).release
9
- # action.perform
10
- # action = TouchAction.new.swipe(....)
11
- # action.perform
12
- # ```
7
+ # @example
8
+ #
9
+ # action = TouchAction.new.press(x: 45, y: 100).wait(5).release
10
+ # action.perform
11
+ # action = TouchAction.new.swipe(....)
12
+ # action.perform
13
13
  #
14
14
  # Or each methods can call without `TouchAction.new` as the following.
15
15
  # In this case, `perform` is called automatically.
16
- # ```ruby
17
- # # called `swipe(...).perform` in this method.
18
- # swipe(start_x: 75, start_y: 500, offset_x: 75, offset_y: 20, duration: 500)
19
- # ```
16
+ #
17
+ # @example
18
+ #
19
+ # # called `swipe(...).perform` in this method.
20
+ # swipe(start_x: 75, start_y: 500, offset_x: 75, offset_y: 20, duration: 500)
20
21
  #
21
22
  # If you'd like to perform the chain with an arbitrary driver:
22
- # ```ruby
23
- # driver = Appium::Driver.new(opts, false).start_driver
24
- # action = TouchAction.new.press(x: 45, y: 100).wait(5).release
25
- # action.perform(@driver)
26
- # action = TouchAction.new.swipe(....)
27
- # action.perform(@driver)
28
- # ```
23
+ #
24
+ # @example
25
+ #
26
+ # driver = Appium::Driver.new(opts, false).start_driver
27
+ # action = TouchAction.new.press(x: 45, y: 100).wait(5).release
28
+ # action.perform(@driver)
29
+ # action = TouchAction.new.swipe(....)
30
+ # action.perform(@driver)
31
+ #
29
32
  class TouchAction < ::Appium::Core::TouchAction
30
33
  COMPLEX_ACTIONS = ::Appium::Core::TouchAction::COMPLEX_ACTIONS
31
34
 
@@ -3,6 +3,11 @@ module Appium
3
3
  module Error
4
4
  class CoreError < StandardError; end
5
5
 
6
+ # Capability related errors
7
+ class NoCapabilityError < CoreError; end
8
+ class CapabilityStructureError < CoreError; end
9
+
10
+ # Appium related errors
6
11
  class NotSupportedAppiumServer < CoreError; end
7
12
  class NoSuchElementError < CoreError; end
8
13
 
@@ -31,6 +31,34 @@ module Appium
31
31
  end
32
32
 
33
33
  module Core
34
+ # Creates a new global driver and extend particular methods to `target`
35
+ # @param [Class] target Extend particular methods to this target.
36
+ # @param [Hash] opts A options include capabilities for the Appium Server and for the client.
37
+ #
38
+ # @example
39
+ #
40
+ # require 'rubygems'
41
+ # require 'appium_lib'
42
+ #
43
+ # # Start iOS driver
44
+ # opts = {
45
+ # caps: {
46
+ # platformName: :ios,
47
+ # app: '/path/to/MyiOS.app'
48
+ # },
49
+ # appium_lib: {
50
+ # server_url: "http://custom-host:8080/wd/hub.com",
51
+ # export_session: false,
52
+ # port: 8080,
53
+ # wait: 0,
54
+ # wait_timeout: 20,
55
+ # wait_interval: 0.3,
56
+ # listener: nil,
57
+ # }
58
+ # }
59
+ # @core_driver = Appium::Core.for(self, opts) # create a core driver with `opts` and extend methods into `self`
60
+ # @core_driver.start_driver(server_url: server_url, http_client_ops: http_client_ops) # start driver
61
+ #
34
62
  def self.for(*args)
35
63
  Core::Driver.for(*args)
36
64
  end
@@ -2,36 +2,53 @@ module Appium
2
2
  module Core
3
3
  class Driver
4
4
  # Selenium webdriver capabilities
5
+ # @return [Core::Base::Capabilities]
5
6
  attr_reader :caps
6
- # Custom URL for the selenium server
7
+
8
+ # Return http client called in start_driver()
9
+ # @return [Appium::Core::Base::Http::Default] the http client
10
+ attr_reader :http_client
11
+
12
+ # Device type to request from the appium server
13
+ attr_reader :device
14
+
15
+ # Automation name sent to appium server or received from server
16
+ # If automation_name is nil, it is not set both client side and server side.
17
+ # @return [Hash]
18
+ attr_reader :automation_name
19
+
20
+ # Custom URL for the selenium server. If set this attribute, ruby_lib try to handshake to the custom url.
21
+ # @return [String]
7
22
  attr_reader :custom_url
23
+
8
24
  # Export session id to textfile in /tmp for 3rd party tools
25
+ # @return [Boolean]
9
26
  attr_reader :export_session
27
+
10
28
  # Default wait time for elements to appear
11
29
  # Returns the default client side wait.
12
30
  # This value is independent of what the server is using
31
+ # Provide Appium::Drive like { appium_lib: { wait: 20 } }
13
32
  # @return [Integer]
14
33
  attr_reader :default_wait
34
+
15
35
  # Appium's server port
36
+ # Provide Appium::Drive like { appium_lib: { port: 8080 } }
37
+ # @return [Integer]
16
38
  attr_reader :port
17
- # Device type to request from the appium server
18
- attr_reader :device
19
- # Automation name sent to appium server or received from server
20
- # If automation_name is nil, it is not set both client side and server side.
21
- attr_reader :automation_name
39
+
22
40
  # Return a time wait timeout
23
41
  # Wait time for ::Appium::Common.wait or ::Appium::Common.wait_true.
24
42
  # Provide Appium::Drive like { appium_lib: { wait_timeout: 20 } }
25
43
  # @return [Integer]
26
44
  attr_reader :wait_timeout
45
+
27
46
  # Return a time wait timeout
28
47
  # Wait interval time for ::Appium::Common.wait or ::Appium::Common.wait_true.
29
48
  # Provide Appium::Drive like { appium_lib: { wait_interval: 20 } }
30
49
  # @return [Integer]
31
50
  attr_reader :wait_interval
32
- # Return http client called in start_driver()
33
- # @return [Appium::Core::Base::Http::Default] the http client
34
- attr_reader :http_client
51
+
35
52
  # instance of AbstractEventListener for logging support
36
53
  attr_reader :listener
37
54
 
@@ -54,6 +71,8 @@ module Appium
54
71
  # @private
55
72
  def initialize(target, opts = {})
56
73
  opts = Appium.symbolize_keys opts
74
+ validate_keys(opts)
75
+
57
76
  @caps = get_caps(opts)
58
77
 
59
78
  set_appium_lib_specific_values(get_appium_lib_opts(opts))
@@ -69,8 +88,14 @@ module Appium
69
88
  # Creates a new global driver and quits the old one if it exists.
70
89
  # You can customise http_client as the following
71
90
  #
91
+ # @param [String] server_url Custom server url to send to requests. Default is "http://127.0.0.1:4723/wd/hub".
92
+ # @option http_client_ops [Hash] :http_client Custom HTTP Client
93
+ # @option http_client_ops [Hash] :open_timeout Custom open timeout for http client.
94
+ # @option http_client_ops [Hash] :read_timeout Custom read timeout for http client.
95
+ # @return [Selenium::WebDriver] the new global driver
96
+ #
72
97
  # @example
73
- # ```ruby
98
+ #
74
99
  # require 'rubygems'
75
100
  # require 'appium_lib'
76
101
  #
@@ -83,17 +108,20 @@ module Appium
83
108
  # app: '/path/to/MyiOS.app'
84
109
  # },
85
110
  # appium_lib: {
86
- # wait_timeout: 30
111
+ # server_url: "http://custom-host:8080/wd/hub.com",
112
+ # export_session: false,
113
+ # port: 8080,
114
+ # wait: 0,
115
+ # wait_timeout: 20,
116
+ # wait_interval: 0.3,
117
+ # listener: nil,
87
118
  # }
88
119
  # }
89
- # Appium::Driver.new(opts).start_driver
120
+ # @driver = Appium::Driver.new(opts).start_driver
90
121
  #
91
- # @option http_client_ops [Hash] :http_client Custom HTTP Client
92
- # @option http_client_ops [Hash] :open_timeout Custom open timeout for http client.
93
- # @option http_client_ops [Hash] :read_timeout Custom read timeout for http client.
94
- # @return [Selenium::WebDriver] the new global driver
95
- def start_driver(server_url:,
122
+ def start_driver(server_url: nil,
96
123
  http_client_ops: { http_client: nil, open_timeout: 999_999, read_timeout: 999_999 })
124
+ server_url = server_url ? server_url : "http://127.0.0.1:#{@port}/wd/hub"
97
125
 
98
126
  # open_timeout and read_timeout are explicit wait.
99
127
  open_timeout = http_client_ops.delete(:open_timeout)
@@ -134,23 +162,24 @@ module Appium
134
162
  end
135
163
 
136
164
  # Returns the server's version info
165
+ # @return [Hash]
137
166
  #
138
- # ```ruby
139
- # {
140
- # "build" => {
141
- # "version" => "0.18.1",
142
- # "revision" => "d242ebcfd92046a974347ccc3a28f0e898595198"
167
+ # @example
168
+ #
169
+ # @driver.appium_server_version
170
+ # {
171
+ # "build" => {
172
+ # "version" => "0.18.1",
173
+ # "revision" => "d242ebcfd92046a974347ccc3a28f0e898595198"
174
+ # }
143
175
  # }
144
- # }
145
- # ```
146
176
  #
147
177
  # Returns blank hash for Selenium Grid since `remote_status` gets 500 error
148
178
  #
149
- # ```ruby
150
- # {}
151
- # ```
179
+ # @example
180
+ #
181
+ # @driver.appium_server_version #=> {}
152
182
  #
153
- # @return [Hash]
154
183
  def appium_server_version
155
184
  @driver.remote_status
156
185
  rescue Selenium::WebDriver::Error::ServerError => e
@@ -161,6 +190,11 @@ module Appium
161
190
 
162
191
  # Return the platform version as an array of integers
163
192
  # @return [Array<Integer>]
193
+ #
194
+ # @example
195
+ #
196
+ # @driver.platform_version #=> [10.1.1]
197
+ #
164
198
  def platform_version
165
199
  p_version = @driver.capabilities['platformVersion']
166
200
  p_version.split('.').map(&:to_i)
@@ -168,10 +202,13 @@ module Appium
168
202
 
169
203
  # Takes a png screenshot and saves to the target path.
170
204
  #
171
- # Example: screenshot '/tmp/hi.png'
172
- #
173
205
  # @param png_save_path [String] the full path to save the png
174
206
  # @return [nil]
207
+ #
208
+ # @example
209
+ #
210
+ # @driver.screenshot '/tmp/hi.png' #=> nil
211
+ #
175
212
  def screenshot(png_save_path)
176
213
  @driver.save_screenshot png_save_path
177
214
  nil
@@ -212,6 +249,28 @@ module Appium
212
249
  target
213
250
  end
214
251
 
252
+ # @private
253
+ def validate_keys(opts)
254
+ flatten_ops = flatten_hash_keys(opts)
255
+
256
+ raise Error::NoCapabilityError unless opts.member?(:caps)
257
+ if !opts.member?(:appium_lib) && flatten_ops.member?(:appium_lib)
258
+ raise Error::CapabilityStructureError, 'Please check the value of appium_lib in the capability'
259
+ end
260
+
261
+ true
262
+ end
263
+
264
+ # @private
265
+ def flatten_hash_keys(hash, flatten_keys_result = [])
266
+ hash.each do |key, value|
267
+ flatten_keys_result << key
268
+ flatten_hash_keys(value, flatten_keys_result) if value.is_a?(Hash)
269
+ end
270
+
271
+ flatten_keys_result
272
+ end
273
+
215
274
  # @private
216
275
  def get_caps(opts)
217
276
  Core::Base::Capabilities.create_capabilities(opts[:caps] || {})
@@ -269,6 +328,14 @@ module Appium
269
328
  return unless @automation_name.nil?
270
329
  @automation_name = @driver.capabilities['automationName']
271
330
  end
272
- end
273
- end
331
+
332
+ # @private
333
+ def write_session_id(session_id)
334
+ File.open('/tmp/appium_lib_session', 'w') { |f| f.puts session_id }
335
+ rescue IOError => e
336
+ ::Appium::Logger.warn e
337
+ nil
338
+ end
339
+ end # class Driver
340
+ end # module Core
274
341
  end # module Appium