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,93 @@
|
|
1
|
+
module WatirNokogiri
|
2
|
+
|
3
|
+
#
|
4
|
+
# Base class for element collections.
|
5
|
+
#
|
6
|
+
|
7
|
+
class ElementCollection
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
def initialize(parent, selector)
|
11
|
+
@parent = parent
|
12
|
+
@selector = selector
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
# Yields each element in collection.
|
17
|
+
#
|
18
|
+
# @yieldparam [WatirNokogiri::Element] element Iterate through the elements in this collection.
|
19
|
+
#
|
20
|
+
|
21
|
+
def each(&blk)
|
22
|
+
to_a.each(&blk)
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Returns number of elements in collection.
|
27
|
+
#
|
28
|
+
# @return [Fixnum]
|
29
|
+
#
|
30
|
+
|
31
|
+
def length
|
32
|
+
elements.length
|
33
|
+
end
|
34
|
+
alias_method :size, :length
|
35
|
+
|
36
|
+
#
|
37
|
+
# Get the element at the given index.
|
38
|
+
# Note that this is 0-indexed.
|
39
|
+
#
|
40
|
+
# @param [Fixnum] idx Index of wanted element, 0-indexed
|
41
|
+
# @return [WatirNokogiri::Element] Returns an instance of a WatirNokogiri::Element subclass
|
42
|
+
#
|
43
|
+
|
44
|
+
def [](idx)
|
45
|
+
to_a[idx] || element_class.new(@parent, :index => idx)
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# First element of this collection
|
50
|
+
#
|
51
|
+
# @return [WatirNokogiri::Element] Returns an instance of a WatirNokogiri::Element subclass
|
52
|
+
#
|
53
|
+
|
54
|
+
def first
|
55
|
+
self[0]
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Last element of the collection
|
60
|
+
#
|
61
|
+
# @return [WatirNokogiri::Element] Returns an instance of a WatirNokogiri::Element subclass
|
62
|
+
#
|
63
|
+
|
64
|
+
def last
|
65
|
+
self[-1]
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# This collection as an Array.
|
70
|
+
#
|
71
|
+
# @return [Array<WatirNokogiri::Element>]
|
72
|
+
#
|
73
|
+
|
74
|
+
def to_a()
|
75
|
+
@to_a ||= elements.map{ |e| element_class.new(@parent, :element => e) }
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def elements()
|
81
|
+
@elements ||= locator_class.new(@parent.nokogiri, @selector, element_class.attribute_list).locate_all
|
82
|
+
end
|
83
|
+
|
84
|
+
def element_class()
|
85
|
+
Element
|
86
|
+
end
|
87
|
+
|
88
|
+
def locator_class()
|
89
|
+
ElementLocator
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module WatirNokogiri
|
3
|
+
|
4
|
+
#
|
5
|
+
# Class representing button elements.
|
6
|
+
#
|
7
|
+
# This class covers both <button> and <input type="submit|reset|image|button" /> elements.
|
8
|
+
#
|
9
|
+
|
10
|
+
class Button < HTMLElement
|
11
|
+
|
12
|
+
# add the attributes from <input>
|
13
|
+
attributes WatirNokogiri::Input.typed_attributes
|
14
|
+
|
15
|
+
VALID_TYPES = %w[button reset submit image]
|
16
|
+
|
17
|
+
#
|
18
|
+
# Returns the text of the button.
|
19
|
+
#
|
20
|
+
# For input elements, returns the "value" attribute.
|
21
|
+
# For button elements, returns the inner text.
|
22
|
+
#
|
23
|
+
# @return [String]
|
24
|
+
#
|
25
|
+
|
26
|
+
def text
|
27
|
+
assert_exists
|
28
|
+
|
29
|
+
tn = @element.node_name.downcase
|
30
|
+
|
31
|
+
case tn
|
32
|
+
when 'input'
|
33
|
+
@element.get_attribute(:value)
|
34
|
+
when 'button'
|
35
|
+
@element.text
|
36
|
+
else
|
37
|
+
raise Exception::Error, "unknown tag name for button: #{tn}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Returns true if this element is enabled.
|
43
|
+
#
|
44
|
+
# @return [Boolean]
|
45
|
+
#
|
46
|
+
|
47
|
+
def enabled?
|
48
|
+
!disabled?
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def locate
|
54
|
+
@parent.assert_exists
|
55
|
+
ButtonLocator.new(@parent.nokogiri, @selector, self.class.attribute_list).locate
|
56
|
+
end
|
57
|
+
|
58
|
+
end # Button
|
59
|
+
|
60
|
+
class ButtonCollection < ElementCollection
|
61
|
+
private
|
62
|
+
|
63
|
+
def locator_class
|
64
|
+
ButtonLocator
|
65
|
+
end
|
66
|
+
|
67
|
+
def element_class
|
68
|
+
Button
|
69
|
+
end
|
70
|
+
end # ButtonsCollection
|
71
|
+
end # Watir
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module WatirNokogiri
|
4
|
+
class CheckBox < Input
|
5
|
+
|
6
|
+
#
|
7
|
+
# Sets checkbox to the given value.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# checkbox.set? #=> false
|
11
|
+
# checkbox.set
|
12
|
+
# checkbox.set? #=> true
|
13
|
+
# checkbox.set(false)
|
14
|
+
# checkbox.set? #=> false
|
15
|
+
#
|
16
|
+
# @param [Boolean] bool
|
17
|
+
#
|
18
|
+
|
19
|
+
def set(bool = true)
|
20
|
+
assert_exists
|
21
|
+
raise NotImplementedError, "not currently supported by WatirNokogiri"
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Returns true if the element is checked
|
26
|
+
# @return [Boolean]
|
27
|
+
#
|
28
|
+
|
29
|
+
def set?
|
30
|
+
assert_exists
|
31
|
+
!@element.get_attribute('checked').nil?
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Unsets checkbox.
|
36
|
+
#
|
37
|
+
# Same as +set(false)+
|
38
|
+
#
|
39
|
+
|
40
|
+
def clear
|
41
|
+
set false
|
42
|
+
end
|
43
|
+
|
44
|
+
end # CheckBox
|
45
|
+
|
46
|
+
module Container
|
47
|
+
def checkbox(*args)
|
48
|
+
CheckBox.new(self, extract_selector(args).merge(:tag_name => "input", :type => "checkbox"))
|
49
|
+
end
|
50
|
+
|
51
|
+
def checkboxes(*args)
|
52
|
+
CheckBoxCollection.new(self, extract_selector(args).merge(:tag_name => "input", :type => "checkbox"))
|
53
|
+
end
|
54
|
+
end # Container
|
55
|
+
|
56
|
+
class CheckBoxCollection < InputCollection
|
57
|
+
def element_class
|
58
|
+
CheckBox
|
59
|
+
end
|
60
|
+
end # CheckBoxCollection
|
61
|
+
end # Watir
|
@@ -0,0 +1,319 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module WatirNokogiri
|
4
|
+
|
5
|
+
#
|
6
|
+
# Base class for HTML elements.
|
7
|
+
#
|
8
|
+
|
9
|
+
class Element
|
10
|
+
extend AttributeHelper
|
11
|
+
|
12
|
+
include Exception
|
13
|
+
include Container
|
14
|
+
|
15
|
+
attributes :string => [:id, :class_name]
|
16
|
+
|
17
|
+
def initialize(parent, selector)
|
18
|
+
@parent = parent
|
19
|
+
@selector = selector
|
20
|
+
@element = nil
|
21
|
+
|
22
|
+
unless @selector.kind_of? Hash
|
23
|
+
raise ArgumentError, "invalid argument: #{selector.inspect}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Returns true if two elements are equal.
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# html.a(:id => "foo") == html.a(:id => "foo")
|
32
|
+
# #=> true
|
33
|
+
#
|
34
|
+
|
35
|
+
def ==(other)
|
36
|
+
return false unless other.kind_of? self.class
|
37
|
+
|
38
|
+
assert_exists
|
39
|
+
@element == other.nokogiri
|
40
|
+
end
|
41
|
+
alias_method :eql?, :==
|
42
|
+
|
43
|
+
#
|
44
|
+
# Returns given attribute value of element.
|
45
|
+
#
|
46
|
+
# @example
|
47
|
+
# html.a(:id => "foo").attribute_value "href"
|
48
|
+
# #=> "http://watir.com"
|
49
|
+
#
|
50
|
+
# @param [String] attribute_name
|
51
|
+
# @return [String]
|
52
|
+
#
|
53
|
+
|
54
|
+
def attribute_value(attribute_name)
|
55
|
+
assert_exists
|
56
|
+
@element.get_attribute(attribute_name) || ''
|
57
|
+
end
|
58
|
+
|
59
|
+
def click(*modifiers)
|
60
|
+
assert_exists
|
61
|
+
raise "Not implemented"
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Returns the css path for the element
|
66
|
+
#
|
67
|
+
|
68
|
+
def css_path()
|
69
|
+
assert_exists
|
70
|
+
@element.css_path
|
71
|
+
end
|
72
|
+
|
73
|
+
#
|
74
|
+
# @api private
|
75
|
+
#
|
76
|
+
|
77
|
+
def document
|
78
|
+
@parent.document
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# @api private
|
83
|
+
#
|
84
|
+
|
85
|
+
def driver
|
86
|
+
@parent.driver
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Returns true if element exists.
|
91
|
+
#
|
92
|
+
# @return [Boolean]
|
93
|
+
#
|
94
|
+
|
95
|
+
def exists?()
|
96
|
+
begin
|
97
|
+
assert_exists
|
98
|
+
return true
|
99
|
+
rescue UnknownObjectException, UnknownFrameException
|
100
|
+
return false
|
101
|
+
end
|
102
|
+
end
|
103
|
+
alias_method :exist?, :exists?
|
104
|
+
|
105
|
+
#
|
106
|
+
# Returns outer (inner + element itself) HTML code of element.
|
107
|
+
#
|
108
|
+
# @example
|
109
|
+
# html.div(:id => "foo").html
|
110
|
+
# #=> "<div id=\"foo\"><a>Click</a></div>"
|
111
|
+
#
|
112
|
+
# @return [String]
|
113
|
+
#
|
114
|
+
|
115
|
+
def html
|
116
|
+
assert_exists
|
117
|
+
@element.to_html
|
118
|
+
end
|
119
|
+
|
120
|
+
def id()
|
121
|
+
assert_exists
|
122
|
+
attribute_value('id')
|
123
|
+
end
|
124
|
+
|
125
|
+
def inspect()
|
126
|
+
if @selector.has_key?(:element)
|
127
|
+
'#<%s:0x%x located=%s selector=%s>' % [self.class, hash*2, !!@element, '{:element=>(nokogiri element)}']
|
128
|
+
else
|
129
|
+
'#<%s:0x%x located=%s selector=%s>' % [self.class, hash*2, !!@element, @selector.inspect]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# @api private
|
135
|
+
#
|
136
|
+
|
137
|
+
def nokogiri()
|
138
|
+
assert_exists
|
139
|
+
@element
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
# Returns given style property of this element.
|
144
|
+
#
|
145
|
+
# @example
|
146
|
+
# html.a(:id => "foo").style
|
147
|
+
# #=> "display: block"
|
148
|
+
# html.a(:id => "foo").style "display"
|
149
|
+
# #=> "block"
|
150
|
+
#
|
151
|
+
# @param [String] property
|
152
|
+
# @return [String]
|
153
|
+
#
|
154
|
+
|
155
|
+
def style(property = nil)
|
156
|
+
assert_exists
|
157
|
+
styles = attribute_value('style').to_s.strip
|
158
|
+
if property
|
159
|
+
properties = Hash[styles.downcase.split(";").map { |p| p.split(":").map(&:strip) }]
|
160
|
+
properties[property]
|
161
|
+
else
|
162
|
+
styles
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
#
|
167
|
+
# Returns parent element of current element.
|
168
|
+
#
|
169
|
+
|
170
|
+
def parent
|
171
|
+
assert_exists
|
172
|
+
|
173
|
+
e = @element.parent
|
174
|
+
|
175
|
+
if e.kind_of?(Nokogiri::XML::Element)
|
176
|
+
WatirNokogiri.element_class_for(e.node_name.downcase).new(@parent, :element => e)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
#
|
181
|
+
# Returns true if the element exists and is visible on the page.
|
182
|
+
#
|
183
|
+
# @return [Boolean]
|
184
|
+
#
|
185
|
+
|
186
|
+
def present?
|
187
|
+
assert_exists
|
188
|
+
raise "Not implemented"
|
189
|
+
end
|
190
|
+
|
191
|
+
#
|
192
|
+
# Returns tag name of the element.
|
193
|
+
#
|
194
|
+
# @return [String]
|
195
|
+
#
|
196
|
+
|
197
|
+
def tag_name
|
198
|
+
assert_exists
|
199
|
+
@element.node_name.downcase
|
200
|
+
end
|
201
|
+
|
202
|
+
#
|
203
|
+
# Returns the text of the element.
|
204
|
+
#
|
205
|
+
# @return [String]
|
206
|
+
#
|
207
|
+
|
208
|
+
def text()
|
209
|
+
assert_exists
|
210
|
+
@element.text.strip.gsub(/\s+/, ' ')
|
211
|
+
end
|
212
|
+
|
213
|
+
#
|
214
|
+
# Cast this Element instance to a more specific subtype.
|
215
|
+
#
|
216
|
+
# @example
|
217
|
+
# browser.element(:xpath => "//input[@type='submit']").to_subtype
|
218
|
+
# #=> #<WatirNokogiri::Button>
|
219
|
+
#
|
220
|
+
|
221
|
+
def to_subtype
|
222
|
+
elem = nokogiri()
|
223
|
+
tag_name = elem.node_name.downcase
|
224
|
+
|
225
|
+
klass = nil
|
226
|
+
|
227
|
+
if tag_name == "input"
|
228
|
+
klass = case elem.get_attribute(:type)
|
229
|
+
when *Button::VALID_TYPES
|
230
|
+
Button
|
231
|
+
when 'checkbox'
|
232
|
+
CheckBox
|
233
|
+
when 'radio'
|
234
|
+
Radio
|
235
|
+
when 'file'
|
236
|
+
FileField
|
237
|
+
else
|
238
|
+
TextField
|
239
|
+
end
|
240
|
+
else
|
241
|
+
klass = WatirNokogiri.element_class_for(tag_name)
|
242
|
+
end
|
243
|
+
|
244
|
+
klass.new(@parent, :element => elem)
|
245
|
+
end
|
246
|
+
|
247
|
+
#
|
248
|
+
# Returns value of the element.
|
249
|
+
#
|
250
|
+
# @return [String]
|
251
|
+
#
|
252
|
+
|
253
|
+
def value
|
254
|
+
assert_exists
|
255
|
+
attribute_value('value')
|
256
|
+
end
|
257
|
+
|
258
|
+
#
|
259
|
+
# Returns true if this element is visible on the page.
|
260
|
+
#
|
261
|
+
# @return [Boolean]
|
262
|
+
#
|
263
|
+
|
264
|
+
def visible?
|
265
|
+
assert_exists
|
266
|
+
raise "Not implemented"
|
267
|
+
end
|
268
|
+
|
269
|
+
#
|
270
|
+
# Returns the xpath of the current element.
|
271
|
+
#
|
272
|
+
|
273
|
+
def xpath()
|
274
|
+
assert_exists
|
275
|
+
@element.path
|
276
|
+
end
|
277
|
+
|
278
|
+
protected
|
279
|
+
|
280
|
+
def assert_exists()
|
281
|
+
return if @element
|
282
|
+
|
283
|
+
@element = @selector[:element] || locate
|
284
|
+
|
285
|
+
unless @element
|
286
|
+
raise UnknownObjectException, "unable to locate element, using #{@selector.inspect}"
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def locate
|
291
|
+
@parent.assert_exists
|
292
|
+
locator_class.new(@parent.nokogiri, @selector, self.class.attribute_list).locate
|
293
|
+
end
|
294
|
+
|
295
|
+
private
|
296
|
+
|
297
|
+
#
|
298
|
+
# Returns attribute value if attribute exists; nil otherwise
|
299
|
+
#
|
300
|
+
def attribute?(attribute)
|
301
|
+
assert_exists
|
302
|
+
@element.get_attribute(attribute.to_s.downcase)
|
303
|
+
end
|
304
|
+
|
305
|
+
def locator_class
|
306
|
+
ElementLocator
|
307
|
+
end
|
308
|
+
|
309
|
+
def method_missing(meth, *args, &blk)
|
310
|
+
method = meth.to_s
|
311
|
+
if method =~ /^data_(.+)$/
|
312
|
+
attribute_value(method.gsub(/_/, '-'), *args)
|
313
|
+
else
|
314
|
+
super
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
end
|