watir 6.15.1 → 6.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -2
- data/.travis.yml +2 -0
- data/CHANGES.md +13 -0
- data/Rakefile +6 -0
- data/lib/watir.rb +1 -0
- data/lib/watir/browser.rb +4 -1
- data/lib/watir/element_collection.rb +27 -17
- data/lib/watir/elements/element.rb +41 -14
- data/lib/watir/elements/iframe.rb +3 -1
- data/lib/watir/elements/radio.rb +7 -2
- data/lib/watir/elements/select.rb +1 -0
- data/lib/watir/locators.rb +21 -21
- data/lib/watir/locators/button/matcher.rb +40 -0
- data/lib/watir/locators/cell/selector_builder.rb +3 -0
- data/lib/watir/locators/element/locator.rb +29 -172
- data/lib/watir/locators/element/matcher.rb +127 -0
- data/lib/watir/locators/element/selector_builder.rb +69 -23
- data/lib/watir/locators/element/selector_builder/xpath.rb +3 -10
- data/lib/watir/locators/row/selector_builder.rb +5 -5
- data/lib/watir/locators/text_area/selector_builder.rb +0 -14
- data/lib/watir/locators/text_area/selector_builder/xpath.rb +2 -2
- data/lib/watir/locators/text_field/matcher.rb +38 -0
- data/lib/watir/radio_set.rb +28 -31
- data/lib/watir/scroll.rb +69 -0
- data/lib/watir/version.rb +1 -1
- data/spec/locator_spec_helper.rb +58 -14
- data/spec/unit/element_locator_spec.rb +46 -591
- data/spec/unit/match_elements/button_spec.rb +80 -0
- data/spec/unit/match_elements/element_spec.rb +368 -0
- data/spec/unit/match_elements/text_field_spec.rb +79 -0
- data/spec/unit/selector_builder/anchor_spec.rb +51 -0
- data/spec/unit/selector_builder/button_spec.rb +206 -0
- data/spec/unit/selector_builder/cell_spec.rb +63 -0
- data/spec/unit/selector_builder/element_spec.rb +744 -0
- data/spec/unit/selector_builder/row_spec.rb +111 -0
- data/spec/unit/selector_builder/text_field_spec.rb +189 -0
- data/spec/unit/selector_builder/textarea_spec.rb +25 -0
- data/spec/watirspec/browser_spec.rb +7 -8
- data/spec/watirspec/element_hidden_spec.rb +1 -2
- data/spec/watirspec/elements/element_spec.rb +52 -16
- data/spec/watirspec/elements/iframe_spec.rb +1 -1
- data/spec/watirspec/elements/select_list_spec.rb +1 -1
- data/spec/watirspec/html/obscured.html +3 -1
- data/spec/watirspec/html/scroll.html +32 -0
- data/spec/watirspec/relaxed_locate_spec.rb +6 -1
- data/spec/watirspec/scroll_spec.rb +106 -0
- data/spec/watirspec/support/rspec_matchers.rb +2 -0
- data/spec/watirspec/wait_spec.rb +1 -1
- data/watir.gemspec +2 -4
- metadata +36 -33
- data/lib/watir/locators/button/locator.rb +0 -32
- data/lib/watir/locators/button/validator.rb +0 -17
- data/lib/watir/locators/cell/locator.rb +0 -13
- data/lib/watir/locators/element/validator.rb +0 -11
- data/lib/watir/locators/row/locator.rb +0 -13
- data/lib/watir/locators/text_field/locator.rb +0 -31
- data/lib/watir/locators/text_field/validator.rb +0 -13
- data/spec/unit/anchor_locator_spec.rb +0 -68
- data/spec/watirspec/selector_builder/button_spec.rb +0 -250
- data/spec/watirspec/selector_builder/cell_spec.rb +0 -92
- data/spec/watirspec/selector_builder/element_spec.rb +0 -628
- data/spec/watirspec/selector_builder/row_spec.rb +0 -148
- data/spec/watirspec/selector_builder/text_spec.rb +0 -199
@@ -0,0 +1,40 @@
|
|
1
|
+
module Watir
|
2
|
+
module Locators
|
3
|
+
class Button
|
4
|
+
class Matcher < Element::Matcher
|
5
|
+
def elements_match?(element, values_to_match)
|
6
|
+
copy_values_to_match = values_to_match.dup
|
7
|
+
value = copy_values_to_match.delete(:value)
|
8
|
+
|
9
|
+
if value
|
10
|
+
matching = matches_values?(fetch_value(element, :text), value)
|
11
|
+
deprecate_value_button if matching
|
12
|
+
|
13
|
+
matching ||= matches_values?(fetch_value(element, :value), value)
|
14
|
+
|
15
|
+
return false unless matching
|
16
|
+
return true if copy_values_to_match.empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
super(element, copy_values_to_match)
|
20
|
+
end
|
21
|
+
|
22
|
+
def deprecate_value_button
|
23
|
+
Watir.logger.deprecate(':value locator key for finding button text',
|
24
|
+
'use :text locator',
|
25
|
+
ids: [:value_button])
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate_tag(element, _tag_name)
|
29
|
+
tag_name = element.tag_name.downcase
|
30
|
+
return unless %w[input button].include?(tag_name)
|
31
|
+
|
32
|
+
# TODO: - Verify this is desired behavior based on https://bugzilla.mozilla.org/show_bug.cgi?id=1290963
|
33
|
+
return if tag_name == 'input' && !Watir::Button::VALID_TYPES.include?(element.attribute('type').downcase)
|
34
|
+
|
35
|
+
element
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -4,179 +4,45 @@ module Watir
|
|
4
4
|
class Locator
|
5
5
|
include Exception
|
6
6
|
|
7
|
-
attr_reader :
|
8
|
-
attr_reader :element_validator
|
7
|
+
attr_reader :element_matcher, :driver_scope
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
partial_link_text
|
15
|
-
tag_name
|
16
|
-
xpath
|
17
|
-
].freeze
|
18
|
-
|
19
|
-
def initialize(query_scope, selector, selector_builder, element_validator)
|
20
|
-
@query_scope = query_scope # either element or browser
|
21
|
-
@selector = selector
|
22
|
-
@selector_builder = selector_builder
|
23
|
-
@element_validator = element_validator
|
9
|
+
def initialize(element_matcher)
|
10
|
+
@query_scope = element_matcher.query_scope
|
11
|
+
@selector = element_matcher.selector
|
12
|
+
@element_matcher = element_matcher
|
24
13
|
end
|
25
14
|
|
26
|
-
def locate
|
27
|
-
|
28
|
-
|
15
|
+
def locate(built)
|
16
|
+
@built = built.dup
|
17
|
+
@driver_scope = (@built.delete(:scope) || @query_scope.browser).wd
|
18
|
+
matching_elements(@built, :first)
|
19
|
+
rescue Selenium::WebDriver::Error::NoSuchElementError
|
29
20
|
nil
|
30
21
|
end
|
31
22
|
|
32
|
-
def locate_all
|
33
|
-
|
23
|
+
def locate_all(built)
|
24
|
+
@built = built.dup
|
25
|
+
@driver_scope = (@built.delete(:scope) || @query_scope.browser).wd
|
26
|
+
raise ArgumentError, "can't locate all elements by :index" if built.key?(:index)
|
34
27
|
|
35
|
-
|
28
|
+
[matching_elements(@built, :all)].flatten
|
36
29
|
end
|
37
30
|
|
38
31
|
private
|
39
32
|
|
40
|
-
def
|
41
|
-
|
42
|
-
tag = selector[:tag_name].is_a?(::Symbol) ? selector.delete(:tag_name).to_s : selector.delete(:tag_name)
|
43
|
-
return if selector.size > 1
|
44
|
-
|
45
|
-
how = selector.keys.first || :tag_name
|
46
|
-
what = selector.values.first || tag
|
47
|
-
|
48
|
-
return unless wd_supported?(how, what, tag)
|
49
|
-
|
50
|
-
filter == :all ? locate_elements(how, what) : locate_element(how, what)
|
51
|
-
end
|
52
|
-
|
53
|
-
def using_watir(filter = :first)
|
54
|
-
selector = @selector.dup
|
55
|
-
raise ArgumentError, "can't locate all elements by :index" if selector.key?(:index) && filter == :all
|
56
|
-
|
57
|
-
@driver_scope ||= @query_scope.wd
|
58
|
-
|
59
|
-
built = selector_builder.build(selector)
|
60
|
-
|
61
|
-
validate_built_selector(built)
|
62
|
-
|
63
|
-
wd_locator = built.select { |key, _value| %i[css xpath link_text partial_link_text].include? key }
|
64
|
-
values_to_match = built.reject { |key, _value| %i[css xpath link_text partial_link_text].include? key }
|
65
|
-
|
66
|
-
if filter == :all || values_to_match.any?
|
67
|
-
locate_matching_elements(wd_locator, values_to_match, filter)
|
68
|
-
else
|
69
|
-
locate_element(wd_locator.keys.first, wd_locator.values.first, @driver_scope)
|
70
|
-
end
|
71
|
-
end
|
33
|
+
def matching_elements(built, filter)
|
34
|
+
return locate_element(*built.to_a.flatten) if built.size == 1 && filter == :first
|
72
35
|
|
73
|
-
|
74
|
-
|
36
|
+
wd_locator_key = (Watir::Locators::W3C_FINDERS & built.keys).first
|
37
|
+
wd_locator = built.select { |k, _v| wd_locator_key == k }
|
38
|
+
match_values = built.reject { |k, _v| wd_locator_key == k }
|
75
39
|
|
76
|
-
|
77
|
-
raise LocatorException, msg
|
78
|
-
end
|
79
|
-
|
80
|
-
def fetch_value(element, how)
|
81
|
-
case how
|
82
|
-
when :text
|
83
|
-
element.text
|
84
|
-
when :visible
|
85
|
-
element.displayed?
|
86
|
-
when :visible_text
|
87
|
-
element.text
|
88
|
-
when :tag_name
|
89
|
-
element.tag_name.downcase
|
90
|
-
when :href
|
91
|
-
element.attribute('href')&.strip
|
92
|
-
else
|
93
|
-
how = how.to_s.tr('_', '-') if how.is_a?(::Symbol)
|
94
|
-
element.attribute(how)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def matching_labels(elements, values_to_match, scope)
|
99
|
-
label_key = values_to_match.key?(:label_element) ? :label_element : :visible_label_element
|
100
|
-
label_value = values_to_match.delete(:label_element) || values_to_match.delete(:visible_label_element)
|
101
|
-
locator_key = label_key.to_s.gsub('label', 'text').gsub('_element', '').to_sym
|
102
|
-
|
103
|
-
Watir::LabelCollection.new(scope, tag_name: 'label').map { |label|
|
104
|
-
next unless matches_values?(label.wd, locator_key => label_value)
|
105
|
-
|
106
|
-
input = label.for.empty? ? label.input : Watir::Input.new(scope, id: label.for)
|
107
|
-
input.wd if elements.include?(input.wd)
|
108
|
-
}.compact
|
109
|
-
end
|
110
|
-
|
111
|
-
def matching_elements(elements, values_to_match, filter: :first)
|
112
|
-
if filter == :first
|
113
|
-
idx = element_index(elements, values_to_match)
|
114
|
-
counter = 0
|
115
|
-
|
116
|
-
# Lazy evaluation to avoid fetching values for elements that will be discarded
|
117
|
-
matches = elements.lazy.select do |el|
|
118
|
-
counter += 1
|
119
|
-
matches_values?(el, values_to_match)
|
120
|
-
end
|
121
|
-
msg = "iterated through #{counter} elements to locate #{@selector.inspect}"
|
122
|
-
matches.take(idx + 1).to_a[idx].tap { Watir.logger.debug msg }
|
123
|
-
else
|
124
|
-
Watir.logger.debug "Iterated through #{elements.size} elements to locate all #{@selector.inspect}"
|
125
|
-
elements.select { |el| matches_values?(el, values_to_match) }
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
def element_index(elements, values_to_match)
|
130
|
-
idx = values_to_match.delete(:index) || 0
|
131
|
-
return idx unless idx.negative?
|
132
|
-
|
133
|
-
elements.reverse!
|
134
|
-
idx.abs - 1
|
135
|
-
end
|
136
|
-
|
137
|
-
def matches_values?(element, values_to_match)
|
138
|
-
matches = values_to_match.all? do |how, what|
|
139
|
-
if how == :tag_name && what.is_a?(String)
|
140
|
-
element_validator.validate(element, what)
|
141
|
-
else
|
142
|
-
val = fetch_value(element, how)
|
143
|
-
what == val || val =~ /#{what}/
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
text_regexp_deprecation(element, values_to_match, matches) if values_to_match[:text]
|
148
|
-
|
149
|
-
matches
|
150
|
-
end
|
151
|
-
|
152
|
-
def text_regexp_deprecation(element, selector, matches)
|
153
|
-
new_element = Watir::Element.new(@query_scope, element: element)
|
154
|
-
text_content = new_element.execute_js(:getTextContent, element).strip
|
155
|
-
text_content_matches = text_content =~ /#{selector[:text]}/
|
156
|
-
return if matches == !!text_content_matches
|
157
|
-
|
158
|
-
key = @selector.key?(:text) ? 'text' : 'label'
|
159
|
-
selector_text = selector[:text].inspect
|
160
|
-
dep = "Using :#{key} locator with RegExp #{selector_text} to match an element that includes hidden text"
|
161
|
-
Watir.logger.deprecate(dep, ":visible_#{key}", ids: [:text_regexp])
|
162
|
-
end
|
163
|
-
|
164
|
-
def locate_element(how, what, scope = @query_scope.wd)
|
165
|
-
scope.find_element(how, what)
|
166
|
-
end
|
167
|
-
|
168
|
-
def locate_elements(how, what, scope = @query_scope.wd)
|
169
|
-
scope.find_elements(how, what)
|
170
|
-
end
|
171
|
-
|
172
|
-
def locate_matching_elements(selector, values_to_match, filter)
|
40
|
+
# TODO: Wrap this to continue trying until default timeout
|
173
41
|
retries = 0
|
174
42
|
begin
|
175
|
-
elements = locate_elements(
|
176
|
-
|
177
|
-
|
178
|
-
end
|
179
|
-
matching_elements(elements, values_to_match, filter: filter)
|
43
|
+
elements = locate_elements(*wd_locator.to_a.flatten)
|
44
|
+
|
45
|
+
element_matcher.match(elements, match_values, filter)
|
180
46
|
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
181
47
|
retries += 1
|
182
48
|
sleep 0.5
|
@@ -186,21 +52,12 @@ module Watir
|
|
186
52
|
end
|
187
53
|
end
|
188
54
|
|
189
|
-
def
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
if %i[partial_link_text link_text link].include?(how)
|
194
|
-
Watir.logger.deprecate(":#{how} locator", ':visible_text', ids: [:link_text])
|
195
|
-
return true if [:a, :link, nil].include?(tag)
|
55
|
+
def locate_element(how, what, scope = driver_scope)
|
56
|
+
scope.find_element(how, what)
|
57
|
+
end
|
196
58
|
|
197
|
-
|
198
|
-
|
199
|
-
return true
|
200
|
-
else
|
201
|
-
return false unless tag.nil?
|
202
|
-
end
|
203
|
-
true
|
59
|
+
def locate_elements(how, what, scope = driver_scope)
|
60
|
+
scope.find_elements(how, what)
|
204
61
|
end
|
205
62
|
end
|
206
63
|
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module Watir
|
2
|
+
module Locators
|
3
|
+
class Element
|
4
|
+
class Matcher
|
5
|
+
include Exception
|
6
|
+
|
7
|
+
attr_reader :query_scope, :selector
|
8
|
+
|
9
|
+
def initialize(query_scope, selector = {})
|
10
|
+
@query_scope = query_scope
|
11
|
+
@selector = selector
|
12
|
+
end
|
13
|
+
|
14
|
+
def match(elements, values_to_match, filter)
|
15
|
+
elements = matching_labels(elements, values_to_match)
|
16
|
+
matching_elements(elements, values_to_match, filter: filter)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def matching_labels(elements, values_to_match)
|
22
|
+
%i[label_element visible_label_element].each do |key|
|
23
|
+
label_value = values_to_match.delete(key)
|
24
|
+
next if label_value.nil?
|
25
|
+
|
26
|
+
locator_key = key.to_s.gsub('label', 'text').gsub('_element', '').to_sym
|
27
|
+
return label_collection(elements, locator_key => label_value).compact
|
28
|
+
end
|
29
|
+
elements
|
30
|
+
end
|
31
|
+
|
32
|
+
def label_collection(elements, locator)
|
33
|
+
@query_scope.labels.map do |label|
|
34
|
+
next unless elements_match?(label.wd, locator)
|
35
|
+
|
36
|
+
input = label.for.empty? ? label.input : Watir::Input.new(@query_scope, id: label.for)
|
37
|
+
input.wd if elements.include?(input.wd)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def matching_elements(elements, values_to_match, filter: :first)
|
42
|
+
if filter == :first
|
43
|
+
idx = element_index(elements, values_to_match)
|
44
|
+
|
45
|
+
# Lazy evaluation to avoid fetching values for elements that will be discarded
|
46
|
+
matches = elements.lazy.select do |el|
|
47
|
+
elements_match?(el, values_to_match)
|
48
|
+
end
|
49
|
+
Watir.logger.debug "Iterating through #{elements.size} elements to locate #{@selector.inspect}"
|
50
|
+
matches.take(idx + 1).to_a[idx]
|
51
|
+
else
|
52
|
+
Watir.logger.debug "Iterating through #{elements.size} elements to locate all #{@selector.inspect}"
|
53
|
+
elements.select { |el| elements_match?(el, values_to_match) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def elements_match?(element, values_to_match)
|
58
|
+
matches = values_to_match.all? do |how, expected|
|
59
|
+
if how == :tag_name
|
60
|
+
validate_tag(element, expected)
|
61
|
+
# TODO: Can this be class_name here or does that get converted?
|
62
|
+
elsif %i[class class_name].include?(how)
|
63
|
+
value = fetch_value(element, how)
|
64
|
+
[expected].flatten.all? do |match|
|
65
|
+
value.split.any? do |class_value|
|
66
|
+
matches_values?(class_value, match)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
else
|
70
|
+
matches_values?(fetch_value(element, how), expected)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
deprecate_text_regexp(element, values_to_match, matches) if values_to_match[:text]
|
75
|
+
|
76
|
+
matches
|
77
|
+
end
|
78
|
+
|
79
|
+
def matches_values?(found, expected)
|
80
|
+
expected.is_a?(Regexp) ? found =~ expected : found == expected
|
81
|
+
end
|
82
|
+
|
83
|
+
def fetch_value(element, how)
|
84
|
+
case how
|
85
|
+
when :text
|
86
|
+
element.text
|
87
|
+
when :visible
|
88
|
+
element.displayed?
|
89
|
+
when :visible_text
|
90
|
+
element.text
|
91
|
+
when :href
|
92
|
+
element.attribute('href')&.strip
|
93
|
+
when :class, :class_name
|
94
|
+
element.attribute('class')
|
95
|
+
else
|
96
|
+
how = how.to_s.tr('_', '-') if how.is_a?(::Symbol)
|
97
|
+
element.attribute(how)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def element_index(elements, values_to_match)
|
102
|
+
idx = values_to_match.delete(:index) || 0
|
103
|
+
return idx unless idx.negative?
|
104
|
+
|
105
|
+
elements.reverse!
|
106
|
+
idx.abs - 1
|
107
|
+
end
|
108
|
+
|
109
|
+
def validate_tag(element, tag_name)
|
110
|
+
matches_values?(element.tag_name.downcase, tag_name)
|
111
|
+
end
|
112
|
+
|
113
|
+
def deprecate_text_regexp(element, selector, matches)
|
114
|
+
new_element = Watir::Element.new(@query_scope, element: element)
|
115
|
+
text_content = new_element.text_content
|
116
|
+
text_content_matches = text_content =~ /#{selector[:text]}/
|
117
|
+
return if matches == !!text_content_matches
|
118
|
+
|
119
|
+
key = @selector.key?(:text) ? 'text' : 'label'
|
120
|
+
selector_text = selector[:text].inspect
|
121
|
+
dep = "Using :#{key} locator with RegExp #{selector_text} to match an element that includes hidden text"
|
122
|
+
Watir.logger.deprecate(dep, ":visible_#{key}", ids: [:text_regexp])
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -3,7 +3,7 @@ module Watir
|
|
3
3
|
class Element
|
4
4
|
class SelectorBuilder
|
5
5
|
include Exception
|
6
|
-
attr_reader :custom_attributes
|
6
|
+
attr_reader :custom_attributes, :built
|
7
7
|
|
8
8
|
WILDCARD_ATTRIBUTE = /^(aria|data)_(.+)$/.freeze
|
9
9
|
INTEGER_CLASS = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4') ? Fixnum : Integer
|
@@ -14,33 +14,53 @@ module Watir
|
|
14
14
|
visible: [TrueClass, FalseClass],
|
15
15
|
tag_name: [String, Regexp, ::Symbol],
|
16
16
|
visible_text: [String, Regexp],
|
17
|
+
scope: [Hash],
|
17
18
|
text: [String, Regexp]).freeze
|
18
19
|
|
19
|
-
def initialize(valid_attributes)
|
20
|
+
def initialize(valid_attributes, query_scope)
|
20
21
|
@valid_attributes = valid_attributes
|
21
22
|
@custom_attributes = []
|
23
|
+
@query_scope = query_scope
|
22
24
|
end
|
23
25
|
|
24
26
|
def build(selector)
|
25
|
-
inspected = selector.inspect
|
26
27
|
@selector = selector
|
27
|
-
normalize_selector
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
deprecated_locators
|
30
|
+
normalize_selector
|
31
|
+
inspected = selector.inspect
|
32
|
+
scope = @query_scope unless @selector.key?(:scope) || @query_scope.is_a?(Watir::Browser)
|
32
33
|
|
33
|
-
built =
|
34
|
+
@built = wd_locator(@selector.keys).nil? ? build_wd_selector(@selector) : @selector
|
35
|
+
@built.delete(:index) if @built[:index]&.zero?
|
36
|
+
@built[:scope] = scope if scope
|
34
37
|
|
35
|
-
|
38
|
+
Watir.logger.info "Converted #{inspected} to #{@built.inspect}"
|
39
|
+
@built
|
40
|
+
end
|
36
41
|
|
37
|
-
|
38
|
-
|
42
|
+
def wd_locator(keys)
|
43
|
+
(Watir::Locators::W3C_FINDERS & keys).first
|
39
44
|
end
|
40
45
|
|
46
|
+
private
|
47
|
+
|
41
48
|
def normalize_selector
|
42
|
-
|
43
|
-
|
49
|
+
wd_locators = @selector.keys & Watir::Locators::W3C_FINDERS
|
50
|
+
raise LocatorException, "Can not locate element with #{wd_locators}" if wd_locators.size > 1
|
51
|
+
|
52
|
+
@selector[:scope] = @query_scope.selector_builder.built if use_scope?
|
53
|
+
|
54
|
+
if @selector.key?(:class) || @selector.key?(:class_name)
|
55
|
+
classes = ([@selector[:class]].flatten + [@selector.delete(:class_name)].flatten).compact
|
56
|
+
|
57
|
+
classes.each do |class_name|
|
58
|
+
next unless class_name.is_a?(String) && class_name.strip.include?(' ')
|
59
|
+
|
60
|
+
deprecate_class_array(class_name)
|
61
|
+
end
|
62
|
+
|
63
|
+
@selector[:class] = classes
|
44
64
|
end
|
45
65
|
|
46
66
|
if @selector[:adjacent] == :ancestor && @selector.key?(:text)
|
@@ -55,12 +75,25 @@ module Watir
|
|
55
75
|
end
|
56
76
|
end
|
57
77
|
|
58
|
-
def
|
59
|
-
if
|
60
|
-
|
61
|
-
|
78
|
+
def use_scope?
|
79
|
+
return false if @query_scope.is_a?(Browser)
|
80
|
+
|
81
|
+
!@selector.key?(:adjacent) &&
|
82
|
+
(Watir::Locators::W3C_FINDERS & @selector.keys).empty? &&
|
83
|
+
!(@query_scope.is_a?(Watir::IFrame) || @query_scope.is_a?(Watir::Radio)) &&
|
84
|
+
@query_scope.selector_builder.built&.size == 1
|
85
|
+
end
|
62
86
|
|
63
|
-
|
87
|
+
def deprecate_class_array(class_name)
|
88
|
+
dep = "Using the :class locator to locate multiple classes with a String value (i.e. \"#{class_name}\")"
|
89
|
+
Watir.logger.deprecate dep,
|
90
|
+
"Array (e.g. #{class_name.split})",
|
91
|
+
ids: [:class_array]
|
92
|
+
end
|
93
|
+
|
94
|
+
def check_type(how, what)
|
95
|
+
if %i[class class_name].include? how
|
96
|
+
[what].flatten.each { |value| raise_unless(value, VALID_WHATS[how]) }
|
64
97
|
else
|
65
98
|
raise_unless(what, VALID_WHATS[how])
|
66
99
|
end
|
@@ -70,8 +103,6 @@ module Watir
|
|
70
103
|
!valid_attribute?(:label)
|
71
104
|
end
|
72
105
|
|
73
|
-
private
|
74
|
-
|
75
106
|
def normalize_locator(how, what)
|
76
107
|
case how
|
77
108
|
when 'text'
|
@@ -80,16 +111,19 @@ module Watir
|
|
80
111
|
when :tag_name
|
81
112
|
what = what.to_s if what.is_a?(::Symbol)
|
82
113
|
[how, what]
|
83
|
-
when :text, :xpath, :index, :
|
114
|
+
when :text, :xpath, :index, :css, :visible, :visible_text, :adjacent
|
115
|
+
[how, what]
|
116
|
+
when :class
|
117
|
+
what = false if what.tap { |arr| arr.delete('') }.empty?
|
84
118
|
[how, what]
|
119
|
+
when :link
|
120
|
+
[:link_text, what]
|
85
121
|
when :label, :visible_label
|
86
122
|
if should_use_label_element?
|
87
123
|
["#{how}_element".to_sym, what]
|
88
124
|
else
|
89
125
|
[how, what]
|
90
126
|
end
|
91
|
-
when :class_name
|
92
|
-
[:class, what]
|
93
127
|
when :caption
|
94
128
|
# This allows any element to be located with 'caption' instead of 'text'
|
95
129
|
Watir.logger.deprecate('Locating elements with :caption', ':text locator', ids: [:caption])
|
@@ -132,6 +166,18 @@ module Watir
|
|
132
166
|
|
133
167
|
raise TypeError, "expected one of #{types}, got #{what.inspect}:#{what.class}"
|
134
168
|
end
|
169
|
+
|
170
|
+
def deprecated_locators
|
171
|
+
%i[partial_link_text link_text link].each do |locator|
|
172
|
+
next unless @selector.key?(locator)
|
173
|
+
|
174
|
+
Watir.logger.deprecate(":#{locator} locator", ':visible_text', ids: [:link_text])
|
175
|
+
tag = @selector[:tag_name]
|
176
|
+
next if tag.nil? || tag == 'a'
|
177
|
+
|
178
|
+
raise LocatorException, "Can not use #{locator} locator to find a #{tag} element"
|
179
|
+
end
|
180
|
+
end
|
135
181
|
end
|
136
182
|
end
|
137
183
|
end
|