appium_lib_core 9.0.0 → 9.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ccf2b5c0df2ae8489c0c9b3382d260f2464c20828b02484888c7f1c738a42084
4
- data.tar.gz: 6aa81ba96bd097f6075a947656533fd20476de3199855827d4278e71449b842e
3
+ metadata.gz: 66d04f7356959668f0eb58b68869126add5dc0e4abfdc79c2aedcb24e8e8dd6f
4
+ data.tar.gz: f49ba5759a02d29a88a2c470f65e5c30277660838fe4aadcc024db77092b6f0d
5
5
  SHA512:
6
- metadata.gz: 7b7c967d705ffd0034af99c930ed6840e272a064cda6dd461710ac8990413b1ee7de7bbb577e9a3231113ec77c5007b737beb82811600c5d2061d21add41b129
7
- data.tar.gz: 24405ae6731acb21cc504d0867410523a63943244d718700b0c24504bdf9cecae0ae54b7e5a647660cd8aec7e5bd9bd6391e160e1796246250e6dfecd78ca2ec
6
+ metadata.gz: dbee76c3700eda2c8a4214644f9de866a8957e4d25d0aa20e10fffe245e1c3d7208863004c4c16d7e32b0bbf79d22a65cfca6999e5783361178e104000b7847a
7
+ data.tar.gz: 3c0fce31f001303602d99a1feec396e51061a2b57f1ce8155dad771d4167dadaf2ef263a579833eba4f7466fbe2ce8055776b0dbd4de3c7c8fb293465570dc43
data/CHANGELOG.md CHANGED
@@ -10,6 +10,18 @@ Read `release_notes.md` for commit level details.
10
10
 
11
11
  ### Deprecations
12
12
 
13
+ ## [9.1.1] - 2024-05-19
14
+
15
+ ### Enhancements
16
+ - Simplify internal code with Selenium 4.21.0 further.
17
+
18
+
19
+ ## [9.1.0] - 2024-05-18
20
+
21
+ ### Enhancements
22
+ - Require Selenium 4.21.0+
23
+ - Simplify internal code with Selenium 4.21.0. Now it requires selenium webdriver v4.21.0.
24
+
13
25
  ## [9.0.0] - 2024-05-14
14
26
 
15
27
  ### Deprecations
@@ -1,5 +1,4 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'appium_lib_core/version'
5
4
 
@@ -11,8 +10,8 @@ Gem::Specification.new do |spec|
11
10
  spec.authors = ['Kazuaki MATSUO']
12
11
  spec.email = ['fly.49.89.over@gmail.com']
13
12
 
14
- spec.summary = %q{Minimal Ruby library for Appium.}
15
- spec.description = %q{Minimal Ruby library for Appium.}
13
+ spec.summary = 'Minimal Ruby library for Appium.'
14
+ spec.description = 'Minimal Ruby library for Appium.'
16
15
  spec.homepage = 'https://github.com/appium/ruby_lib_core/'
17
16
  spec.license = 'Apache-2.0'
18
17
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
@@ -22,16 +21,17 @@ Gem::Specification.new do |spec|
22
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
22
  spec.require_paths = ['lib']
24
23
 
25
- spec.add_runtime_dependency 'selenium-webdriver', '~> 4.2'
26
24
  spec.add_runtime_dependency 'faye-websocket', '~> 0.11.0'
25
+ spec.add_runtime_dependency 'selenium-webdriver', '~> 4.21'
27
26
 
28
- spec.add_development_dependency 'rake', '~> 13.0'
29
- spec.add_development_dependency 'yard', '~> 0.9.11'
27
+ spec.add_development_dependency 'appium_thor', '~> 2.0'
30
28
  spec.add_development_dependency 'minitest', '~> 5.0'
31
29
  spec.add_development_dependency 'minitest-reporters', '~> 1.1'
32
- spec.add_development_dependency 'webmock', '~> 3.23.0'
33
- spec.add_development_dependency 'rubocop', '1.63.5'
34
- spec.add_development_dependency 'appium_thor', '~> 2.0'
35
30
  spec.add_development_dependency 'parallel_tests'
31
+ spec.add_development_dependency 'rake', '~> 13.0'
32
+ spec.add_development_dependency 'rubocop', '1.63.5'
36
33
  spec.add_development_dependency 'simplecov'
