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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +15 -15
  3. data/.idea/deployment.xml +21 -21
  4. data/.idea/inspectionProfiles/Project_Default.xml +8 -8
  5. data/.idea/misc.xml +5 -5
  6. data/.idea/modules.xml +7 -7
  7. data/.idea/runConfigurations/Android_Test.xml +41 -41
  8. data/.idea/runConfigurations.xml +9 -9
  9. data/.idea/sshConfigs.xml +12 -12
  10. data/.idea/vcs.xml +5 -5
  11. data/.idea/webServers.xml +20 -20
  12. data/.rspec +3 -3
  13. data/.rubocop.yml +13 -13
  14. data/CHANGELOG.md +5 -5
  15. data/CODE_OF_CONDUCT.md +102 -102
  16. data/Gemfile +12 -12
  17. data/LICENSE.txt +21 -21
  18. data/README.md +378 -378
  19. data/Rakefile +12 -12
  20. data/bin/console +17 -17
  21. data/bin/setup +8 -8
  22. data/lib/testa_appium_driver/android/class_selectors.rb +437 -437
  23. data/lib/testa_appium_driver/android/driver.rb +69 -69
  24. data/lib/testa_appium_driver/android/locator/attributes.rb +113 -113
  25. data/lib/testa_appium_driver/android/locator.rb +141 -141
  26. data/lib/testa_appium_driver/android/scroll_actions/uiautomator_scroll_actions.rb +61 -61
  27. data/lib/testa_appium_driver/android/selenium_element.rb +7 -7
  28. data/lib/testa_appium_driver/common/bounds.rb +149 -149
  29. data/lib/testa_appium_driver/common/constants.rb +36 -36
  30. data/lib/testa_appium_driver/common/exceptions/strategy_mix_exception.rb +11 -11
  31. data/lib/testa_appium_driver/common/helpers.rb +270 -270
  32. data/lib/testa_appium_driver/common/locator/scroll_actions.rb +397 -397
  33. data/lib/testa_appium_driver/common/locator.rb +610 -610
  34. data/lib/testa_appium_driver/common/scroll_actions/json_wire_scroll_actions.rb +3 -3
  35. data/lib/testa_appium_driver/common/scroll_actions/w3c_scroll_actions.rb +237 -237
  36. data/lib/testa_appium_driver/common/scroll_actions.rb +246 -246
  37. data/lib/testa_appium_driver/common/selenium_element.rb +19 -19
  38. data/lib/testa_appium_driver/driver.rb +312 -312
  39. data/lib/testa_appium_driver/ios/driver.rb +48 -48
  40. data/lib/testa_appium_driver/ios/locator/attributes.rb +80 -80
  41. data/lib/testa_appium_driver/ios/locator.rb +70 -70
  42. data/lib/testa_appium_driver/ios/selenium_element.rb +6 -6
  43. data/lib/testa_appium_driver/ios/type_selectors.rb +187 -187
  44. data/lib/testa_appium_driver/version.rb +5 -5
  45. data/lib/testa_appium_driver.rb +6 -6
  46. data/testa_appium_driver.gemspec +41 -41
  47. data/testa_appium_driver.iml +27 -78
  48. 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