appium_lib_core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rubocop.yml +20 -0
- data/.travis.yml +16 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +202 -0
- data/README.md +5 -0
- data/Rakefile +62 -0
- data/Thorfile +7 -0
- data/appium_lib_core.gemspec +35 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/appium_lib_core.rb +41 -0
- data/lib/appium_lib_core/android.rb +5 -0
- data/lib/appium_lib_core/android/device.rb +174 -0
- data/lib/appium_lib_core/android/espresso/bridge.rb +16 -0
- data/lib/appium_lib_core/android/search_context.rb +18 -0
- data/lib/appium_lib_core/android/touch.rb +17 -0
- data/lib/appium_lib_core/android/uiautomator1/bridge.rb +16 -0
- data/lib/appium_lib_core/android/uiautomator2/bridge.rb +16 -0
- data/lib/appium_lib_core/android_espresso.rb +5 -0
- data/lib/appium_lib_core/android_uiautomator2.rb +5 -0
- data/lib/appium_lib_core/common.rb +6 -0
- data/lib/appium_lib_core/common/base.rb +8 -0
- data/lib/appium_lib_core/common/base/bridge.rb +47 -0
- data/lib/appium_lib_core/common/base/capabilities.rb +16 -0
- data/lib/appium_lib_core/common/base/command.rb +10 -0
- data/lib/appium_lib_core/common/base/driver.rb +51 -0
- data/lib/appium_lib_core/common/base/http_default.rb +13 -0
- data/lib/appium_lib_core/common/base/search_context.rb +89 -0
- data/lib/appium_lib_core/common/base/wait.rb +56 -0
- data/lib/appium_lib_core/common/command.rb +77 -0
- data/lib/appium_lib_core/common/device.rb +567 -0
- data/lib/appium_lib_core/common/error.rb +18 -0
- data/lib/appium_lib_core/common/log.rb +30 -0
- data/lib/appium_lib_core/common/logger.rb +30 -0
- data/lib/appium_lib_core/device/multi_touch.rb +48 -0
- data/lib/appium_lib_core/device/touch_actions.rb +191 -0
- data/lib/appium_lib_core/driver.rb +459 -0
- data/lib/appium_lib_core/ios.rb +7 -0
- data/lib/appium_lib_core/ios/device.rb +54 -0
- data/lib/appium_lib_core/ios/search_context.rb +27 -0
- data/lib/appium_lib_core/ios/touch.rb +17 -0
- data/lib/appium_lib_core/ios/uiautomation/bridge.rb +18 -0
- data/lib/appium_lib_core/ios/uiautomation/patch.rb +20 -0
- data/lib/appium_lib_core/ios/xcuitest/bridge.rb +18 -0
- data/lib/appium_lib_core/ios/xcuitest/device.rb +66 -0
- data/lib/appium_lib_core/ios/xcuitest/search_context.rb +40 -0
- data/lib/appium_lib_core/ios_xcuitest.rb +8 -0
- data/lib/appium_lib_core/patch.rb +78 -0
- data/lib/appium_lib_core/version.rb +6 -0
- data/release_notes.md +0 -0
- metadata +262 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
module Appium
|
2
|
+
module Core
|
3
|
+
class Base
|
4
|
+
module SearchContext
|
5
|
+
# referenced: ::Selenium::WebDriver::SearchContext
|
6
|
+
|
7
|
+
FINDERS = ::Selenium::WebDriver::SearchContext::FINDERS.merge(accessibility_id: 'accessibility id')
|
8
|
+
|
9
|
+
def self.add_finders(finders)
|
10
|
+
FINDERS.merge!(finders)
|
11
|
+
end
|
12
|
+
|
13
|
+
#
|
14
|
+
# Find the first element matching the given arguments
|
15
|
+
#
|
16
|
+
# @overload find_element(how, what)
|
17
|
+
# @param [Symbol, String] how The method to find the element by
|
18
|
+
# @param [String] what The locator to use
|
19
|
+
# @overload find_element(opts)
|
20
|
+
# @param [Hash] opts Find options
|
21
|
+
# @option opts [Symbol] :how Key named after the method to find the element by, containing the locator
|
22
|
+
# @return [Element]
|
23
|
+
#
|
24
|
+
# @raise [Error::NoSuchElementError] if the element doesn't exist
|
25
|
+
#
|
26
|
+
# @example Find element with accessibility id
|
27
|
+
# find_elements :accessibility_id, 'Animation'
|
28
|
+
# find_elements :accessibility_id, 'Animation'
|
29
|
+
#
|
30
|
+
def find_element(*args)
|
31
|
+
how, what = extract_args(args)
|
32
|
+
by = _set_by_from_finders(how)
|
33
|
+
begin
|
34
|
+
bridge.find_element_by by, what.to_s, ref
|
35
|
+
rescue Selenium::WebDriver::Error::TimeOutError
|
36
|
+
raise Selenium::WebDriver::Error::NoSuchElementError
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Find all elements matching the given arguments
|
42
|
+
#
|
43
|
+
# @see SearchContext#find_element
|
44
|
+
#
|
45
|
+
def find_elements(*args)
|
46
|
+
how, what = extract_args(args)
|
47
|
+
by = _set_by_from_finders(how)
|
48
|
+
begin
|
49
|
+
bridge.find_elements_by by, what.to_s, ref
|
50
|
+
rescue Selenium::WebDriver::Error::TimeOutError
|
51
|
+
raise Selenium::WebDriver::Error::NoSuchElementError
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def _set_by_from_finders(how)
|
58
|
+
finders = FINDERS
|
59
|
+
by = finders[how.to_sym]
|
60
|
+
raise ArgumentError, "cannot find element by #{how.inspect}" unless by
|
61
|
+
by
|
62
|
+
end
|
63
|
+
|
64
|
+
def extract_args(args)
|
65
|
+
case args.size
|
66
|
+
when 2
|
67
|
+
args
|
68
|
+
when 1
|
69
|
+
arg = args.first
|
70
|
+
|
71
|
+
unless arg.respond_to?(:shift)
|
72
|
+
raise ArgumentError, "expected #{arg.inspect}:#{arg.class} to respond to #shift"
|
73
|
+
end
|
74
|
+
|
75
|
+
# this will be a single-entry hash, so use #shift over #first or #[]
|
76
|
+
arr = arg.dup.shift
|
77
|
+
unless arr.size == 2
|
78
|
+
raise ArgumentError, "expected #{arr.inspect} to have 2 elements"
|
79
|
+
end
|
80
|
+
|
81
|
+
arr
|
82
|
+
else
|
83
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for 2)"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end # module SearchContext
|
87
|
+
end # class Base
|
88
|
+
end # module Core
|
89
|
+
end # module Appium
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# rubocop:disable Lint/HandleExceptions
|
2
|
+
module Appium
|
3
|
+
module Core
|
4
|
+
class Base
|
5
|
+
class Wait < ::Selenium::WebDriver::Wait
|
6
|
+
require 'timeout' # for wait
|
7
|
+
|
8
|
+
def initialize(opts = {})
|
9
|
+
valid_keys = [:timeout, :interval, :message, :ignore, :return_if_true]
|
10
|
+
invalid_keys = []
|
11
|
+
opts.keys.each { |key| invalid_keys << key unless valid_keys.include?(key) }
|
12
|
+
# [:one, :two] => :one, :two
|
13
|
+
unless invalid_keys.empty?
|
14
|
+
raise "Invalid keys #{invalid_keys.to_s[1..-2]}. Valid keys are #{valid_keys.to_s[1..-2]}"
|
15
|
+
end
|
16
|
+
|
17
|
+
@timeout = opts.fetch(:timeout, DEFAULT_TIMEOUT)
|
18
|
+
@interval = opts.fetch(:interval, DEFAULT_INTERVAL)
|
19
|
+
@message = opts[:message]
|
20
|
+
@ignored = Array(opts[:ignore] || ::Exception)
|
21
|
+
@return_if_true = opts[:return_if_true]
|
22
|
+
|
23
|
+
super(timeout: @timeout, interval: @interval, message: @message, ignore: @ignored)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Wait code from the selenium Ruby gem
|
27
|
+
# https://github.com/SeleniumHQ/selenium/blob/cf501dda3f0ed12233de51ce8170c0e8090f0c20/rb/lib/selenium/webdriver/common/wait.rb
|
28
|
+
def until
|
29
|
+
end_time = Time.now + @timeout
|
30
|
+
last_error = nil
|
31
|
+
|
32
|
+
until Time.now > end_time
|
33
|
+
begin
|
34
|
+
return yield unless @return_if_true
|
35
|
+
|
36
|
+
result = yield
|
37
|
+
return result if result
|
38
|
+
rescue ::Errno::ECONNREFUSED => e
|
39
|
+
raise e
|
40
|
+
rescue *@ignored => last_error
|
41
|
+
# swallowed
|
42
|
+
end
|
43
|
+
|
44
|
+
sleep @interval
|
45
|
+
end
|
46
|
+
|
47
|
+
msg = @message ? @message.dup : "timed out after #{@timeout} seconds"
|
48
|
+
|
49
|
+
msg << " (#{last_error.message})" if last_error
|
50
|
+
|
51
|
+
raise Selenium::WebDriver::Error::TimeOutError, msg
|
52
|
+
end
|
53
|
+
end # module Wait
|
54
|
+
end # module Base
|
55
|
+
end # module Core
|
56
|
+
end # module Appium
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require_relative 'base/command'
|
2
|
+
|
3
|
+
module Appium
|
4
|
+
module Core
|
5
|
+
# ref: https://github.com/appium/appium-base-driver/blob/master/lib/mjsonwp/routes.js
|
6
|
+
module Commands
|
7
|
+
COMMAND_NO_ARG = {
|
8
|
+
# Common
|
9
|
+
shake: [:post, 'session/:session_id/appium/device/shake'.freeze],
|
10
|
+
launch_app: [:post, 'session/:session_id/appium/app/launch'.freeze],
|
11
|
+
close_app: [:post, 'session/:session_id/appium/app/close'.freeze],
|
12
|
+
reset: [:post, 'session/:session_id/appium/app/reset'.freeze],
|
13
|
+
device_locked?: [:post, 'session/:session_id/appium/device/is_locked'.freeze],
|
14
|
+
unlock: [:post, 'session/:session_id/appium/device/unlock'.freeze],
|
15
|
+
device_time: [:get, 'session/:session_id/appium/device/system_time'.freeze],
|
16
|
+
current_context: [:get, 'session/:session_id/context'.freeze],
|
17
|
+
|
18
|
+
# Android
|
19
|
+
open_notifications: [:post, 'session/:session_id/appium/device/open_notifications'.freeze],
|
20
|
+
toggle_airplane_mode: [:post, 'session/:session_id/appium/device/toggle_airplane_mode'.freeze],
|
21
|
+
current_activity: [:get, 'session/:session_id/appium/device/current_activity'.freeze],
|
22
|
+
current_package: [:get, 'session/:session_id/appium/device/current_package'.freeze],
|
23
|
+
get_system_bars: [:get, 'session/:session_id/appium/device/system_bars'.freeze],
|
24
|
+
get_display_density: [:get, 'session/:session_id/appium/device/display_density'.freeze],
|
25
|
+
is_keyboard_shown: [:get, 'session/:session_id/appium/device/is_keyboard_shown'.freeze],
|
26
|
+
get_network_connection: [:get, 'session/:session_id/network_connection'.freeze],
|
27
|
+
get_performance_data_types: [:post, 'session/:session_id/appium/performanceData/types'.freeze],
|
28
|
+
stop_recording_screen: [:post, 'session/:session_id/appium/stop_recording_screen'.freeze]
|
29
|
+
# iOS
|
30
|
+
}.freeze
|
31
|
+
|
32
|
+
# Some commands differ for each driver.
|
33
|
+
COMMAND = {
|
34
|
+
# common
|
35
|
+
available_contexts: [:get, 'session/:session_id/contexts'.freeze],
|
36
|
+
set_context: [:post, 'session/:session_id/context'.freeze],
|
37
|
+
app_strings: [:post, 'session/:session_id/appium/app/strings'.freeze],
|
38
|
+
lock: [:post, 'session/:session_id/appium/device/lock'.freeze],
|
39
|
+
install_app: [:post, 'session/:session_id/appium/device/install_app'.freeze],
|
40
|
+
remove_app: [:post, 'session/:session_id/appium/device/remove_app'.freeze],
|
41
|
+
app_installed?: [:post, 'session/:session_id/appium/device/app_installed'.freeze],
|
42
|
+
background_app: [:post, 'session/:session_id/appium/app/background'.freeze],
|
43
|
+
hide_keyboard: [:post, 'session/:session_id/appium/device/hide_keyboard'.freeze],
|
44
|
+
press_keycode: [:post, 'session/:session_id/appium/device/press_keycode'.freeze],
|
45
|
+
long_press_keycode: [:post, 'session/:session_id/appium/device/long_press_keycode'.freeze],
|
46
|
+
set_immediate_value: [:post, 'session/:session_id/appium/element/:id/value'.freeze],
|
47
|
+
replace_value: [:post, 'session/:session_id/appium/element/:id/replace_value'.freeze],
|
48
|
+
push_file: [:post, 'session/:session_id/appium/device/push_file'.freeze],
|
49
|
+
pull_file: [:post, 'session/:session_id/appium/device/pull_file'.freeze],
|
50
|
+
pull_folder: [:post, 'session/:session_id/appium/device/pull_folder'.freeze],
|
51
|
+
get_settings: [:get, 'session/:session_id/appium/settings'.freeze],
|
52
|
+
update_settings: [:post, 'session/:session_id/appium/settings'.freeze],
|
53
|
+
touch_actions: [:post, 'session/:session_id/touch/perform'.freeze],
|
54
|
+
multi_touch: [:post, 'session/:session_id/touch/multi/perform'.freeze]
|
55
|
+
}.freeze
|
56
|
+
|
57
|
+
COMMAND_ANDROID = {
|
58
|
+
start_activity: [:post, 'session/:session_id/appium/device/start_activity'.freeze],
|
59
|
+
end_coverage: [:post, 'session/:session_id/appium/app/end_test_coverage'.freeze],
|
60
|
+
set_network_connection: [:post, 'session/:session_id/network_connection'.freeze],
|
61
|
+
get_performance_data: [:post, 'session/:session_id/appium/getPerformanceData'.freeze],
|
62
|
+
start_recording_screen: [:post, 'session/:session_id/appium/start_recording_screen'.freeze]
|
63
|
+
}.freeze
|
64
|
+
|
65
|
+
COMMAND_IOS = {
|
66
|
+
touch_id: [:post, 'session/:session_id/appium/simulator/touch_id'.freeze],
|
67
|
+
toggle_touch_id_enrollment: [:post, 'session/:session_id/appium/simulator/toggle_touch_id_enrollment'.freeze]
|
68
|
+
}.freeze
|
69
|
+
|
70
|
+
COMMANDS = {}.merge(COMMAND).merge(COMMAND_ANDROID).merge(COMMAND_IOS)
|
71
|
+
.merge(COMMAND_NO_ARG).freeze
|
72
|
+
|
73
|
+
COMMANDS_EXTEND_OSS = COMMANDS.merge(::Appium::Core::Base::Commands::OSS).freeze
|
74
|
+
COMMANDS_EXTEND_W3C = COMMANDS.merge(::Appium::Core::Base::Commands::W3C).freeze
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,567 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Appium
|
4
|
+
module Core
|
5
|
+
module Device
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
####
|
9
|
+
## No argument
|
10
|
+
####
|
11
|
+
|
12
|
+
# @!method current_activity
|
13
|
+
# Get current activity name
|
14
|
+
# @return [String] An activity name
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
#
|
18
|
+
# @driver.current_activity # '.ApiDemos'
|
19
|
+
#
|
20
|
+
|
21
|
+
# @!method current_package
|
22
|
+
# Get current package name
|
23
|
+
# @return [String] A package name
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
#
|
27
|
+
# @driver.current_package # 'com.example.android.apis'
|
28
|
+
#
|
29
|
+
|
30
|
+
# @!method get_system_bars
|
31
|
+
# Get system bar's information
|
32
|
+
# @return [String]
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
#
|
36
|
+
# @driver.get_system_bars
|
37
|
+
#
|
38
|
+
|
39
|
+
# @!method get_display_density
|
40
|
+
# Get connected device's density.
|
41
|
+
# @return [Integer] The size of density
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
#
|
45
|
+
# @driver.get_display_density # 320
|
46
|
+
#
|
47
|
+
|
48
|
+
# @!method is_keyboard_shown
|
49
|
+
# Get whether keyboard is displayed or not.
|
50
|
+
# @return [Bool] Return true if keyboard is shown. Return false if keyboard is hidden.
|
51
|
+
#
|
52
|
+
# @example
|
53
|
+
# @driver.is_keyboard_shown # false
|
54
|
+
#
|
55
|
+
|
56
|
+
# @!method launch_app
|
57
|
+
# Start the simulator and application configured with desired capabilities
|
58
|
+
#
|
59
|
+
# @example
|
60
|
+
#
|
61
|
+
# @driver.launch_app
|
62
|
+
#
|
63
|
+
|
64
|
+
# @!method reset
|
65
|
+
# Reset the device, relaunching the application.
|
66
|
+
#
|
67
|
+
# @example
|
68
|
+
#
|
69
|
+
# @driver.reset
|
70
|
+
#
|
71
|
+
|
72
|
+
# @!method shake
|
73
|
+
# Cause the device to shake
|
74
|
+
#
|
75
|
+
# @example
|
76
|
+
#
|
77
|
+
# @driver.shake
|
78
|
+
#
|
79
|
+
|
80
|
+
# @!method toggle_flight_mode
|
81
|
+
# Toggle flight mode on or off
|
82
|
+
#
|
83
|
+
# @example
|
84
|
+
#
|
85
|
+
# @driver.toggle_flight_mode
|
86
|
+
#
|
87
|
+
|
88
|
+
# @!method device_locked?
|
89
|
+
# Check current device status is weather locked or not
|
90
|
+
#
|
91
|
+
# @example
|
92
|
+
#
|
93
|
+
# @driver.device_locked?
|
94
|
+
#
|
95
|
+
|
96
|
+
# @!method get_network_connection
|
97
|
+
# Get the device network connection current status
|
98
|
+
# See set_network_connection method for return value
|
99
|
+
|
100
|
+
####
|
101
|
+
## With arguments
|
102
|
+
####
|
103
|
+
|
104
|
+
# @!method app_strings(language = nil)
|
105
|
+
# Return the hash of all localization strings.
|
106
|
+
# @return [Hash]
|
107
|
+
#
|
108
|
+
# @example
|
109
|
+
#
|
110
|
+
# @driver.app_strings #=> "TransitionsTitle"=>"Transitions", "WebTitle"=>"Web"
|
111
|
+
#
|
112
|
+
|
113
|
+
# @!method background_app(duration = 0)
|
114
|
+
# Backgrounds the app for a set number of seconds.
|
115
|
+
# This is a blocking application
|
116
|
+
# @param [Integer] duration How many seconds to background the app for.
|
117
|
+
# @return [String]
|
118
|
+
#
|
119
|
+
# @example
|
120
|
+
#
|
121
|
+
# @driver.background_app
|
122
|
+
# @driver.background_app(5)
|
123
|
+
# @driver.background_app(-1) #=> the app never come back. https://github.com/appium/appium/issues/7741
|
124
|
+
#
|
125
|
+
|
126
|
+
# @!method hide_keyboard(close_key = nil, strategy = nil)
|
127
|
+
# Hide the onscreen keyboard
|
128
|
+
# @param [String] close_key The name of the key which closes the keyboard.
|
129
|
+
# Defaults to 'Done' for iOS(except for XCUITest).
|
130
|
+
# @param [Symbol] strategy The symbol of the strategy which closes the keyboard.
|
131
|
+
# XCUITest ignore this argument.
|
132
|
+
# Default for iOS is `:pressKey`. Default for Android is `:tapOutside`.
|
133
|
+
#
|
134
|
+
# @example
|
135
|
+
#
|
136
|
+
# @driver.hide_keyboard # Close a keyboard with the 'Done' button
|
137
|
+
# @driver.hide_keyboard('Finished') # Close a keyboard with the 'Finished' button
|
138
|
+
# @driver.hide_keyboard(nil, :tapOutside) # Close a keyboard with tapping out side of keyboard
|
139
|
+
#
|
140
|
+
|
141
|
+
# @!method press_keycode(key, metastate = nil)
|
142
|
+
# Press keycode on the device.
|
143
|
+
# http://developer.android.com/reference/android/view/KeyEvent.html
|
144
|
+
# @param [integer] key The key to press.
|
145
|
+
# @param [String] metastate The state the metakeys should be in when pressing the key.
|
146
|
+
#
|
147
|
+
# @example
|
148
|
+
#
|
149
|
+
# @driver.press_keycode 82
|
150
|
+
#
|
151
|
+
|
152
|
+
# @!method long_press_keycode(key, metastate = nil)
|
153
|
+
# Long press keycode on the device.
|
154
|
+
# http://developer.android.com/reference/android/view/KeyEvent.html
|
155
|
+
# @param [integer] key The key to long press.
|
156
|
+
# @param [String] metastate The state the metakeys should be in when long pressing the key.
|
157
|
+
#
|
158
|
+
# @example
|
159
|
+
#
|
160
|
+
# @driver.long_press_keycode 82
|
161
|
+
#
|
162
|
+
|
163
|
+
# @!method push_file(path, filedata)
|
164
|
+
# Place a file in a specific location on the device.
|
165
|
+
# @param [String] path The absolute path on the device to store data at.
|
166
|
+
# @param [String] filedata Raw file data to be sent to the device. Converted to base64 in the method.
|
167
|
+
#
|
168
|
+
# @example
|
169
|
+
#
|
170
|
+
# @driver.push_file "/file/to/path", data
|
171
|
+
#
|
172
|
+
|
173
|
+
# @!method pull_file(path)
|
174
|
+
# Retrieve a file from the device. This can retrieve an absolute path or
|
175
|
+
# a path relative to the installed app (iOS only).
|
176
|
+
# @param [String] path Either an absolute path OR, for iOS devices, a path relative to the app, as described.
|
177
|
+
#
|
178
|
+
# @example
|
179
|
+
#
|
180
|
+
# @driver.pull_file '/local/data/some/path' #=> Get the file at that path
|
181
|
+
# @driver.pull_file 'Shenanigans.app/some/file' #=> Get 'some/file' from the install location of Shenanigans.app
|
182
|
+
#
|
183
|
+
|
184
|
+
# @!method pull_folder(path)
|
185
|
+
# Retrieve a folder from the device.
|
186
|
+
# @param [String] path absolute path to the folder
|
187
|
+
#
|
188
|
+
# @example
|
189
|
+
#
|
190
|
+
# @driver.pull_folder '/data/local/tmp' #=> Get the folder at that path
|
191
|
+
#
|
192
|
+
|
193
|
+
# @!method get_settings
|
194
|
+
# Get appium Settings for current test session
|
195
|
+
#
|
196
|
+
# @example
|
197
|
+
#
|
198
|
+
# @driver.pull_folder '/data/local/tmp' #=> Get the folder at that path
|
199
|
+
#
|
200
|
+
|
201
|
+
# @!method update_settings(settings)
|
202
|
+
# Update Appium Settings for current test session
|
203
|
+
# @param [Hash] settings Settings to update, keys are settings, values to value to set each setting to
|
204
|
+
#
|
205
|
+
# @example
|
206
|
+
#
|
207
|
+
# @driver.update_settings('allowInvisibleElements': true)
|
208
|
+
#
|
209
|
+
|
210
|
+
# @!method set_immediate_value(element, *value)
|
211
|
+
# Set the value to element directly
|
212
|
+
#
|
213
|
+
# @example
|
214
|
+
#
|
215
|
+
# set_immediate_value element, 'hello'
|
216
|
+
#
|
217
|
+
|
218
|
+
# @!method replace_value(element, *value)
|
219
|
+
# Replace the value to element directly
|
220
|
+
#
|
221
|
+
# @example
|
222
|
+
#
|
223
|
+
# replace_value element, 'hello'
|
224
|
+
#
|
225
|
+
|
226
|
+
# @!method ime_activate(ime_name)
|
227
|
+
# Android only. Make an engine that is available active.
|
228
|
+
# @param [String] ime_name The IME owning the activity [required]
|
229
|
+
#
|
230
|
+
# @example
|
231
|
+
#
|
232
|
+
# ime_activate engine: 'com.android.inputmethod.latin/.LatinIME'
|
233
|
+
#
|
234
|
+
|
235
|
+
# @!method ime_available_engines
|
236
|
+
# Android only. List all available input engines on the machine.
|
237
|
+
#
|
238
|
+
# @example
|
239
|
+
#
|
240
|
+
# ime_available_engines #=> Get the list of IME installed in the target device
|
241
|
+
#
|
242
|
+
|
243
|
+
# @!method ime_active_engine
|
244
|
+
# Android only. Get the name of the active IME engine.
|
245
|
+
#
|
246
|
+
# @example
|
247
|
+
#
|
248
|
+
# ime_active_engine #=> Get the current active IME such as 'com.android.inputmethod.latin/.LatinIME'
|
249
|
+
#
|
250
|
+
|
251
|
+
# @!method ime_activated
|
252
|
+
# Android only. Indicates whether IME input is active at the moment (not if it is available).
|
253
|
+
#
|
254
|
+
# @example
|
255
|
+
#
|
256
|
+
# ime_activated #=> True if IME is activated
|
257
|
+
#
|
258
|
+
|
259
|
+
# @!method ime_deactivate
|
260
|
+
# Android only. De-activates the currently-active IME engine.
|
261
|
+
#
|
262
|
+
# @example
|
263
|
+
#
|
264
|
+
# ime_deactivate #=> Deactivate current IME engine
|
265
|
+
#
|
266
|
+
|
267
|
+
####
|
268
|
+
## class << self
|
269
|
+
####
|
270
|
+
|
271
|
+
class << self
|
272
|
+
def extended(_mod)
|
273
|
+
extend_webdriver_with_forwardable
|
274
|
+
|
275
|
+
::Appium::Core::Commands::COMMAND_NO_ARG.each_key do |method|
|
276
|
+
add_endpoint_method method
|
277
|
+
end
|
278
|
+
|
279
|
+
# call http://www.rubydoc.info/gems/selenium-webdriver/Selenium/WebDriver/DriverExtensions/HasRemoteStatus#remote_status-instance_method
|
280
|
+
add_endpoint_method(:remote_status) do
|
281
|
+
def remote_status
|
282
|
+
execute(:status, {}) || []
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
# TODO: Don't define selenium-side methods. We pick up from them.
|
287
|
+
# ::Appium::Core::Base::Commands::OSS.each_key do |method|
|
288
|
+
# add_endpoint_method method
|
289
|
+
# end
|
290
|
+
|
291
|
+
add_endpoint_method(:available_contexts) do
|
292
|
+
def available_contexts
|
293
|
+
# return empty array instead of nil on failure
|
294
|
+
execute(:available_contexts, {}) || []
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
add_endpoint_method(:app_strings) do
|
299
|
+
def app_strings(language = nil)
|
300
|
+
opts = language ? { language: language } : {}
|
301
|
+
execute :app_strings, {}, opts
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
add_endpoint_method(:lock) do
|
306
|
+
def lock(duration)
|
307
|
+
execute :lock, {}, seconds: duration
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
add_endpoint_method(:install_app) do
|
312
|
+
def install_app(path)
|
313
|
+
execute :install_app, {}, appPath: path
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
add_endpoint_method(:remove_app) do
|
318
|
+
def remove_app(id)
|
319
|
+
execute :remove_app, {}, appId: id
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
add_endpoint_method(:app_installed?) do
|
324
|
+
def app_installed?(app_id)
|
325
|
+
execute :app_installed?, {}, bundleId: app_id
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
add_endpoint_method(:background_app) do
|
330
|
+
def background_app(duration = 0)
|
331
|
+
execute :background_app, {}, seconds: duration
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
add_endpoint_method(:set_context) do
|
336
|
+
def set_context(context = null)
|
337
|
+
execute :set_context, {}, name: context
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
add_endpoint_method(:hide_keyboard) do
|
342
|
+
def hide_keyboard(close_key = nil, strategy = nil)
|
343
|
+
option = {}
|
344
|
+
|
345
|
+
option[:key] = close_key || 'Done' # default to Done key.
|
346
|
+
option[:strategy] = strategy || :pressKey # default to pressKey
|
347
|
+
|
348
|
+
execute :hide_keyboard, {}, option
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
add_endpoint_method(:press_keycode) do
|
353
|
+
def press_keycode(key, metastate = nil)
|
354
|
+
args = { keycode: key }
|
355
|
+
args[:metastate] = metastate if metastate
|
356
|
+
execute :press_keycode, {}, args
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
add_endpoint_method(:long_press_keycode) do
|
361
|
+
def long_press_keycode(key, metastate = nil)
|
362
|
+
args = { keycode: key }
|
363
|
+
args[:metastate] = metastate if metastate
|
364
|
+
execute :long_press_keycode, {}, args
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
add_endpoint_method(:set_immediate_value) do
|
369
|
+
def set_immediate_value(element, *value)
|
370
|
+
keys = ::Selenium::WebDriver::Keys.encode(value)
|
371
|
+
execute :set_immediate_value, { id: element.ref }, value: Array(keys)
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
add_endpoint_method(:replace_value) do
|
376
|
+
def replace_value(element, *value)
|
377
|
+
keys = ::Selenium::WebDriver::Keys.encode(value)
|
378
|
+
execute :replace_value, { id: element.ref }, value: Array(keys)
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
add_endpoint_method(:push_file) do
|
383
|
+
def push_file(path, filedata)
|
384
|
+
encoded_data = Base64.encode64 filedata
|
385
|
+
execute :push_file, {}, path: path, data: encoded_data
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
add_endpoint_method(:pull_file) do
|
390
|
+
def pull_file(path)
|
391
|
+
data = execute :pull_file, {}, path: path
|
392
|
+
Base64.decode64 data
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
add_endpoint_method(:pull_folder) do
|
397
|
+
def pull_folder(path)
|
398
|
+
data = execute :pull_folder, {}, path: path
|
399
|
+
Base64.decode64 data
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
add_endpoint_method(:get_settings) do
|
404
|
+
def get_settings
|
405
|
+
execute :get_settings, {}
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
add_endpoint_method(:update_settings) do
|
410
|
+
def update_settings(settings)
|
411
|
+
execute :update_settings, {}, settings: settings
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
add_touch_actions
|
416
|
+
add_ime_actions
|
417
|
+
end
|
418
|
+
|
419
|
+
# def extended
|
420
|
+
|
421
|
+
# @private
|
422
|
+
def add_endpoint_method(method)
|
423
|
+
block_given? ? create_bridge_command(method, &Proc.new) : create_bridge_command(method)
|
424
|
+
|
425
|
+
delegate_driver_method method
|
426
|
+
delegate_from_appium_driver method
|
427
|
+
end
|
428
|
+
|
429
|
+
# @private CoreBridge
|
430
|
+
def extend_webdriver_with_forwardable
|
431
|
+
return if ::Appium::Core::Base::Driver.is_a? Forwardable
|
432
|
+
::Appium::Core::Base::Driver.class_eval do
|
433
|
+
extend Forwardable
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
# @private
|
438
|
+
def delegate_driver_method(method)
|
439
|
+
return if ::Appium::Core::Base::Driver.method_defined? method
|
440
|
+
::Appium::Core::Base::Driver.class_eval { def_delegator :@bridge, method }
|
441
|
+
end
|
442
|
+
|
443
|
+
# @private
|
444
|
+
def delegate_from_appium_driver(method, delegation_target = :driver)
|
445
|
+
def_delegator delegation_target, method
|
446
|
+
end
|
447
|
+
|
448
|
+
# @private
|
449
|
+
def create_bridge_command(method)
|
450
|
+
::Appium::Core::Base::CoreBridgeOSS.class_eval do
|
451
|
+
block_given? ? class_eval(&Proc.new) : define_method(method) { execute method }
|
452
|
+
end
|
453
|
+
::Appium::Core::Base::CoreBridgeW3C.class_eval do
|
454
|
+
block_given? ? class_eval(&Proc.new) : define_method(method) { execute method }
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
def add_touch_actions
|
459
|
+
add_endpoint_method(:touch_actions) do
|
460
|
+
def touch_actions(actions)
|
461
|
+
actions = { actions: [actions].flatten }
|
462
|
+
execute :touch_actions, {}, actions
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
add_endpoint_method(:multi_touch) do
|
467
|
+
def multi_touch(actions)
|
468
|
+
execute :multi_touch, {}, actions: actions
|
469
|
+
end
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
def add_ime_actions
|
474
|
+
add_endpoint_method(:ime_activate) do
|
475
|
+
def ime_activate(ime_name)
|
476
|
+
# from Selenium::WebDriver::Remote::OSS
|
477
|
+
execute :ime_activate_engine, {}, engine: ime_name
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
add_endpoint_method(:ime_available_engines) do
|
482
|
+
def ime_available_engines
|
483
|
+
execute :ime_get_available_engines
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
add_endpoint_method(:ime_active_engine) do
|
488
|
+
# from Selenium::WebDriver::Remote::OSS
|
489
|
+
def ime_active_engine
|
490
|
+
execute :ime_get_active_engine
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
add_endpoint_method(:ime_activated) do
|
495
|
+
# from Selenium::WebDriver::Remote::OSS
|
496
|
+
def ime_activated
|
497
|
+
execute :ime_is_activated
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
add_endpoint_method(:ime_deactivate) do
|
502
|
+
# from Selenium::WebDriver::Remote::OSS
|
503
|
+
def ime_deactivate
|
504
|
+
execute :ime_deactivate, {}
|
505
|
+
end
|
506
|
+
end
|
507
|
+
end
|
508
|
+
end # class << self
|
509
|
+
|
510
|
+
# @!method set_context(context)
|
511
|
+
# Change the context to the given context.
|
512
|
+
# @param [String] context The context to change to
|
513
|
+
#
|
514
|
+
# @example
|
515
|
+
#
|
516
|
+
# @driver.set_context "NATIVE_APP"
|
517
|
+
#
|
518
|
+
|
519
|
+
# @!method current_context
|
520
|
+
# @return [String] The context currently being used.
|
521
|
+
#
|
522
|
+
# @example
|
523
|
+
#
|
524
|
+
# @driver.current_context
|
525
|
+
#
|
526
|
+
|
527
|
+
# @!method available_contexts
|
528
|
+
# @return [Array<String>] All usable contexts, as an array of strings.
|
529
|
+
#
|
530
|
+
# @example
|
531
|
+
#
|
532
|
+
# @driver.available_contexts
|
533
|
+
#
|
534
|
+
|
535
|
+
# Perform a block within the given context, then switch back to the starting context.
|
536
|
+
# @param [String] context The context to switch to for the duration of the block.
|
537
|
+
#
|
538
|
+
# @example
|
539
|
+
#
|
540
|
+
# result = @driver.within_context('NATIVE_APP') do
|
541
|
+
# @driver.find_element :tag, "button"
|
542
|
+
# end # The result of `find_element :tag, "button"`
|
543
|
+
#
|
544
|
+
def within_context(context)
|
545
|
+
existing_context = current_context
|
546
|
+
set_context context
|
547
|
+
if block_given?
|
548
|
+
result = yield
|
549
|
+
set_context existing_context
|
550
|
+
result
|
551
|
+
else
|
552
|
+
set_context existing_context
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
# Change to the default context. This is equivalent to `set_context nil`.
|
557
|
+
#
|
558
|
+
# @example
|
559
|
+
#
|
560
|
+
# @driver.switch_to_default_context
|
561
|
+
#
|
562
|
+
def switch_to_default_context
|
563
|
+
set_context nil
|
564
|
+
end
|
565
|
+
end # module Device
|
566
|
+
end # module Core
|
567
|
+
end # module Appium
|