34
+ spec.add_development_dependency 'webmock', '~> 3.23.0'
35
+ spec.add_development_dependency 'yard', '~> 0.9.11'
36
+ spec.metadata['rubygems_mfa_required'] = 'true'
37
37
  end
@@ -15,6 +15,12 @@
15
15
  module Appium
16
16
  module Core
17
17
  class Base
18
+ class LocatorConverter
19
+ def convert(how, what)
20
+ [how, what]
21
+ end
22
+ end # LocatorConverter
23
+
18
24
  class Bridge < ::Selenium::WebDriver::Remote::Bridge
19
25
  include Device::DeviceLock
20
26
  include Device::Keyboard
@@ -31,6 +37,8 @@ module Appium
31
37
  include Device::ExecuteDriver
32
38
  include Device::Orientation
33
39
 
40
+ Bridge.locator_converter = LocatorConverter.new
41
+
34
42
  # Prefix for extra capability defined by W3C
35
43
  APPIUM_PREFIX = 'appium:'
36
44
 
@@ -153,6 +161,18 @@ module Appium
153
161
  public
154
162
 
155
163
  # command for Appium 2.0.
164
+
165
+ # Example:
166
+ # driver.add_command(name: :available_contexts, method: :get, url: 'session/:session_id/contexts') do
167
+ # execute(:available_contexts, {}) || []
168
+ # end
169
+ # Then,
170
+ # driver.available_contexts #=> ["NATIVE_APP"]
171
+
172
+ # def add_command(method:, url:, name:, &block)
173
+ # Bridge.add_command name, method, url, &block
174
+ # end
175
+
156
176
  def add_command(method:, url:, name:, &block)
157
177
  ::Appium::Logger.info "Overriding the method '#{name}' for '#{url}'" if @available_commands.key? name
158
178
 
@@ -162,7 +182,7 @@ module Appium
162
182
  end
163
183
 
164
184
  def commands(command)
165
- @available_commands[command]
185
+ @available_commands[command] || Bridge.extra_commands[command]
166
186
  end
167
187
 
168
188
  def status
@@ -216,52 +236,8 @@ module Appium
216
236
  end
217
237
 
218
238
  # For Appium
219
- # override
220
- def active_element
221
- ::Appium::Core::Element.new self, element_id_from(execute(:get_active_element))
222
- end
223
239
  alias switch_to_active_element active_element
224
240
 
225
- # For Appium
226
- # override
227
- def find_element_by(how, what, parent_ref = [])
228
- how, what = convert_locator(how, what)
229
-
230
- return execute_atom(:findElements, Support::RelativeLocator.new(what).as_json).first if how == 'relative'
231
-
232
- parent_type, parent_id = parent_ref
233
- id = case parent_type
234
- when :element
235
- execute :find_child_element, { id: parent_id }, { using: how, value: what.to_s }
236
- when :shadow_root
237
- execute :find_shadow_child_element, { id: parent_id }, { using: how, value: what.to_s }
238
- else
239
- execute :find_element, {}, { using: how, value: what.to_s }
240
- end
241
-
242
- ::Appium::Core::Element.new self, element_id_from(id)
243
- end
244
-
245
- # For Appium
246
- # override
247
- def find_elements_by(how, what, parent_ref = [])
248
- how, what = convert_locator(how, what)
249
-
250
- return execute_atom :findElements, Support::RelativeLocator.new(what).as_json if how == 'relative'
251
-
252
- parent_type, parent_id = parent_ref
253
- ids = case parent_type
254
- when :element
255
- execute :find_child_elements, { id: parent_id }, { using: how, value: what.to_s }
256
- when :shadow_root
257
- execute :find_shadow_child_elements, { id: parent_id }, { using: how, value: what.to_s }
258
- else
259
- execute :find_elements, {}, { using: how, value: what.to_s }
260
- end
261
-
262
- ids.map { |id| ::Appium::Core::Element.new self, element_id_from(id) }
263
- end
264
-
265
241
  # For Appium
266
242
  # @param [Hash] id The id which can get as a response from server
267
243
  # @return [::Appium::Core::Element]
@@ -351,55 +327,6 @@ module Appium
351
327
  def send_command(command_params)
352
328
  execute :chrome_send_command, {}, command_params
353
329
  end
