appium_lib_core 5.0.0 → 6.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +140 -0
- data/README.md +55 -10
- data/appium_lib_core.gemspec +5 -5
- data/lib/appium_lib_core/common/base/bridge.rb +54 -40
- data/lib/appium_lib_core/common/base/capabilities.rb +8 -16
- data/lib/appium_lib_core/common/base/driver.rb +68 -40
- data/lib/appium_lib_core/common/base/has_location.rb +10 -10
- data/lib/appium_lib_core/common/base/http_default.rb +1 -1
- data/lib/appium_lib_core/common/base/rotable.rb +11 -3
- data/lib/appium_lib_core/common/base/search_context.rb +1 -2
- data/lib/appium_lib_core/common/command.rb +4 -2
- data/lib/appium_lib_core/common/device/app_management.rb +8 -14
- data/lib/appium_lib_core/common/device/value.rb +1 -3
- data/lib/appium_lib_core/common/error.rb +0 -4
- data/lib/appium_lib_core/driver.rb +170 -62
- data/lib/appium_lib_core/support/event_firing_bridge.rb +57 -0
- data/lib/appium_lib_core/version.rb +2 -2
- data/lib/appium_lib_core/{ios/uiautomation/bridge.rb → windows/device/app_management.rb} +20 -12
- data/lib/appium_lib_core/windows/device.rb +2 -0
- data/lib/appium_lib_core.rb +19 -5
- metadata +21 -34
- data/.github/ISSUE_TEMPLATE/issue-report.md +0 -29
- data/.github/contributing.md +0 -26
- data/.github/dependabot.yml +0 -8
- data/.github/issue_template.md +0 -20
- data/.github/workflows/unittest.yml +0 -67
- data/.gitignore +0 -18
- data/.rubocop.yml +0 -146
- data/azure-pipelines.yml +0 -15
- data/ci-jobs/functional/android_setup.yml +0 -3
- data/ci-jobs/functional/ios_setup.yml +0 -7
- data/ci-jobs/functional/publish_test_result.yml +0 -18
- data/ci-jobs/functional/run_appium.yml +0 -25
- data/ci-jobs/functional/start-emulator.sh +0 -26
- data/ci-jobs/functional_test.yml +0 -298
- data/docs/mobile_command.md +0 -34
- data/lib/appium_lib_core/ios/uiautomation/device.rb +0 -44
- data/lib/appium_lib_core/ios/uiautomation/patch.rb +0 -34
- data/lib/appium_lib_core/ios.rb +0 -20
- data/release_notes.md +0 -932
- data/script/commands.rb +0 -166
@@ -29,7 +29,6 @@ module Appium
|
|
29
29
|
class Driver < ::Selenium::WebDriver::Driver
|
30
30
|
include ::Selenium::WebDriver::DriverExtensions::UploadsFiles
|
31
31
|
include ::Selenium::WebDriver::DriverExtensions::HasSessionId
|
32
|
-
include ::Selenium::WebDriver::DriverExtensions::HasRemoteStatus
|
33
32
|
include ::Selenium::WebDriver::DriverExtensions::HasWebStorage
|
34
33
|
|
35
34
|
include ::Appium::Core::Base::Rotatable
|
@@ -41,36 +40,54 @@ module Appium
|
|
41
40
|
|
42
41
|
include ::Appium::Core::Waitable
|
43
42
|
|
44
|
-
private
|
45
|
-
|
46
43
|
# Private API.
|
47
44
|
# Do not use this for general use. Used by flutter driver to get bridge for creating a new element
|
48
45
|
attr_reader :bridge
|
49
46
|
|
50
47
|
def initialize(bridge: nil, listener: nil, **opts)
|
48
|
+
original_opts = opts.dup
|
49
|
+
|
51
50
|
# For ::Appium::Core::Waitable
|
52
51
|
@wait_timeout = opts.delete(:wait_timeout)
|
53
52
|
@wait_interval = opts.delete(:wait_interval)
|
54
53
|
|
55
|
-
#
|
56
|
-
|
57
|
-
@
|
54
|
+
# Selenium WebDriver attributes
|
55
|
+
@devtools = nil
|
56
|
+
@bidi = nil
|
58
57
|
|
59
|
-
|
58
|
+
# in the selenium webdriver as well
|
59
|
+
bridge ||= create_bridge(**opts)
|
60
|
+
add_extensions(bridge.browser)
|
61
|
+
@bridge = listener ? ::Appium::Support::EventFiringBridge.new(bridge, listener, **original_opts) : bridge
|
60
62
|
end
|
61
63
|
|
64
|
+
private
|
65
|
+
|
62
66
|
# Create a proper bridge instance.
|
63
67
|
#
|
64
68
|
# @return [::Appium::Core::Base::Bridge]
|
65
69
|
#
|
66
70
|
def create_bridge(**opts)
|
71
|
+
# for a new session request
|
67
72
|
capabilities = opts.delete(:capabilities)
|
68
73
|
bridge_opts = { http_client: opts.delete(:http_client), url: opts.delete(:url) }
|
74
|
+
|
75
|
+
# for attaching to an existing session
|
76
|
+
session_id = opts.delete(:existing_session_id)
|
77
|
+
automation_name = opts.delete(:automation_name)
|
78
|
+
platform_name = opts.delete(:platform_name)
|
79
|
+
|
69
80
|
raise ::Appium::Core::Error::ArgumentError, "Unable to create a driver with parameters: #{opts}" unless opts.empty?
|
70
81
|
|
71
82
|
bridge = ::Appium::Core::Base::Bridge.new(**bridge_opts)
|
72
83
|
|
73
|
-
|
84
|
+
if session_id.nil?
|
85
|
+
bridge.create_session(capabilities)
|
86
|
+
else
|
87
|
+
# attach to the existing session id
|
88
|
+
bridge.attach_to(session_id, platform_name, automation_name)
|
89
|
+
end
|
90
|
+
|
74
91
|
bridge
|
75
92
|
end
|
76
93
|
|
@@ -181,6 +198,31 @@ module Appium
|
|
181
198
|
|
182
199
|
### Methods for Appium
|
183
200
|
|
201
|
+
# Perform 'key' actions for W3C module.
|
202
|
+
# Generate +key+ pointer action here and users can use this via +driver.key_action+
|
203
|
+
# - https://seleniumhq.github.io/selenium/docs/api/rb/Selenium/WebDriver/W3CActionBuilder.html
|
204
|
+
# - https://seleniumhq.github.io/selenium/docs/api/rb/Selenium/WebDriver/KeyActions.html
|
205
|
+
#
|
206
|
+
# The pointer type is 'key' by default in the Appium Ruby client.
|
207
|
+
# +driver.action+ in Appium Ruby client has 'pointer' action by default.
|
208
|
+
# This method is a shortcut to set 'key' type.
|
209
|
+
# Hense this method is equal to +driver.action(devices: [::Selenium::WebDriver::Interactions.key('keyboard')])+
|
210
|
+
# as below example.
|
211
|
+
#
|
212
|
+
# @example
|
213
|
+
#
|
214
|
+
# element = @driver.find_element(:id, "some id")
|
215
|
+
# @driver.key_action.send_key('hiあ').perform # The 'send_key' is a part of 'KeyActions'
|
216
|
+
# # is equal to:
|
217
|
+
# # @driver.action(devices: [::Selenium::WebDriver::Interactions.key('keyboard')]).send_keys('hiあ').perform
|
218
|
+
#
|
219
|
+
def key_action(async: false)
|
220
|
+
@bridge.action(
|
221
|
+
async: async,
|
222
|
+
devices: [::Selenium::WebDriver::Interactions.key('keyboard')]
|
223
|
+
)
|
224
|
+
end
|
225
|
+
|
184
226
|
# Lock the device
|
185
227
|
# @return [String]
|
186
228
|
#
|
@@ -542,12 +584,6 @@ module Appium
|
|
542
584
|
# @driver.launch_app
|
543
585
|
#
|
544
586
|
def launch_app
|
545
|
-
# TODO: Define only in Windows module when ruby_lib_core removes this method
|
546
|
-
if @automation_name != :windows
|
547
|
-
::Appium::Logger.warn(
|
548
|
-
'[DEPRECATION] launch_app is deprecated. Please use activate_app instead.'
|
549
|
-
)
|
550
|
-
end
|
551
587
|
@bridge.launch_app
|
552
588
|
end
|
553
589
|
|
@@ -559,12 +595,6 @@ module Appium
|
|
559
595
|
# @driver.close_app
|
560
596
|
#
|
561
597
|
def close_app
|
562
|
-
# TODO: Define only in Windows module when ruby_lib_core removes this method
|
563
|
-
if @automation_name != :windows
|
564
|
-
::Appium::Logger.warn(
|
565
|
-
'[DEPRECATION] close_app is deprecated. Please use terminate_app instead.'
|
566
|
-
)
|
567
|
-
end
|
568
598
|
@bridge.close_app
|
569
599
|
end
|
570
600
|
|
@@ -609,7 +639,9 @@ module Appium
|
|
609
639
|
@bridge.background_app(duration)
|
610
640
|
end
|
611
641
|
|
612
|
-
# Install the given app onto the device
|
642
|
+
# Install the given app onto the device.
|
643
|
+
# Each options can be snake-case or camel-case. Snake-cases will be converted to camel-case
|
644
|
+
# as options value.
|
613
645
|
#
|
614
646
|
# @param [String] path The absolute local path or remote http URL to an .ipa or .apk file,
|
615
647
|
# or a .zip containing one of these.
|
@@ -623,26 +655,26 @@ module Appium
|
|
623
655
|
# @param [Boolean] grant_permissions Only for Android. whether to automatically grant application permissions
|
624
656
|
# on Android 6+ after the installation completes. +false+ by default
|
625
657
|
#
|
658
|
+
# Other parameters such as https://github.com/appium/appium-xcuitest-driver#mobile-installapp also can be set.
|
659
|
+
# Then, arguments in snake case will be camel case as its request parameters.
|
660
|
+
#
|
626
661
|
# @example
|
627
662
|
#
|
628
663
|
# @driver.install_app("/path/to/test.apk")
|
629
664
|
# @driver.install_app("/path/to/test.apk", replace: true, timeout: 20000, allow_test_packages: true,
|
630
665
|
# use_sdcard: false, grant_permissions: false)
|
666
|
+
# @driver.install_app("/path/to/test.ipa", timeoutMs: 20000)
|
631
667
|
#
|
632
|
-
def install_app(path,
|
633
|
-
|
634
|
-
|
635
|
-
allow_test_packages: nil,
|
636
|
-
use_sdcard: nil,
|
637
|
-
grant_permissions: nil)
|
638
|
-
@bridge.install_app(path,
|
639
|
-
replace: replace,
|
640
|
-
timeout: timeout,
|
641
|
-
allow_test_packages: allow_test_packages,
|
642
|
-
use_sdcard: use_sdcard,
|
643
|
-
grant_permissions: grant_permissions)
|
668
|
+
def install_app(path, **options)
|
669
|
+
options = options.transform_keys { |key| key.to_s.gsub(/_./) { |v| v[1].upcase } } unless options.nil?
|
670
|
+
@bridge.install_app(path, options)
|
644
671
|
end
|
645
672
|
|
673
|
+
# def capitalize(s)
|
674
|
+
# chars =
|
675
|
+
# chars[1:].map(&:capitalize).join
|
676
|
+
# end
|
677
|
+
|
646
678
|
# @param [Strong] app_id BundleId for iOS or package name for Android
|
647
679
|
# @param [Boolean] keep_data Only for Android. Whether to keep application data and caches after it is uninstalled.
|
648
680
|
# +false+ by default
|
@@ -924,8 +956,6 @@ module Appium
|
|
924
956
|
# # "appPackage"=>"io.appium.android.apis",
|
925
957
|
# # "appActivity"=>"io.appium.android.apis.ApiDemos",
|
926
958
|
# # "someCapability"=>"some_capability",
|
927
|
-
# # "unicodeKeyboard"=>true,
|
928
|
-
# # "resetKeyboard"=>true},
|
929
959
|
# # "automationName"=>"uiautomator2",
|
930
960
|
# # "app"=>"/path/to/app/api.apk.zip",
|
931
961
|
# # "platformVersion"=>"8.1.0",
|
@@ -933,8 +963,6 @@ module Appium
|
|
933
963
|
# # "appPackage"=>"io.appium.android.apis",
|
934
964
|
# # "appActivity"=>"io.appium.android.apis.ApiDemos",
|
935
965
|
# # "someCapability"=>"some_capability",
|
936
|
-
# # "unicodeKeyboard"=>true,
|
937
|
-
# # "resetKeyboard"=>true,
|
938
966
|
# # "deviceUDID"=>"emulator-5554",
|
939
967
|
# # "deviceScreenSize"=>"1080x1920",
|
940
968
|
# # "deviceScreenDensity"=>420,
|
@@ -1021,7 +1049,7 @@ module Appium
|
|
1021
1049
|
|
1022
1050
|
# @since Appium 1.8.2
|
1023
1051
|
# Return an element if current view has a partial image. The logic depends on template matching by OpenCV.
|
1024
|
-
# {https://github.com/appium/appium/blob/
|
1052
|
+
# {https://github.com/appium/appium/blob/1.x/docs/en/writing-running-appium/image-comparison.md image-comparison}
|
1025
1053
|
#
|
1026
1054
|
# You can handle settings for the comparision following below.
|
1027
1055
|
# {https://github.com/appium/appium-base-driver/blob/master/lib/basedriver/device-settings.js#L6 device-settings}
|
@@ -1043,14 +1071,14 @@ module Appium
|
|
1043
1071
|
|
1044
1072
|
# @since Appium 1.8.2
|
1045
1073
|
# Return elements if current view has a partial image. The logic depends on template matching by OpenCV.
|
1046
|
-
# {https://github.com/appium/appium/blob/
|
1074
|
+
# {https://github.com/appium/appium/blob/1.x/docs/en/writing-running-appium/image-comparison.md image-comparison}
|
1047
1075
|
#
|
1048
1076
|
# You can handle settings for the comparision following below.
|
1049
1077
|
# {https://github.com/appium/appium-base-driver/blob/master/lib/basedriver/device-settings.js#L6 device-settings}
|
1050
1078
|
#
|
1051
1079
|
# @param [String] img_path A path to a partial image you'd like to find
|
1052
1080
|
#
|
1053
|
-
# @return [Array
|
1081
|
+
# @return [Array<::Appium::Core::Element>]
|
1054
1082
|
#
|
1055
1083
|
# @example
|
1056
1084
|
#
|
@@ -21,11 +21,11 @@ module Appium
|
|
21
21
|
module HasLocation
|
22
22
|
# Get the location of the device.
|
23
23
|
#
|
24
|
-
# @return [::
|
24
|
+
# @return [::Appium::Location]
|
25
25
|
#
|
26
26
|
# @example
|
27
27
|
#
|
28
|
-
# driver.location #=> ::
|
28
|
+
# driver.location #=> ::Appium::Location.new(10, 10, 10)
|
29
29
|
#
|
30
30
|
def location
|
31
31
|
@bridge.location
|
@@ -33,15 +33,15 @@ module Appium
|
|
33
33
|
|
34
34
|
# Set the location of the device.
|
35
35
|
#
|
36
|
-
# @param [::
|
36
|
+
# @param [::Appium::Location] location Set the location.
|
37
37
|
#
|
38
38
|
# @example
|
39
39
|
#
|
40
|
-
# driver.location = ::
|
40
|
+
# driver.location = ::Appium::Location.new(10, 10, 10)
|
41
41
|
#
|
42
42
|
def location=(location)
|
43
|
-
unless location.is_a?(::
|
44
|
-
raise TypeError, "expected #{::
|
43
|
+
unless location.is_a?(::Appium::Location)
|
44
|
+
raise TypeError, "expected #{::Appium::Location}, got #{location.inspect}:#{location.class}"
|
45
45
|
end
|
46
46
|
|
47
47
|
@bridge.set_location location.latitude, location.longitude, location.altitude
|
@@ -56,17 +56,17 @@ module Appium
|
|
56
56
|
# in meters/second @since Appium 1.21.0 and in knots for emulators @since Appium 1.22.0.
|
57
57
|
# @param [String, Number] satellites Sets the count of geo satellites being tracked in range 1..12 @since Appium 1.22.0.
|
58
58
|
# This number is respected on Emulators.
|
59
|
-
# @param [::
|
59
|
+
# @param [::Appium::Location]
|
60
60
|
#
|
61
61
|
# @example
|
62
62
|
#
|
63
|
-
# driver.location = ::
|
63
|
+
# driver.location = ::Appium::Location.new(10, 10, 10)
|
64
64
|
#
|
65
65
|
def set_location(latitude, longitude, altitude, speed: nil, satellites: nil)
|
66
66
|
if speed.nil? && satellites.nil?
|
67
|
-
self.location = ::
|
67
|
+
self.location = ::Appium::Location.new(Float(latitude), Float(longitude), Float(altitude))
|
68
68
|
else
|
69
|
-
loc = ::
|
69
|
+
loc = ::Appium::Location.new(Float(latitude), Float(longitude), Float(altitude))
|
70
70
|
|
71
71
|
speed = Float(speed) unless speed.nil?
|
72
72
|
satellites = Integer(satellites) unless satellites.nil?
|
@@ -37,7 +37,7 @@ module Appium
|
|
37
37
|
attr_reader :additional_headers
|
38
38
|
|
39
39
|
# override
|
40
|
-
def initialize(open_timeout: nil, read_timeout: nil)
|
40
|
+
def initialize(open_timeout: nil, read_timeout: nil)
|
41
41
|
@open_timeout = open_timeout
|
42
42
|
@read_timeout = read_timeout
|
43
43
|
@additional_headers = {}
|
@@ -20,12 +20,18 @@ module Appium
|
|
20
20
|
#
|
21
21
|
|
22
22
|
module Rotatable
|
23
|
-
ORIENTATIONS = %i[
|
23
|
+
ORIENTATIONS = %i[
|
24
|
+
landscape
|
25
|
+
portrait
|
26
|
+
uia_device_orientation_landscaperight
|
27
|
+
uia_device_orientation_portrait_upsidedown
|
28
|
+
].freeze
|
24
29
|
|
25
30
|
#
|
26
31
|
# Change the screen orientation
|
27
32
|
#
|
28
|
-
# @param [:landscape, :portrait
|
33
|
+
# @param [:landscape, :portrait,
|
34
|
+
# :uia_device_orientation_landscaperight, :uia_device_orientation_portrait_upsidedown] orientation
|
29
35
|
#
|
30
36
|
#
|
31
37
|
def rotation=(orientation)
|
@@ -36,11 +42,13 @@ module Appium
|
|
36
42
|
bridge.screen_orientation = orientation.to_s.upcase
|
37
43
|
end
|
38
44
|
alias rotate rotation=
|
45
|
+
alias orientation= rotation=
|
39
46
|
|
40
47
|
#
|
41
48
|
# Get the current screen orientation
|
42
49
|
#
|
43
|
-
# @return [:landscape, :portrait
|
50
|
+
# @return [:landscape, :portrait,
|
51
|
+
# :uia_device_orientation_landscaperight, :uia_device_orientation_portrait_upsidedown] orientation
|
44
52
|
#
|
45
53
|
# @api public
|
46
54
|
#
|
@@ -28,7 +28,6 @@ module Appium
|
|
28
28
|
data_matcher: '-android datamatcher', # Available in Espresso
|
29
29
|
view_matcher: '-android viewmatcher', # Available in Espresso
|
30
30
|
# iOS
|
31
|
-
uiautomation: '-ios uiautomation',
|
32
31
|
predicate: '-ios predicate string',
|
33
32
|
class_chain: '-ios class chain',
|
34
33
|
# Windows with windows prefix
|
@@ -48,7 +47,7 @@ module Appium
|
|
48
47
|
#
|
49
48
|
# == Find with image
|
50
49
|
# Return an element if current view has a partial image. The logic depends on template matching by OpenCV.
|
51
|
-
# {https://github.com/appium/appium/blob/
|
50
|
+
# {https://github.com/appium/appium/blob/1.x/docs/en/writing-running-appium/image-comparison.md image-comparison}
|
52
51
|
#
|
53
52
|
# You can handle settings for the comparision following {https://github.com/appium/appium-base-driver/blob/master/lib/basedriver/device-settings.js#L6 here}
|
54
53
|
#
|
@@ -70,11 +70,15 @@ module Appium
|
|
70
70
|
find_elements: [:post, 'session/:session_id/elements'],
|
71
71
|
find_child_element: [:post, 'session/:session_id/element/:id/element'],
|
72
72
|
find_child_elements: [:post, 'session/:session_id/element/:id/elements'],
|
73
|
+
find_shadow_child_element: [:post, 'session/:session_id/shadow/:id/element'],
|
74
|
+
find_shadow_child_elements: [:post, 'session/:session_id/shadow/:id/elements'],
|
73
75
|
get_active_element: [:get, 'session/:session_id/element/active'],
|
74
76
|
is_element_selected: [:get, 'session/:session_id/element/:id/selected'],
|
75
77
|
get_element_attribute: [:get, 'session/:session_id/element/:id/attribute/:name'],
|
76
78
|
get_element_property: [:get, 'session/:session_id/element/:id/property/:name'],
|
77
79
|
get_element_css_value: [:get, 'session/:session_id/element/:id/css/:property_name'],
|
80
|
+
get_element_aria_role: [:get, 'session/:session_id/element/:id/computedrole'],
|
81
|
+
get_element_aria_label: [:get, 'session/:session_id/element/:id/computedlabel'],
|
78
82
|
get_element_text: [:get, 'session/:session_id/element/:id/text'],
|
79
83
|
get_element_tag_name: [:get, 'session/:session_id/element/:id/name'],
|
80
84
|
get_element_rect: [:get, 'session/:session_id/element/:id/rect'],
|
@@ -171,8 +175,6 @@ module Appium
|
|
171
175
|
ime_deactivate: [:post, 'session/:session_id/ime/deactivate'],
|
172
176
|
ime_activate_engine: [:post, 'session/:session_id/ime/activate'],
|
173
177
|
|
174
|
-
send_keys_to_active_element: [:post, 'session/:session_id/keys'],
|
175
|
-
|
176
178
|
### Logs
|
177
179
|
get_available_log_types: [:get, 'session/:session_id/log/types'],
|
178
180
|
get_log: [:post, 'session/:session_id/log'],
|
@@ -18,10 +18,16 @@ module Appium
|
|
18
18
|
module Device
|
19
19
|
module AppManagement
|
20
20
|
def launch_app
|
21
|
+
::Appium::Logger.warn(
|
22
|
+
'[DEPRECATION] launch_app is deprecated. Please use activate_app instead.'
|
23
|
+
)
|
21
24
|
execute :launch_app
|
22
25
|
end
|
23
26
|
|
24
27
|
def close_app
|
28
|
+
::Appium::Logger.warn(
|
29
|
+
'[DEPRECATION] close_app is deprecated. Please use terminate_app instead.'
|
30
|
+
)
|
25
31
|
execute :close_app
|
26
32
|
end
|
27
33
|
|
@@ -39,21 +45,9 @@ module Appium
|
|
39
45
|
raise NotImplementedError
|
40
46
|
end
|
41
47
|
|
42
|
-
def install_app(path,
|
43
|
-
replace: nil,
|
44
|
-
timeout: nil,
|
45
|
-
allow_test_packages: nil,
|
46
|
-
use_sdcard: nil,
|
47
|
-
grant_permissions: nil)
|
48
|
+
def install_app(path, options = {})
|
48
49
|
args = { appPath: path }
|
49
|
-
|
50
|
-
args[:options] = {} if options?(replace, timeout, allow_test_packages, use_sdcard, grant_permissions)
|
51
|
-
|
52
|
-
args[:options][:replace] = replace unless replace.nil?
|
53
|
-
args[:options][:timeout] = timeout unless timeout.nil?
|
54
|
-
args[:options][:allowTestPackages] = allow_test_packages unless allow_test_packages.nil?
|
55
|
-
args[:options][:useSdcard] = use_sdcard unless use_sdcard.nil?
|
56
|
-
args[:options][:grantPermissions] = grant_permissions unless grant_permissions.nil?
|
50
|
+
args[:options] = options unless options.empty?
|
57
51
|
|
58
52
|
execute :install_app, {}, args
|
59
53
|
end
|
@@ -41,9 +41,7 @@ module Appium
|
|
41
41
|
# Keep .split(//) for backward compatibility for now
|
42
42
|
text = keys.join
|
43
43
|
|
44
|
-
|
45
|
-
# { value: text.split(//), text: text }
|
46
|
-
{ value: text.chars }
|
44
|
+
{ text: text }
|
47
45
|
end
|
48
46
|
end # module Value
|
49
47
|
end # module Device
|
@@ -17,10 +17,6 @@ module Appium
|
|
17
17
|
module Error
|
18
18
|
class CoreError < StandardError; end
|
19
19
|
|
20
|
-
# Capability related errors
|
21
|
-
class NoCapabilityError < CoreError; end
|
22
|
-
class CapabilityStructureError < CoreError; end
|
23
|
-
|
24
20
|
# Appium related errors
|
25
21
|
class NotSupportedAppiumServer < CoreError; end
|
26
22
|
class NoSuchElementError < CoreError; end
|