watir 6.16.5 → 6.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +32 -107
- data/.travis.yml +24 -21
- data/CHANGES.md +16 -0
- data/Gemfile +3 -1
- data/Rakefile +3 -3
- data/appveyor.yml +2 -1
- data/lib/watir-webdriver.rb +1 -1
- data/lib/watir.rb +0 -1
- data/lib/watir/adjacent.rb +8 -10
- data/lib/watir/after_hooks.rb +4 -4
- data/lib/watir/browser.rb +5 -1
- data/lib/watir/capabilities.rb +9 -6
- data/lib/watir/cookies.rb +1 -1
- data/lib/watir/elements/element.rb +59 -46
- data/lib/watir/elements/file_field.rb +1 -0
- data/lib/watir/elements/iframe.rb +2 -2
- data/lib/watir/elements/link.rb +0 -9
- data/lib/watir/elements/radio.rb +1 -1
- data/lib/watir/elements/select.rb +2 -2
- data/lib/watir/generator/base/spec_extractor.rb +4 -4
- data/lib/watir/js_execution.rb +1 -1
- data/lib/watir/legacy_wait.rb +1 -1
- data/lib/watir/locators/element/selector_builder.rb +11 -12
- data/lib/watir/locators/element/selector_builder/xpath.rb +40 -13
- data/lib/watir/locators/text_field/selector_builder/xpath.rb +3 -1
- data/lib/watir/logger.rb +5 -2
- data/lib/watir/version.rb +1 -1
- data/lib/watir/window.rb +1 -1
- data/lib/watirspec.rb +1 -1
- data/lib/watirspec/guards.rb +1 -1
- data/lib/watirspec/rake_tasks.rb +2 -0
- data/lib/watirspec/runner.rb +4 -0
- data/spec/unit/container_spec.rb +1 -1
- data/spec/unit/logger_spec.rb +5 -7
- data/spec/unit/selector_builder/button_spec.rb +16 -15
- data/spec/unit/selector_builder/element_spec.rb +58 -9
- data/spec/unit/selector_builder/text_field_spec.rb +14 -14
- data/spec/watirspec/after_hooks_spec.rb +64 -78
- data/spec/watirspec/alert_spec.rb +69 -79
- data/spec/watirspec/browser_spec.rb +48 -46
- data/spec/watirspec/cookies_spec.rb +52 -37
- data/spec/watirspec/drag_and_drop_spec.rb +14 -38
- data/spec/watirspec/elements/button_spec.rb +2 -0
- data/spec/watirspec/elements/buttons_spec.rb +1 -1
- data/spec/watirspec/elements/checkbox_spec.rb +8 -4
- data/spec/watirspec/elements/date_field_spec.rb +18 -9
- data/spec/watirspec/elements/date_time_field_spec.rb +3 -4
- data/spec/watirspec/elements/div_spec.rb +62 -54
- data/spec/watirspec/elements/element_spec.rb +60 -78
- data/spec/watirspec/elements/elements_spec.rb +12 -3
- data/spec/watirspec/elements/filefield_spec.rb +25 -50
- data/spec/watirspec/elements/form_spec.rb +6 -8
- data/spec/watirspec/elements/frame_spec.rb +10 -13
- data/spec/watirspec/elements/iframe_spec.rb +17 -12
- data/spec/watirspec/elements/iframes_spec.rb +2 -2
- data/spec/watirspec/elements/link_spec.rb +18 -9
- data/spec/watirspec/elements/links_spec.rb +11 -3
- data/spec/watirspec/elements/option_spec.rb +15 -17
- data/spec/watirspec/elements/select_list_spec.rb +66 -80
- data/spec/watirspec/elements/text_field_spec.rb +8 -4
- data/spec/watirspec/elements/tr_spec.rb +0 -9
- data/spec/watirspec/html/forms_with_input_elements.html +1 -0
- data/spec/watirspec/html/iframes.html +3 -0
- data/spec/watirspec/html/non_control_elements.html +4 -4
- data/spec/watirspec/html/right_click.html +12 -0
- data/spec/watirspec/html/wait.html +1 -1
- data/spec/watirspec/relaxed_locate_spec.rb +16 -20
- data/spec/watirspec/support/rspec_matchers.rb +7 -6
- data/spec/watirspec/user_editable_spec.rb +1 -1
- data/spec/watirspec/wait_spec.rb +13 -17
- data/spec/watirspec/window_switching_spec.rb +162 -163
- data/spec/watirspec_helper.rb +7 -5
- data/watir.gemspec +4 -5
- metadata +14 -16
- data/lib/watir/elements/area.rb +0 -10
data/lib/watir/cookies.rb
CHANGED
@@ -61,7 +61,7 @@ module Watir
|
|
61
61
|
cookie[:path] = opts[:path] if opts.key?(:path)
|
62
62
|
expires = opts[:expires]
|
63
63
|
if expires
|
64
|
-
cookie[:expires] =
|
64
|
+
cookie[:expires] = expires.is_a?(String) ? ::Time.parse(expires) : expires
|
65
65
|
end
|
66
66
|
cookie[:domain] = opts[:domain] if opts.key?(:domain)
|
67
67
|
|
@@ -18,6 +18,17 @@ module Watir
|
|
18
18
|
attr_accessor :keyword
|
19
19
|
attr_reader :selector
|
20
20
|
|
21
|
+
# https://www.w3.org/TR/html52/single-page.html#casesensitivity
|
22
|
+
CASE_INSENSITIVE_ATTRIBUTES = %i[accept accept_charset align alink axis
|
23
|
+
bgcolor charset checked clear codetype
|
24
|
+
color compact declare defer dir direction
|
25
|
+
disabled enctype face frame hreflang
|
26
|
+
http_equiv lang language link media
|
27
|
+
method multiple nohref noresize noshade
|
28
|
+
nowrap readonly rel rev rules scope
|
29
|
+
scrolling selected shape target text
|
30
|
+
type valign valuetype vlink].freeze
|
31
|
+
|
21
32
|
#
|
22
33
|
# temporarily add :id and :class_name manually since they're no longer specified in the HTML spec.
|
23
34
|
#
|
@@ -54,12 +65,9 @@ module Watir
|
|
54
65
|
|
55
66
|
def exists?
|
56
67
|
if located? && stale?
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
ids: [:stale_exists]
|
61
|
-
# TODO: Change this to `reset!` after removing deprecation
|
62
|
-
return false
|
68
|
+
reset!
|
69
|
+
elsif located?
|
70
|
+
return true
|
63
71
|
end
|
64
72
|
|
65
73
|
assert_exists
|
@@ -196,15 +204,35 @@ module Watir
|
|
196
204
|
end
|
197
205
|
|
198
206
|
#
|
199
|
-
# Right clicks the element.
|
200
|
-
# Note that
|
207
|
+
# Right clicks the element, optionally while pressing the given modifier keys.
|
208
|
+
# Note that support for holding a modifier key is currently experimental,
|
209
|
+
# and may not work at all. Also, the browser support may vary.
|
201
210
|
#
|
202
211
|
# @example
|
203
212
|
# browser.element(name: "new_user_button").right_click
|
204
213
|
#
|
214
|
+
# @example Right click an element with shift key pressed
|
215
|
+
# browser.element(name: "new_user_button").right_click(:shift)
|
216
|
+
#
|
217
|
+
# @example Click an element with several modifier keys pressed
|
218
|
+
# browser.element(name: "new_user_button").right_click(:shift, :alt)
|
219
|
+
#
|
220
|
+
# @param [:shift, :alt, :control, :command, :meta] modifiers to press while right clicking.
|
221
|
+
#
|
222
|
+
|
223
|
+
def right_click(*modifiers)
|
224
|
+
element_call(:wait_for_present) do
|
225
|
+
action = driver.action
|
226
|
+
if modifiers.any?
|
227
|
+
modifiers.each { |mod| action.key_down mod }
|
228
|
+
action.context_click(@element)
|
229
|
+
modifiers.each { |mod| action.key_up mod }
|
230
|
+
action.perform
|
231
|
+
else
|
232
|
+
action.context_click(@element).perform
|
233
|
+
end
|
234
|
+
end
|
205
235
|
|
206
|
-
def right_click
|
207
|
-
element_call(:wait_for_present) { driver.action.context_click(@element).perform }
|
208
236
|
browser.after_hooks.run
|
209
237
|
end
|
210
238
|
|
@@ -247,7 +275,7 @@ module Watir
|
|
247
275
|
# Note that browser support may vary.
|
248
276
|
#
|
249
277
|
# @example
|
250
|
-
# browser.div(id: "draggable").drag_and_drop_by 100,
|
278
|
+
# browser.div(id: "draggable").drag_and_drop_by 100, 25
|
251
279
|
#
|
252
280
|
# @param [Integer] right_by
|
253
281
|
# @param [Integer] down_by
|
@@ -358,6 +386,8 @@ module Watir
|
|
358
386
|
#
|
359
387
|
|
360
388
|
def scroll_into_view
|
389
|
+
Watir.logger.deprecate 'Element#scroll_into_view', 'Element#scroll methods', ids: [:scroll_into_view]
|
390
|
+
|
361
391
|
element_call { @element.location_once_scrolled_into_view }
|
362
392
|
end
|
363
393
|
|
@@ -460,16 +490,7 @@ module Watir
|
|
460
490
|
msg = '#visible? behavior will be changing slightly, consider switching to #present? ' \
|
461
491
|
'(more details: http://watir.com/element-existentialism/)'
|
462
492
|
Watir.logger.warn msg, ids: [:visible_element]
|
463
|
-
|
464
|
-
if displayed.nil? && display_check
|
465
|
-
Watir.logger.deprecate 'Checking `#visible? == false` to determine a stale element',
|
466
|
-
'`#stale? == true`',
|
467
|
-
reference: 'http://watir.com/staleness-changes',
|
468
|
-
ids: [:stale_visible]
|
469
|
-
end
|
470
|
-
raise unknown_exception if displayed.nil?
|
471
|
-
|
472
|
-
displayed
|
493
|
+
display_check
|
473
494
|
end
|
474
495
|
|
475
496
|
#
|
@@ -492,14 +513,7 @@ module Watir
|
|
492
513
|
#
|
493
514
|
|
494
515
|
def present?
|
495
|
-
|
496
|
-
if displayed.nil? && display_check
|
497
|
-
Watir.logger.deprecate 'Checking `#present? == false` to determine a stale element',
|
498
|
-
'`#stale? == true`',
|
499
|
-
reference: 'http://watir.com/staleness-changes',
|
500
|
-
ids: [:stale_present]
|
501
|
-
end
|
502
|
-
displayed
|
516
|
+
display_check
|
503
517
|
rescue UnknownObjectException, UnknownFrameException
|
504
518
|
false
|
505
519
|
end
|
@@ -547,7 +561,7 @@ module Watir
|
|
547
561
|
#
|
548
562
|
|
549
563
|
def to_subtype
|
550
|
-
tag = tag_name
|
564
|
+
tag = tag_name
|
551
565
|
klass = if tag == 'input'
|
552
566
|
case attribute_value(:type)
|
553
567
|
when 'checkbox'
|
@@ -595,7 +609,7 @@ module Watir
|
|
595
609
|
def stale_in_context?
|
596
610
|
@element.css_value('staleness_check') # any wire call will check for staleness
|
597
611
|
false
|
598
|
-
rescue Selenium::WebDriver::Error::
|
612
|
+
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
599
613
|
true
|
600
614
|
end
|
601
615
|
|
@@ -720,7 +734,9 @@ module Watir
|
|
720
734
|
end
|
721
735
|
|
722
736
|
def ensure_context
|
723
|
-
|
737
|
+
if @query_scope.is_a?(Browser) || !@query_scope.located? || @query_scope.located? && @query_scope.stale?
|
738
|
+
@query_scope.locate
|
739
|
+
end
|
724
740
|
@query_scope.switch_to! if @query_scope.is_a?(IFrame)
|
725
741
|
end
|
726
742
|
|
@@ -770,26 +786,25 @@ module Watir
|
|
770
786
|
@element.displayed?
|
771
787
|
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
772
788
|
reset!
|
773
|
-
|
789
|
+
retry
|
774
790
|
end
|
775
791
|
|
776
792
|
# TODO: - this will get addressed with Watir::Executor implementation
|
777
793
|
# rubocop:disable Metrics/AbcSize
|
778
794
|
# rubocop:disable Metrics/MethodLength
|
779
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
780
795
|
# rubocop:disable Metrics/CyclomaticComplexity:
|
781
796
|
def element_call(precondition = nil, &block)
|
782
797
|
caller = caller_locations(1, 1)[0].label
|
783
|
-
already_locked =
|
784
|
-
|
798
|
+
already_locked = browser.timer.locked?
|
799
|
+
browser.timer = Wait::Timer.new(timeout: Watir.default_timeout) unless already_locked
|
785
800
|
|
786
801
|
begin
|
787
802
|
check_condition(precondition, caller)
|
788
803
|
Watir.logger.debug "-> `Executing #{inspect}##{caller}`"
|
789
804
|
yield
|
790
|
-
rescue unknown_exception =>
|
805
|
+
rescue unknown_exception => e
|
791
806
|
element_call(:wait_for_exists, &block) if precondition.nil?
|
792
|
-
msg =
|
807
|
+
msg = e.message
|
793
808
|
msg += '; Maybe look in an iframe?' if @query_scope.iframe.exists?
|
794
809
|
custom_attributes = @locator.nil? ? [] : selector_builder.custom_attributes
|
795
810
|
unless custom_attributes.empty?
|
@@ -799,24 +814,22 @@ module Watir
|
|
799
814
|
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
800
815
|
reset!
|
801
816
|
retry
|
802
|
-
|
803
|
-
|
817
|
+
# TODO: - InvalidElementStateError is deprecated, so no longer calling `raise_disabled`
|
818
|
+
# need a better way to handle this
|
819
|
+
rescue Selenium::WebDriver::Error::ElementNotInteractableError
|
820
|
+
raise_present unless browser.timer.remaining_time.positive?
|
804
821
|
raise_present unless %i[wait_for_present wait_for_enabled wait_for_writable].include?(precondition)
|
805
822
|
retry
|
806
|
-
rescue Selenium::WebDriver::Error::InvalidElementStateError
|
807
|
-
raise_disabled unless Wait.timer.remaining_time.positive?
|
808
|
-
raise_disabled unless %i[wait_for_present wait_for_enabled wait_for_writable].include?(precondition)
|
809
|
-
retry
|
810
823
|
rescue Selenium::WebDriver::Error::NoSuchWindowError
|
811
824
|
raise NoMatchingWindowFoundException, 'browser window was closed'
|
812
825
|
ensure
|
813
826
|
Watir.logger.debug "<- `Completed #{inspect}##{caller}`"
|
814
|
-
|
827
|
+
browser.timer.reset! unless already_locked
|
815
828
|
end
|
816
829
|
end
|
817
830
|
# rubocop:enable Metrics/AbcSize
|
818
831
|
# rubocop:enable Metrics/MethodLength
|
819
|
-
|
832
|
+
|
820
833
|
# rubocop:enable Metrics/CyclomaticComplexity:
|
821
834
|
|
822
835
|
def check_condition(condition, caller)
|
@@ -134,8 +134,8 @@ module Watir
|
|
134
134
|
@element
|
135
135
|
end
|
136
136
|
|
137
|
-
def respond_to_missing?(meth, _include_private
|
138
|
-
@driver.respond_to?(meth) || @element.respond_to?(meth) || super
|
137
|
+
def respond_to_missing?(meth, _include_private)
|
138
|
+
@driver.respond_to?(meth) || @element.respond_to?(meth) || super(meth, false)
|
139
139
|
end
|
140
140
|
|
141
141
|
def method_missing(meth, *args, &blk)
|
data/lib/watir/elements/link.rb
CHANGED
@@ -3,13 +3,4 @@ module Watir
|
|
3
3
|
alias link a
|
4
4
|
alias links as
|
5
5
|
end # Container
|
6
|
-
|
7
|
-
class Anchor < HTMLElement
|
8
|
-
#
|
9
|
-
# @todo temporarily add href attribute
|
10
|
-
#
|
11
|
-
# @see https://www.w3.org/Bugs/Public/show_bug.cgi?id=23192
|
12
|
-
#
|
13
|
-
attribute String, :href, :href
|
14
|
-
end # Anchor
|
15
6
|
end # Watir
|
data/lib/watir/elements/radio.rb
CHANGED
@@ -170,8 +170,8 @@ module Watir
|
|
170
170
|
str_or_rx.inspect.sub('\\A', '^')
|
171
171
|
.sub('\\Z', '$')
|
172
172
|
.sub('\\z', '$')
|
173
|
-
.sub(%r{
|
174
|
-
.sub(%r{
|
173
|
+
.sub(%r{^/}, '')
|
174
|
+
.sub(%r{/[a-z]*$}, '')
|
175
175
|
.gsub(/\(\?#.+\)/, '')
|
176
176
|
.gsub(/\(\?-\w+:/, '(')
|
177
177
|
else
|
@@ -109,8 +109,8 @@ module Watir
|
|
109
109
|
begin
|
110
110
|
intf = fetch_interface(implementor_name).first
|
111
111
|
intf.implements << fetch_interface(implementee_name).first
|
112
|
-
rescue InterfaceNotFound =>
|
113
|
-
puts
|
112
|
+
rescue InterfaceNotFound => e
|
113
|
+
puts e.message
|
114
114
|
end
|
115
115
|
end
|
116
116
|
end
|
@@ -123,8 +123,8 @@ module Watir
|
|
123
123
|
begin
|
124
124
|
intf = fetch_interface(includer_name).first
|
125
125
|
intf.includes << fetch_interface(includee_name).first
|
126
|
-
rescue InterfaceNotFound =>
|
127
|
-
puts
|
126
|
+
rescue InterfaceNotFound => e
|
127
|
+
puts e.message
|
128
128
|
end
|
129
129
|
end
|
130
130
|
end
|
data/lib/watir/js_execution.rb
CHANGED
@@ -54,7 +54,7 @@ module Watir
|
|
54
54
|
long: {flashes: 5, delay: 0.5},
|
55
55
|
rainbow: {flashes: 5, color: %w[red orange yellow green blue indigo violet]}
|
56
56
|
}
|
57
|
-
return flash(presets[preset]) unless presets[preset].nil?
|
57
|
+
return flash(**presets[preset]) unless presets[preset].nil?
|
58
58
|
|
59
59
|
background_color = original_color = style('background-color')
|
60
60
|
background_color = 'white' if background_color.empty?
|
data/lib/watir/legacy_wait.rb
CHANGED
@@ -6,11 +6,10 @@ module Watir
|
|
6
6
|
attr_reader :custom_attributes, :built
|
7
7
|
|
8
8
|
WILDCARD_ATTRIBUTE = /^(aria|data)_(.+)$/.freeze
|
9
|
-
INTEGER_CLASS = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4') ? Fixnum : Integer
|
10
9
|
VALID_WHATS = Hash.new([String, Regexp, TrueClass, FalseClass]).merge(adjacent: [::Symbol],
|
11
10
|
xpath: [String],
|
12
11
|
css: [String],
|
13
|
-
index: [
|
12
|
+
index: [Integer],
|
14
13
|
visible: [TrueClass, FalseClass],
|
15
14
|
tag_name: [String, Regexp, ::Symbol],
|
16
15
|
visible_text: [String, Regexp],
|
@@ -53,11 +52,7 @@ module Watir
|
|
53
52
|
if @selector.key?(:class) || @selector.key?(:class_name)
|
54
53
|
classes = ([@selector[:class]].flatten + [@selector.delete(:class_name)].flatten).compact
|
55
54
|
|
56
|
-
classes
|
57
|
-
next unless class_name.is_a?(String) && class_name.strip.include?(' ')
|
58
|
-
|
59
|
-
deprecate_class_array(class_name)
|
60
|
-
end
|
55
|
+
deprecate_class_array(classes)
|
61
56
|
|
62
57
|
@selector[:class] = classes
|
63
58
|
end
|
@@ -83,11 +78,15 @@ module Watir
|
|
83
78
|
scope_invalid_locators.empty?
|
84
79
|
end
|
85
80
|
|
86
|
-
def deprecate_class_array(
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
81
|
+
def deprecate_class_array(class_array)
|
82
|
+
class_array.each do |class_name|
|
83
|
+
next unless class_name.is_a?(String) && class_name.strip.include?(' ')
|
84
|
+
|
85
|
+
dep = "Using the :class locator to locate multiple classes with a String value (i.e. \"#{class_name}\")"
|
86
|
+
Watir.logger.deprecate dep,
|
87
|
+
"Array (e.g. #{class_name.split})",
|
88
|
+
ids: [:class_array]
|
89
|
+
end
|
91
90
|
end
|
92
91
|
|
93
92
|
def check_type(how, what)
|
@@ -12,6 +12,7 @@ module Watir
|
|
12
12
|
|
13
13
|
def build(selector)
|
14
14
|
@selector = selector
|
15
|
+
@valid_attributes = build_valid_attributes
|
15
16
|
|
16
17
|
@built = (@selector.keys & CAN_NOT_BUILD).each_with_object({}) do |key, hash|
|
17
18
|
hash[key] = @selector.delete(key)
|
@@ -45,9 +46,10 @@ module Watir
|
|
45
46
|
end
|
46
47
|
|
47
48
|
def predicate_expression(key, val)
|
48
|
-
|
49
|
+
case val
|
50
|
+
when true
|
49
51
|
attribute_presence(key)
|
50
|
-
|
52
|
+
when false
|
51
53
|
attribute_absence(key)
|
52
54
|
else
|
53
55
|
equal_pair(key, val)
|
@@ -55,11 +57,9 @@ module Watir
|
|
55
57
|
end
|
56
58
|
|
57
59
|
def predicate_conversion(key, regexp)
|
58
|
-
|
59
|
-
# https://github.com/watir/watir/issues/72
|
60
|
-
downcase = key == :type || regexp.casefold?
|
60
|
+
downcase = case_insensitive_attribute?(key) || regexp.casefold?
|
61
61
|
|
62
|
-
lhs = lhs_for(key, downcase)
|
62
|
+
lhs = lhs_for(key, downcase: downcase)
|
63
63
|
|
64
64
|
results = RegexpDisassembler.new(regexp).substrings
|
65
65
|
|
@@ -72,8 +72,10 @@ module Watir
|
|
72
72
|
|
73
73
|
add_to_matching(key, regexp, results)
|
74
74
|
|
75
|
-
results.map { |
|
76
|
-
"
|
75
|
+
results.map { |rhs|
|
76
|
+
rhs = "'#{rhs}'"
|
77
|
+
rhs = XpathSupport.downcase(rhs) if downcase
|
78
|
+
"contains(#{lhs}, #{rhs})"
|
77
79
|
}.flatten.compact.join(' and ')
|
78
80
|
end
|
79
81
|
|
@@ -200,7 +202,7 @@ module Watir
|
|
200
202
|
regexp.casefold? ? !results.first.casecmp(regexp.source).zero? : results.first != regexp.source
|
201
203
|
end
|
202
204
|
|
203
|
-
def lhs_for(key, downcase
|
205
|
+
def lhs_for(key, downcase: false)
|
204
206
|
case key
|
205
207
|
when String
|
206
208
|
"@#{key}"
|
@@ -211,7 +213,7 @@ module Watir
|
|
211
213
|
when :text
|
212
214
|
'normalize-space()'
|
213
215
|
when :contains_text
|
214
|
-
'
|
216
|
+
'normalize-space()'
|
215
217
|
when ::Symbol
|
216
218
|
lhs = "@#{key.to_s.tr('_', '-')}"
|
217
219
|
downcase ? XpathSupport.downcase(lhs) : lhs
|
@@ -221,11 +223,11 @@ module Watir
|
|
221
223
|
end
|
222
224
|
|
223
225
|
def attribute_presence(attribute)
|
224
|
-
lhs_for(attribute
|
226
|
+
lhs_for(attribute)
|
225
227
|
end
|
226
228
|
|
227
229
|
def attribute_absence(attribute)
|
228
|
-
lhs = lhs_for(attribute
|
230
|
+
lhs = lhs_for(attribute)
|
229
231
|
"not(#{lhs})"
|
230
232
|
end
|
231
233
|
|
@@ -236,9 +238,34 @@ module Watir
|
|
236
238
|
|
237
239
|
negate_xpath ? "not(#{expression})" : expression
|
238
240
|
else
|
239
|
-
|
241
|
+
downcase = case_insensitive_attribute?(key)
|
242
|
+
|
243
|
+
lhs = lhs_for(key, downcase: downcase)
|
244
|
+
rhs = XpathSupport.escape(value)
|
245
|
+
rhs = XpathSupport.downcase(rhs) if downcase
|
246
|
+
|
247
|
+
"#{lhs}=#{rhs}"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def build_valid_attributes
|
252
|
+
tag_name = @selector[:tag_name]
|
253
|
+
if tag_name.is_a?(String) && Watir.tag_to_class[tag_name.to_sym]
|
254
|
+
Watir.tag_to_class[tag_name.to_sym].attribute_list
|
255
|
+
else
|
256
|
+
Watir::HTMLElement.attribute_list
|
240
257
|
end
|
241
258
|
end
|
259
|
+
|
260
|
+
def case_insensitive_attribute?(attribute)
|
261
|
+
# type attributes can be upper case - downcase them
|
262
|
+
# https://github.com/watir/watir/issues/72
|
263
|
+
return true if attribute == :type
|
264
|
+
return true if Watir::Element::CASE_INSENSITIVE_ATTRIBUTES.include?(attribute) &&
|
265
|
+
@valid_attributes.include?(attribute)
|
266
|
+
|
267
|
+
false
|
268
|
+
end
|
242
269
|
end
|
243
270
|
end
|
244
271
|
end
|