354
-
355
- private
356
-
357
- def unwrap_script_result(arg)
358
- case arg
359
- when Array
360
- arg.map { |e| unwrap_script_result(e) }
361
- when Hash
362
- element_id = element_id_from(arg)
363
- return ::Appium::Core::Element.new(self, element_id) if element_id
364
-
365
- shadow_root_id = shadow_root_id_from(arg)
366
- return ::Selenium::WebDriver::Remote::ShadowRoot.new self, shadow_root_id if shadow_root_id
367
-
368
- arg.each { |k, v| arg[k] = unwrap_script_result(v) }
369
- else
370
- arg
371
- end
372
- end
373
-
374
- def element_id_from(id)
375
- id['ELEMENT'] || id['element-6066-11e4-a52e-4f735466cecf']
376
- end
377
-
378
- # Don't convert locators for Appium in native context
379
- def convert_locator(how, what)
380
- # case how
381
- # when 'class name'
382
- # how = 'css selector'
383
- # what = ".#{escape_css(what)}"
384
- # when 'id'
385
- # how = 'css selector'
386
- # what = "##{escape_css(what)}"
387
- # when 'name'
388
- # how = 'css selector'
389
- # what = "*[name='#{escape_css(what)}']"
390
- # when 'tag name'
391
- # how = 'css selector'
392
- # end
393
- #
394
- # if what.is_a?(Hash)
395
- # what = what.each_with_object({}) do |(h, w), hash|
396
- # h, w = convert_locator(h.to_s, w)
397
- # hash[h] = w
398
- # end
399
- # end
400
-
401
- [how, what]
402
- end
403
330
  end # class Bridge
404
331
  end # class Base
405
332
  end # module Core
@@ -32,7 +32,6 @@ module Appium
32
32
  include ::Selenium::WebDriver::DriverExtensions::HasWebStorage
33
33
 
34
34
  include ::Appium::Core::Base::Rotatable
35
- include ::Appium::Core::Base::SearchContext
36
35
  include ::Appium::Core::Base::TakesScreenshot
37
36
  include ::Appium::Core::Base::HasRemoteStatus
38
37
  include ::Appium::Core::Base::HasLocation
@@ -40,6 +39,8 @@ module Appium
40
39
 
41
40
  include ::Appium::Core::Waitable
42
41
 
42
+ ::Selenium::WebDriver::SearchContext.extra_finders = APPIUM_EXTRA_FINDERS
43
+
43
44
  # Private API.
44
45
  # Do not use this for general use. Used by flutter driver to get bridge for creating a new element
45
46
  attr_reader :bridge
@@ -57,6 +58,7 @@ module Appium
57
58
  @bidi = nil
58
59
 
59
60
  # in the selenium webdriver as well
61
+ ::Selenium::WebDriver::Remote::Bridge.element_class = ::Appium::Core::Element
60
62
  bridge ||= create_bridge(**opts)
61
63
  add_extensions(bridge.browser)
62
64
  @bridge = listener ? ::Appium::Support::EventFiringBridge.new(bridge, listener, **original_opts) : bridge
@@ -1023,8 +1025,8 @@ module Appium
1023
1025
  # ele = @driver.convert_to_element(response) #=> ::Appium::Core::Element
1024
1026
  # ele.rect #=> Can get the rect of the element
1025
1027
  #
1026
- def convert_to_element(id)
1027
- @bridge.convert_to_element id
1028
+ def convert_to_element(response_id)
1029
+ @bridge.convert_to_element response_id
1028
1030
  end
1029
1031
  end # class Driver
1030
1032
  end # class Base
@@ -31,6 +31,9 @@ module Appium
31
31
  class Default < ::Selenium::WebDriver::Remote::Http::Default
32
32
  attr_reader :additional_headers
33
33
 
34
+ ::Selenium::WebDriver::Remote::Http::Common.user_agent = \
35
+ "appium/ruby_lib_core/#{VERSION} (#{::Selenium::WebDriver::Remote::Http::Common.user_agent})"
36
+
34
37
  # override
35
38
  def initialize(open_timeout: nil, read_timeout: nil)
36
39
  @open_timeout = open_timeout
@@ -39,6 +42,17 @@ module Appium
39
42
  super
40
43
  end
41
44
 
