watir 6.13.0 → 6.14.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 +141 -0
- data/.travis.yml +6 -0
- data/CHANGES.md +12 -0
- data/Gemfile +4 -10
- data/README.md +64 -49
- data/Rakefile +28 -16
- data/lib/watir.rb +13 -15
- data/lib/watir/adjacent.rb +15 -13
- data/lib/watir/after_hooks.rb +8 -10
- data/lib/watir/alert.rb +7 -8
- data/lib/watir/aliases.rb +2 -2
- data/lib/watir/attribute_helper.rb +18 -20
- data/lib/watir/browser.rb +42 -75
- data/lib/watir/capabilities.rb +19 -10
- data/lib/watir/cell_container.rb +0 -2
- data/lib/watir/container.rb +4 -4
- data/lib/watir/cookies.rb +7 -8
- data/lib/watir/element_collection.rb +37 -22
- data/lib/watir/elements/area.rb +0 -2
- data/lib/watir/elements/button.rb +1 -3
- data/lib/watir/elements/cell.rb +0 -1
- data/lib/watir/elements/checkbox.rb +5 -7
- data/lib/watir/elements/date_field.rb +5 -9
- data/lib/watir/elements/date_time_field.rb +6 -10
- data/lib/watir/elements/dlist.rb +2 -4
- data/lib/watir/elements/element.rb +201 -99
- data/lib/watir/elements/file_field.rb +3 -4
- data/lib/watir/elements/font.rb +2 -4
- data/lib/watir/elements/form.rb +0 -2
- data/lib/watir/elements/hidden.rb +3 -4
- data/lib/watir/elements/html_elements.rb +24 -76
- data/lib/watir/elements/iframe.rb +57 -71
- data/lib/watir/elements/image.rb +3 -4
- data/lib/watir/elements/input.rb +0 -2
- data/lib/watir/elements/link.rb +2 -5
- data/lib/watir/elements/list.rb +4 -4
- data/lib/watir/elements/option.rb +3 -6
- data/lib/watir/elements/radio.rb +4 -6
- data/lib/watir/elements/row.rb +0 -1
- data/lib/watir/elements/select.rb +41 -43
- data/lib/watir/elements/svg_elements.rb +0 -116
- data/lib/watir/elements/table.rb +1 -2
- data/lib/watir/elements/table_cell.rb +2 -3
- data/lib/watir/elements/text_field.rb +4 -6
- data/lib/watir/exception.rb +0 -1
- data/lib/watir/extensions/nokogiri.rb +2 -4
- data/lib/watir/generator.rb +3 -3
- data/lib/watir/generator/base.rb +10 -10
- data/lib/watir/generator/base/generator.rb +26 -29
- data/lib/watir/generator/base/idl_sorter.rb +34 -32
- data/lib/watir/generator/base/spec_extractor.rb +132 -114
- data/lib/watir/generator/base/util.rb +1 -3
- data/lib/watir/generator/base/visitor.rb +140 -140
- data/lib/watir/generator/html.rb +4 -4
- data/lib/watir/generator/html/generator.rb +2 -4
- data/lib/watir/generator/html/spec_extractor.rb +33 -33
- data/lib/watir/generator/html/visitor.rb +14 -14
- data/lib/watir/generator/svg.rb +3 -3
- data/lib/watir/generator/svg/generator.rb +1 -3
- data/lib/watir/generator/svg/spec_extractor.rb +35 -35
- data/lib/watir/generator/svg/visitor.rb +14 -14
- data/lib/watir/has_window.rb +2 -4
- data/lib/watir/js_execution.rb +7 -9
- data/lib/watir/js_snippets.rb +3 -3
- data/lib/watir/js_snippets/attributeValues.js +11 -0
- data/lib/watir/legacy_wait.rb +7 -12
- data/lib/watir/locators.rb +9 -11
- data/lib/watir/locators/button/locator.rb +2 -3
- data/lib/watir/locators/button/selector_builder.rb +9 -9
- data/lib/watir/locators/button/selector_builder/xpath.rb +1 -1
- data/lib/watir/locators/button/validator.rb +2 -2
- data/lib/watir/locators/cell/locator.rb +0 -2
- data/lib/watir/locators/cell/selector_builder.rb +3 -5
- data/lib/watir/locators/element/locator.rb +85 -64
- data/lib/watir/locators/element/selector_builder.rb +40 -38
- data/lib/watir/locators/element/selector_builder/xpath.rb +20 -18
- data/lib/watir/locators/element/validator.rb +1 -1
- data/lib/watir/locators/row/locator.rb +0 -2
- data/lib/watir/locators/row/selector_builder.rb +6 -9
- data/lib/watir/locators/text_area/selector_builder.rb +1 -1
- data/lib/watir/locators/text_field/locator.rb +1 -3
- data/lib/watir/locators/text_field/selector_builder.rb +5 -5
- data/lib/watir/locators/text_field/selector_builder/xpath.rb +1 -1
- data/lib/watir/locators/text_field/validator.rb +3 -2
- data/lib/watir/logger.rb +11 -21
- data/lib/watir/navigation.rb +49 -0
- data/lib/watir/radio_set.rb +17 -18
- data/lib/watir/row_container.rb +3 -5
- data/lib/watir/screenshot.rb +2 -4
- data/lib/watir/user_editable.rb +13 -8
- data/lib/watir/version.rb +3 -0
- data/lib/watir/wait.rb +56 -55
- data/lib/watir/wait/timer.rb +1 -3
- data/lib/watir/window.rb +36 -45
- data/lib/watir/xpath_support.rb +1 -3
- data/lib/watirspec.rb +11 -11
- data/lib/watirspec/guards.rb +10 -7
- data/lib/watirspec/implementation.rb +3 -4
- data/lib/watirspec/rake_tasks.rb +30 -29
- data/lib/watirspec/remote_server.rb +3 -3
- data/lib/watirspec/runner.rb +1 -2
- data/lib/watirspec/server.rb +3 -0
- data/lib/watirspec/server/app.rb +14 -6
- data/spec/implementation_spec.rb +9 -9
- data/spec/locator_spec_helper.rb +3 -4
- data/spec/spec_helper.rb +3 -7
- data/spec/unit/container_spec.rb +9 -10
- data/spec/unit/element_locator_spec.rb +224 -219
- data/spec/unit/logger_spec.rb +4 -4
- data/spec/unit/unit_helper.rb +0 -2
- data/spec/unit/wait_spec.rb +26 -28
- data/spec/watirspec/adjacent_spec.rb +130 -130
- data/spec/watirspec/after_hooks_spec.rb +63 -63
- data/spec/watirspec/alert_spec.rb +6 -6
- data/spec/watirspec/attributes_spec.rb +6 -6
- data/spec/watirspec/browser_spec.rb +161 -162
- data/spec/watirspec/click_spec.rb +9 -9
- data/spec/watirspec/cookies_spec.rb +15 -14
- data/spec/watirspec/drag_and_drop_spec.rb +15 -16
- data/spec/watirspec/element_hidden_spec.rb +19 -21
- data/spec/watirspec/elements/area_spec.rb +18 -21
- data/spec/watirspec/elements/areas_spec.rb +13 -15
- data/spec/watirspec/elements/button_spec.rb +96 -99
- data/spec/watirspec/elements/buttons_spec.rb +17 -19
- data/spec/watirspec/elements/checkbox_spec.rb +102 -100
- data/spec/watirspec/elements/checkboxes_spec.rb +13 -15
- data/spec/watirspec/elements/collections_spec.rb +35 -37
- data/spec/watirspec/elements/date_field_spec.rb +46 -47
- data/spec/watirspec/elements/date_fields_spec.rb +13 -15
- data/spec/watirspec/elements/date_time_field_spec.rb +62 -57
- data/spec/watirspec/elements/date_time_fields_spec.rb +14 -15
- data/spec/watirspec/elements/dd_spec.rb +46 -48
- data/spec/watirspec/elements/dds_spec.rb +13 -15
- data/spec/watirspec/elements/del_spec.rb +27 -28
- data/spec/watirspec/elements/dels_spec.rb +13 -15
- data/spec/watirspec/elements/div_spec.rb +89 -91
- data/spec/watirspec/elements/divs_spec.rb +17 -19
- data/spec/watirspec/elements/dl_spec.rb +52 -54
- data/spec/watirspec/elements/dls_spec.rb +13 -15
- data/spec/watirspec/elements/dt_spec.rb +46 -48
- data/spec/watirspec/elements/dts_spec.rb +13 -15
- data/spec/watirspec/elements/element_spec.rb +240 -189
- data/spec/watirspec/elements/elements_spec.rb +16 -16
- data/spec/watirspec/elements/em_spec.rb +38 -40
- data/spec/watirspec/elements/ems_spec.rb +13 -15
- data/spec/watirspec/elements/filefield_spec.rb +45 -46
- data/spec/watirspec/elements/filefields_spec.rb +13 -15
- data/spec/watirspec/elements/font_spec.rb +11 -13
- data/spec/watirspec/elements/form_spec.rb +13 -15
- data/spec/watirspec/elements/forms_spec.rb +13 -15
- data/spec/watirspec/elements/frame_spec.rb +48 -50
- data/spec/watirspec/elements/frames_spec.rb +13 -15
- data/spec/watirspec/elements/hidden_spec.rb +23 -25
- data/spec/watirspec/elements/hiddens_spec.rb +13 -15
- data/spec/watirspec/elements/hn_spec.rb +22 -24
- data/spec/watirspec/elements/hns_spec.rb +13 -13
- data/spec/watirspec/elements/iframe_spec.rb +106 -74
- data/spec/watirspec/elements/iframes_spec.rb +16 -18
- data/spec/watirspec/elements/image_spec.rb +30 -32
- data/spec/watirspec/elements/images_spec.rb +13 -15
- data/spec/watirspec/elements/input_spec.rb +4 -5
- data/spec/watirspec/elements/ins_spec.rb +27 -29
- data/spec/watirspec/elements/inses_spec.rb +13 -15
- data/spec/watirspec/elements/label_spec.rb +17 -19
- data/spec/watirspec/elements/labels_spec.rb +13 -15
- data/spec/watirspec/elements/li_spec.rb +23 -25
- data/spec/watirspec/elements/link_spec.rb +45 -48
- data/spec/watirspec/elements/links_spec.rb +14 -16
- data/spec/watirspec/elements/lis_spec.rb +13 -15
- data/spec/watirspec/elements/list_spec.rb +14 -15
- data/spec/watirspec/elements/map_spec.rb +19 -20
- data/spec/watirspec/elements/maps_spec.rb +13 -15
- data/spec/watirspec/elements/meta_spec.rb +10 -10
- data/spec/watirspec/elements/metas_spec.rb +13 -15
- data/spec/watirspec/elements/ol_spec.rb +20 -21
- data/spec/watirspec/elements/ols_spec.rb +13 -15
- data/spec/watirspec/elements/option_spec.rb +63 -63
- data/spec/watirspec/elements/p_spec.rb +27 -26
- data/spec/watirspec/elements/pre_spec.rb +24 -25
- data/spec/watirspec/elements/pres_spec.rb +13 -15
- data/spec/watirspec/elements/ps_spec.rb +13 -15
- data/spec/watirspec/elements/radio_spec.rb +96 -97
- data/spec/watirspec/elements/radios_spec.rb +13 -15
- data/spec/watirspec/elements/select_list_spec.rb +244 -237
- data/spec/watirspec/elements/select_lists_spec.rb +15 -16
- data/spec/watirspec/elements/span_spec.rb +32 -31
- data/spec/watirspec/elements/spans_spec.rb +13 -15
- data/spec/watirspec/elements/strong_spec.rb +23 -24
- data/spec/watirspec/elements/strongs_spec.rb +13 -15
- data/spec/watirspec/elements/table_nesting_spec.rb +15 -14
- data/spec/watirspec/elements/table_spec.rb +61 -62
- data/spec/watirspec/elements/tables_spec.rb +15 -17
- data/spec/watirspec/elements/tbody_spec.rb +25 -26
- data/spec/watirspec/elements/tbodys_spec.rb +17 -19
- data/spec/watirspec/elements/td_spec.rb +20 -22
- data/spec/watirspec/elements/tds_spec.rb +9 -11
- data/spec/watirspec/elements/text_field_spec.rb +55 -56
- data/spec/watirspec/elements/text_fields_spec.rb +15 -16
- data/spec/watirspec/elements/textarea_spec.rb +2 -2
- data/spec/watirspec/elements/textareas_spec.rb +1 -1
- data/spec/watirspec/elements/tfoot_spec.rb +22 -23
- data/spec/watirspec/elements/tfoots_spec.rb +19 -19
- data/spec/watirspec/elements/thead_spec.rb +21 -23
- data/spec/watirspec/elements/theads_spec.rb +19 -19
- data/spec/watirspec/elements/tr_spec.rb +20 -22
- data/spec/watirspec/elements/trs_spec.rb +17 -19
- data/spec/watirspec/elements/ul_spec.rb +17 -19
- data/spec/watirspec/elements/uls_spec.rb +13 -14
- data/spec/watirspec/html/data_attributes.html +1 -0
- data/spec/watirspec/radio_set_spec.rb +100 -99
- data/spec/watirspec/relaxed_locate_spec.rb +19 -43
- data/spec/watirspec/screenshot_spec.rb +4 -4
- data/spec/watirspec/special_chars_spec.rb +2 -4
- data/spec/watirspec/support/rspec_matchers.rb +85 -22
- data/spec/watirspec/user_editable_spec.rb +84 -85
- data/spec/watirspec/wait_spec.rb +74 -95
- data/spec/watirspec/window_switching_spec.rb +131 -132
- data/spec/watirspec_helper.rb +12 -9
- data/support/travis.sh +4 -0
- data/support/version_differ.rb +12 -13
- data/watir.gemspec +29 -22
- metadata +76 -50
@@ -5,8 +5,8 @@ module Watir
|
|
5
5
|
def validate(element, _selector)
|
6
6
|
tag_name = element.tag_name.downcase
|
7
7
|
return unless %w[input button].include?(tag_name)
|
8
|
-
# TODO - Verify this is desired behavior based on https://bugzilla.mozilla.org/show_bug.cgi?id=1290963
|
9
|
-
return if tag_name ==
|
8
|
+
# TODO: - Verify this is desired behavior based on https://bugzilla.mozilla.org/show_bug.cgi?id=1290963
|
9
|
+
return if tag_name == 'input' && !Watir::Button::VALID_TYPES.include?(element.attribute(:type).downcase)
|
10
10
|
|
11
11
|
element
|
12
12
|
end
|
@@ -3,16 +3,14 @@ module Watir
|
|
3
3
|
class Cell
|
4
4
|
class SelectorBuilder < Element::SelectorBuilder
|
5
5
|
def build_wd_selector(selectors)
|
6
|
-
return if selectors.values.any? { |e| e.
|
6
|
+
return if selectors.values.any? { |e| e.is_a? Regexp }
|
7
7
|
|
8
8
|
expressions = %w[./th ./td]
|
9
9
|
attr_expr = xpath_builder.attribute_expression(nil, selectors)
|
10
10
|
|
11
|
-
unless attr_expr.empty?
|
12
|
-
expressions.map! { |e| "#{e}[#{attr_expr}]" }
|
13
|
-
end
|
11
|
+
expressions.map! { |e| "#{e}[#{attr_expr}]" } unless attr_expr.empty?
|
14
12
|
|
15
|
-
xpath = expressions.join(
|
13
|
+
xpath = expressions.join(' | ')
|
16
14
|
|
17
15
|
p build_wd_selector: xpath if $DEBUG
|
18
16
|
|
@@ -5,24 +5,24 @@ module Watir
|
|
5
5
|
attr_reader :selector_builder
|
6
6
|
attr_reader :element_validator
|
7
7
|
|
8
|
-
W3C_FINDERS = [
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
]
|
8
|
+
W3C_FINDERS = %i[
|
9
|
+
css
|
10
|
+
link
|
11
|
+
link_text
|
12
|
+
partial_link_text
|
13
|
+
tag_name
|
14
|
+
xpath
|
15
|
+
].freeze
|
16
16
|
|
17
17
|
# Regular expressions that can be reliably converted to xpath `contains`
|
18
18
|
# expressions in order to optimize the locator.
|
19
|
-
CONVERTABLE_REGEXP =
|
19
|
+
CONVERTABLE_REGEXP = /
|
20
20
|
\A
|
21
21
|
([^\[\]\\^$.|?*+()]*) # leading literal characters
|
22
22
|
[^|]*? # do not try to convert expressions with alternates
|
23
23
|
([^\[\]\\^$.|?*+()]*) # trailing literal characters
|
24
24
|
\z
|
25
|
-
|
25
|
+
/x
|
26
26
|
|
27
27
|
def initialize(query_scope, selector, selector_builder, element_validator)
|
28
28
|
@query_scope = query_scope # either element or browser
|
@@ -39,6 +39,7 @@ module Watir
|
|
39
39
|
|
40
40
|
def locate_all
|
41
41
|
return [@selector[:element]] if @selector.key?(:element)
|
42
|
+
|
42
43
|
using_selenium(:all) || using_watir(:all)
|
43
44
|
end
|
44
45
|
|
@@ -66,27 +67,18 @@ module Watir
|
|
66
67
|
unless how
|
67
68
|
raise Error, "internal error: unable to build Selenium selector from #{@normalized_selector.inspect}"
|
68
69
|
end
|
70
|
+
|
69
71
|
what = add_regexp_predicates(what) if how == :xpath
|
70
72
|
|
71
73
|
if filter == :all || !@filter_selector.empty?
|
72
|
-
|
73
|
-
begin
|
74
|
-
elements = locate_elements(how, what, @driver_scope) || []
|
75
|
-
filter_elements(elements, filter: filter)
|
76
|
-
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
77
|
-
retries += 1
|
78
|
-
sleep 0.5
|
79
|
-
retry unless retries > 2
|
80
|
-
target = filter == :all ? "element collection" : "element"
|
81
|
-
raise StandardError, "Unable to locate #{target} from #{@selector} due to changing page"
|
82
|
-
end
|
74
|
+
locate_filtered_elements(how, what, filter)
|
83
75
|
else
|
84
76
|
locate_element(how, what, @driver_scope)
|
85
77
|
end
|
86
78
|
end
|
87
79
|
|
88
80
|
def validate(elements, tag_name)
|
89
|
-
elements.compact.all? { |element| element_validator.validate(element,
|
81
|
+
elements.compact.all? { |element| element_validator.validate(element, tag_name: tag_name) }
|
90
82
|
end
|
91
83
|
|
92
84
|
def fetch_value(element, how)
|
@@ -100,21 +92,19 @@ module Watir
|
|
100
92
|
when :tag_name
|
101
93
|
element.tag_name.downcase
|
102
94
|
when :href
|
103
|
-
|
95
|
+
element.attribute('href')&.strip
|
96
|
+
when String, ::Symbol
|
97
|
+
how = how.to_s.tr('_', '-') if how.is_a?(::Symbol)
|
98
|
+
element.attribute(how)
|
104
99
|
else
|
105
|
-
|
100
|
+
raise Error::Exception, "Unable to fetch value for #{how}"
|
106
101
|
end
|
107
102
|
end
|
108
103
|
|
109
104
|
def filter_elements(elements, filter: :first)
|
110
105
|
selector = @filter_selector.dup
|
111
106
|
if filter == :first
|
112
|
-
idx = selector
|
113
|
-
if idx < 0
|
114
|
-
elements.reverse!
|
115
|
-
idx = idx.abs - 1
|
116
|
-
end
|
117
|
-
|
107
|
+
idx = element_index(elements, selector)
|
118
108
|
counter = 0
|
119
109
|
|
120
110
|
# Lazy evaluation to avoid fetching values for elements that will be discarded
|
@@ -122,18 +112,26 @@ module Watir
|
|
122
112
|
counter += 1
|
123
113
|
matches_selector?(el, selector)
|
124
114
|
end
|
125
|
-
|
126
|
-
|
127
|
-
val
|
115
|
+
msg = "Filtered through #{counter} elements to locate #{@selector.inspect}"
|
116
|
+
matches.take(idx + 1).to_a[idx].tap { Watir.logger.debug msg }
|
128
117
|
else
|
129
118
|
Watir.logger.debug "Iterated through #{elements.size} elements to locate all #{@selector.inspect}"
|
130
119
|
elements.select { |el| matches_selector?(el, selector) }
|
131
120
|
end
|
132
121
|
end
|
133
122
|
|
123
|
+
def element_index(elements, selector)
|
124
|
+
idx = selector.delete(:index) || 0
|
125
|
+
return idx unless idx.negative?
|
126
|
+
|
127
|
+
elements.reverse!
|
128
|
+
idx.abs - 1
|
129
|
+
end
|
130
|
+
|
134
131
|
def create_normalized_selector(filter)
|
135
132
|
return @normalized_selector if @normalized_selector
|
136
|
-
|
133
|
+
|
134
|
+
@driver_scope = @query_scope.wd
|
137
135
|
|
138
136
|
@normalized_selector = selector_builder.normalized_selector
|
139
137
|
|
@@ -151,46 +149,56 @@ module Watir
|
|
151
149
|
if @normalized_selector.key?(:index) && filter == :all
|
152
150
|
raise ArgumentError, "can't locate all elements by :index"
|
153
151
|
end
|
152
|
+
|
154
153
|
@normalized_selector
|
155
154
|
end
|
156
155
|
|
157
156
|
def create_filter_selector
|
158
157
|
return @filter_selector if @filter_selector
|
158
|
+
|
159
159
|
@filter_selector = {}
|
160
160
|
|
161
161
|
# Remove selectors that can never be used in XPath builder
|
162
|
-
[
|
162
|
+
%i[visible visible_text].each do |how|
|
163
163
|
next unless @normalized_selector.key?(how)
|
164
|
+
|
164
165
|
@filter_selector[how] = @normalized_selector.delete(how)
|
165
166
|
end
|
166
167
|
|
167
|
-
if tag_validation_required?(@normalized_selector)
|
168
|
-
tag_name = @normalized_selector[:tag_name].is_a?(::Symbol) ? @normalized_selector[:tag_name].to_s : @normalized_selector[:tag_name]
|
169
|
-
@filter_selector[:tag_name] = tag_name
|
170
|
-
end
|
168
|
+
set_tag_validation if tag_validation_required?(@normalized_selector)
|
171
169
|
|
172
170
|
# Regexp locators currently need to be validated even if they are included in the XPath builder
|
173
171
|
# TODO: Identify Regexp that can have an exact equivalent using XPath contains (ie would not require
|
174
172
|
# filtering) vs approximations (ie would still requiring filtering)
|
175
173
|
@normalized_selector.each do |how, what|
|
176
174
|
next unless what.is_a?(Regexp)
|
175
|
+
|
177
176
|
@filter_selector[how] = @normalized_selector.delete(how)
|
178
177
|
end
|
179
178
|
|
180
179
|
if @normalized_selector[:index] && !@normalized_selector[:adjacent]
|
181
180
|
idx = @normalized_selector.delete(:index)
|
182
181
|
|
183
|
-
# Do not add {index: 0} filter if the only filter.
|
184
|
-
|
182
|
+
# Do not add {index: 0} filter if the only filter.
|
183
|
+
# This will allow using #find_element instead of #find_elements.
|
184
|
+
implicit_idx_filter = @filter_selector.empty? && idx.zero?
|
185
185
|
@filter_selector[:index] = idx unless implicit_idx_filter
|
186
186
|
end
|
187
187
|
|
188
188
|
@filter_selector
|
189
189
|
end
|
190
190
|
|
191
|
+
def set_tag_validation
|
192
|
+
@filter_selector[:tag_name] = if @normalized_selector[:tag_name].is_a?(::Symbol)
|
193
|
+
@normalized_selector[:tag_name].to_s
|
194
|
+
else
|
195
|
+
@normalized_selector[:tag_name]
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
191
199
|
def process_label(label_key)
|
192
|
-
regexp = @normalized_selector[label_key].
|
193
|
-
return unless (regexp || label_key == :visible_label)
|
200
|
+
regexp = @normalized_selector[label_key].is_a?(Regexp)
|
201
|
+
return unless (regexp || label_key == :visible_label) && selector_builder.should_use_label_element?
|
194
202
|
|
195
203
|
label = label_from_text(label_key)
|
196
204
|
unless label # label not found, stop looking for element
|
@@ -218,9 +226,10 @@ module Watir
|
|
218
226
|
def matches_selector?(element, selector)
|
219
227
|
matches = selector.all? do |how, what|
|
220
228
|
if how == :tag_name && what.is_a?(String)
|
221
|
-
element_validator.validate(element,
|
229
|
+
element_validator.validate(element, tag_name: what)
|
222
230
|
else
|
223
|
-
|
231
|
+
val = fetch_value(element, how)
|
232
|
+
what == val || val =~ /#{what}/
|
224
233
|
end
|
225
234
|
end
|
226
235
|
|
@@ -230,13 +239,15 @@ module Watir
|
|
230
239
|
end
|
231
240
|
|
232
241
|
def text_regexp_deprecation(element, selector, matches)
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
242
|
+
new_element = Watir::Element.new(@query_scope, element: element)
|
243
|
+
text_content = new_element.execute_js(:getTextContent, element).strip
|
244
|
+
text_content_matches = text_content =~ /#{selector[:text]}/
|
245
|
+
return if matches == !!text_content_matches
|
246
|
+
|
247
|
+
key = @selector.key?(:text) ? 'text' : 'label'
|
248
|
+
selector_text = selector[:text].inspect
|
249
|
+
dep = "Using :#{key} locator with RegExp #{selector_text} to match an element that includes hidden text"
|
250
|
+
Watir.logger.deprecate(dep, ":visible_#{key}", ids: [:text_regexp])
|
240
251
|
end
|
241
252
|
|
242
253
|
def can_convert_regexp_to_contains?
|
@@ -247,20 +258,18 @@ module Watir
|
|
247
258
|
return what unless can_convert_regexp_to_contains?
|
248
259
|
|
249
260
|
@filter_selector.each do |key, value|
|
250
|
-
next if [
|
261
|
+
next if %i[tag_name text visible_text visible index].include?(key)
|
251
262
|
|
252
263
|
predicates = regexp_selector_to_predicates(key, value)
|
253
|
-
unless predicates.empty?
|
254
|
-
what = "(#{what})[#{predicates.join(' and ')}]"
|
255
|
-
end
|
264
|
+
what = "(#{what})[#{predicates.join(' and ')}]" unless predicates.empty?
|
256
265
|
end
|
257
266
|
what
|
258
267
|
end
|
259
268
|
|
260
|
-
def regexp_selector_to_predicates(key,
|
261
|
-
return [] if
|
269
|
+
def regexp_selector_to_predicates(key, regexp)
|
270
|
+
return [] if regexp.casefold?
|
262
271
|
|
263
|
-
match =
|
272
|
+
match = regexp.source.match(CONVERTABLE_REGEXP)
|
264
273
|
return [] unless match
|
265
274
|
|
266
275
|
lhs = selector_builder.xpath_builder.lhs_for(nil, key)
|
@@ -273,10 +282,6 @@ module Watir
|
|
273
282
|
(selector.key?(:css) || selector.key?(:xpath)) && selector.key?(:tag_name)
|
274
283
|
end
|
275
284
|
|
276
|
-
def ensure_scope_context
|
277
|
-
@query_scope.wd
|
278
|
-
end
|
279
|
-
|
280
285
|
def locate_element(how, what, scope = @query_scope.wd)
|
281
286
|
scope.find_element(how, what)
|
282
287
|
end
|
@@ -285,12 +290,28 @@ module Watir
|
|
285
290
|
scope.find_elements(how, what)
|
286
291
|
end
|
287
292
|
|
293
|
+
def locate_filtered_elements(how, what, filter)
|
294
|
+
retries = 0
|
295
|
+
begin
|
296
|
+
elements = locate_elements(how, what, @driver_scope) || []
|
297
|
+
filter_elements(elements, filter: filter)
|
298
|
+
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
299
|
+
retries += 1
|
300
|
+
sleep 0.5
|
301
|
+
retry unless retries > 2
|
302
|
+
target = filter == :all ? 'element collection' : 'element'
|
303
|
+
raise StandardError, "Unable to locate #{target} from #{@selector} due to changing page"
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
288
307
|
def wd_supported?(how, what, tag)
|
289
308
|
return false unless W3C_FINDERS.include? how
|
290
|
-
return false unless what.
|
309
|
+
return false unless what.is_a?(String)
|
310
|
+
|
291
311
|
if %i[partial_link_text link_text link].include?(how)
|
292
312
|
Watir.logger.deprecate(":#{how} locator", ':visible_text', ids: [:visible_text])
|
293
313
|
return true if [:a, :link, nil].include?(tag)
|
314
|
+
|
294
315
|
raise StandardError, "Can not use #{how} locator to find a #{what} element"
|
295
316
|
elsif how == :tag_name
|
296
317
|
return true
|
@@ -30,27 +30,19 @@ module Watir
|
|
30
30
|
def check_type(how, what)
|
31
31
|
case how
|
32
32
|
when :index
|
33
|
-
|
34
|
-
raise TypeError, "expected Integer, got #{what.inspect}:#{what.class}"
|
35
|
-
end
|
33
|
+
raise_unless_int(what)
|
36
34
|
when :visible
|
37
|
-
|
38
|
-
raise TypeError, "expected TrueClass or FalseClass, got #{what.inspect}:#{what.class}"
|
39
|
-
end
|
35
|
+
raise_unless_boolean(what)
|
40
36
|
when :visible_text
|
41
|
-
|
42
|
-
raise TypeError, "expected String or Regexp, got #{what.inspect}:#{what.class}"
|
43
|
-
end
|
37
|
+
raise_unless_str_regex(what)
|
44
38
|
else
|
45
|
-
if what.is_a?(Array) &&
|
46
|
-
raise TypeError,
|
47
|
-
end
|
48
|
-
if what.is_a?(Symbol) && how != :adjacent
|
49
|
-
raise TypeError, "Symbol is not a valid value"
|
50
|
-
end
|
51
|
-
unless VALID_WHATS.any? { |t| what.is_a? t }
|
52
|
-
raise TypeError, "expected one of #{VALID_WHATS.inspect}, got #{what.inspect}:#{what.class}"
|
39
|
+
if what.is_a?(Array) && !%i[class class_name].include?(how)
|
40
|
+
raise TypeError, 'Only :class locator can have a value of an Array'
|
53
41
|
end
|
42
|
+
raise TypeError, 'Symbol is not a valid value' if what.is_a?(Symbol) && how != :adjacent
|
43
|
+
return if VALID_WHATS.any? { |t| what.is_a? t }
|
44
|
+
|
45
|
+
raise TypeError, "expected one of #{VALID_WHATS.inspect}, got #{what.inspect}:#{what.class}"
|
54
46
|
end
|
55
47
|
end
|
56
48
|
|
@@ -61,6 +53,7 @@ module Watir
|
|
61
53
|
def build(selector)
|
62
54
|
inspect = selector.inspect
|
63
55
|
return given_xpath_or_css(selector) if selector.key?(:xpath) || selector.key?(:css)
|
56
|
+
|
64
57
|
built = build_wd_selector(selector)
|
65
58
|
Watir.logger.debug "Converted #{inspect} to #{built}"
|
66
59
|
built
|
@@ -90,47 +83,39 @@ module Watir
|
|
90
83
|
|
91
84
|
def check_custom_attribute(attribute)
|
92
85
|
return if valid_attribute?(attribute) || attribute.to_s =~ WILDCARD_ATTRIBUTE
|
86
|
+
|
93
87
|
@custom_attributes << attribute.to_s
|
94
88
|
end
|
95
89
|
|
96
90
|
def given_xpath_or_css(selector)
|
97
|
-
|
98
|
-
|
99
|
-
|
91
|
+
locator = {}
|
92
|
+
locator[:xpath] = selector.delete(:xpath) if selector.key?(:xpath)
|
93
|
+
locator[:css] = selector.delete(:css) if selector.key?(:css)
|
100
94
|
|
101
|
-
if
|
102
|
-
|
103
|
-
end
|
95
|
+
return if locator.empty?
|
96
|
+
raise ArgumentError, ":xpath and :css cannot be combined (#{selector.inspect})" if locator.size > 1
|
104
97
|
|
105
|
-
|
106
|
-
[:xpath, xpath]
|
107
|
-
elsif css
|
108
|
-
[:css, css]
|
109
|
-
end
|
110
|
-
|
111
|
-
if selector.any? && !can_be_combined_with_xpath_or_css?(selector)
|
112
|
-
raise ArgumentError, "#{how} cannot be combined with other selectors (#{selector.inspect})"
|
113
|
-
end
|
98
|
+
return locator.first unless selector.any? && !can_be_combined_with_xpath_or_css?(selector)
|
114
99
|
|
115
|
-
|
100
|
+
msg = "#{locator.keys.first} cannot be combined with other selectors (#{selector.inspect})"
|
101
|
+
raise ArgumentError, msg
|
116
102
|
end
|
117
103
|
|
118
104
|
def build_wd_selector(selectors)
|
119
105
|
return if selectors.values.any? { |e| e.is_a? Regexp }
|
106
|
+
|
120
107
|
build_xpath(selectors)
|
121
108
|
end
|
122
109
|
|
123
110
|
def valid_attribute?(attribute)
|
124
|
-
@valid_attributes
|
111
|
+
@valid_attributes&.include?(attribute)
|
125
112
|
end
|
126
113
|
|
127
114
|
def can_be_combined_with_xpath_or_css?(selector)
|
128
115
|
keys = selector.keys
|
129
116
|
return true if keys == [:tag_name]
|
130
117
|
|
131
|
-
if selector[:tag_name] ==
|
132
|
-
return keys.sort == [:tag_name, :type]
|
133
|
-
end
|
118
|
+
return keys.sort == %i[tag_name type] if selector[:tag_name] == 'input'
|
134
119
|
|
135
120
|
false
|
136
121
|
end
|
@@ -141,10 +126,27 @@ module Watir
|
|
141
126
|
|
142
127
|
def xpath_builder_class
|
143
128
|
Kernel.const_get("#{self.class.name}::XPath")
|
144
|
-
rescue
|
129
|
+
rescue StandardError
|
145
130
|
XPath
|
146
131
|
end
|
147
132
|
|
133
|
+
def raise_unless_int(what)
|
134
|
+
return if what.is_a?(Integer)
|
135
|
+
|
136
|
+
raise TypeError, "expected Integer, got #{what.inspect}:#{what.class}"
|
137
|
+
end
|
138
|
+
|
139
|
+
def raise_unless_boolean(what)
|
140
|
+
return if what.is_a?(TrueClass) || what.is_a?(FalseClass)
|
141
|
+
|
142
|
+
raise TypeError, "expected TrueClass or FalseClass, got #{what.inspect}:#{what.class}"
|
143
|
+
end
|
144
|
+
|
145
|
+
def raise_unless_str_regex(what)
|
146
|
+
return if what.is_a?(String) || what.is_a?(Regexp)
|
147
|
+
|
148
|
+
raise TypeError, "expected String or Regexp, got #{what.inspect}:#{what.class}"
|
149
|
+
end
|
148
150
|
end
|
149
151
|
end
|
150
152
|
end
|