appium_lib_core 9.0.0 → 9.1.1

Sign up to get free protection for your applications and to get access to all the features.
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.