45
+ def set_additional_header(key, value)
46
+ @additional_headers[key] = value
47
+ ::Selenium::WebDriver::Remote::Http::Common.extra_headers = @additional_headers
48
+ end
49
+
50
+ def delete_additional_header(key)
51
+ @additional_headers.delete key
52
+ ::Selenium::WebDriver::Remote::Http::Common.extra_headers = @additional_headers
53
+ @common_headers.delete key if defined? @common_headers
54
+ end
55
+
42
56
  # Update <code>server_url</code> provided when ruby_lib _core created a default http client.
43
57
  # Set <code>@http</code> as nil to re-create http client for the <code>server_url</code>
44
58
  #
@@ -59,13 +73,6 @@ module Appium
59
73
  @server_url = URI.parse "#{scheme}://#{host}:#{port}#{path}"
60
74
  end
61
75
 
62
- def request(verb, url, headers, payload, redirects = 0)
63
- headers['User-Agent'] = "appium/ruby_lib_core/#{VERSION} (#{headers['User-Agent']})"
64
- headers = headers.merge @additional_headers unless @additional_headers.empty?
65
-
66
- super(verb, url, headers, payload, redirects)
67
- end
68
-
69
76
  private
70
77
 
71
78
  def validate_url_param(scheme, host, port, path)
