appium_lib 10.4.0 → 11.1.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.
@@ -27,7 +27,7 @@ module Appium
27
27
  @filter = value.to_s.downcase
28
28
  end
29
29
 
30
- def initialize
30
+ def initialize # rubocop:disable Lint/MissingSuper
31
31
  reset
32
32
  @filter = false
33
33
  end
@@ -217,7 +217,7 @@ module Appium
217
217
  # [^\/]+ - type is made up of at least one non-/ characters
218
218
  # \\/ - / ends the type and starts the name
219
219
  # [\S]+$ - the name contains at least one non-space character and then the line is ended
220
- resource_id = /^[a-zA-Z_][a-zA-Z0-9\._]*:[^\/]+\/[\S]+$/
220
+ resource_id = /^[a-zA-Z_][a-zA-Z0-9._]*:[^\/]+\/\S+$/
221
221
  string.match(resource_id) ? on_match : ''
222
222
  end
223
223
 
@@ -60,9 +60,9 @@ module Appium
60
60
  # uiautomator index doesn't support last
61
61
  # and it's 0 indexed
62
62
  button_index = tags(BUTTON).length
63
- button_index -= 1 if button_index > 0
63
+ button_index -= 1 if button_index.positive?
64
64
  image_button_index = tags(IMAGE_BUTTON).length
65
- image_button_index -= 1 if image_button_index > 0
65
+ image_button_index -= 1 if image_button_index.positive?
66
66
 
67
67
  find_element :uiautomator,
