testa_appium_driver 0.1.8 → 0.1.12

Sign up to get free protection for your applications and to get access to all the features.
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 -63
  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 -396
  33. data/lib/testa_appium_driver/common/locator.rb +610 -578
  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 -278
  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