@@ -12,172 +12,102 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- module Appium
16
- module Core
17
- class Base
18
- module SearchContext
19
- # referenced: ::Selenium::WebDriver::SearchContext
20
-
21
- FINDERS = ::Selenium::WebDriver::SearchContext::FINDERS.merge(
22
- accessibility_id: 'accessibility id',
23
- image: '-image',
24
- custom: '-custom',
25
- # Android
26
- uiautomator: '-android uiautomator', # Unavailable in Espresso
27
- viewtag: '-android viewtag', # Available in Espresso
28
- data_matcher: '-android datamatcher', # Available in Espresso
29
- view_matcher: '-android viewmatcher', # Available in Espresso
30
- # iOS
31
- predicate: '-ios predicate string',
32
- class_chain: '-ios class chain'
33
- )
34
-
35
- # rubocop:disable Layout/LineLength
36
- #
37
- # Find the first element matching the given arguments
38
- #
39
- # - Android can find with uiautomator like a {http://developer.android.com/tools/help/uiautomator/UiSelector.html UISelector}.
40
- # - iOS can find with a {https://developer.apple.com/library/ios/documentation/ToolsLanguages/Reference/UIAWindowClassReference/UIAWindow/UIAWindow.html#//apple_ref/doc/uid/TP40009930 UIAutomation command}.
41
- # - iOS, only for XCUITest(WebDriverAgent), can find with a {https://github.com/facebook/WebDriverAgent/wiki/Queries class chain}
42
- #
43
- # == Find with image
44
- # Return an element if current view has a partial image. The logic depends on template matching by OpenCV.
45
- # {https://github.com/appium/appium/blob/1.x/docs/en/writing-running-appium/image-comparison.md image-comparison}
46
- #
47
- # You can handle settings for the comparision following {https://github.com/appium/appium-base-driver/blob/master/lib/basedriver/device-settings.js#L6 here}
48
- #
49
- # == Espresso viewmatcher and datamatcher
50
- # Espresso has {https://developer.android.com/training/testing/espresso/basics _onView_ matcher}
51
- # and {https://medium.com/androiddevelopers/adapterviews-and-espresso-f4172aa853cf _onData_ matcher} for more reference
52
- # that allows you to target adapters instead of Views. This method find methods based on reflections
53
- #
54
- # This is a selector strategy that allows users to pass a selector of the form:
55
- #
56
- # <code>{ name: '<name>', args: ['arg1', 'arg2', '...'], class: '<optional class>' }</code>
57
- #
58
- # - _name_: The name of a method to invoke. The method must return
59
- # a Hamcrest {http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html Matcher}
60
- # - _args_: The args provided to the method
61
- # - _class_: The class name that the method is part of (defaults to <code>org.hamcrest.Matchers</code>).
62
- # Can be fully qualified, or simple, and simple defaults to <code>androidx.test.espresso.matcher</code> package
63
- # (e.g.: <code>class=CursorMatchers</code> fully qualified is <code>class=androidx.test.espresso.matcher.CursorMatchers</code>
64
- #
65
- # See example how to send viewmatcher and datamatcher in Ruby client
66
- #
67
- #
68
- # @overload find_element(how, what)
69
- # @param [Symbol, String] how The method to find the element by
70
- # @param [String] what The locator to use
71
- #
72
- # @overload find_element(opts)
73
- # @param [Hash] opts Find options
74
- # @option opts [Symbol] :how Key named after the method to find the element by, containing the locator
75
- # @return [Element]
76
- # @raise [Error::NoSuchElementError] if the element doesn't exist
77
- #
78
- # @example Find element with each keys
79
- #
80
- # # with accessibility id. All platforms.
81
- # @driver.find_elements :accessibility_id, 'Animation'
82
- # @driver.find_elements :accessibility_id, 'Animation'
83
- #
84
- # # with base64 encoded template image. All platforms.
85
- # @driver.find_elements :image, Base64.strict_encode64(File.read(file_path))
86
- #
87
- # # For Android
88
- # ## With uiautomator
89
- # @driver.find_elements :uiautomator, 'new UiSelector().clickable(true)'
90
- # ## With viewtag, but only for Espresso
91
- # ## 'setTag'/'getTag' in https://developer.android.com/reference/android/view/View
92
- # @driver.find_elements :viewtag, 'new UiSelector().clickable(true)'
93
- # # With data_matcher. The argument should be JSON format.
94
- # @driver.find_elements :data_matcher, { name: 'hasEntry', args: %w(title Animation) }.to_json
95
- #
96
- # # For iOS
97
- # ## With :predicate
98
- # @driver.find_elements :predicate, "isWDVisible == 1"
99
- # @driver.find_elements :predicate, 'wdName == "Buttons"'
100
- # @driver.find_elements :predicate, 'wdValue == "SearchBar" AND isWDDivisible == 1'
101
- #
102
- # ## With Class Chain
103
- # ### select the third child button of the first child window element
104
- # @driver.find_elements :class_chain, 'XCUIElementTypeWindow/XCUIElementTypeButton[3]'
105
- # ### select all the children windows
106
- # @driver.find_elements :class_chain, 'XCUIElementTypeWindow'
107
- # ### select the second last child of the second child window
108
- # @driver.find_elements :class_chain, 'XCUIElementTypeWindow[2]/XCUIElementTypeAny[-2]'
109
- # ### matching predicate. <code>'</code> is the mark.
110
- # @driver.find_elements :class_chain, 'XCUIElementTypeWindow['visible = 1]['name = "bla"']'
111
- # ### containing predicate. '$' is the mark.
112
- # ### Require appium-xcuitest-driver 2.54.0+. PR: https://github.com/facebook/WebDriverAgent/pull/707/files
113
- # @driver.find_elements :class_chain, 'XCUIElementTypeWindow[$name = \"bla$$$bla\"$]'
114
- # e = find_element :class_chain, "**/XCUIElementTypeWindow[$name == 'Buttons'$]"
115
- # e.tag_name #=> "XCUIElementTypeWindow"
116
- # e = find_element :class_chain, "**/XCUIElementTypeStaticText[$name == 'Buttons'$]"
117
- # e.tag_name #=> "XCUIElementTypeStaticText"
118
- #
119
- # rubocop:enable Layout/LineLength
120
- def find_element(*args)
121
- how, what = extract_args(args)
122
- by = _set_by_from_finders(how)
123
- begin
124
- bridge.find_element_by by, what.to_s, ref
125
- rescue Selenium::WebDriver::Error::TimeoutError
126
- raise Selenium::WebDriver::Error::NoSuchElementError
127
- end
128
- end
129
-
130
- #
131
- # Find all elements matching the given arguments
132
- #
133
- # @return [Array<Selenium::WebDriver::Element>]
134
- #
135
- # @see SearchContext#find_elements
136
- #
137
- def find_elements(*args)
138
- how, what = extract_args(args)
139
- by = _set_by_from_finders(how)
140
- begin
141
- bridge.find_elements_by by, what.to_s, ref
142
- rescue Selenium::WebDriver::Error::TimeoutError
143
- []
144
- end
145
- end
146
-
147
- private
148
-
149
- def _set_by_from_finders(how)
150
- by = FINDERS[how.to_sym]
151
- unless by
152
- raise ::Appium::Core::Error::ArgumentError,
153
- "cannot find element by #{how.inspect}. Available finders are #{FINDERS.keys}."
154
- end
155
-
156
- by
157
- end
158
-
159
- def extract_args(args)
160
- case args.size
161
- when 2
162
- args
163
- when 1
164
- arg = args.first
165
-
166
- unless arg.respond_to?(:shift)
167
- raise ::Appium::Core::Error::ArgumentError, "expected #{arg.inspect}:#{arg.class} to respond to #shift"
168
- end
169
-
170
- # this will be a single-entry hash, so use #shift over #first or #[]
171
- arr = arg.dup.shift
172
-
173
- raise ::Appium::Core::Error::ArgumentError, "expected #{arr.inspect} to have 2 elements" unless arr.size == 2
15
+ # rubocop:disable Layout/LineLength
16
+ #
17
+ # Find the first element matching the given arguments
18
+ #
19
+ # - Android can find with uiautomator like a {http://developer.android.com/tools/help/uiautomator/UiSelector.html UISelector}.
20
+ # - iOS can find with a {https://developer.apple.com/library/ios/documentation/ToolsLanguages/Reference/UIAWindowClassReference/UIAWindow/UIAWindow.html#//apple_ref/doc/uid/TP40009930 UIAutomation command}.
21
+ # - iOS, only for XCUITest(WebDriverAgent), can find with a {https://github.com/facebook/WebDriverAgent/wiki/Queries class chain}
22
+ #
23
+ # == Find with image
24
+ # Return an element if current view has a partial image. The logic depends on template matching by OpenCV.
25
+ # {https://github.com/appium/appium/blob/1.x/docs/en/writing-running-appium/image-comparison.md image-comparison}
26
+ #
27
+ # You can handle settings for the comparision following {https://github.com/appium/appium-base-driver/blob/master/lib/basedriver/device-settings.js#L6 here}
28
+ #
29
+ # == Espresso viewmatcher and datamatcher
30
+ # Espresso has {https://developer.android.com/training/testing/espresso/basics _onView_ matcher}
31
+ # and {https://medium.com/androiddevelopers/adapterviews-and-espresso-f4172aa853cf _onData_ matcher} for more reference
32
+ # that allows you to target adapters instead of Views. This method find methods based on reflections
33
+ #
34
+ # This is a selector strategy that allows users to pass a selector of the form:
35
+ #
36
+ # <code>{ name: '<name>', args: ['arg1', 'arg2', '...'], class: '<optional class>' }</code>
37
+ #
38
+ # - _name_: The name of a method to invoke. The method must return
39
+ # a Hamcrest {http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html Matcher}
40
+ # - _args_: The args provided to the method
41
+ # - _class_: The class name that the method is part of (defaults to <code>org.hamcrest.Matchers</code>).
42
+ # Can be fully qualified, or simple, and simple defaults to <code>androidx.test.espresso.matcher</code> package
43
+ # (e.g.: <code>class=CursorMatchers</code> fully qualified is <code>class=androidx.test.espresso.matcher.CursorMatchers</code>
44
+ #
45
+ # See example how to send viewmatcher and datamatcher in Ruby client
46
+ #
47
+ #
48
+ # @overload find_element(how, what)
49
+ # @param [Symbol, String] how The method to find the element by
50
+ # @param [String] what The locator to use
51
+ #
52
+ # @overload find_element(opts)
53
+ # @param [Hash] opts Find options
54
+ # @option opts [Symbol] :how Key named after the method to find the element by, containing the locator
55
+ # @return [Element]
56
+ # @raise [Error::NoSuchElementError] if the element doesn't exist
57
+ #
58
+ # @example Find element with each keys
59
+ #
60
+ # # with accessibility id. All platforms.
61
+ # @driver.find_elements :accessibility_id, 'Animation'
62
+ # @driver.find_elements :accessibility_id, 'Animation'
63
+ #
64
+ # # with base64 encoded template image. All platforms.
65
+ # @driver.find_elements :image, Base64.strict_encode64(File.read(file_path))
66
+ #
67
+ # # For Android
68
+ # ## With uiautomator
69
+ # @driver.find_elements :uiautomator, 'new UiSelector().clickable(true)'
70
+ # ## With viewtag, but only for Espresso
71
+ # ## 'setTag'/'getTag' in https://developer.android.com/reference/android/view/View
72
+ # @driver.find_elements :viewtag, 'new UiSelector().clickable(true)'
73
+ # # With data_matcher. The argument should be JSON format.
74
+ # @driver.find_elements :data_matcher, { name: 'hasEntry', args: %w(title Animation) }.to_json
75
+ #
76
+ # # For iOS
77
+ # ## With :predicate
78
+ # @driver.find_elements :predicate, "isWDVisible == 1"
79
+ # @driver.find_elements :predicate, 'wdName == "Buttons"'
80
+ # @driver.find_elements :predicate, 'wdValue == "SearchBar" AND isWDDivisible == 1'
81
+ #
82
+ # ## With Class Chain
83
+ # ### select the third child button of the first child window element
84
+ # @driver.find_elements :class_chain, 'XCUIElementTypeWindow/XCUIElementTypeButton[3]'
85
+ # ### select all the children windows
86
+ # @driver.find_elements :class_chain, 'XCUIElementTypeWindow'
87
+ # ### select the second last child of the second child window
88
+ # @driver.find_elements :class_chain, 'XCUIElementTypeWindow[2]/XCUIElementTypeAny[-2]'
89
+ # ### matching predicate. <code>'</code> is the mark.
90
+ # @driver.find_elements :class_chain, 'XCUIElementTypeWindow['visible = 1]['name = "bla"']'
91
+ # ### containing predicate. '$' is the mark.
92
+ # ### Require appium-xcuitest-driver 2.54.0+. PR: https://github.com/facebook/WebDriverAgent/pull/707/files
93
+ # @driver.find_elements :class_chain, 'XCUIElementTypeWindow[$name = \"bla$$$bla\"$]'
94
+ # e = find_element :class_chain, "**/XCUIElementTypeWindow[$name == 'Buttons'$]"
95
+ # e.tag_name #=> "XCUIElementTypeWindow"
96
+ # e = find_element :class_chain, "**/XCUIElementTypeStaticText[$name == 'Buttons'$]"
97
+ # e.tag_name #=> "XCUIElementTypeStaticText"
98
+ #
99
+ # rubocop:enable Layout/LineLength
174
100
 