68
68
  _button_visible_selectors(button_index: button_index,
@@ -63,9 +63,9 @@ module Appium
63
63
  # uiautomator index doesn't support last
64
64
  # and it's 0 indexed
65
65
  button_index = tags(::Appium::Android::BUTTON).length
66
- button_index -= 1 if button_index > 0
66
+ button_index -= 1 if button_index.positive?
67
67
  image_button_index = tags(::Appium::Android::IMAGE_BUTTON).length
68
- image_button_index -= 1 if image_button_index > 0
68
+ image_button_index -= 1 if image_button_index.positive?
69
69
 
70
70
  _button_visible_selectors_xpath(button_index: button_index,
71
71
  image_button_index: image_button_index)
@@ -60,9 +60,9 @@ module Appium
60
60
  # uiautomator index doesn't support last
61
61
  # and it's 0 indexed
62
62
  button_index = tags(::Appium::Android::Button).length
63
- button_index -= 1 if button_index > 0
63
+ button_index -= 1 if button_index.positive?
64
64
  image_button_index = tags(::Appium::Android::ImageButton).length
65
- image_button_index -= 1 if image_button_index > 0
65
+ image_button_index -= 1 if image_button_index.positive?
66
66
 
67
67
  elements = find_elements :uiautomator,
68
68
  _button_visible_selectors(button_index: button_index,
@@ -77,9 +77,8 @@ module Appium
77
77
  Appium::Logger.info "Loading #{toml}" if verbose
78
78
 
79
79
  data = Tomlrb.load_file(toml, symbolize_keys: true)
80
- if verbose
81
- Appium::Logger.info data unless data.empty?
82
- end
80
+
81
+ Appium::Logger.info data if verbose && !data.empty?
83
82
 
84
83
  if data && data[:caps] && data[:caps][:app] && !data[:caps][:app].empty?
85
84
  data[:caps][:app] = Appium::Driver.absolute_app_path data
@@ -200,12 +199,17 @@ module Appium
200
199
  raise 'Driver is nil' if driver.nil?
201
200
 
202
201
  # Wrap single class into an array
203
- class_array = [class_array] unless class_array.class == Array
202
+ class_array = [class_array] unless class_array.instance_of? Array
204
203
  # Promote Appium driver methods to class instance methods.
205
204
  class_array.each do |klass|
206
- driver.public_methods(false).each do |m|
205
+ driver.public_methods(false).each do |method|
207
206
  klass.class_eval do
208
- define_method m do |*args, &block|
207
+ if method_defined? method
208
+ ::Appium::Logger.warn "'#{method}' is already defined. Skipping to override it."
209
+ next
210
+ end
211
+
212
+ define_method method do |*args, &block|
209
213
  begin
210
214
  # Prefer existing method.
211
215
  # super will invoke method missing on driver
@@ -215,7 +219,14 @@ module Appium
215
219
  # so rescue argument error
216
220
  # and call the name method on $driver
217
221
  rescue NoMethodError, ArgumentError
218
- driver.send m, *args, &block if driver.respond_to?(m)
222
+ if args.size == 1 && args.first.is_a?(Hash)
223
+ # To prevent warnings by keyword arguments (for Ruby 2.7 and 3)
224
+ driver.send method, **args.first, &block if driver.respond_to?(method)
225
+ else
226
+ ::Appium::Logger.warn "Should fix this '#{args}' for Ruby 2.7 (and 3)" if args.first.is_a?(Hash)
227
+
228
+ driver.send method, *args, &block if driver.respond_to?(method)
229
+ end
219
230
  end
220
231
  end
221
232
  end
@@ -29,7 +29,8 @@ module Appium
29
29
  # Return yield and ignore any exceptions.
30
30
  def ignore
31
31
  yield
32
- rescue Exception # rubocop:disable Lint/HandleExceptions, Lint/RescueException
32
+ rescue Exception # rubocop:disable Lint/RescueException
33
+ # Ignored
33
34
  end
34
35
 
35
36
  # Navigate back.
@@ -73,7 +74,7 @@ module Appium
73
74
  class CountElements < Nokogiri::XML::SAX::Document
74
75
  attr_reader :result
75
76
 
76
- def initialize(platform)
77
+ def initialize(platform) # rubocop:disable Lint/MissingSuper
77
78
  reset
78
79
  @platform = platform
79
80
  end
@@ -213,7 +214,7 @@ module Appium
213
214
  @filter = value.to_s.downcase
214
215
  end
215
216
 
216
- def initialize
217
+ def initialize # rubocop:disable Lint/MissingSuper
217
218
  reset
218
219
  @filter = false
219
220
  end
@@ -232,8 +233,9 @@ module Appium
232
233
  "#{string} #{attr[0]}: #{attr1}\n"
233
234
  end
234
235
 
235
- r.concat "\n#{name}\n#{attr_string}" unless attr_string.nil? || attr_string.empty?
236
- r
236
+ return r if attr_string.nil? || attr_string.empty?
237
+
238
+ "#{r}\n#{name}\n#{attr_string}"
237
239
  end
238
240
  end
239
241
 
@@ -45,7 +45,7 @@ module Appium
45
45
  opts = opts.is_a?(Numeric) ? { timeout: opts } : opts
46
46
 
47
47
  if opts.is_a? Hash
48
- opts.empty? ? @core.wait_true { yield } : @core.wait_true(opts) { yield }
48
+ opts.empty? ? @core.wait_true { yield } : @core.wait_true(**opts) { yield }
49
49
  else
50
50
  ::Appium::Logger.warn('Arguments should be Hash like {timeout: 100}')
51
51
  end
@@ -74,7 +74,7 @@ module Appium
74
74
  opts = opts.is_a?(Numeric) ? { timeout: opts } : opts
75
75
 
76
76
  if opts.is_a? Hash
77
- opts.empty? ? @core.wait { yield } : @core.wait(opts) { yield }
77
+ opts.empty? ? @core.wait { yield } : @core.wait(**opts) { yield }
78
78
  else
79
79
  ::Appium::Logger.warn('Arguments should be Hash like {timeout: 100}')
80
80
  end
@@ -163,9 +163,8 @@ module Appium
163
163
  global_driver = true # if global_driver is nil, then global_driver must be default value.
164
164
  end
165
165
 
166
- if global_driver
167
- $driver.driver_quit if $driver
168
- end
166
+ $driver&.driver_quit if global_driver
167
+
169
168
  raise 'opts must be a hash' unless opts.is_a? Hash
170
169
 
171
170
  @core = ::Appium::Core.for(opts)
@@ -253,7 +252,7 @@ module Appium
253
252
  # https://github.com/YOU-i-Labs/appium-youiengine-driver
254
253
  Appium::Logger.debug('YouiEngine')
255
254
  else
256
- Appium::Logger.debug('no device matched') # core also shows waring message
255
+ Appium::Logger.debug('no device matched') # core also shows warning message
257
256
  end
258
257
  end
259
258
  end
@@ -277,7 +276,6 @@ module Appium
277
276
 
278
277
  # Returns a hash of the driver attributes
279
278
  def driver_attributes
280
- # rubocop:disable Layout/AlignHash
281
279
  {
282
280
  caps: @core.caps,
283
281
  automation_name: @core.automation_name,
@@ -295,7 +293,6 @@ module Appium
295
293
  wait_timeout: @core.wait_timeout,
296
294
  wait_interval: @core.wait_interval
297
295
  }
298
- # rubocop:enable Layout/AlignHash
299
296
  end
300
297
 
301
298
  def device_is_android?
@@ -426,14 +423,12 @@ module Appium
426
423
  return app_path if app_path =~ URI::DEFAULT_PARSER.make_regexp # public URL for Sauce
427
424
 
428
425
  absolute_app_path = File.expand_path app_path
429
- app_path = if File.exist? absolute_app_path
430
- absolute_app_path
431
- else
432
- ::Appium::Logger.info("Use #{app_path}")
433
- app_path
434
- end
435
-
436
- app_path
426
+ if File.exist? absolute_app_path
427
+ absolute_app_path
428
+ else
429
+ ::Appium::Logger.info("Use #{app_path}")
430
+ app_path
431
+ end
437
432
  end
438
433
 
439
434
  # Get the server url
@@ -798,6 +793,48 @@ module Appium
798
793
  @driver.set_location(latitude, longitude, altitude)
799
794
  end
800
795
 
796
+ # @since Appium 1.16.0
797
+ #
798
+ # Logs a custom event. The event is available via {::Appium::Core::Events#get} or
799
+ # <code>driver.session_capabilities['events']</code> with <code>eventTimings</code> capabilities.
800
+ #
801
+ # @param [String] vendor The vendor prefix for the event
802
+ # @param [String] event The name of event
803
+ # @return [nil]
804
+ #
805
+ # @example
806
+ #
807
+ # log_event vendor: 'appium', event: 'funEvent'
808
+ #
809
+ # log_event = { vendor: 'appium', event: 'anotherEvent' }
810
+ # log_events #=> {...., 'appium:funEvent' => [1572957315, 1572960305],
811
+ # # 'appium:anotherEvent' => 1572959315}
812
+ #
813
+ def log_event(vendor:, event:)
814
+ @driver.logs.event vendor: vendor, event: event
815
+ end
816
+
817
+ def log_event=(log_event)
818
+ raise ArgumentError('log_event should be Hash like { vendor: "appium", event: "funEvent"}') unless log_event.is_a?(Hash)
819
+
820
+ @driver.logs.event vendor: log_event[:vendor], event: log_event[:event]
821
+ end
822
+
823
+ # @since Appium 1.16.0
824
+ # Returns events with filtering with 'type'. Defaults to all available events.
825
+ #
826
+ # @param [String] type The type of events to get
827
+ # @return [Hash]
828
+ #
829
+ # @example
830
+ #
831
+ # log_events #=> {}
832
+ # log_events #=> {'commands' => [{'cmd' => 123455, ....}], 'startTime' => 1572954894127, }
833
+ #
834
+ def log_events(type = nil)
835
+ @driver.logs.events(type)
836
+ end
837
+
801
838
  # Quit the driver and Pry.
802
839
  # quit and exit are reserved by Pry.
803
840
  # @return [void]
@@ -807,11 +844,3 @@ module Appium
807
844
  end
808
845
  end # class Driver
809
846
  end # module Appium
810
-
811
- # Paging in Pry is annoying :q required to exit.
812
- # With pager disabled, the output is similar to IRB
813
- # Only set if Pry is defined and there is no `.pryrc` files.
814
- if defined?(Pry) && !(File.exist?(Pry::HOME_RC_FILE) || File.exist?(Pry::LOCAL_RC_FILE))
815
- Appium::Logger.debug 'Pry.config.pager = false is set.'
816
- Pry.config.pager = false
817
- end
@@ -21,7 +21,7 @@ module Appium
21
21
  def start_element(type, attrs = [])
22
22
  return if filter && !filter.eql?(type)
23
23
 
24
- page = attrs.each_with_object({}) do |hash, attr|
24
+ page = attrs.each_with_object({}) do |attr, hash|
25
25
  hash[attr[0]] = attr[1] if %w(name label value hint visible).include?(attr[0])
26
26
  hash
27
27
  end
@@ -49,6 +49,7 @@ module Appium
49
49
  puts " visible: #{visible}" if visible
50
50
  end
51
51
  end
52
+
52
53
  # iOS only. On Android uiautomator always returns an empty string for EditText password.
53
54
  #
54
55
  # Password character returned from value of UIASecureTextField
@@ -76,7 +77,7 @@ module Appium
76
77
  source = get_source
77
78
 
78
79
  # current_context may be nil which breaks start_with
79
- if current_context && current_context.start_with?('WEBVIEW')
80
+ if current_context&.start_with?('WEBVIEW')
80
81
  parser = @android_html_parser ||= Nokogiri::HTML::SAX::Parser.new(Appium::Common::HTMLElements.new)
81
82
  parser.document.reset
82
83
  parser.document.filter = class_name
@@ -470,7 +471,7 @@ module Appium
470
471
  # will be present.
471
472
  _validate_object opts[:name], opts[:label], opts[:value]
472
473
 
473
- # note that mainWindow is sometimes nil so it's passed as a param
474
+ # NOTE: that mainWindow is sometimes nil so it's passed as a param
474
475
  # $._elementOrElementsByType will validate that the window isn't nil
475
476
  element_or_elements_by_type = <<-JS
476
477
  (function() {
@@ -15,7 +15,6 @@
15
15
  require_relative 'xcuitest/element'
16
16
  require_relative 'xcuitest/command'
17
17
  require_relative 'xcuitest/helper'
18
- require_relative 'xcuitest/element'
19
18
  require_relative 'xcuitest/bridge'
20
19
 
21
20
  module Appium
@@ -79,7 +79,7 @@ module Appium
79
79
  # double_tap x: 100, y: 100
80
80
  # double_tap element: find_element(:accessibility_id, "some item")
81
81
  # ```
82
- def double_tap(x: nil, y: nil, element: nil) # rubocop:disable Naming/UncommunicativeMethodParamName
82
+ def double_tap(x: nil, y: nil, element: nil)
83
83
  return 'Set x, y or element' if (x.nil? || y.nil?) && element.nil?
84
84
 
85
85
  args = element.nil? ? { x: x, y: y } : { element: element.ref }
@@ -96,7 +96,7 @@ module Appium
96
96
  # touch_and_hold x: 100, y: 100, duration: 2.0
97
97
  # touch_and_hold element: find_element(:accessibility_id, "some item")
98
98
  # ```
99
- def touch_and_hold(x: nil, y: nil, element: nil, duration: 1.0) # rubocop:disable Naming/UncommunicativeMethodParamName
99
+ def touch_and_hold(x: nil, y: nil, element: nil, duration: 1.0)
100
100
  return 'Set x, y or element' if (x.nil? || y.nil?) && element.nil?
101
101
 
102
102
  args = element.nil? ? { x: x, y: y } : { element: element.ref }
@@ -121,10 +121,10 @@ module Appium
121
121
  # Otherwise they should be calculated relatively to screen borders.
122
122
  #
123
123
  # ```ruby
124
- # tap x: 100, y: 100
125
- # tap x: 100, y: 100, element: find_element(:accessibility_id, "some item")
124
+ # one_finger_tap x: 100, y: 100
125
+ # one_finger_tap x: 100, y: 100, element: find_element(:accessibility_id, "some item")
126
126
  # ```
127
- def tap(x:, y:, element: nil) # rubocop:disable Naming/UncommunicativeMethodParamName
127
+ def one_finger_tap(x:, y:, element: nil)
128
128
  args = { x: x, y: y }
129
129
  args[:element] = element.ref if element
130
130
  @driver.execute_script 'mobile: tap', args
@@ -33,8 +33,7 @@ module Appium
33
33
  # xcuitest_install_app(app: "path/to/app.app")
34
34
  #
35
35
  def xcuitest_install_app(app:)
36
- args = { app: app }
37
- @driver.execute_script 'mobile: installApp', args
36
+ @driver.install_app app
38
37
  end
39
38
 
40
39
  # Verifies whether the application with given bundle identifier is installed on the device.
@@ -47,8 +46,7 @@ module Appium
47
46
  # xcuitest_app_installed?(bundle_id: "io.appium.bundle") #=> true or false
48
47
  #
49
48
  def xcuitest_app_installed?(bundle_id:)
50
- args = { bundleId: bundle_id }
51
- @driver.execute_script 'mobile: isAppInstalled', args
49
+ @driver.app_installed? bundle_id
52
50
  end
53
51
 
54
52
  # Uninstalls an existing application from the device under test. This endpoint does not verify
@@ -62,8 +60,7 @@ module Appium
62
60
  # xcuitest_remove_app(bundle_id: "io.appium.bundle") #=> 1
63
61
  #
64
62
  def xcuitest_remove_app(bundle_id:)
65
- args = { bundleId: bundle_id }
66
- @driver.execute_script 'mobile: removeApp', args
63
+ @driver.remove_app bundle_id
67
64
  end
68
65
 
69
66
  # Executes an existing application on the device. If the application is already running then
@@ -92,8 +89,7 @@ module Appium
92
89
  # xcuitest_terminate_app(bundle_id: "io.appium.bundle") #=> 1
93
90
  #
94
91
  def xcuitest_terminate_app(bundle_id:)
95
- args = { bundleId: bundle_id }
96
- @driver.execute_script 'mobile: terminateApp', args
92
+ @driver.terminate_app bundle_id
97
93
  end
98
94
 
99
95
  # Get the status of an existing application on the device.
@@ -114,8 +110,7 @@ module Appium
114
110
  # xcuitest_query_app_status(bundle_id: "io.appium.bundle") #=> 1
115
111
  #
116
112
  def xcuitest_query_app_status(bundle_id:)
117
- args = { bundleId: bundle_id }
118
- @driver.execute_script 'mobile: queryAppState', args
113
+ @driver.app_state bundle_id
119
114
  end
120
115
 
121
116
  # Activates an existing application on the device under test and moves it to the foreground.
@@ -130,8 +125,7 @@ module Appium
130
125
  # xcuitest_activate_app(bundle_id: "io.appium.bundle") #=> 1
131
126
  #
132
127
  def xcuitest_activate_app(bundle_id:)
133
- args = { bundleId: bundle_id }
134
- @driver.execute_script 'mobile: activateApp', args
128
+ @driver.activate_app bundle_id
135
129
  end
136
130
  end
137
131
  end # module Xcuitest
@@ -74,7 +74,7 @@ module Appium
74
74
  c_names = class_names.map { |class_name| %(type == "#{class_name}") }.join(' || ')
75
75
 
76
76
  predicate = if value
77
- %((#{c_names}) && (name contains[c] "#{value}" || label contains[c] "#{value}" || value contains[c] "#{value}")) # rubocop:disable Metrics/LineLength
77
+ %((#{c_names}) && (name contains[c] "#{value}" || label contains[c] "#{value}" || value contains[c] "#{value}")) # rubocop:disable Layout/LineLength
78
78
  else
79
79
  c_names
80
80
  end
@@ -14,6 +14,6 @@
14
14
 
15
15
  module Appium
16
16
  # Version and Date are defined on the 'Appium' module, not 'Appium::Common'
17
- VERSION = '10.4.0' unless defined? ::Appium::VERSION
18
- DATE = '2019-07-19' unless defined? ::Appium::DATE
17
+ VERSION = '11.1.0' unless defined? ::Appium::VERSION
18
+ DATE = '2020-12-29' unless defined? ::Appium::DATE
19
19
  end
data/readme.md CHANGED
@@ -21,7 +21,7 @@ We can avoid the class driver with current `ruby_lib`, but if you'd like to impl
21
21
  # Setup
22
22
  ## Requirement
23
23
  - [Appium](https://github.com/appium/appium#requirements)
24
- - Ruby: 2.2+
24
+ - Ruby: 2.4+
25
25
 
26
26
  ### Ruby Lib and Appium
27
27
  - Ruby library version over `9.8.0` requires Appium over `1.8`
@@ -1,3 +1,46 @@
1
+ #### v11.1.0 2020-12-29
2
+
3
+ - [bc3da9b](https://github.com/appium/ruby_lib/commit/bc3da9bc1ee58d5e96811b72f3ed737ed0e9c401) Release 11.1.0
4
+ - [3c33cd6](https://github.com/appium/ruby_lib/commit/3c33cd639f8ce55fb81c5ae2116a863407529599) ci: Set up CI with Azure Pipelines (#895)
5
+ - [ecee089](https://github.com/appium/ruby_lib/commit/ecee08981f935295e6413cd98dea4366cbc7bc69) feat: work with Ruby 3 (#893)
6
+ - [bb3d715](https://github.com/appium/ruby_lib/commit/bb3d715e39509ac091b8f493cca42eb4fe8fd5bf) feat: work with Ruby 3 (#892)
7
+ - [eb5cee7](https://github.com/appium/ruby_lib/commit/eb5cee7a926b90bbedd6aa28f013a0b3c5f38510) chore: Update rubocop requirement from = 1.6.1 to = 1.7.0 (#891)
8
+ - [219181d](https://github.com/appium/ruby_lib/commit/219181d80f3b86999706f90a68996945fdc7b1d0) fix: rubocop (#890)
9
+ - [334b791](https://github.com/appium/ruby_lib/commit/334b791a3c4420598e3e832023aa1a16af92492f) chore: Update fakefs requirement from ~> 0.13.0 to ~> 1.3.0 (#888)
10
+
11
+
12
+ #### v11.0.0 2020-12-19
13
+
14
+ - [b4313b0](https://github.com/appium/ruby_lib/commit/b4313b09e62dd22bb95c2e0bc6edd296c7ece7b4) Release 11.0.0
15
+ - [42f01dd](https://github.com/appium/ruby_lib/commit/42f01dd3513e82f9a7ed25ac9055a65dfaa7d81f) feat: bump ruby version (#887)
16
+ - [dc228b3](https://github.com/appium/ruby_lib/commit/dc228b33487281d0428dcd20e92263d7132dd53e) ci: move to GitHub Actions (#882)
17
+
18
+
19
+ #### v10.6.0 2020-04-03
20
+
21
+ - [65f690f](https://github.com/appium/ruby_lib/commit/65f690f1fec62a5f8868270287b0099d8b22a2ac) Release 10.6.0
22
+ - [f792db3](https://github.com/appium/ruby_lib/commit/f792db3afbfe3f6056e0af60ce9f6be3e2cecadc) feat: remove pager off (#879)
23
+ - [7ad3189](https://github.com/appium/ruby_lib/commit/7ad318925c0cd2c3e73cc015a1ec929485b8af85) Update hashdiff requirement from ~> 0.3.7 to ~> 1.0.0 (#874)
24
+ - [457e765](https://github.com/appium/ruby_lib/commit/457e7657175e6c9ba981ca476098469e91e522e1) Update rubocop requirement from ~> 0.61.0 to ~> 0.68.1 (#875)
25
+ - [9a2b9fa](https://github.com/appium/ruby_lib/commit/9a2b9fa736877141f92d35b9e2ae97657d9955d7) Update rake requirement from ~> 12.0 to ~> 13.0 (#876)
26
+ - [8748244](https://github.com/appium/ruby_lib/commit/8748244f75ae9344e8b22dd20b2d42fb0bd84d75) fix ruby27 warning (#872)
27
+ - [f1734ab](https://github.com/appium/ruby_lib/commit/f1734ab0ff2a210463ab6a83120a673e1b6efd4a) ci: add 2.7 (#871)
28
+ - [b26a8f7](https://github.com/appium/ruby_lib/commit/b26a8f7c00c966ee3f193b4c97255a4751f0041e) fix a yardoc syntax
29
+
30
+
31
+ #### v10.5.0 2019-11-09
32
+
33
+ - [722c3a9](https://github.com/appium/ruby_lib/commit/722c3a9aa387d3537b648a50dc24070e62fcc57a) Release 10.5.0
34
+ - [7a2197b](https://github.com/appium/ruby_lib/commit/7a2197b46f6ec15f1adc8626bbff1be74640e98e) feat: Add log event/s (#868)
35
+
36
+
37
+ #### v10.4.1 2019-09-11
38
+
39
+ - [12317e4](https://github.com/appium/ruby_lib/commit/12317e4d74b20d01813526b28e642e3522193fa3) Release 10.4.1
40
+ - [58218e1](https://github.com/appium/ruby_lib/commit/58218e18f74df362e874b2a39d9e922b27b6bd5e) fix ios page (#866)
41
+ - [7f010e7](https://github.com/appium/ruby_lib/commit/7f010e70149847ae5af8dcf08eae889311f78e6d) fix typo in a comment
42
+
43
+
1
44
  #### v10.4.0 2019-07-19
2
45
 
3
46
  - [954a3a8](https://github.com/appium/ruby_lib/commit/954a3a8d4d5cd56fa5a4e80d021805759dbf5e10) Release 10.4.0