testa_appium_driver 0.1.11 → 0.1.12
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/.gitignore +15 -15
- data/.idea/deployment.xml +21 -21
- data/.idea/inspectionProfiles/Project_Default.xml +8 -8
- data/.idea/misc.xml +5 -5
- data/.idea/modules.xml +7 -7
- data/.idea/runConfigurations/Android_Test.xml +41 -41
- data/.idea/runConfigurations.xml +9 -9
- data/.idea/sshConfigs.xml +12 -12
- data/.idea/vcs.xml +5 -5
- data/.idea/webServers.xml +20 -20
- data/.rspec +3 -3
- data/.rubocop.yml +13 -13
- data/CHANGELOG.md +5 -5
- data/CODE_OF_CONDUCT.md +102 -102
- data/Gemfile +12 -12
- data/LICENSE.txt +21 -21
- data/README.md +378 -378
- data/Rakefile +12 -12
- data/bin/console +17 -17
- data/bin/setup +8 -8
- data/lib/testa_appium_driver/android/class_selectors.rb +437 -437
- data/lib/testa_appium_driver/android/driver.rb +69 -69
- data/lib/testa_appium_driver/android/locator/attributes.rb +113 -113
- data/lib/testa_appium_driver/android/locator.rb +141 -141
- data/lib/testa_appium_driver/android/scroll_actions/uiautomator_scroll_actions.rb +61 -61
- data/lib/testa_appium_driver/android/selenium_element.rb +7 -7
- data/lib/testa_appium_driver/common/bounds.rb +149 -149
- data/lib/testa_appium_driver/common/constants.rb +36 -36
- data/lib/testa_appium_driver/common/exceptions/strategy_mix_exception.rb +11 -11
- data/lib/testa_appium_driver/common/helpers.rb +270 -270
- data/lib/testa_appium_driver/common/locator/scroll_actions.rb +397 -397
- data/lib/testa_appium_driver/common/locator.rb +610 -610
- data/lib/testa_appium_driver/common/scroll_actions/json_wire_scroll_actions.rb +3 -3
- data/lib/testa_appium_driver/common/scroll_actions/w3c_scroll_actions.rb +237 -237
- data/lib/testa_appium_driver/common/scroll_actions.rb +246 -246
- data/lib/testa_appium_driver/common/selenium_element.rb +19 -19
- data/lib/testa_appium_driver/driver.rb +312 -312
- data/lib/testa_appium_driver/ios/driver.rb +48 -48
- data/lib/testa_appium_driver/ios/locator/attributes.rb +80 -80
- data/lib/testa_appium_driver/ios/locator.rb +70 -70
- data/lib/testa_appium_driver/ios/selenium_element.rb +6 -6
- data/lib/testa_appium_driver/ios/type_selectors.rb +187 -187
- data/lib/testa_appium_driver/version.rb +5 -5
- data/lib/testa_appium_driver.rb +6 -6
- data/testa_appium_driver.gemspec +41 -41
- data/testa_appium_driver.iml +27 -78
- metadata +3 -3
@@ -1,70 +1,70 @@
|
|
1
|
-
require_relative 'class_selectors'
|
2
|
-
require_relative 'locator'
|
3
|
-
require_relative 'scroll_actions/uiautomator_scroll_actions'
|
4
|
-
require_relative 'selenium_element'
|
5
|
-
|
6
|
-
module TestaAppiumDriver
|
7
|
-
class Driver
|
8
|
-
include ClassSelectors
|
9
|
-
|
10
|
-
|
11
|
-
# executes shell command
|
12
|
-
# @param [String] command Shell command name to execute for example echo or rm
|
13
|
-
# @param [Array<String>] args Array of command arguments, example: ['-f', '/sdcard/my_file.txt']
|
14
|
-
# @param [Integer] timeout Command timeout in milliseconds. If the command blocks for longer than this timeout then an exception is going to be thrown. The default timeout is 20000 ms
|
15
|
-
# @param [Boolean] includeStderr Whether to include stderr stream into the returned result.
|
16
|
-
def shell(command, args: nil, timeout: nil, includeStderr: true)
|
17
|
-
params = {
|
18
|
-
command: command,
|
19
|
-
includeStderr: includeStderr
|
20
|
-
}
|
21
|
-
params[:args] = args unless args.nil?
|
22
|
-
params[:timeout] = timeout unless timeout.nil?
|
23
|
-
@driver.execute_script("mobile: shell", params)
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
def scrollable
|
28
|
-
locator = Locator.new(self, self, {single: true})
|
29
|
-
locator.xpath_selector = "//androidx.recyclerview.widget.RecyclerView|//android.widget.ScrollView|//android.widget.ListView|//android.widget.HorizontalScrollView"
|
30
|
-
locator.ui_selector = "new UiSelector().scrollable(true).instance(0)"
|
31
|
-
locator
|
32
|
-
end
|
33
|
-
|
34
|
-
|
35
|
-
def scrollables
|
36
|
-
locator = Locator.new(self, self, {single: false})
|
37
|
-
locator.xpath_selector = "//androidx.recyclerview.widget.RecyclerView|//android.widget.ScrollView|//android.widget.ListView|//android.widget.HorizontalScrollView"
|
38
|
-
locator.ui_selector = "new UiSelector().scrollable(true)"
|
39
|
-
locator
|
40
|
-
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
private
|
45
|
-
def handle_testa_opts
|
46
|
-
if @testa_opts[:default_find_strategy].nil?
|
47
|
-
@default_find_strategy = DEFAULT_ANDROID_FIND_STRATEGY
|
48
|
-
else
|
49
|
-
case @testa_opts[:default_find_strategy].to_sym
|
50
|
-
when FIND_STRATEGY_UIAUTOMATOR, FIND_STRATEGY_XPATH
|
51
|
-
@default_find_strategy = @testa_opts[:default_find_strategy].to_sym
|
52
|
-
else
|
53
|
-
raise "Default find strategy #{@testa_opts[:default_find_strategy]} not supported for Android"
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
|
58
|
-
if @testa_opts[:default_scroll_strategy].nil?
|
59
|
-
@default_scroll_strategy = DEFAULT_ANDROID_SCROLL_STRATEGY
|
60
|
-
else
|
61
|
-
case @testa_opts[:default_scroll_strategy].to_sym
|
62
|
-
when SCROLL_STRATEGY_W3C, SCROLL_STRATEGY_UIAUTOMATOR
|
63
|
-
@default_scroll_strategy = @testa_opts[:default_scroll_strategy].to_sym
|
64
|
-
else
|
65
|
-
raise "Default scroll strategy #{@testa_opts[:default_scroll_strategy]} not supported for Android"
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
1
|
+
require_relative 'class_selectors'
|
2
|
+
require_relative 'locator'
|
3
|
+
require_relative 'scroll_actions/uiautomator_scroll_actions'
|
4
|
+
require_relative 'selenium_element'
|
5
|
+
|
6
|
+
module TestaAppiumDriver
|
7
|
+
class Driver
|
8
|
+
include ClassSelectors
|
9
|
+
|
10
|
+
|
11
|
+
# executes shell command
|
12
|
+
# @param [String] command Shell command name to execute for example echo or rm
|
13
|
+
# @param [Array<String>] args Array of command arguments, example: ['-f', '/sdcard/my_file.txt']
|
14
|
+
# @param [Integer] timeout Command timeout in milliseconds. If the command blocks for longer than this timeout then an exception is going to be thrown. The default timeout is 20000 ms
|
15
|
+
# @param [Boolean] includeStderr Whether to include stderr stream into the returned result.
|
16
|
+
def shell(command, args: nil, timeout: nil, includeStderr: true)
|
17
|
+
params = {
|
18
|
+
command: command,
|
19
|
+
includeStderr: includeStderr
|
20
|
+
}
|
21
|
+
params[:args] = args unless args.nil?
|
22
|
+
params[:timeout] = timeout unless timeout.nil?
|
23
|
+
@driver.execute_script("mobile: shell", params)
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def scrollable
|
28
|
+
locator = Locator.new(self, self, {single: true})
|
29
|
+
locator.xpath_selector = "//androidx.recyclerview.widget.RecyclerView|//android.widget.ScrollView|//android.widget.ListView|//android.widget.HorizontalScrollView"
|
30
|
+
locator.ui_selector = "new UiSelector().scrollable(true).instance(0)"
|
31
|
+
locator
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def scrollables
|
36
|
+
locator = Locator.new(self, self, {single: false})
|
37
|
+
locator.xpath_selector = "//androidx.recyclerview.widget.RecyclerView|//android.widget.ScrollView|//android.widget.ListView|//android.widget.HorizontalScrollView"
|
38
|
+
locator.ui_selector = "new UiSelector().scrollable(true)"
|
39
|
+
locator
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
private
|
45
|
+
def handle_testa_opts
|
46
|
+
if @testa_opts[:default_find_strategy].nil?
|
47
|
+
@default_find_strategy = DEFAULT_ANDROID_FIND_STRATEGY
|
48
|
+
else
|
49
|
+
case @testa_opts[:default_find_strategy].to_sym
|
50
|
+
when FIND_STRATEGY_UIAUTOMATOR, FIND_STRATEGY_XPATH
|
51
|
+
@default_find_strategy = @testa_opts[:default_find_strategy].to_sym
|
52
|
+
else
|
53
|
+
raise "Default find strategy #{@testa_opts[:default_find_strategy]} not supported for Android"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
if @testa_opts[:default_scroll_strategy].nil?
|
59
|
+
@default_scroll_strategy = DEFAULT_ANDROID_SCROLL_STRATEGY
|
60
|
+
else
|
61
|
+
case @testa_opts[:default_scroll_strategy].to_sym
|
62
|
+
when SCROLL_STRATEGY_W3C, SCROLL_STRATEGY_UIAUTOMATOR
|
63
|
+
@default_scroll_strategy = @testa_opts[:default_scroll_strategy].to_sym
|
64
|
+
else
|
65
|
+
raise "Default scroll strategy #{@testa_opts[:default_scroll_strategy]} not supported for Android"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
70
|
end
|
@@ -1,114 +1,114 @@
|
|
1
|
-
module TestaAppiumDriver
|
2
|
-
module Attributes
|
3
|
-
|
4
|
-
#noinspection RubyNilAnalysis
|
5
|
-
def attribute(name, *args)
|
6
|
-
elements = execute(*args)
|
7
|
-
|
8
|
-
@driver = get_driver if self.instance_of?(Selenium::WebDriver::Element)
|
9
|
-
|
10
|
-
if elements.kind_of?(Selenium::WebDriver::Element)
|
11
|
-
r = elements.send(:attribute, name.to_s)
|
12
|
-
r = TestaAppiumDriver::Bounds.from_android(r, @driver) if name.to_s == "bounds"
|
13
|
-
else
|
14
|
-
r = elements.map { |e| e.send(:attribute, name.to_s) }
|
15
|
-
r.map! { |b| TestaAppiumDriver::Bounds.from_android(b, @driver) } if name.to_s == "bounds"
|
16
|
-
end
|
17
|
-
r
|
18
|
-
end
|
19
|
-
|
20
|
-
def text(*args)
|
21
|
-
attribute("text", *args)
|
22
|
-
end
|
23
|
-
|
24
|
-
def package(*args)
|
25
|
-
attribute("package", *args)
|
26
|
-
end
|
27
|
-
|
28
|
-
def class_name(*args)
|
29
|
-
attribute("className", *args)
|
30
|
-
end
|
31
|
-
|
32
|
-
def checkable?(*args)
|
33
|
-
attribute("checkable", *args).to_s == "true"
|
34
|
-
end
|
35
|
-
|
36
|
-
def checked?(*args)
|
37
|
-
attribute("checked", *args).to_s == "true"
|
38
|
-
end
|
39
|
-
|
40
|
-
def clickable?(*args)
|
41
|
-
attribute("clickable", *args).to_s == "true"
|
42
|
-
end
|
43
|
-
|
44
|
-
def desc(*args)
|
45
|
-
attribute("contentDescription", *args)
|
46
|
-
end
|
47
|
-
|
48
|
-
def enabled?(*args)
|
49
|
-
attribute("enabled", *args).to_s == "true"
|
50
|
-
end
|
51
|
-
|
52
|
-
def focusable?(*args)
|
53
|
-
attribute("focusable", *args).to_s == "true"
|
54
|
-
end
|
55
|
-
|
56
|
-
def focused?(*args)
|
57
|
-
attribute("focused", *args).to_s == "true"
|
58
|
-
end
|
59
|
-
|
60
|
-
def long_clickable?(*args)
|
61
|
-
attribute("longClickable", *args).to_s == "true"
|
62
|
-
end
|
63
|
-
|
64
|
-
def password?(*args)
|
65
|
-
attribute("password", *args).to_s == "true"
|
66
|
-
end
|
67
|
-
|
68
|
-
def id(*args)
|
69
|
-
attribute("resourceId", *args)
|
70
|
-
end
|
71
|
-
|
72
|
-
def scrollable?(*args)
|
73
|
-
attribute("scrollable", *args).to_s == "true"
|
74
|
-
end
|
75
|
-
|
76
|
-
def selected?(*args)
|
77
|
-
attribute("selected", *args).to_s == "true"
|
78
|
-
end
|
79
|
-
|
80
|
-
def displayed?(*args)
|
81
|
-
attribute("displayed", *args).to_s == "true"
|
82
|
-
end
|
83
|
-
|
84
|
-
def selection_start(*args)
|
85
|
-
attribute("selection-start", *args)
|
86
|
-
end
|
87
|
-
|
88
|
-
def selection_end(*args)
|
89
|
-
attribute("selection-end", *args)
|
90
|
-
end
|
91
|
-
|
92
|
-
def bounds(*args)
|
93
|
-
attribute("bounds", *args)
|
94
|
-
end
|
95
|
-
|
96
|
-
end
|
97
|
-
|
98
|
-
class Locator
|
99
|
-
include TestaAppiumDriver::Attributes
|
100
|
-
|
101
|
-
|
102
|
-
# element index in parent element, starts from 0
|
103
|
-
#noinspection RubyNilAnalysis,RubyYardReturnMatch
|
104
|
-
# @return [Integer, nil] index of element
|
105
|
-
def index(*args)
|
106
|
-
raise "Index not supported for uiautomator strategy" if @strategy == FIND_STRATEGY_UIAUTOMATOR
|
107
|
-
this = execute(*args)
|
108
|
-
children = self.dup.parent.children.execute
|
109
|
-
index = children.index(this)
|
110
|
-
raise "Index not found" if index.nil?
|
111
|
-
index.to_i
|
112
|
-
end
|
113
|
-
end
|
1
|
+
module TestaAppiumDriver
|
2
|
+
module Attributes
|
3
|
+
|
4
|
+
#noinspection RubyNilAnalysis
|
5
|
+
def attribute(name, *args)
|
6
|
+
elements = execute(*args)
|
7
|
+
|
8
|
+
@driver = get_driver if self.instance_of?(Selenium::WebDriver::Element)
|
9
|
+
|
10
|
+
if elements.kind_of?(Selenium::WebDriver::Element)
|
11
|
+
r = elements.send(:attribute, name.to_s)
|
12
|
+
r = TestaAppiumDriver::Bounds.from_android(r, @driver) if name.to_s == "bounds"
|
13
|
+
else
|
14
|
+
r = elements.map { |e| e.send(:attribute, name.to_s) }
|
15
|
+
r.map! { |b| TestaAppiumDriver::Bounds.from_android(b, @driver) } if name.to_s == "bounds"
|
16
|
+
end
|
17
|
+
r
|
18
|
+
end
|
19
|
+
|
20
|
+
def text(*args)
|
21
|
+
attribute("text", *args)
|
22
|
+
end
|
23
|
+
|
24
|
+
def package(*args)
|
25
|
+
attribute("package", *args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def class_name(*args)
|
29
|
+
attribute("className", *args)
|
30
|
+
end
|
31
|
+
|
32
|
+
def checkable?(*args)
|
33
|
+
attribute("checkable", *args).to_s == "true"
|
34
|
+
end
|
35
|
+
|
36
|
+
def checked?(*args)
|
37
|
+
attribute("checked", *args).to_s == "true"
|
38
|
+
end
|
39
|
+
|
40
|
+
def clickable?(*args)
|
41
|
+
attribute("clickable", *args).to_s == "true"
|
42
|
+
end
|
43
|
+
|
44
|
+
def desc(*args)
|
45
|
+
attribute("contentDescription", *args)
|
46
|
+
end
|
47
|
+
|
48
|
+
def enabled?(*args)
|
49
|
+
attribute("enabled", *args).to_s == "true"
|
50
|
+
end
|
51
|
+
|
52
|
+
def focusable?(*args)
|
53
|
+
attribute("focusable", *args).to_s == "true"
|
54
|
+
end
|
55
|
+
|
56
|
+
def focused?(*args)
|
57
|
+
attribute("focused", *args).to_s == "true"
|
58
|
+
end
|
59
|
+
|
60
|
+
def long_clickable?(*args)
|
61
|
+
attribute("longClickable", *args).to_s == "true"
|
62
|
+
end
|
63
|
+
|
64
|
+
def password?(*args)
|
65
|
+
attribute("password", *args).to_s == "true"
|
66
|
+
end
|
67
|
+
|
68
|
+
def id(*args)
|
69
|
+
attribute("resourceId", *args)
|
70
|
+
end
|
71
|
+
|
72
|
+
def scrollable?(*args)
|
73
|
+
attribute("scrollable", *args).to_s == "true"
|
74
|
+
end
|
75
|
+
|
76
|
+
def selected?(*args)
|
77
|
+
attribute("selected", *args).to_s == "true"
|
78
|
+
end
|
79
|
+
|
80
|
+
def displayed?(*args)
|
81
|
+
attribute("displayed", *args).to_s == "true"
|
82
|
+
end
|
83
|
+
|
84
|
+
def selection_start(*args)
|
85
|
+
attribute("selection-start", *args)
|
86
|
+
end
|
87
|
+
|
88
|
+
def selection_end(*args)
|
89
|
+
attribute("selection-end", *args)
|
90
|
+
end
|
91
|
+
|
92
|
+
def bounds(*args)
|
93
|
+
attribute("bounds", *args)
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
class Locator
|
99
|
+
include TestaAppiumDriver::Attributes
|
100
|
+
|
101
|
+
|
102
|
+
# element index in parent element, starts from 0
|
103
|
+
#noinspection RubyNilAnalysis,RubyYardReturnMatch
|
104
|
+
# @return [Integer, nil] index of element
|
105
|
+
def index(*args)
|
106
|
+
raise "Index not supported for uiautomator strategy" if @strategy == FIND_STRATEGY_UIAUTOMATOR
|
107
|
+
this = execute(*args)
|
108
|
+
children = self.dup.parent.children.execute
|
109
|
+
index = children.index(this)
|
110
|
+
raise "Index not found" if index.nil?
|
111
|
+
index.to_i
|
112
|
+
end
|
113
|
+
end
|
114
114
|
end
|
@@ -1,142 +1,142 @@
|
|
1
|
-
require_relative 'locator/attributes'
|
2
|
-
|
3
|
-
module TestaAppiumDriver
|
4
|
-
#noinspection RubyTooManyInstanceVariablesInspection
|
5
|
-
class Locator
|
6
|
-
attr_accessor :closing_parenthesis
|
7
|
-
include ClassSelectors
|
8
|
-
|
9
|
-
def init(params, selectors, single)
|
10
|
-
@closing_parenthesis = 0
|
11
|
-
|
12
|
-
|
13
|
-
@ui_selector = hash_to_uiautomator(selectors, single)
|
14
|
-
|
15
|
-
|
16
|
-
if is_scrollable_selector?(selectors, single)
|
17
|
-
if selectors[:class] == "android.widget.HorizontalScrollView"
|
18
|
-
@scroll_orientation = :horizontal
|
19
|
-
else
|
20
|
-
@scroll_orientation = :vertical
|
21
|
-
end
|
22
|
-
|
23
|
-
if !params[:top].nil? || !params[:bottom].nil? || !params[:right].nil? || !params[:left].nil?
|
24
|
-
@scroll_deadzone = {}
|
25
|
-
@scroll_deadzone[:top] = params[:top].to_f unless params[:top].nil?
|
26
|
-
@scroll_deadzone[:bottom] = params[:bottom].to_f unless params[:bottom].nil?
|
27
|
-
@scroll_deadzone[:right] = params[:right].to_f unless params[:right].nil?
|
28
|
-
@scroll_deadzone[:left] = params[:left].to_f unless params[:left].nil?
|
29
|
-
end
|
30
|
-
|
31
|
-
params[:scrollable_locator] = self.dup
|
32
|
-
end
|
33
|
-
|
34
|
-
@scrollable_locator = params[:scrollable_locator] if params[:scrollable_locator]
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
# resolve selector which will be used for finding element
|
39
|
-
def strategies_and_selectors
|
40
|
-
ss = []
|
41
|
-
if @can_use_id_strategy
|
42
|
-
ss.push({"#{FIND_STRATEGY_ID}": @can_use_id_strategy})
|
43
|
-
end
|
44
|
-
if @strategy.nil? || @strategy == FIND_STRATEGY_UIAUTOMATOR
|
45
|
-
ss.push({"#{FIND_STRATEGY_UIAUTOMATOR}": ui_selector})
|
46
|
-
end
|
47
|
-
|
48
|
-
if @strategy.nil? || @strategy == FIND_STRATEGY_XPATH
|
49
|
-
ss.push({"#{FIND_STRATEGY_XPATH}": @xpath_selector})
|
50
|
-
end
|
51
|
-
|
52
|
-
if @strategy == FIND_STRATEGY_IMAGE
|
53
|
-
ss.push({"#{FIND_STRATEGY_IMAGE}": @image_selector})
|
54
|
-
end
|
55
|
-
ss
|
56
|
-
end
|
57
|
-
|
58
|
-
|
59
|
-
# @param [Boolean] include_semicolon should the semicolon be included at the end
|
60
|
-
# @return ui_selector for uiautomator find strategy
|
61
|
-
def ui_selector(include_semicolon = true)
|
62
|
-
@ui_selector + ")" * @closing_parenthesis + (include_semicolon ? ";" : "");
|
63
|
-
end
|
64
|
-
|
65
|
-
def ui_selector=(value)
|
66
|
-
@ui_selector = value
|
67
|
-
end
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
# @return [TestaAppiumDriver::Locator]
|
73
|
-
def from_parent(selectors = {})
|
74
|
-
raise "Cannot add from_parent selector to array" unless @single
|
75
|
-
raise StrategyMixException.new(@strategy, @strategy_reason, FIND_STRATEGY_UIAUTOMATOR, "from_parent") if @strategy != FIND_STRATEGY_UIAUTOMATOR
|
76
|
-
|
77
|
-
locator = self.dup
|
78
|
-
locator.strategy = FIND_STRATEGY_UIAUTOMATOR
|
79
|
-
locator.strategy_reason = "from_parent"
|
80
|
-
locator.closing_parenthesis += 1
|
81
|
-
locator.ui_selector = "#{locator.ui_selector}.fromParent(#{hash_to_uiautomator(selectors)}"
|
82
|
-
locator
|
83
|
-
end
|
84
|
-
|
85
|
-
|
86
|
-
# @return [Locator] new child locator element
|
87
|
-
def add_child_selector(params)
|
88
|
-
params, selectors = extract_selectors_from_params(params)
|
89
|
-
single = params[:single]
|
90
|
-
raise "Cannot add child selector to Array" if single && !@single
|
91
|
-
|
92
|
-
locator = self.dup
|
93
|
-
locator.can_use_id_strategy = false
|
94
|
-
if (@strategy.nil? && !single) || @strategy == FIND_STRATEGY_XPATH
|
95
|
-
locator.strategy = FIND_STRATEGY_XPATH
|
96
|
-
locator.strategy_reason = "multiple child selector"
|
97
|
-
add_xpath_child_selectors(locator, selectors, single)
|
98
|
-
elsif @strategy == FIND_STRATEGY_UIAUTOMATOR
|
99
|
-
locator = add_uiautomator_child_selector(locator, selectors, single)
|
100
|
-
elsif @strategy == FIND_STRATEGY_IMAGE
|
101
|
-
locator = add_image_child_selector(locator, selectors, single)
|
102
|
-
else
|
103
|
-
# both paths are valid
|
104
|
-
add_xpath_child_selectors(locator, selectors, single)
|
105
|
-
locator = add_uiautomator_child_selector(locator, selectors, single)
|
106
|
-
end
|
107
|
-
|
108
|
-
if is_scrollable_selector?(selectors, single)
|
109
|
-
locator.scrollable_locator = locator
|
110
|
-
if selectors[:class] == "android.widget.HorizontalScrollView"
|
111
|
-
locator.scrollable_locator.scroll_orientation = :horizontal
|
112
|
-
else
|
113
|
-
locator.scrollable_locator.scroll_orientation = :vertical
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
locator.last_selector_adjacent = false
|
118
|
-
locator
|
119
|
-
end
|
120
|
-
|
121
|
-
|
122
|
-
private
|
123
|
-
def add_uiautomator_child_selector(locator, selectors, single)
|
124
|
-
if locator.single && !single
|
125
|
-
# current locator stays single, the child locator looks for multiple
|
126
|
-
params = selectors.merge({single: single, scrollable_locator: locator.scrollable_locator})
|
127
|
-
params[:default_find_strategy] = locator.default_find_strategy
|
128
|
-
params[:default_scroll_strategy] = locator.default_scroll_strategy
|
129
|
-
Locator.new(@driver, self, params)
|
130
|
-
else
|
131
|
-
locator.single = true
|
132
|
-
locator.ui_selector = "#{locator.ui_selector(false)}.childSelector(#{hash_to_uiautomator(selectors, single)})"
|
133
|
-
locator
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def add_image_child_selector(locator, selectors, single)
|
138
|
-
params = selectors.merge({single: single, scrollable_locator: locator.scrollable_locator})
|
139
|
-
Locator.new(@driver, self, params)
|
140
|
-
end
|
141
|
-
end
|
1
|
+
require_relative 'locator/attributes'
|
2
|
+
|
3
|
+
module TestaAppiumDriver
|
4
|
+
#noinspection RubyTooManyInstanceVariablesInspection
|
5
|
+
class Locator
|
6
|
+
attr_accessor :closing_parenthesis
|
7
|
+
include ClassSelectors
|
8
|
+
|
9
|
+
def init(params, selectors, single)
|
10
|
+
@closing_parenthesis = 0
|
11
|
+
|
12
|
+
|
13
|
+
@ui_selector = hash_to_uiautomator(selectors, single)
|
14
|
+
|
15
|
+
|
16
|
+
if is_scrollable_selector?(selectors, single)
|
17
|
+
if selectors[:class] == "android.widget.HorizontalScrollView"
|
18
|
+
@scroll_orientation = :horizontal
|
19
|
+
else
|
20
|
+
@scroll_orientation = :vertical
|
21
|
+
end
|
22
|
+
|
23
|
+
if !params[:top].nil? || !params[:bottom].nil? || !params[:right].nil? || !params[:left].nil?
|
24
|
+
@scroll_deadzone = {}
|
25
|
+
@scroll_deadzone[:top] = params[:top].to_f unless params[:top].nil?
|
26
|
+
@scroll_deadzone[:bottom] = params[:bottom].to_f unless params[:bottom].nil?
|
27
|
+
@scroll_deadzone[:right] = params[:right].to_f unless params[:right].nil?
|
28
|
+
@scroll_deadzone[:left] = params[:left].to_f unless params[:left].nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
params[:scrollable_locator] = self.dup
|
32
|
+
end
|
33
|
+
|
34
|
+
@scrollable_locator = params[:scrollable_locator] if params[:scrollable_locator]
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
# resolve selector which will be used for finding element
|
39
|
+
def strategies_and_selectors
|
40
|
+
ss = []
|
41
|
+
if @can_use_id_strategy
|
42
|
+
ss.push({"#{FIND_STRATEGY_ID}": @can_use_id_strategy})
|
43
|
+
end
|
44
|
+
if @strategy.nil? || @strategy == FIND_STRATEGY_UIAUTOMATOR
|
45
|
+
ss.push({"#{FIND_STRATEGY_UIAUTOMATOR}": ui_selector})
|
46
|
+
end
|
47
|
+
|
48
|
+
if @strategy.nil? || @strategy == FIND_STRATEGY_XPATH
|
49
|
+
ss.push({"#{FIND_STRATEGY_XPATH}": @xpath_selector})
|
50
|
+
end
|
51
|
+
|
52
|
+
if @strategy == FIND_STRATEGY_IMAGE
|
53
|
+
ss.push({"#{FIND_STRATEGY_IMAGE}": @image_selector})
|
54
|
+
end
|
55
|
+
ss
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
# @param [Boolean] include_semicolon should the semicolon be included at the end
|
60
|
+
# @return ui_selector for uiautomator find strategy
|
61
|
+
def ui_selector(include_semicolon = true)
|
62
|
+
@ui_selector + ")" * @closing_parenthesis + (include_semicolon ? ";" : "");
|
63
|
+
end
|
64
|
+
|
65
|
+
def ui_selector=(value)
|
66
|
+
@ui_selector = value
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
# @return [TestaAppiumDriver::Locator]
|
73
|
+
def from_parent(selectors = {})
|
74
|
+
raise "Cannot add from_parent selector to array" unless @single
|
75
|
+
raise StrategyMixException.new(@strategy, @strategy_reason, FIND_STRATEGY_UIAUTOMATOR, "from_parent") if @strategy != FIND_STRATEGY_UIAUTOMATOR
|
76
|
+
|
77
|
+
locator = self.dup
|
78
|
+
locator.strategy = FIND_STRATEGY_UIAUTOMATOR
|
79
|
+
locator.strategy_reason = "from_parent"
|
80
|
+
locator.closing_parenthesis += 1
|
81
|
+
locator.ui_selector = "#{locator.ui_selector}.fromParent(#{hash_to_uiautomator(selectors)}"
|
82
|
+
locator
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
# @return [Locator] new child locator element
|
87
|
+
def add_child_selector(params)
|
88
|
+
params, selectors = extract_selectors_from_params(params)
|
89
|
+
single = params[:single]
|
90
|
+
raise "Cannot add child selector to Array" if single && !@single
|
91
|
+
|
92
|
+
locator = self.dup
|
93
|
+
locator.can_use_id_strategy = false
|
94
|
+
if (@strategy.nil? && !single) || @strategy == FIND_STRATEGY_XPATH
|
95
|
+
locator.strategy = FIND_STRATEGY_XPATH
|
96
|
+
locator.strategy_reason = "multiple child selector"
|
97
|
+
add_xpath_child_selectors(locator, selectors, single)
|
98
|
+
elsif @strategy == FIND_STRATEGY_UIAUTOMATOR
|
99
|
+
locator = add_uiautomator_child_selector(locator, selectors, single)
|
100
|
+
elsif @strategy == FIND_STRATEGY_IMAGE
|
101
|
+
locator = add_image_child_selector(locator, selectors, single)
|
102
|
+
else
|
103
|
+
# both paths are valid
|
104
|
+
add_xpath_child_selectors(locator, selectors, single)
|
105
|
+
locator = add_uiautomator_child_selector(locator, selectors, single)
|
106
|
+
end
|
107
|
+
|
108
|
+
if is_scrollable_selector?(selectors, single)
|
109
|
+
locator.scrollable_locator = locator
|
110
|
+
if selectors[:class] == "android.widget.HorizontalScrollView"
|
111
|
+
locator.scrollable_locator.scroll_orientation = :horizontal
|
112
|
+
else
|
113
|
+
locator.scrollable_locator.scroll_orientation = :vertical
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
locator.last_selector_adjacent = false
|
118
|
+
locator
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
private
|
123
|
+
def add_uiautomator_child_selector(locator, selectors, single)
|
124
|
+
if locator.single && !single
|
125
|
+
# current locator stays single, the child locator looks for multiple
|
126
|
+
params = selectors.merge({single: single, scrollable_locator: locator.scrollable_locator})
|
127
|
+
params[:default_find_strategy] = locator.default_find_strategy
|
128
|
+
params[:default_scroll_strategy] = locator.default_scroll_strategy
|
129
|
+
Locator.new(@driver, self, params)
|
130
|
+
else
|
131
|
+
locator.single = true
|
132
|
+
locator.ui_selector = "#{locator.ui_selector(false)}.childSelector(#{hash_to_uiautomator(selectors, single)})"
|
133
|
+
locator
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def add_image_child_selector(locator, selectors, single)
|
138
|
+
params = selectors.merge({single: single, scrollable_locator: locator.scrollable_locator})
|
139
|
+
Locator.new(@driver, self, params)
|
140
|
+
end
|
141
|
+
end
|
142
142
|
end
|