175
- arr
176
- else
177
- raise ::Appium::Core::Error::ArgumentError, "wrong number of arguments (#{args.size} for 2)"
178
- end
179
- end
180
- end # module SearchContext
181
- end # class Base
182
- end # module Core
183
- end # module Appium
101
+ APPIUM_EXTRA_FINDERS = {
102
+ accessibility_id: 'accessibility id',
103
+ image: '-image',
104
+ custom: '-custom',
105
+ # Android
106
+ uiautomator: '-android uiautomator', # Unavailable in Espresso
107
+ viewtag: '-android viewtag', # Available in Espresso
108
+ data_matcher: '-android datamatcher', # Available in Espresso
109
+ view_matcher: '-android viewmatcher', # Available in Espresso
110
+ # iOS
111
+ predicate: '-ios predicate string',
112
+ class_chain: '-ios class chain'
113
+ }.freeze
@@ -402,7 +402,7 @@ module Appium
402
402
 
403
403
  if @enable_idempotency_header
404
404
  if @http_client.instance_variable_defined? :@additional_headers
405
- @http_client.additional_headers[Appium::Core::Base::Http::RequestHeaders::KEYS[:idempotency]] = SecureRandom.uuid
405
+ @http_client.set_additional_header Appium::Core::Base::Http::RequestHeaders::KEYS[:idempotency], SecureRandom.uuid
406
406
  else
