appium_lib 9.4.9 → 9.4.10
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 +4 -4
- data/.github/ISSUE_TEMPLATE.md +21 -0
- data/.gitignore +3 -1
- data/CHANGELOG.md +9 -0
- data/Rakefile +9 -1
- data/appium_lib.gemspec +1 -1
- data/contributing.md +14 -1
- data/docs/android_docs.md +256 -229
- data/docs/ios_docs.md +282 -255
- data/lib/appium_lib.rb +0 -1
- data/lib/appium_lib/android/helper.rb +1 -7
- data/lib/appium_lib/common/error.rb +3 -0
- data/lib/appium_lib/common/patch.rb +17 -7
- data/lib/appium_lib/common/version.rb +2 -2
- data/lib/appium_lib/driver.rb +77 -40
- data/lib/appium_lib/ios/mobile_methods.rb +20 -14
- data/lib/appium_lib/ios/xcuitest_gestures.rb +182 -180
- data/lib/appium_lib/logger.rb +6 -0
- data/release_notes.md +6 -0
- metadata +3 -3
- data/lib/appium_lib/rails/duplicable.rb +0 -118
data/lib/appium_lib.rb
CHANGED
@@ -35,13 +35,7 @@ module Appium
|
|
35
35
|
# scoped to: text resource-id content-desc
|
36
36
|
attributes_values = attributes.values
|
37
37
|
strings = $driver.lazy_load_strings
|
38
|
-
id_matches
|
39
|
-
|
40
|
-
unless strings.empty?
|
41
|
-
id_matches = strings.select do |_key, value|
|
42
|
-
attributes_values.include? value
|
43
|
-
end
|
44
|
-
end
|
38
|
+
id_matches = strings.empty? ? [] : strings.select { |_key, value| attributes_values.include? value }
|
45
39
|
|
46
40
|
string_ids = nil
|
47
41
|
|
@@ -26,16 +26,26 @@ module Appium
|
|
26
26
|
# execute_script 'mobile: tap', :x => 0.0, :y => 0.98
|
27
27
|
# ```
|
28
28
|
#
|
29
|
-
# https://github.com/appium/appium/wiki/Automating-mobile-gestures
|
30
29
|
# @return [OpenStruct] the relative x, y in a struct. ex: { x: 0.50, y: 0.20 }
|
31
30
|
def location_rel
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
# TODO: Remove with 'refine Appium ruby binding'
|
32
|
+
# https://github.com/appium/ruby_lib/issues/602
|
33
|
+
if ::Appium.selenium_webdriver_version_more?('3.4.0')
|
34
|
+
rect = self.rect
|
35
|
+
location_x = rect.x.to_f
|
36
|
+
location_y = rect.y.to_f
|
37
|
+
|
38
|
+
size_width = rect.width.to_f
|
39
|
+
size_height = rect.height.to_f
|
40
|
+
else
|
41
|
+
location = self.location
|
42
|
+
location_x = location.x.to_f
|
43
|
+
location_y = location.y.to_f
|
35
44
|
|
36
|
-
|
37
|
-
|
38
|
-
|
45
|
+
size = self.size
|
46
|
+
size_width = size.width.to_f
|
47
|
+
size_height = size.height.to_f
|
48
|
+
end
|
39
49
|
|
40
50
|
center_x = location_x + (size_width / 2.0)
|
41
51
|
center_y = location_y + (size_height / 2.0)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Appium
|
2
2
|
# Version and Date are defined on the 'Appium' module, not 'Appium::Common'
|
3
|
-
VERSION = '9.4.
|
4
|
-
DATE = '2017-07-
|
3
|
+
VERSION = '9.4.10'.freeze unless defined? ::Appium::VERSION
|
4
|
+
DATE = '2017-07-29'.freeze unless defined? ::Appium::DATE
|
5
5
|
end
|
data/lib/appium_lib/driver.rb
CHANGED
@@ -248,6 +248,11 @@ module Appium
|
|
248
248
|
nil # return nil
|
249
249
|
end
|
250
250
|
|
251
|
+
def self.selenium_webdriver_version_more?(version)
|
252
|
+
require 'rubygems'
|
253
|
+
Gem.loaded_specs['selenium-webdriver'].version >= Gem::Version.new(version)
|
254
|
+
end
|
255
|
+
|
251
256
|
class Driver
|
252
257
|
module Capabilities
|
253
258
|
# except for browser_name, default capability is equal to ::Selenium::WebDriver::Remote::Capabilities.firefox
|
@@ -366,30 +371,11 @@ module Appium
|
|
366
371
|
raise 'opts must be a hash' unless opts.is_a? Hash
|
367
372
|
|
368
373
|
opts = Appium.symbolize_keys opts
|
369
|
-
|
370
374
|
@caps = Capabilities.init_caps_for_appium(opts[:caps] || {})
|
371
375
|
|
372
376
|
appium_lib_opts = opts[:appium_lib] || {}
|
373
377
|
|
374
|
-
|
375
|
-
@custom_url = appium_lib_opts.fetch :server_url, false
|
376
|
-
@export_session = appium_lib_opts.fetch :export_session, false
|
377
|
-
@default_wait = appium_lib_opts.fetch :wait, 0
|
378
|
-
@sauce_username = appium_lib_opts.fetch :sauce_username, ENV['SAUCE_USERNAME']
|
379
|
-
@sauce_username = nil if !@sauce_username || (@sauce_username.is_a?(String) && @sauce_username.empty?)
|
380
|
-
@sauce_access_key = appium_lib_opts.fetch :sauce_access_key, ENV['SAUCE_ACCESS_KEY']
|
381
|
-
@sauce_access_key = nil if !@sauce_access_key || (@sauce_access_key.is_a?(String) && @sauce_access_key.empty?)
|
382
|
-
@sauce_endpoint = appium_lib_opts.fetch :sauce_endpoint, ENV['SAUCE_ENDPOINT']
|
383
|
-
@sauce_endpoint = 'ondemand.saucelabs.com:443/wd/hub' if
|
384
|
-
!@sauce_endpoint || (@sauce_endpoint.is_a?(String) && @sauce_endpoint.empty?)
|
385
|
-
@appium_port = appium_lib_opts.fetch :port, 4723
|
386
|
-
# timeout and interval used in ::Appium::Comm.wait/wait_true
|
387
|
-
@appium_wait_timeout = appium_lib_opts.fetch :wait_timeout, 30
|
388
|
-
@appium_wait_interval = appium_lib_opts.fetch :wait_interval, 0.5
|
389
|
-
|
390
|
-
# to pass it in Selenium.new.
|
391
|
-
# `listener = opts.delete(:listener)` is called in Selenium::Driver.new
|
392
|
-
@listener = appium_lib_opts.fetch :listener, nil
|
378
|
+
set_appium_lib_specific_values(appium_lib_opts)
|
393
379
|
|
394
380
|
# Path to the .apk, .app or .app.zip.
|
395
381
|
# The path can be local or remote for Sauce.
|
@@ -402,6 +388,9 @@ module Appium
|
|
402
388
|
@appium_device = @appium_device.is_a?(Symbol) ? @appium_device : @appium_device.downcase.strip.intern if @appium_device
|
403
389
|
|
404
390
|
@automation_name = @caps[:automationName] if @caps[:automationName]
|
391
|
+
@automation_name = if @automation_name
|
392
|
+
@automation_name.is_a?(Symbol) ? @automation_name : @automation_name.downcase.strip.intern
|
393
|
+
end
|
405
394
|
|
406
395
|
# load common methods
|
407
396
|
extend Appium::Common
|
@@ -411,7 +400,10 @@ module Appium
|
|
411
400
|
extend Appium::Android
|
412
401
|
else
|
413
402
|
extend Appium::Ios
|
414
|
-
|
403
|
+
if automation_name_is_xcuitest? # Override touch actions
|
404
|
+
extend Appium::Ios::Xcuitest
|
405
|
+
extend Appium::Ios::Xcuitest::Gesture
|
406
|
+
end
|
415
407
|
end
|
416
408
|
|
417
409
|
# apply os specific patches
|
@@ -437,9 +429,36 @@ module Appium
|
|
437
429
|
self # return newly created driver
|
438
430
|
end
|
439
431
|
|
432
|
+
private
|
433
|
+
|
434
|
+
def set_appium_lib_specific_values(appium_lib_opts)
|
435
|
+
@custom_url = appium_lib_opts.fetch :server_url, false
|
436
|
+
@export_session = appium_lib_opts.fetch :export_session, false
|
437
|
+
@default_wait = appium_lib_opts.fetch :wait, 0
|
438
|
+
|
439
|
+
@sauce_username = appium_lib_opts.fetch :sauce_username, ENV['SAUCE_USERNAME']
|
440
|
+
@sauce_username = nil if !@sauce_username || (@sauce_username.is_a?(String) && @sauce_username.empty?)
|
441
|
+
@sauce_access_key = appium_lib_opts.fetch :sauce_access_key, ENV['SAUCE_ACCESS_KEY']
|
442
|
+
@sauce_access_key = nil if !@sauce_access_key || (@sauce_access_key.is_a?(String) && @sauce_access_key.empty?)
|
443
|
+
@sauce_endpoint = appium_lib_opts.fetch :sauce_endpoint, ENV['SAUCE_ENDPOINT']
|
444
|
+
@sauce_endpoint = 'ondemand.saucelabs.com:443/wd/hub' if
|
445
|
+
!@sauce_endpoint || (@sauce_endpoint.is_a?(String) && @sauce_endpoint.empty?)
|
446
|
+
|
447
|
+
@appium_port = appium_lib_opts.fetch :port, 4723
|
448
|
+
# timeout and interval used in ::Appium::Comm.wait/wait_true
|
449
|
+
@appium_wait_timeout = appium_lib_opts.fetch :wait_timeout, 30
|
450
|
+
@appium_wait_interval = appium_lib_opts.fetch :wait_interval, 0.5
|
451
|
+
|
452
|
+
# to pass it in Selenium.new.
|
453
|
+
# `listener = opts.delete(:listener)` is called in Selenium::Driver.new
|
454
|
+
@listener = appium_lib_opts.fetch :listener, nil
|
455
|
+
end
|
456
|
+
|
457
|
+
public
|
458
|
+
|
440
459
|
# Returns a hash of the driver attributes
|
441
460
|
def driver_attributes
|
442
|
-
|
461
|
+
{
|
443
462
|
caps: @caps,
|
444
463
|
automation_name: @automation_name,
|
445
464
|
custom_url: @custom_url,
|
@@ -455,12 +474,6 @@ module Appium
|
|
455
474
|
wait_timeout: @appium_wait_timeout,
|
456
475
|
wait_interval: @appium_wait_interval
|
457
476
|
}
|
458
|
-
|
459
|
-
# Return duplicates so attributes are immutable
|
460
|
-
attributes.each do |key, value|
|
461
|
-
attributes[key] = value.duplicable? ? value.dup : value
|
462
|
-
end
|
463
|
-
attributes
|
464
477
|
end
|
465
478
|
|
466
479
|
def device_is_android?
|
@@ -470,13 +483,13 @@ module Appium
|
|
470
483
|
# Return true if automationName is 'XCUITest'
|
471
484
|
# @return [Boolean]
|
472
485
|
def automation_name_is_xcuitest?
|
473
|
-
!@automation_name.nil? &&
|
486
|
+
!@automation_name.nil? && @automation_name == :xcuitest
|
474
487
|
end
|
475
488
|
|
476
489
|
# Return true if automationName is 'uiautomator2'
|
477
490
|
# @return [Boolean]
|
478
491
|
def automation_name_is_uiautomator2?
|
479
|
-
!@automation_name.nil? &&
|
492
|
+
!@automation_name.nil? && @automation_name == :uiautomator2
|
480
493
|
end
|
481
494
|
|
482
495
|
# Return true if the target Appium server is over REQUIRED_VERSION_XCUITEST.
|
@@ -512,11 +525,11 @@ module Appium
|
|
512
525
|
def appium_server_version
|
513
526
|
driver.remote_status
|
514
527
|
rescue Selenium::WebDriver::Error::WebDriverError => ex
|
515
|
-
raise unless ex.message.include?('content-type=""')
|
528
|
+
raise ::Appium::Error::ServerError unless ex.message.include?('content-type=""')
|
516
529
|
# server (TestObject for instance) does not respond to status call
|
517
530
|
{}
|
518
531
|
rescue Selenium::WebDriver::Error::ServerError => e
|
519
|
-
raise unless e.message.include?('status code 500')
|
532
|
+
raise ::Appium::Error::ServerError unless e.message.include?('status code 500')
|
520
533
|
# driver.remote_status returns 500 error for using selenium grid
|
521
534
|
{}
|
522
535
|
end
|
@@ -612,11 +625,33 @@ module Appium
|
|
612
625
|
end
|
613
626
|
|
614
627
|
# Creates a new global driver and quits the old one if it exists.
|
628
|
+
# You can customise http_client as the following
|
629
|
+
#
|
630
|
+
# @example
|
631
|
+
# ```ruby
|
632
|
+
# require 'rubygems'
|
633
|
+
# require 'appium_lib'
|
634
|
+
#
|
635
|
+
# # platformName takes a string or a symbol.
|
636
|
+
#
|
637
|
+
# # Start iOS driver
|
638
|
+
# opts = {
|
639
|
+
# caps: {
|
640
|
+
# platformName: :ios,
|
641
|
+
# app: '/path/to/MyiOS.app'
|
642
|
+
# },
|
643
|
+
# appium_lib: {
|
644
|
+
# wait_timeout: 30
|
645
|
+
# }
|
646
|
+
# }
|
647
|
+
# custom_http_client = Custom::Http::Client.new(opts)
|
648
|
+
# Appium::Driver.new(opts).start_driver(custom_http_client)
|
615
649
|
#
|
616
650
|
# @return [Selenium::WebDriver] the new global driver
|
617
|
-
def start_driver
|
651
|
+
def start_driver(http_client =
|
652
|
+
Selenium::WebDriver::Remote::Http::Default.new(open_timeout: 999_999, read_timeout: 999_999))
|
618
653
|
# open_timeout and read_timeout are explicit wait.
|
619
|
-
@http_client ||=
|
654
|
+
@http_client ||= http_client
|
620
655
|
|
621
656
|
begin
|
622
657
|
driver_quit
|
@@ -631,12 +666,7 @@ module Appium
|
|
631
666
|
@driver.extend Selenium::WebDriver::DriverExtensions::HasLocation
|
632
667
|
|
633
668
|
# export session
|
634
|
-
if @export_session
|
635
|
-
# rubocop:disable Style/RescueModifier
|
636
|
-
File.open('/tmp/appium_lib_session', 'w') do |f|
|
637
|
-
f.puts @driver.session_id
|
638
|
-
end rescue nil
|
639
|
-
end
|
669
|
+
write_session_id(@driver.session_id) if @export_session
|
640
670
|
rescue Errno::ECONNREFUSED
|
641
671
|
raise "ERROR: Unable to connect to Appium. Is the server running on #{server_url}?"
|
642
672
|
end
|
@@ -774,6 +804,13 @@ module Appium
|
|
774
804
|
|
775
805
|
private
|
776
806
|
|
807
|
+
def write_session_id(session_id)
|
808
|
+
File.open('/tmp/appium_lib_session', 'w') { |f| f.puts session_id }
|
809
|
+
rescue IOError => e
|
810
|
+
::Appium::Logger.warn e
|
811
|
+
nil
|
812
|
+
end
|
813
|
+
|
777
814
|
# If "automationName" is set only server side, this method set "automationName" attribute into @automation_name.
|
778
815
|
# Since @automation_name is set only client side before start_driver is called.
|
779
816
|
def set_automation_name_if_nil
|
@@ -16,24 +16,30 @@ module Appium
|
|
16
16
|
# find_elements :predicate, 'wdName == "Buttons"'
|
17
17
|
# find_elements :predicate, 'wdValue == "SearchBar" AND isWDDivisible == 1'
|
18
18
|
# ```
|
19
|
-
#
|
20
|
-
# @!method ios_class_chain_find
|
21
|
-
# Only for XCUITest(WebDriverAgent)
|
22
|
-
# find_element/s can be used with a [class chain]( https://github.com/facebook/WebDriverAgent/wiki/Queries)
|
23
|
-
#
|
24
|
-
# ```ruby
|
25
|
-
# # select the third child button of the first child window element
|
26
|
-
# find_elements :class_chain, 'XCUIElementTypeWindow/XCUIElementTypeButton[3]'
|
27
|
-
# # select all the children windows
|
28
|
-
# find_elements :class_chain, 'XCUIElementTypeWindow'
|
29
|
-
# # select the second last child of the second child window
|
30
|
-
# find_elements :class_chain, 'XCUIElementTypeWindow[2]/XCUIElementTypeAny[-2]'
|
31
|
-
# ```
|
32
19
|
def extended(_mod)
|
33
20
|
::Appium::Driver::SearchContext::FINDERS[:uiautomation] = '-ios uiautomation'
|
34
21
|
::Appium::Driver::SearchContext::FINDERS[:predicate] = '-ios predicate string'
|
35
|
-
::Appium::Driver::SearchContext::FINDERS[:class_chain] = '-ios class chain'
|
36
22
|
end
|
37
23
|
end # class << self
|
24
|
+
|
25
|
+
module Xcuitest
|
26
|
+
class << self
|
27
|
+
# @!method ios_class_chain_find
|
28
|
+
# Only for XCUITest(WebDriverAgent)
|
29
|
+
# find_element/s can be used with a [class chain]( https://github.com/facebook/WebDriverAgent/wiki/Queries)
|
30
|
+
#
|
31
|
+
# ```ruby
|
32
|
+
# # select the third child button of the first child window element
|
33
|
+
# find_elements :class_chain, 'XCUIElementTypeWindow/XCUIElementTypeButton[3]'
|
34
|
+
# # select all the children windows
|
35
|
+
# find_elements :class_chain, 'XCUIElementTypeWindow'
|
36
|
+
# # select the second last child of the second child window
|
37
|
+
# find_elements :class_chain, 'XCUIElementTypeWindow[2]/XCUIElementTypeAny[-2]'
|
38
|
+
# ```
|
39
|
+
def extended(_mod)
|
40
|
+
::Appium::Driver::SearchContext::FINDERS[:class_chain] = '-ios class chain'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
38
44
|
end # module Ios
|
39
45
|
end # module Appium
|
@@ -1,184 +1,186 @@
|
|
1
1
|
module Appium
|
2
2
|
module Ios
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
3
|
+
module Xcuitest
|
4
|
+
module Gesture
|
5
|
+
# @param [string] direction Either 'up', 'down', 'left' or 'right'.
|
6
|
+
# @option opts [Element] :element Element to swipe on
|
7
|
+
#
|
8
|
+
# ```ruby
|
9
|
+
# swipe direction: "down"
|
10
|
+
# ```
|
11
|
+
def swipe(direction:, element: nil)
|
12
|
+
return unless %w(up down left right).include?(direction)
|
13
|
+
|
14
|
+
args = { direction: direction }
|
15
|
+
args[:element] = element.ref if element
|
16
|
+
|
17
|
+
execute_script 'mobile: swipe', args
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param [string] direction Either 'up', 'down', 'left' or 'right'.
|
21
|
+
# @option opts [String] :name the accessibility id of the child element, to which scrolling is performed.
|
22
|
+
# @option opts [Element] :element Element id to long tap on.
|
23
|
+
# @option opts [bool] :to_visible Boolean parameter. If set to true then asks to scroll to the first visible
|
24
|
+
# element in the parent container. Has no effect if element is not set
|
25
|
+
# @option opts [String] :predicate_string the NSPredicate locator of the child element,
|
26
|
+
# to which the scrolling should be performed. Has no effect if element is not a container
|
27
|
+
#
|
28
|
+
# ```ruby
|
29
|
+
# scroll direction: "down"
|
30
|
+
# ```
|
31
|
+
def scroll(direction:, name: nil, element: nil, to_visible: nil, predicate_string: nil)
|
32
|
+
return 'Set "up", "down", "left" or "right" for :direction' unless %w(up down left right).include?(direction)
|
33
|
+
|
34
|
+
args = { direction: direction }
|
35
|
+
args[:element] = element.ref if element
|
36
|
+
args[:name] = name if name
|
37
|
+
args[:toVisible] = to_visible if to_visible
|
38
|
+
args[:predicateString] = predicate_string if predicate_string
|
39
|
+
|
40
|
+
execute_script 'mobile: scroll', args
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param scale [scale] X tap coordinate of type float. Mandatory parameter
|
44
|
+
# @param velocity [float] Y tap coordinate of type float. Mandatory parameter
|
45
|
+
# @option opts [Element] :element Element id to long tap on.
|
46
|
+
#
|
47
|
+
# ```ruby
|
48
|
+
# pinch scale: 0.5, velocity: -1
|
49
|
+
# ```
|
50
|
+
def pinch(scale:, velocity: 1.0, element: nil)
|
51
|
+
return unless automation_name_is_xcuitest?
|
52
|
+
|
53
|
+
args = { scale: scale, velocity: velocity }
|
54
|
+
args[:element] = element.ref if element
|
55
|
+
|
56
|
+
execute_script 'mobile: pinch', args
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param x [float] X Screen x tap coordinate of type float. Mandatory parameter only if element is not set
|
60
|
+
# @param y [float] Y Screen y tap coordinate of type float. Mandatory parameter only if element is not set
|
61
|
+
# @option opts [Element] :element Element to long tap on.
|
62
|
+
#
|
63
|
+
# ```ruby
|
64
|
+
# double_tap x: 100, y: 100
|
65
|
+
# double_tap element: find_element(:accessibility_id, "some item")
|
66
|
+
# ```
|
67
|
+
def double_tap(x: nil, y: nil, element: nil)
|
68
|
+
return 'require XCUITest(WDA)' unless automation_name_is_xcuitest?
|
69
|
+
return 'Set x, y or element' if (x.nil? || y.nil?) && element.nil?
|
70
|
+
|
71
|
+
args = element.nil? ? { x: x, y: y } : { element: element.ref }
|
72
|
+
execute_script 'mobile: doubleTap', args
|
73
|
+
end
|
74
|
+
|
75
|
+
# @param x [float] Screen x long tap coordinate of type float. Mandatory parameter only if element is not set
|
76
|
+
# @param y [float] Screen y long tap coordinate of type float. Mandatory parameter only if element is not set
|
77
|
+
# @param duration [Float] The float duration of press action in seconds. Mandatory parameter
|
78
|
+
# @option opts [Element] :element The internal element identifier (as hexadecimal hash string) to long tap on
|
79
|
+
#
|
80
|
+
# ```ruby
|
81
|
+
# touch_and_hold x: 100, y: 100
|
82
|
+
# touch_and_hold x: 100, y: 100, duration: 2.0
|
83
|
+
# touch_and_hold element: find_element(:accessibility_id, "some item")
|
84
|
+
# ```
|
85
|
+
def touch_and_hold(x: nil, y: nil, element: nil, duration: 1.0)
|
86
|
+
return 'require XCUITest(WDA)' unless automation_name_is_xcuitest?
|
87
|
+
return 'Set x, y or element' if (x.nil? || y.nil?) && element.nil?
|
88
|
+
|
89
|
+
args = element.nil? ? { x: x, y: y } : { element: element.ref }
|
90
|
+
args[:duration] = duration
|
91
|
+
execute_script 'mobile: touchAndHold', args
|
92
|
+
end
|
93
|
+
|
94
|
+
# @param [Element] :element Element to long tap on.
|
95
|
+
#
|
96
|
+
# ```ruby
|
97
|
+
# two_finger_tap element: find_element(:accessibility_id, "some item")
|
98
|
+
# ```
|
99
|
+
def two_finger_tap(element:)
|
100
|
+
return 'require XCUITest(WDA)' unless automation_name_is_xcuitest?
|
101
|
+
|
102
|
+
args = { element: element.ref }
|
103
|
+
execute_script 'mobile: twoFingerTap', args
|
104
|
+
end
|
105
|
+
|
106
|
+
# @param x [float] X tap coordinate of type float. Mandatory parameter
|
107
|
+
# @param y [float] Y tap coordinate of type float. Mandatory parameter
|
108
|
+
# @option opts [Element] :element Element id to long tap on. x and y tap coordinates will be calculated
|
109
|
+
# relatively to the current element position on the screen if this argument is provided.
|
110
|
+
# Otherwise they should be calculated relatively to screen borders.
|
111
|
+
#
|
112
|
+
# ```ruby
|
113
|
+
# tap x: 100, y: 100
|
114
|
+
# tap x: 100, y: 100, element: find_element(:accessibility_id, "some item")
|
115
|
+
# ```
|
116
|
+
def tap(x:, y:, element: nil)
|
117
|
+
return 'require XCUITest(WDA)' unless automation_name_is_xcuitest?
|
118
|
+
|
119
|
+
args = { x: x, y: y }
|
120
|
+
args[:element] = element.ref if element
|
121
|
+
execute_script 'mobile: tap', args
|
122
|
+
end
|
123
|
+
|
124
|
+
# rubocop:disable Metrics/ParameterLists
|
125
|
+
# @param duration [float] Float number of seconds in range [0.5, 60]. How long the tap gesture at starting
|
126
|
+
# drag point should be before to start dragging. Mandatory parameter
|
127
|
+
# @param from_x [float] The x coordinate of starting drag point (type float). Mandatory parameter
|
128
|
+
# @param from_y [float] The y coordinate of starting drag point (type float). Mandatory parameter
|
129
|
+
# @param to_x [float] The x coordinate of ending drag point (type float). Mandatory parameter
|
130
|
+
# @param to_y [float] The y coordinate of ending drag point (type float). Mandatory parameter
|
131
|
+
# @option opts [Element] :element Element id to perform drag on. All the coordinates will be calculated
|
132
|
+
# relatively this this element position on the screen. Absolute screen coordinates are expected
|
133
|
+
# if this argument is not set
|
134
|
+
#
|
135
|
+
# ```ruby
|
136
|
+
# drag_from_to_for_duration from_x: 100, from_y: 100, to_x: 150, to_y: 150
|
137
|
+
# ```
|
138
|
+
def drag_from_to_for_duration(from_x:, from_y:, to_x:, to_y:, duration: 1.0, element: nil)
|
139
|
+
return 'require XCUITest(WDA)' unless automation_name_is_xcuitest?
|
140
|
+
|
141
|
+
args = { fromX: from_x, fromY: from_y, toX: to_x, toY: to_y, duration: duration }
|
142
|
+
args[:element] = element.ref if element
|
143
|
+
execute_script 'mobile: dragFromToForDuration', args
|
144
|
+
end
|
145
|
+
# rubocop:enable Metrics/ParameterLists
|
146
|
+
|
147
|
+
# https://github.com/facebook/WebDriverAgent/pull/523
|
148
|
+
# https://github.com/appium/appium-xcuitest-driver/pull/420
|
149
|
+
# @param order [String] The order to move picker to. "next" or "previous".
|
150
|
+
# @param element [Element] Element id to perform select picker wheel on.
|
151
|
+
# @option opts [Integer] :offset The value in range [0.01, 0.5]. Default is 0.2 in server side.
|
152
|
+
# https://github.com/facebook/WebDriverAgent/pull/549/files
|
153
|
+
#
|
154
|
+
# ```ruby
|
155
|
+
# select_picker_wheel order: "next", element: find_element(:accessibility_id, "some picker")
|
156
|
+
# ```
|
157
|
+
def select_picker_wheel(element:, order:, offset: nil)
|
158
|
+
return 'require XCUITest(WDA)' unless automation_name_is_xcuitest?
|
159
|
+
return 'Set "next" or "previous" for :order' unless %w(next previous).include?(order)
|
160
|
+
|
161
|
+
args = { element: element.ref, order: order }
|
162
|
+
args[:offset] = offset if offset
|
163
|
+
execute_script 'mobile: selectPickerWheelValue', args
|
164
|
+
end
|
165
|
+
|
166
|
+
# @param action [String] The following actions are supported: accept, dismiss and getButtons. Mandatory parameter
|
167
|
+
# @param button_label [String] The label text of an existing alert button to click on.
|
168
|
+
# This is an optional parameter and is only valid in combination with accept and dismiss actions.
|
169
|
+
# @return {} or Selenium::WebDriver::Error::NoSuchAlertError if no action sheet or alert
|
170
|
+
# or button labels if action is equal to getButtons.
|
171
|
+
#
|
172
|
+
# ```ruby
|
173
|
+
# alert action: "accept"
|
174
|
+
# alert action: "dismiss"
|
175
|
+
# ```
|
176
|
+
def alert(action:, button_label: nil)
|
177
|
+
return 'Set "accept", "dismiss" or "getButtons" for :action' unless %w(accept dismiss getButtons).include?(action)
|
178
|
+
|
179
|
+
args = { action: action }
|
180
|
+
args[:button_label] if button_label
|
181
|
+
execute_script 'mobile: alert', args
|
182
|
+
end
|
183
|
+
end # module Gesture
|
184
|
+
end # module Xcuitest
|
183
185
|
end # module Ios
|
184
186
|
end # module Appium
|