watir-nokogiri 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +22 -0
- data/README.md +65 -0
- data/lib/watir-nokogiri.rb +69 -0
- data/lib/watir-nokogiri/aliases.rb +6 -0
- data/lib/watir-nokogiri/attribute_helper.rb +145 -0
- data/lib/watir-nokogiri/cell_container.rb +31 -0
- data/lib/watir-nokogiri/container.rb +50 -0
- data/lib/watir-nokogiri/document.rb +171 -0
- data/lib/watir-nokogiri/element_collection.rb +93 -0
- data/lib/watir-nokogiri/elements/button.rb +71 -0
- data/lib/watir-nokogiri/elements/checkbox.rb +61 -0
- data/lib/watir-nokogiri/elements/dlist.rb +12 -0
- data/lib/watir-nokogiri/elements/element.rb +319 -0
- data/lib/watir-nokogiri/elements/file_field.rb +45 -0
- data/lib/watir-nokogiri/elements/font.rb +11 -0
- data/lib/watir-nokogiri/elements/form.rb +17 -0
- data/lib/watir-nokogiri/elements/frame.rb +75 -0
- data/lib/watir-nokogiri/elements/generated.rb +2662 -0
- data/lib/watir-nokogiri/elements/hidden.rb +24 -0
- data/lib/watir-nokogiri/elements/image.rb +59 -0
- data/lib/watir-nokogiri/elements/input.rb +34 -0
- data/lib/watir-nokogiri/elements/link.rb +7 -0
- data/lib/watir-nokogiri/elements/option.rb +83 -0
- data/lib/watir-nokogiri/elements/radio.rb +44 -0
- data/lib/watir-nokogiri/elements/select.rb +126 -0
- data/lib/watir-nokogiri/elements/table.rb +44 -0
- data/lib/watir-nokogiri/elements/table_cell.rb +36 -0
- data/lib/watir-nokogiri/elements/table_row.rb +46 -0
- data/lib/watir-nokogiri/elements/table_section.rb +15 -0
- data/lib/watir-nokogiri/elements/text_area.rb +22 -0
- data/lib/watir-nokogiri/elements/text_field.rb +44 -0
- data/lib/watir-nokogiri/exception.rb +20 -0
- data/lib/watir-nokogiri/locators/button_locator.rb +54 -0
- data/lib/watir-nokogiri/locators/child_cell_locator.rb +24 -0
- data/lib/watir-nokogiri/locators/child_row_locator.rb +29 -0
- data/lib/watir-nokogiri/locators/element_locator.rb +298 -0
- data/lib/watir-nokogiri/locators/text_area_locator.rb +20 -0
- data/lib/watir-nokogiri/locators/text_field_locator.rb +71 -0
- data/lib/watir-nokogiri/row_container.rb +42 -0
- data/lib/watir-nokogiri/user_editable.rb +38 -0
- data/lib/watir-nokogiri/version.rb +3 -0
- data/lib/watir-nokogiri/xpath_support.rb +22 -0
- metadata +102 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
module WatirNokogiri
|
2
|
+
class TableRow < HTMLElement
|
3
|
+
include CellContainer
|
4
|
+
|
5
|
+
# @private
|
6
|
+
attr_writer :locator_class
|
7
|
+
|
8
|
+
#
|
9
|
+
# Get the n'th cell (<th> or <td>) of this row
|
10
|
+
#
|
11
|
+
# @return Watir::TableCell
|
12
|
+
#
|
13
|
+
|
14
|
+
def [](idx)
|
15
|
+
cell(:index, idx)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def locator_class
|
21
|
+
@locator_class || super
|
22
|
+
end
|
23
|
+
end # TableRow
|
24
|
+
|
25
|
+
class TableRowCollection < ElementCollection
|
26
|
+
attr_writer :locator_class
|
27
|
+
|
28
|
+
def elements
|
29
|
+
# we do this craziness since the xpath used will find direct child rows
|
30
|
+
# before any rows inside thead/tbody/tfoot...
|
31
|
+
elements = super
|
32
|
+
|
33
|
+
if locator_class == ChildRowLocator and @parent.kind_of? Table
|
34
|
+
# This sorting will not do anything since nokogiri does not know the rowIndex
|
35
|
+
# BUG: https://github.com/jkotests/watir-nokogiri/issues/1
|
36
|
+
elements = elements.sort_by { |row| row.get_attribute(:rowIndex).to_i }
|
37
|
+
end
|
38
|
+
|
39
|
+
elements
|
40
|
+
end
|
41
|
+
|
42
|
+
def locator_class
|
43
|
+
@locator_class || super
|
44
|
+
end
|
45
|
+
end # TableRowCollection
|
46
|
+
end # Watir
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module WatirNokogiri
|
2
|
+
class TableSection < HTMLElement
|
3
|
+
include RowContainer
|
4
|
+
|
5
|
+
#
|
6
|
+
# Returns table section row with given index.
|
7
|
+
#
|
8
|
+
# @param [Fixnum] idx
|
9
|
+
#
|
10
|
+
|
11
|
+
def [](idx)
|
12
|
+
row(:index => idx)
|
13
|
+
end
|
14
|
+
end # TableSection
|
15
|
+
end # WatirNokogiri
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module WatirNokogiri
|
2
|
+
class TextArea < HTMLElement
|
3
|
+
include UserEditable
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def locator_class
|
8
|
+
TextAreaLocator
|
9
|
+
end
|
10
|
+
|
11
|
+
end # TextArea
|
12
|
+
|
13
|
+
class TextAreaCollection < ElementCollection
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def locator_class
|
18
|
+
TextAreaLocator
|
19
|
+
end
|
20
|
+
|
21
|
+
end # TextAreaCollection
|
22
|
+
end # WatirNokogiri
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module WatirNokogiri
|
3
|
+
class TextField < Input
|
4
|
+
include UserEditable
|
5
|
+
|
6
|
+
attributes WatirNokogiri::TextArea.typed_attributes
|
7
|
+
remove_method :type # we want Input#type here, which was overriden by TextArea's attributes
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def locator_class
|
12
|
+
TextFieldLocator
|
13
|
+
end
|
14
|
+
|
15
|
+
def selector_string
|
16
|
+
selector = @selector.dup
|
17
|
+
selector[:type] = '(any text type)'
|
18
|
+
selector[:tag_name] = "input or textarea"
|
19
|
+
selector.inspect
|
20
|
+
end
|
21
|
+
end # TextField
|
22
|
+
|
23
|
+
module Container
|
24
|
+
def text_field(*args)
|
25
|
+
TextField.new(self, extract_selector(args).merge(:tag_name => "input"))
|
26
|
+
end
|
27
|
+
|
28
|
+
def text_fields(*args)
|
29
|
+
TextFieldCollection.new(self, extract_selector(args).merge(:tag_name => "input"))
|
30
|
+
end
|
31
|
+
end # Container
|
32
|
+
|
33
|
+
class TextFieldCollection < InputCollection
|
34
|
+
private
|
35
|
+
|
36
|
+
def locator_class
|
37
|
+
TextFieldLocator
|
38
|
+
end
|
39
|
+
|
40
|
+
def element_class
|
41
|
+
TextField
|
42
|
+
end
|
43
|
+
end # TextFieldCollection
|
44
|
+
end # WatirNokogiri
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module WatirNokogiri
|
4
|
+
module Exception
|
5
|
+
class Error < StandardError; end
|
6
|
+
|
7
|
+
class UnknownObjectException < Error; end
|
8
|
+
class ObjectDisabledException < Error; end
|
9
|
+
class ObjectReadOnlyException < Error; end
|
10
|
+
class NoValueFoundException < Error; end
|
11
|
+
class MissingWayOfFindingObjectException < Error; end
|
12
|
+
class UnknownCellException < Error; end
|
13
|
+
class NoMatchingWindowFoundException < Error; end
|
14
|
+
class NoStatusBarException < Error; end
|
15
|
+
class NavigationException < Error; end
|
16
|
+
class UnknownFrameException < Error; end
|
17
|
+
class UnknownRowException < Error; end
|
18
|
+
|
19
|
+
end # Exception
|
20
|
+
end # WatirNokogiri
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module WatirNokogiri
|
2
|
+
class ButtonLocator < ElementLocator
|
3
|
+
|
4
|
+
def build_nokogiri_selector(selectors)
|
5
|
+
return if selectors.values.any? { |e| e.kind_of? Regexp }
|
6
|
+
|
7
|
+
selectors.delete(:tag_name) || raise("internal error: no tag_name?!")
|
8
|
+
|
9
|
+
@building = :button
|
10
|
+
button_attr_exp = attribute_expression(selectors)
|
11
|
+
|
12
|
+
@building = :input
|
13
|
+
selectors[:type] = Button::VALID_TYPES
|
14
|
+
input_attr_exp = attribute_expression(selectors)
|
15
|
+
|
16
|
+
xpath = ".//button"
|
17
|
+
xpath << "[#{button_attr_exp}]" unless button_attr_exp.empty?
|
18
|
+
xpath << " | .//input"
|
19
|
+
xpath << "[#{input_attr_exp}]"
|
20
|
+
|
21
|
+
p :build_nokogiri_selector => xpath if $DEBUG
|
22
|
+
|
23
|
+
[:xpath, xpath]
|
24
|
+
end
|
25
|
+
|
26
|
+
def lhs_for(key)
|
27
|
+
if @building == :input && key == :text
|
28
|
+
"@value"
|
29
|
+
else
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def equal_pair(key, value)
|
35
|
+
if @building == :button && key == :value
|
36
|
+
# :value should look for both node text and @value attribute
|
37
|
+
text = XpathSupport.escape(value)
|
38
|
+
"(text()=#{text} or @value=#{text})"
|
39
|
+
else
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def tag_name_matches?(tag_name, _)
|
45
|
+
!!(/^(input|button)$/ === tag_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
def validate_element(element)
|
49
|
+
return if element.node_name.downcase == "input" && !Button::VALID_TYPES.include?(element.get_attribute(:type).downcase)
|
50
|
+
super
|
51
|
+
end
|
52
|
+
|
53
|
+
end # ButtonLocator
|
54
|
+
end # WatirNokogiri
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module WatirNokogiri
|
2
|
+
class ChildCellLocator < ElementLocator
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def build_nokogiri_selector(selectors)
|
7
|
+
return if selectors.values.any? { |e| e.kind_of? Regexp }
|
8
|
+
|
9
|
+
expressions = %w[./th ./td]
|
10
|
+
attr_expr = attribute_expression(selectors)
|
11
|
+
|
12
|
+
unless attr_expr.empty?
|
13
|
+
expressions.map! { |e| "#{e}[#{attr_expr}]" }
|
14
|
+
end
|
15
|
+
|
16
|
+
xpath = expressions.join(" | ")
|
17
|
+
|
18
|
+
p :build_nokogiri_selector => xpath if $DEBUG
|
19
|
+
|
20
|
+
[:xpath, xpath]
|
21
|
+
end
|
22
|
+
|
23
|
+
end # ChildCellLocator
|
24
|
+
end # WatirNokogiri
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module WatirNokogiri
|
2
|
+
class ChildRowLocator < ElementLocator
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def build_nokogiri_selector(selectors)
|
7
|
+
return if selectors.values.any? { |e| e.kind_of? Regexp }
|
8
|
+
selectors.delete(:tag_name) || raise("internal error: no tag_name?!")
|
9
|
+
|
10
|
+
expressions = %w[./tr]
|
11
|
+
unless %w[tbody tfoot thead].include?(@nokogiri.node_name.downcase)
|
12
|
+
expressions += %w[./tbody/tr ./thead/tr ./tfoot/tr]
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_expr = attribute_expression(selectors)
|
16
|
+
|
17
|
+
unless attr_expr.empty?
|
18
|
+
expressions.map! { |e| "#{e}[#{attr_expr}]" }
|
19
|
+
end
|
20
|
+
|
21
|
+
xpath = expressions.join(" | ")
|
22
|
+
|
23
|
+
p :build_nokogiri_selector => xpath if $DEBUG
|
24
|
+
|
25
|
+
[:xpath, xpath]
|
26
|
+
end
|
27
|
+
|
28
|
+
end # ChildRowLocator
|
29
|
+
end # WatirNokogiri
|
@@ -0,0 +1,298 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module WatirNokogiri
|
3
|
+
class ElementLocator
|
4
|
+
include WatirNokogiri::Exception
|
5
|
+
|
6
|
+
def initialize(nokogiri, selector, valid_attributes)
|
7
|
+
@nokogiri = nokogiri
|
8
|
+
@selector = selector.dup
|
9
|
+
@valid_attributes = valid_attributes
|
10
|
+
end
|
11
|
+
|
12
|
+
def locate()
|
13
|
+
idx = @selector.delete(:index)
|
14
|
+
if idx
|
15
|
+
element = locate_all[idx]
|
16
|
+
else
|
17
|
+
element = locate_all.first
|
18
|
+
end
|
19
|
+
|
20
|
+
# This actually only applies when finding by xpath - browser.text_field(:xpath, "//input[@type='radio']")
|
21
|
+
# We don't need to validate the element if we built the xpath ourselves.
|
22
|
+
# It is also used to alter behavior of methods locating more than one type of element
|
23
|
+
# (e.g. text_field locates both input and textarea)
|
24
|
+
validate_element(element) if element
|
25
|
+
end
|
26
|
+
|
27
|
+
def locate_all()
|
28
|
+
selector = normalized_selector
|
29
|
+
|
30
|
+
if selector.has_key? :index
|
31
|
+
raise ArgumentError, "can't locate all elements by :index"
|
32
|
+
end
|
33
|
+
|
34
|
+
how, what = given_css(selector) ||
|
35
|
+
given_xpath(selector) ||
|
36
|
+
build_nokogiri_selector(selector)
|
37
|
+
|
38
|
+
case how
|
39
|
+
when :css
|
40
|
+
@nokogiri.css(what)
|
41
|
+
when :xpath
|
42
|
+
@nokogiri.xpath(what)
|
43
|
+
else
|
44
|
+
find_by_regexp_selector(selector, :select)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def find_by_regexp_selector(selector, method = :find)
|
49
|
+
parent = @nokogiri
|
50
|
+
rx_selector = delete_regexps_from(selector)
|
51
|
+
|
52
|
+
if rx_selector.has_key?(:label) && should_use_label_element?
|
53
|
+
label = label_from_text(rx_selector.delete(:label)) || (return [])
|
54
|
+
if (id = label.get_attribute('for'))
|
55
|
+
selector[:id] = id
|
56
|
+
else
|
57
|
+
parent = label
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
how, what = build_nokogiri_selector(selector)
|
62
|
+
|
63
|
+
unless how
|
64
|
+
raise Error, "internal error: unable to build WebDriver selector from #{selector.inspect}"
|
65
|
+
end
|
66
|
+
|
67
|
+
elements = parent.xpath(what)
|
68
|
+
elements.__send__(method) { |el| matches_selector?(el, rx_selector) }
|
69
|
+
end
|
70
|
+
|
71
|
+
def delete_regexps_from(selector)
|
72
|
+
rx_selector = {}
|
73
|
+
|
74
|
+
selector.dup.each do |how, what|
|
75
|
+
next unless what.kind_of?(Regexp)
|
76
|
+
rx_selector[how] = what
|
77
|
+
selector.delete how
|
78
|
+
end
|
79
|
+
|
80
|
+
rx_selector
|
81
|
+
end
|
82
|
+
|
83
|
+
def assert_valid_as_attribute(attribute)
|
84
|
+
unless valid_attribute? attribute or attribute.to_s =~ /^data_.+$/
|
85
|
+
raise MissingWayOfFindingObjectException, "invalid attribute: #{attribute.inspect}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def valid_attribute?(attribute)
|
90
|
+
@valid_attributes && @valid_attributes.include?(attribute)
|
91
|
+
end
|
92
|
+
|
93
|
+
def should_use_label_element?
|
94
|
+
@selector[:tag_name] != "option"
|
95
|
+
end
|
96
|
+
|
97
|
+
def label_from_text(label_exp)
|
98
|
+
# TODO: this won't work correctly if @nokogiri is a sub-element
|
99
|
+
@nokogiri.search('label').find do |el|
|
100
|
+
matches_selector?(el, :text => label_exp)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def matches_selector?(element, selector)
|
105
|
+
selector.all? do |how, what|
|
106
|
+
what === fetch_value(element, how)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def fetch_value(element, how)
|
111
|
+
case how
|
112
|
+
when :text
|
113
|
+
element.text
|
114
|
+
when :tag_name
|
115
|
+
element.node_name.downcase
|
116
|
+
when :href
|
117
|
+
(href = element.get_attribute('href')) && href.strip
|
118
|
+
else
|
119
|
+
element.get_attribute(how.to_s.gsub("_", "-"))
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def normalized_selector
|
124
|
+
selector = {}
|
125
|
+
|
126
|
+
@selector.each do |how, what|
|
127
|
+
check_type(how, what)
|
128
|
+
|
129
|
+
how, what = normalize_selector(how, what)
|
130
|
+
selector[how] = what
|
131
|
+
end
|
132
|
+
|
133
|
+
selector
|
134
|
+
end
|
135
|
+
|
136
|
+
def normalize_selector(how, what)
|
137
|
+
case how
|
138
|
+
when :tag_name, :text, :xpath, :index, :class, :label, :css
|
139
|
+
# include :class since the valid attribute is 'class_name'
|
140
|
+
# include :for since the valid attribute is 'html_for'
|
141
|
+
[how, what]
|
142
|
+
when :class_name
|
143
|
+
[:class, what]
|
144
|
+
when :caption
|
145
|
+
[:text, what]
|
146
|
+
when :for
|
147
|
+
assert_valid_as_attribute :html_for
|
148
|
+
[how, what]
|
149
|
+
else
|
150
|
+
assert_valid_as_attribute how
|
151
|
+
[how, what]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
VALID_WHATS = [String, Regexp]
|
157
|
+
|
158
|
+
def check_type(how, what)
|
159
|
+
case how
|
160
|
+
when :index
|
161
|
+
unless what.kind_of?(Fixnum)
|
162
|
+
raise TypeError, "expected Fixnum, got #{what.inspect}:#{what.class}"
|
163
|
+
end
|
164
|
+
else
|
165
|
+
unless VALID_WHATS.any? { |t| what.kind_of? t }
|
166
|
+
raise TypeError, "expected one of #{VALID_WHATS.inspect}, got #{what.inspect}:#{what.class}"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def given_xpath(selector)
|
172
|
+
return unless xpath = selector.delete(:xpath)
|
173
|
+
|
174
|
+
unless selector.empty? || can_be_combined_with_xpath?(selector)
|
175
|
+
raise ArgumentError, ":xpath cannot be combined with other selectors (#{selector.inspect})"
|
176
|
+
end
|
177
|
+
|
178
|
+
[:xpath, xpath]
|
179
|
+
end
|
180
|
+
|
181
|
+
def can_be_combined_with_xpath?(selector)
|
182
|
+
# ouch - is this worth it?
|
183
|
+
keys = selector.keys
|
184
|
+
return true if keys == [:tag_name]
|
185
|
+
|
186
|
+
if selector[:tag_name] == "input"
|
187
|
+
return keys == [:tag_name, :type] || keys == [:type, :tag_name]
|
188
|
+
end
|
189
|
+
|
190
|
+
false
|
191
|
+
end
|
192
|
+
|
193
|
+
def given_css(selector)
|
194
|
+
return unless css = selector.delete(:css)
|
195
|
+
|
196
|
+
unless selector.empty? || can_be_combined_with_css?(selector)
|
197
|
+
raise ArgumentError, ":css cannot be combined with other selectors (#{selector.inspect})"
|
198
|
+
end
|
199
|
+
|
200
|
+
[:css, xpath]
|
201
|
+
end
|
202
|
+
|
203
|
+
def can_be_combined_with_css?(selector)
|
204
|
+
# ouch - is this worth it?
|
205
|
+
keys = selector.keys
|
206
|
+
return true if keys == [:tag_name]
|
207
|
+
|
208
|
+
if selector[:tag_name] == "input"
|
209
|
+
return keys == [:tag_name, :type] || keys == [:type, :tag_name]
|
210
|
+
end
|
211
|
+
|
212
|
+
false
|
213
|
+
end
|
214
|
+
|
215
|
+
def build_nokogiri_selector(selectors)
|
216
|
+
unless selectors.values.any? { |e| e.kind_of? Regexp }
|
217
|
+
build_xpath(selectors)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def build_xpath(selectors)
|
222
|
+
xpath = ".//"
|
223
|
+
xpath << (selectors.delete(:tag_name) || '*').to_s
|
224
|
+
|
225
|
+
idx = selectors.delete :index
|
226
|
+
|
227
|
+
# the remaining entries should be attributes
|
228
|
+
unless selectors.empty?
|
229
|
+
xpath << "[" << attribute_expression(selectors) << "]"
|
230
|
+
end
|
231
|
+
|
232
|
+
if idx
|
233
|
+
xpath << "[#{idx + 1}]"
|
234
|
+
end
|
235
|
+
|
236
|
+
p :xpath => xpath, :selectors => selectors if $DEBUG
|
237
|
+
|
238
|
+
[:xpath, xpath]
|
239
|
+
end
|
240
|
+
|
241
|
+
def attribute_expression(selectors)
|
242
|
+
selectors.map do |key, val|
|
243
|
+
if val.kind_of?(Array)
|
244
|
+
"(" + val.map { |v| equal_pair(key, v) }.join(" or ") + ")"
|
245
|
+
else
|
246
|
+
equal_pair(key, val)
|
247
|
+
end
|
248
|
+
end.join(" and ")
|
249
|
+
end
|
250
|
+
|
251
|
+
def equal_pair(key, value)
|
252
|
+
if key == :class
|
253
|
+
klass = XpathSupport.escape " #{value} "
|
254
|
+
"contains(concat(' ', @class, ' '), #{klass})"
|
255
|
+
elsif key == :label && should_use_label_element?
|
256
|
+
# we assume :label means a corresponding label element, not the attribute
|
257
|
+
text = "normalize-space()=#{XpathSupport.escape value}"
|
258
|
+
"(@id=//label[#{text}]/@for or parent::label[#{text}])"
|
259
|
+
else
|
260
|
+
"#{lhs_for(key)}=#{XpathSupport.escape value}"
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def lhs_for(key)
|
265
|
+
case key
|
266
|
+
when :text, 'text'
|
267
|
+
'normalize-space()'
|
268
|
+
when :href
|
269
|
+
# TODO: change this behaviour?
|
270
|
+
'normalize-space(@href)'
|
271
|
+
when :type
|
272
|
+
# type attributes can be upper case - downcase them
|
273
|
+
# https://github.com/watir/watir-webdriver/issues/72
|
274
|
+
XpathSupport.downcase('@type')
|
275
|
+
else
|
276
|
+
"@#{key.to_s.gsub("_", "-")}"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def validate_element(element)
|
281
|
+
tn = @selector[:tag_name]
|
282
|
+
element_tag_name = element.node_name.downcase
|
283
|
+
|
284
|
+
return if tn && !tag_name_matches?(element_tag_name, tn)
|
285
|
+
|
286
|
+
if element_tag_name == 'input'
|
287
|
+
return if @selector[:type] && @selector[:type] != element.get_attribute(:type).downcase
|
288
|
+
end
|
289
|
+
|
290
|
+
element
|
291
|
+
end
|
292
|
+
|
293
|
+
def tag_name_matches?(element_tag_name, tag_name)
|
294
|
+
tag_name === element_tag_name
|
295
|
+
end
|
296
|
+
|
297
|
+
end # ElementLocator
|
298
|
+
end # WatirNokogiri
|