diff --git a/CHANGELOG.md b/CHANGELOG.md
index ddfeb8b1..ac93b9e9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@ Read `release_notes.md` for commit level details.
## [Unreleased]
### Enhancements
+- Simplify internal code with Selenium 4.21.0. Now it requires selenium webdriver v4.21.0.
### Bug fixes
diff --git a/appium_lib_core.gemspec b/appium_lib_core.gemspec
index 77aa3173..b8fd1087 100644
--- a/appium_lib_core.gemspec
+++ b/appium_lib_core.gemspec
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ['lib']
- spec.add_runtime_dependency 'selenium-webdriver', '~> 4.2'
+ spec.add_runtime_dependency 'selenium-webdriver', '~> 4.21'
spec.add_runtime_dependency 'faye-websocket', '~> 0.11.0'
spec.add_development_dependency 'rake', '~> 13.0'
diff --git a/lib/appium_lib_core/common/base/bridge.rb b/lib/appium_lib_core/common/base/bridge.rb
index 26a23c45..3d6b5c3a 100644
--- a/lib/appium_lib_core/common/base/bridge.rb
+++ b/lib/appium_lib_core/common/base/bridge.rb
@@ -15,6 +15,12 @@
module Appium
module Core
class Base
+ class LocatorConverter
+ def convert(how, what)
+ [how, what]
+ end
+ end # LocatorConverter
+
class Bridge < ::Selenium::WebDriver::Remote::Bridge
include Device::DeviceLock
include Device::Keyboard
@@ -31,6 +37,8 @@ class Bridge < ::Selenium::WebDriver::Remote::Bridge
include Device::ExecuteDriver
include Device::Orientation
+ Bridge.locator_converter = LocatorConverter.new
+
# Prefix for extra capability defined by W3C
APPIUM_PREFIX = 'appium:'
@@ -153,6 +161,18 @@ def json_create(value)
public
# command for Appium 2.0.
+
+ # Example:
+ # driver.add_command(name: :available_contexts, method: :get, url: 'session/:session_id/contexts') do
+ # execute(:available_contexts, {}) || []
+ # end
+ # Then,
+ # driver.available_contexts #=> ["NATIVE_APP"]
+
+ # def add_command(method:, url:, name:, &block)
+ # Bridge.add_command name, method, url, &block
+ # end
+
def add_command(method:, url:, name:, &block)
::Appium::Logger.info "Overriding the method '#{name}' for '#{url}'" if @available_commands.key? name
@@ -162,7 +182,7 @@ def add_command(method:, url:, name:, &block)
end
def commands(command)
- @available_commands[command]
+ @available_commands[command] || Bridge.extra_commands[command]
end
def status
@@ -216,52 +236,8 @@ def element_attribute(element, name)
end
# For Appium
- # override
- def active_element
- ::Appium::Core::Element.new self, element_id_from(execute(:get_active_element))
- end
alias switch_to_active_element active_element
- # For Appium
- # override
- def find_element_by(how, what, parent_ref = [])
- how, what = convert_locator(how, what)
-
- return execute_atom(:findElements, Support::RelativeLocator.new(what).as_json).first if how == 'relative'
-
- parent_type, parent_id = parent_ref
- id = case parent_type
- when :element
- execute :find_child_element, { id: parent_id }, { using: how, value: what.to_s }
- when :shadow_root
- execute :find_shadow_child_element, { id: parent_id }, { using: how, value: what.to_s }
- else
- execute :find_element, {}, { using: how, value: what.to_s }
- end
-
- ::Appium::Core::Element.new self, element_id_from(id)
- end
-
- # For Appium
- # override
- def find_elements_by(how, what, parent_ref = [])
- how, what = convert_locator(how, what)
-
- return execute_atom :findElements, Support::RelativeLocator.new(what).as_json if how == 'relative'
-
- parent_type, parent_id = parent_ref
- ids = case parent_type
- when :element
- execute :find_child_elements, { id: parent_id }, { using: how, value: what.to_s }
- when :shadow_root
- execute :find_shadow_child_elements, { id: parent_id }, { using: how, value: what.to_s }
- else
- execute :find_elements, {}, { using: how, value: what.to_s }
- end
-
- ids.map { |id| ::Appium::Core::Element.new self, element_id_from(id) }
- end
-
# For Appium
# @param [Hash] id The id which can get as a response from server
# @return [::Appium::Core::Element]
@@ -370,36 +346,6 @@ def unwrap_script_result(arg)
arg
end
end
-
- def element_id_from(id)
- id['ELEMENT'] || id['element-6066-11e4-a52e-4f735466cecf']
- end
-
- # Don't convert locators for Appium in native context
- def convert_locator(how, what)
- # case how
- # when 'class name'
- # how = 'css selector'
- # what = ".#{escape_css(what)}"
- # when 'id'
- # how = 'css selector'
- # what = "##{escape_css(what)}"
- # when 'name'
- # how = 'css selector'
- # what = "*[name='#{escape_css(what)}']"
- # when 'tag name'
- # how = 'css selector'
- # end
- #
- # if what.is_a?(Hash)
- # what = what.each_with_object({}) do |(h, w), hash|
- # h, w = convert_locator(h.to_s, w)
- # hash[h] = w
- # end
- # end
-
- [how, what]
- end
end # class Bridge
end # class Base
end # module Core
diff --git a/lib/appium_lib_core/common/base/driver.rb b/lib/appium_lib_core/common/base/driver.rb
index 3199ca0f..3a3d0501 100644
--- a/lib/appium_lib_core/common/base/driver.rb
+++ b/lib/appium_lib_core/common/base/driver.rb
@@ -32,7 +32,6 @@ class Driver < ::Selenium::WebDriver::Driver
include ::Selenium::WebDriver::DriverExtensions::HasWebStorage
include ::Appium::Core::Base::Rotatable
- include ::Appium::Core::Base::SearchContext
include ::Appium::Core::Base::TakesScreenshot
include ::Appium::Core::Base::HasRemoteStatus
include ::Appium::Core::Base::HasLocation
@@ -40,6 +39,8 @@ class Driver < ::Selenium::WebDriver::Driver
include ::Appium::Core::Waitable
+ ::Selenium::WebDriver::SearchContext.extra_finders = APPIUM_EXTRA_FINDERS
+
# Private API.
# Do not use this for general use. Used by flutter driver to get bridge for creating a new element
attr_reader :bridge
@@ -57,6 +58,7 @@ def initialize(bridge: nil, listener: nil, **opts) # rubocop:disable Lint/Missin
@bidi = nil
# in the selenium webdriver as well
+ ::Selenium::WebDriver::Remote::Bridge.element_class = ::Appium::Core::Element
bridge ||= create_bridge(**opts)
add_extensions(bridge.browser)
@bridge = listener ? ::Appium::Support::EventFiringBridge.new(bridge, listener, **original_opts) : bridge
@@ -1023,8 +1025,8 @@ def execute_driver(script: '', type: 'webdriverio', timeout_ms: nil)
# ele = @driver.convert_to_element(response) #=> ::Appium::Core::Element
# ele.rect #=> Can get the rect of the element
#
- def convert_to_element(id)
- @bridge.convert_to_element id
+ def convert_to_element(response_id)
+ @bridge.convert_to_element response_id
end
end # class Driver
end # class Base
diff --git a/lib/appium_lib_core/common/base/http_default.rb b/lib/appium_lib_core/common/base/http_default.rb
index ea9b23c3..da61b3c1 100644
--- a/lib/appium_lib_core/common/base/http_default.rb
+++ b/lib/appium_lib_core/common/base/http_default.rb
@@ -31,6 +31,9 @@ module RequestHeaders
class Default < ::Selenium::WebDriver::Remote::Http::Default
attr_reader :additional_headers
+ ::Selenium::WebDriver::Remote::Http::Common.user_agent = \
+ "appium/ruby_lib_core/#{VERSION} (#{::Selenium::WebDriver::Remote::Http::Common.user_agent})"
+
# override
def initialize(open_timeout: nil, read_timeout: nil)
@open_timeout = open_timeout
@@ -39,6 +42,17 @@ def initialize(open_timeout: nil, read_timeout: nil)
super
end
+ def set_additional_header(key, value)
+ @additional_headers[key] = value
+ ::Selenium::WebDriver::Remote::Http::Common.extra_headers = @additional_headers
+ end
+
+ def delete_additional_header(key)
+ @additional_headers.delete key
+ ::Selenium::WebDriver::Remote::Http::Common.extra_headers = @additional_headers
+ @common_headers.delete key if defined? @common_headers
+ end
+
# Update server_url
provided when ruby_lib _core created a default http client.
# Set @http
as nil to re-create http client for the server_url
#
@@ -59,13 +73,6 @@ def update_sending_request_to(scheme:, host:, port:, path:)
@server_url = URI.parse "#{scheme}://#{host}:#{port}#{path}"
end
- def request(verb, url, headers, payload, redirects = 0)
- headers['User-Agent'] = "appium/ruby_lib_core/#{VERSION} (#{headers['User-Agent']})"
- headers = headers.merge @additional_headers unless @additional_headers.empty?
-
- super(verb, url, headers, payload, redirects)
- end
-
private
def validate_url_param(scheme, host, port, path)
diff --git a/lib/appium_lib_core/common/base/search_context.rb b/lib/appium_lib_core/common/base/search_context.rb
index 35977c09..66797950 100644
--- a/lib/appium_lib_core/common/base/search_context.rb
+++ b/lib/appium_lib_core/common/base/search_context.rb
@@ -12,172 +12,102 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-module Appium
- module Core
- class Base
- module SearchContext
- # referenced: ::Selenium::WebDriver::SearchContext
-
- FINDERS = ::Selenium::WebDriver::SearchContext::FINDERS.merge(
- accessibility_id: 'accessibility id',
- image: '-image',
- custom: '-custom',
- # Android
- uiautomator: '-android uiautomator', # Unavailable in Espresso
- viewtag: '-android viewtag', # Available in Espresso
- data_matcher: '-android datamatcher', # Available in Espresso
- view_matcher: '-android viewmatcher', # Available in Espresso
- # iOS
- predicate: '-ios predicate string',
- class_chain: '-ios class chain'
- )
-
- # rubocop:disable Layout/LineLength
- #
- # Find the first element matching the given arguments
- #
- # - Android can find with uiautomator like a {http://developer.android.com/tools/help/uiautomator/UiSelector.html UISelector}.
- # - 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}.
- # - iOS, only for XCUITest(WebDriverAgent), can find with a {https://github.com/facebook/WebDriverAgent/wiki/Queries class chain}
- #
- # == Find with image
- # Return an element if current view has a partial image. The logic depends on template matching by OpenCV.
- # {https://github.com/appium/appium/blob/1.x/docs/en/writing-running-appium/image-comparison.md image-comparison}
- #
- # You can handle settings for the comparision following {https://github.com/appium/appium-base-driver/blob/master/lib/basedriver/device-settings.js#L6 here}
- #
- # == Espresso viewmatcher and datamatcher
- # Espresso has {https://developer.android.com/training/testing/espresso/basics _onView_ matcher}
- # and {https://medium.com/androiddevelopers/adapterviews-and-espresso-f4172aa853cf _onData_ matcher} for more reference
- # that allows you to target adapters instead of Views. This method find methods based on reflections
- #
- # This is a selector strategy that allows users to pass a selector of the form:
- #
- # { name: '', args: ['arg1', 'arg2', '...'], class: '' }
- #
- # - _name_: The name of a method to invoke. The method must return
- # a Hamcrest {http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html Matcher}
- # - _args_: The args provided to the method
- # - _class_: The class name that the method is part of (defaults to org.hamcrest.Matchers
).
- # Can be fully qualified, or simple, and simple defaults to androidx.test.espresso.matcher
package
- # (e.g.: class=CursorMatchers
fully qualified is class=androidx.test.espresso.matcher.CursorMatchers
- #
- # See example how to send viewmatcher and datamatcher in Ruby client
- #
- #
- # @overload find_element(how, what)
- # @param [Symbol, String] how The method to find the element by
- # @param [String] what The locator to use
- #
- # @overload find_element(opts)
- # @param [Hash] opts Find options
- # @option opts [Symbol] :how Key named after the method to find the element by, containing the locator
- # @return [Element]
- # @raise [Error::NoSuchElementError] if the element doesn't exist
- #
- # @example Find element with each keys
- #
- # # with accessibility id. All platforms.
- # @driver.find_elements :accessibility_id, 'Animation'
- # @driver.find_elements :accessibility_id, 'Animation'
- #
- # # with base64 encoded template image. All platforms.
- # @driver.find_elements :image, Base64.strict_encode64(File.read(file_path))
- #
- # # For Android
- # ## With uiautomator
- # @driver.find_elements :uiautomator, 'new UiSelector().clickable(true)'
- # ## With viewtag, but only for Espresso
- # ## 'setTag'/'getTag' in https://developer.android.com/reference/android/view/View
- # @driver.find_elements :viewtag, 'new UiSelector().clickable(true)'
- # # With data_matcher. The argument should be JSON format.
- # @driver.find_elements :data_matcher, { name: 'hasEntry', args: %w(title Animation) }.to_json
- #
- # # For iOS
- # ## With :predicate
- # @driver.find_elements :predicate, "isWDVisible == 1"
- # @driver.find_elements :predicate, 'wdName == "Buttons"'
- # @driver.find_elements :predicate, 'wdValue == "SearchBar" AND isWDDivisible == 1'
- #
- # ## With Class Chain
- # ### select the third child button of the first child window element
- # @driver.find_elements :class_chain, 'XCUIElementTypeWindow/XCUIElementTypeButton[3]'
- # ### select all the children windows
- # @driver.find_elements :class_chain, 'XCUIElementTypeWindow'
- # ### select the second last child of the second child window
- # @driver.find_elements :class_chain, 'XCUIElementTypeWindow[2]/XCUIElementTypeAny[-2]'
- # ### matching predicate. '
is the mark.
- # @driver.find_elements :class_chain, 'XCUIElementTypeWindow['visible = 1]['name = "bla"']'
- # ### containing predicate. '$' is the mark.
- # ### Require appium-xcuitest-driver 2.54.0+. PR: https://github.com/facebook/WebDriverAgent/pull/707/files
- # @driver.find_elements :class_chain, 'XCUIElementTypeWindow[$name = \"bla$$$bla\"$]'
- # e = find_element :class_chain, "**/XCUIElementTypeWindow[$name == 'Buttons'$]"
- # e.tag_name #=> "XCUIElementTypeWindow"
- # e = find_element :class_chain, "**/XCUIElementTypeStaticText[$name == 'Buttons'$]"
- # e.tag_name #=> "XCUIElementTypeStaticText"
- #
- # rubocop:enable Layout/LineLength
- def find_element(*args)
- how, what = extract_args(args)
- by = _set_by_from_finders(how)
- begin
- bridge.find_element_by by, what.to_s, ref
- rescue Selenium::WebDriver::Error::TimeoutError
- raise Selenium::WebDriver::Error::NoSuchElementError
- end
- end
-
- #
- # Find all elements matching the given arguments
- #
- # @return [Array]
- #
- # @see SearchContext#find_elements
- #
- def find_elements(*args)
- how, what = extract_args(args)
- by = _set_by_from_finders(how)
- begin
- bridge.find_elements_by by, what.to_s, ref
- rescue Selenium::WebDriver::Error::TimeoutError
- []
- end
- end
-
- private
-
- def _set_by_from_finders(how)
- by = FINDERS[how.to_sym]
- unless by
- raise ::Appium::Core::Error::ArgumentError,
- "cannot find element by #{how.inspect}. Available finders are #{FINDERS.keys}."
- end
-
- by
- end
-
- def extract_args(args)
- case args.size
- when 2
- args
- when 1
- arg = args.first
-
- unless arg.respond_to?(:shift)
- raise ::Appium::Core::Error::ArgumentError, "expected #{arg.inspect}:#{arg.class} to respond to #shift"
- end
-
- # this will be a single-entry hash, so use #shift over #first or #[]
- arr = arg.dup.shift
-
- raise ::Appium::Core::Error::ArgumentError, "expected #{arr.inspect} to have 2 elements" unless arr.size == 2
+# rubocop:disable Layout/LineLength
+#
+# Find the first element matching the given arguments
+#
+# - Android can find with uiautomator like a {http://developer.android.com/tools/help/uiautomator/UiSelector.html UISelector}.
+# - 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}.
+# - iOS, only for XCUITest(WebDriverAgent), can find with a {https://github.com/facebook/WebDriverAgent/wiki/Queries class chain}
+#
+# == Find with image
+# Return an element if current view has a partial image. The logic depends on template matching by OpenCV.
+# {https://github.com/appium/appium/blob/1.x/docs/en/writing-running-appium/image-comparison.md image-comparison}
+#
+# You can handle settings for the comparision following {https://github.com/appium/appium-base-driver/blob/master/lib/basedriver/device-settings.js#L6 here}
+#
+# == Espresso viewmatcher and datamatcher
+# Espresso has {https://developer.android.com/training/testing/espresso/basics _onView_ matcher}
+# and {https://medium.com/androiddevelopers/adapterviews-and-espresso-f4172aa853cf _onData_ matcher} for more reference
+# that allows you to target adapters instead of Views. This method find methods based on reflections
+#
+# This is a selector strategy that allows users to pass a selector of the form:
+#
+# { name: '', args: ['arg1', 'arg2', '...'], class: '' }
+#
+# - _name_: The name of a method to invoke. The method must return
+# a Hamcrest {http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html Matcher}
+# - _args_: The args provided to the method
+# - _class_: The class name that the method is part of (defaults to org.hamcrest.Matchers
).
+# Can be fully qualified, or simple, and simple defaults to androidx.test.espresso.matcher
package
+# (e.g.: class=CursorMatchers
fully qualified is class=androidx.test.espresso.matcher.CursorMatchers
+#
+# See example how to send viewmatcher and datamatcher in Ruby client
+#
+#
+# @overload find_element(how, what)
+# @param [Symbol, String] how The method to find the element by
+# @param [String] what The locator to use
+#
+# @overload find_element(opts)
+# @param [Hash] opts Find options
+# @option opts [Symbol] :how Key named after the method to find the element by, containing the locator
+# @return [Element]
+# @raise [Error::NoSuchElementError] if the element doesn't exist
+#
+# @example Find element with each keys
+#
+# # with accessibility id. All platforms.
+# @driver.find_elements :accessibility_id, 'Animation'
+# @driver.find_elements :accessibility_id, 'Animation'
+#
+# # with base64 encoded template image. All platforms.
+# @driver.find_elements :image, Base64.strict_encode64(File.read(file_path))
+#
+# # For Android
+# ## With uiautomator
+# @driver.find_elements :uiautomator, 'new UiSelector().clickable(true)'
+# ## With viewtag, but only for Espresso
+# ## 'setTag'/'getTag' in https://developer.android.com/reference/android/view/View
+# @driver.find_elements :viewtag, 'new UiSelector().clickable(true)'
+# # With data_matcher. The argument should be JSON format.
+# @driver.find_elements :data_matcher, { name: 'hasEntry', args: %w(title Animation) }.to_json
+#
+# # For iOS
+# ## With :predicate
+# @driver.find_elements :predicate, "isWDVisible == 1"
+# @driver.find_elements :predicate, 'wdName == "Buttons"'
+# @driver.find_elements :predicate, 'wdValue == "SearchBar" AND isWDDivisible == 1'
+#
+# ## With Class Chain
+# ### select the third child button of the first child window element
+# @driver.find_elements :class_chain, 'XCUIElementTypeWindow/XCUIElementTypeButton[3]'
+# ### select all the children windows
+# @driver.find_elements :class_chain, 'XCUIElementTypeWindow'
+# ### select the second last child of the second child window
+# @driver.find_elements :class_chain, 'XCUIElementTypeWindow[2]/XCUIElementTypeAny[-2]'
+# ### matching predicate. '
is the mark.
+# @driver.find_elements :class_chain, 'XCUIElementTypeWindow['visible = 1]['name = "bla"']'
+# ### containing predicate. '$' is the mark.
+# ### Require appium-xcuitest-driver 2.54.0+. PR: https://github.com/facebook/WebDriverAgent/pull/707/files
+# @driver.find_elements :class_chain, 'XCUIElementTypeWindow[$name = \"bla$$$bla\"$]'
+# e = find_element :class_chain, "**/XCUIElementTypeWindow[$name == 'Buttons'$]"
+# e.tag_name #=> "XCUIElementTypeWindow"
+# e = find_element :class_chain, "**/XCUIElementTypeStaticText[$name == 'Buttons'$]"
+# e.tag_name #=> "XCUIElementTypeStaticText"
+#
+# rubocop:enable Layout/LineLength
- arr
- else
- raise ::Appium::Core::Error::ArgumentError, "wrong number of arguments (#{args.size} for 2)"
- end
- end
- end # module SearchContext
- end # class Base
- end # module Core
-end # module Appium
+APPIUM_EXTRA_FINDERS = {
+ accessibility_id: 'accessibility id',
+ image: '-image',
+ custom: '-custom',
+ # Android
+ uiautomator: '-android uiautomator', # Unavailable in Espresso
+ viewtag: '-android viewtag', # Available in Espresso
+ data_matcher: '-android datamatcher', # Available in Espresso
+ view_matcher: '-android viewmatcher', # Available in Espresso
+ # iOS
+ predicate: '-ios predicate string',
+ class_chain: '-ios class chain'
+}.freeze
diff --git a/lib/appium_lib_core/driver.rb b/lib/appium_lib_core/driver.rb
index ceb5eba6..27aa9d54 100644
--- a/lib/appium_lib_core/driver.rb
+++ b/lib/appium_lib_core/driver.rb
@@ -402,7 +402,7 @@ def start_driver(server_url: nil,
if @enable_idempotency_header
if @http_client.instance_variable_defined? :@additional_headers
- @http_client.additional_headers[Appium::Core::Base::Http::RequestHeaders::KEYS[:idempotency]] = SecureRandom.uuid
+ @http_client.set_additional_header Appium::Core::Base::Http::RequestHeaders::KEYS[:idempotency], SecureRandom.uuid
else
::Appium::Logger.warn 'No additional_headers attribute in this http client instance'
end
@@ -426,7 +426,7 @@ def start_driver(server_url: nil,
if @http_client.instance_variable_defined? :@additional_headers
# We only need the key for a new session request. Should remove it for other following commands.
- @http_client.additional_headers.delete Appium::Core::Base::Http::RequestHeaders::KEYS[:idempotency]
+ @http_client.delete_additional_header Appium::Core::Base::Http::RequestHeaders::KEYS[:idempotency]
end
# TODO: this method can be removed after releasing Appium 2.0, and after a while
diff --git a/lib/appium_lib_core/element.rb b/lib/appium_lib_core/element.rb
index aa41cdc0..58eeca8f 100644
--- a/lib/appium_lib_core/element.rb
+++ b/lib/appium_lib_core/element.rb
@@ -17,9 +17,10 @@ module Core
# Implement useful features for element.
# Patch for Selenium Webdriver.
class Element < ::Selenium::WebDriver::Element
- include ::Appium::Core::Base::SearchContext
include ::Appium::Core::Base::TakesScreenshot
+ ::Selenium::WebDriver::SearchContext.extra_finders = APPIUM_EXTRA_FINDERS
+
# Retuns the element id.
#
# @return [String]
diff --git a/test/test_helper.rb b/test/test_helper.rb
index da53f673..f35dca6f 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -453,6 +453,8 @@ def android_mock_create_session_w3c
.to_return(headers: HEADER, status: 200, body: { value: nil }.to_json)
driver = @core.start_driver
+ assert_equal ::Appium::Core::Base::Driver, driver.class
+ assert_equal ::Appium::Core::Base::Bridge, driver.bridge.class
assert_equal({}, driver.send(:bridge).http.additional_headers)
assert_requested(
diff --git a/test/unit/common_test.rb b/test/unit/common_test.rb
index 135c3725..51c76589 100644
--- a/test/unit/common_test.rb
+++ b/test/unit/common_test.rb
@@ -22,6 +22,7 @@ class AppiumCoreBaseBridgeTest < Minitest::Test
include AppiumLibCoreTest::Mock
def setup
+ ::Selenium::WebDriver::Remote::Bridge.element_class = ::Appium::Core::Element
@bridge = Appium::Core::Base::Bridge.new url: 'http://127.0.0.1:4723/wd/hub'
end
diff --git a/test/unit/driver_test.rb b/test/unit/driver_test.rb
index ad5eec0b..b6ee380e 100644
--- a/test/unit/driver_test.rb
+++ b/test/unit/driver_test.rb
@@ -442,27 +442,31 @@ def _android_mock_create_session_w3c_with_custom_http_client(core)
# https://www.w3.org/TR/webdriver1/
def test_search_context_in_element_class
- assert_equal 20, ::Appium::Core::Element::FINDERS.length
- assert_equal({ class: 'class name',
- class_name: 'class name',
- css: 'css selector', # Defined in W3C spec
- id: 'id',
- link: 'link text', # Defined in W3C spec
- link_text: 'link text', # Defined in W3C spec
- name: 'name',
- partial_link_text: 'partial link text', # Defined in W3C spec
- relative: 'relative', # Defined in Selenium
- tag_name: 'tag name', # Defined in W3C spec
- xpath: 'xpath', # Defined in W3C spec
- accessibility_id: 'accessibility id',
- image: '-image',
- custom: '-custom',
- uiautomator: '-android uiautomator',
- viewtag: '-android viewtag',
- data_matcher: '-android datamatcher',
- view_matcher: '-android viewmatcher',
- predicate: '-ios predicate string',
- class_chain: '-ios class chain' }, ::Appium::Core::Element::FINDERS)
+ assert_equal(
+ {
+ class: 'class name',
+ class_name: 'class name',
+ css: 'css selector', # Defined in W3C spec
+ id: 'id',
+ link: 'link text', # Defined in W3C spec
+ link_text: 'link text', # Defined in W3C spec
+ name: 'name',
+ partial_link_text: 'partial link text', # Defined in W3C spec
+ relative: 'relative', # Defined in Selenium
+ tag_name: 'tag name', # Defined in W3C spec
+ xpath: 'xpath', # Defined in W3C spec
+ accessibility_id: 'accessibility id',
+ image: '-image',
+ custom: '-custom',
+ uiautomator: '-android uiautomator',
+ viewtag: '-android viewtag',
+ data_matcher: '-android datamatcher',
+ view_matcher: '-android viewmatcher',
+ predicate: '-ios predicate string',
+ class_chain: '-ios class chain'
+ },
+ ::Appium::Core::Element::FINDERS.merge(::Selenium::WebDriver::SearchContext.extra_finders)
+ )
end
def test_attach_to_an_existing_session