407
407
  ::Appium::Logger.warn 'No additional_headers attribute in this http client instance'
408
408
  end
@@ -426,7 +426,7 @@ module Appium
426
426
 
427
427
  if @http_client.instance_variable_defined? :@additional_headers
428
428
  # We only need the key for a new session request. Should remove it for other following commands.
429
- @http_client.additional_headers.delete Appium::Core::Base::Http::RequestHeaders::KEYS[:idempotency]
429
+ @http_client.delete_additional_header Appium::Core::Base::Http::RequestHeaders::KEYS[:idempotency]
430
430
  end
431
431
 
432
432
  # TODO: this method can be removed after releasing Appium 2.0, and after a while
@@ -17,9 +17,10 @@ module Appium
17
17
  # Implement useful features for element.
18
18
  # Patch for Selenium Webdriver.
19
19
  class Element < ::Selenium::WebDriver::Element
20
- include ::Appium::Core::Base::SearchContext
21
20
  include ::Appium::Core::Base::TakesScreenshot
22
21
 
22
+ ::Selenium::WebDriver::SearchContext.extra_finders = APPIUM_EXTRA_FINDERS
23
+
23
24
  # Retuns the element id.
24
25
  #
25
26
  # @return [String]
@@ -14,7 +14,7 @@
14
14
 
15
15
  module Appium
16
16
  module Core
17
- VERSION = '9.0.0' unless defined? ::Appium::Core::VERSION
18
- DATE = '2024-05-14' unless defined? ::Appium::Core::DATE
17
+ VERSION = '9.1.1' unless defined? ::Appium::Core::VERSION
18
+ DATE = '2024-05-19' unless defined? ::Appium::Core::DATE
19
19
  end
20
20
  end
metadata CHANGED
@@ -1,113 +1,113 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appium_lib_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.0.0
4
+ version: 9.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kazuaki MATSUO
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-05-14 00:00:00.000000000 Z
11
+ date: 2024-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: selenium-webdriver
14
+ name: faye-websocket
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '4.2'
19
+ version: 0.11.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '4.2'
26
+ version: 0.11.0
27
27
  - !ruby/object:Gem::Dependency
28
- name: faye-websocket
28
+ name: selenium-webdriver
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.11.0
33
+ version: '4.21'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.11.0
40
+ version: '4.21'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rake
42
+ name: appium_thor
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '13.0'
47
+ version: '2.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '13.0'
54
+ version: '2.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: yard
56
+ name: minitest
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.9.11
61
+ version: '5.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.9.11
68
+ version: '5.0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: minitest
70
+ name: minitest-reporters
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '5.0'
75
+ version: '1.1'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '5.0'
82
+ version: '1.1'
83
83
  - !ruby/object:Gem::Dependency
84
- name: minitest-reporters
84
+ name: parallel_tests
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '1.1'
89
+ version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '1.1'
96
+ version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: webmock
98
+ name: rake
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 3.23.0
103
+ version: '13.0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 3.23.0
110
+ version: '13.0'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rubocop
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -123,47 +123,47 @@ dependencies:
123
123
  - !ruby/object:Gem::Version
124
124
  version: 1.63.5
125
125
  - !ruby/object:Gem::Dependency
126
- name: appium_thor
126
+ name: simplecov
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - "~>"
129
+ - - ">="
130
130
  - !ruby/object:Gem::Version
131
- version: '2.0'
131
+ version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - "~>"
136
+ - - ">="
137
137
  - !ruby/object:Gem::Version
138
- version: '2.0'
138
+ version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
- name: parallel_tests
140
+ name: webmock
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - ">="
143
+ - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '0'
145
+ version: 3.23.0
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - ">="
150
+ - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '0'
152
+ version: 3.23.0
153
153
  - !ruby/object:Gem::Dependency
154
- name: simplecov
154
+ name: yard
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - ">="
157
+ - - "~>"
158
158
  - !ruby/object:Gem::Version
159
- version: '0'
159
+ version: 0.9.11
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
- - - ">="
164
+ - - "~>"
165
165
  - !ruby/object:Gem::Version
166
- version: '0'
166
+ version: 0.9.11
167
167
  description: Minimal Ruby library for Appium.
168
168
  email:
169
169
  - fly.49.89.over@gmail.com
@@ -258,7 +258,8 @@ files:
258
258
  homepage: https://github.com/appium/ruby_lib_core/
259
259
  licenses:
260
260
  - Apache-2.0
261
- metadata: {}
261
+ metadata:
262
+ rubygems_mfa_required: 'true'
262
263
  post_install_message:
263
264
  rdoc_options: []
264
265
  require_paths:
@@ -274,7 +275,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
274
275
  - !ruby/object:Gem::Version
275
276
  version: '0'
276
277
  requirements: []
277
- rubygems_version: 3.4.10
278
+ rubygems_version: 3.5.9
278
279
  signing_key:
279
280
  specification_version: 4
280
281
  summary: Minimal Ruby library for Appium.