watir 1.5.2 → 1.5.3
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/readme.rb +20 -12
- data/unittests/html/table1.html +41 -1
- data/unittests/links_test.rb +2 -2
- data/unittests/navigate_test.rb +2 -2
- data/unittests/parent_child_test.rb +0 -15
- data/unittests/table_test.rb +5 -2
- data/unittests/textarea_test.rb +55 -39
- data/unittests/windows/iedialog_test.rb +2 -2
- data/watir.rb +20 -4386
- data/watir/{elements.rb → bonus-elements.rb} +0 -0
- data/watir/collections.rb +317 -0
- data/watir/container.rb +883 -0
- data/watir/element.rb +306 -0
- data/watir/element_collections.rb +82 -0
- data/watir/form.rb +151 -0
- data/watir/frame.rb +60 -0
- data/watir/ie.rb +973 -0
- data/watir/image.rb +131 -0
- data/watir/input_elements.rb +518 -0
- data/watir/link.rb +65 -0
- data/watir/locator.rb +79 -0
- data/watir/logger.rb +19 -0
- data/watir/modal_dialog.rb +123 -0
- data/watir/non_control_elements.rb +91 -0
- data/watir/page-container.rb +106 -0
- data/watir/popup.rb +30 -0
- data/watir/table.rb +356 -0
- data/watir/win32.rb +29 -0
- metadata +21 -3
data/watir/element.rb
ADDED
@@ -0,0 +1,306 @@
|
|
1
|
+
module Watir
|
2
|
+
# Base class for html elements.
|
3
|
+
# This is not a class that users would normally access.
|
4
|
+
class Element # Wrapper
|
5
|
+
include Watir::Exception
|
6
|
+
include Container # presumes @container is defined
|
7
|
+
attr_accessor :container
|
8
|
+
|
9
|
+
# number of spaces that separate the property from the value in the to_s method
|
10
|
+
TO_S_SIZE = 14
|
11
|
+
|
12
|
+
# ole_object - the ole object for the element being wrapped
|
13
|
+
def initialize(ole_object)
|
14
|
+
@o = ole_object
|
15
|
+
@original_color = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# Return the ole object, allowing any methods of the DOM that Watir doesn't support to be used.
|
19
|
+
def ole_object # BUG: should use an attribute reader and rename the instance variable
|
20
|
+
return @o
|
21
|
+
end
|
22
|
+
def ole_object=(o)
|
23
|
+
@o = o
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def self.def_wrap(ruby_method_name, ole_method_name=nil)
|
28
|
+
ole_method_name = ruby_method_name unless ole_method_name
|
29
|
+
class_eval "def #{ruby_method_name}
|
30
|
+
assert_exists
|
31
|
+
ole_object.invoke('#{ole_method_name}')
|
32
|
+
end"
|
33
|
+
end
|
34
|
+
def self.def_wrap_guard(method_name)
|
35
|
+
class_eval "def #{method_name}
|
36
|
+
assert_exists
|
37
|
+
begin
|
38
|
+
ole_object.invoke('#{method_name}')
|
39
|
+
rescue
|
40
|
+
''
|
41
|
+
end
|
42
|
+
end"
|
43
|
+
end
|
44
|
+
|
45
|
+
public
|
46
|
+
def assert_exists
|
47
|
+
locate if defined?(locate)
|
48
|
+
unless ole_object
|
49
|
+
raise UnknownObjectException.new("Unable to locate object, using #{@how} and #{@what}")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
def assert_enabled
|
53
|
+
unless enabled?
|
54
|
+
raise ObjectDisabledException, "object #{@how} and #{@what} is disabled"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# return the name of the element (as defined in html)
|
59
|
+
def_wrap_guard :name
|
60
|
+
# return the id of the element
|
61
|
+
def_wrap_guard :id
|
62
|
+
# return whether the element is disabled
|
63
|
+
def_wrap :disabled
|
64
|
+
alias disabled? disabled
|
65
|
+
# return the value of the element
|
66
|
+
def_wrap_guard :value
|
67
|
+
# return the title of the element
|
68
|
+
def_wrap_guard :title
|
69
|
+
# return the style of the element
|
70
|
+
def_wrap_guard :style
|
71
|
+
|
72
|
+
def_wrap_guard :alt
|
73
|
+
def_wrap_guard :src
|
74
|
+
|
75
|
+
# return the type of the element
|
76
|
+
def_wrap_guard :type # input elements only
|
77
|
+
# return the url the link points to
|
78
|
+
def_wrap :href # link only
|
79
|
+
# return the ID of the control that this label is associated with
|
80
|
+
def_wrap :for, :htmlFor # label only
|
81
|
+
# return the class name of the element
|
82
|
+
# raise an ObjectNotFound exception if the object cannot be found
|
83
|
+
def_wrap :class_name, :className
|
84
|
+
# return the unique COM number for the element
|
85
|
+
def_wrap :unique_number, :uniqueNumber
|
86
|
+
# Return the outer html of the object - see http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/outerhtml.asp?frame=true
|
87
|
+
def_wrap :html, :outerHTML
|
88
|
+
|
89
|
+
# return the text before the element
|
90
|
+
def before_text # label only
|
91
|
+
assert_exists
|
92
|
+
begin
|
93
|
+
ole_object.getAdjacentText("afterEnd").strip
|
94
|
+
rescue
|
95
|
+
''
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# return the text after the element
|
100
|
+
def after_text # label only
|
101
|
+
assert_exists
|
102
|
+
begin
|
103
|
+
ole_object.getAdjacentText("beforeBegin").strip
|
104
|
+
rescue
|
105
|
+
''
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Return the innerText of the object
|
110
|
+
# Raise an ObjectNotFound exception if the object cannot be found
|
111
|
+
def text
|
112
|
+
assert_exists
|
113
|
+
return ole_object.innerText.strip
|
114
|
+
end
|
115
|
+
|
116
|
+
def ole_inner_elements
|
117
|
+
assert_exists
|
118
|
+
return ole_object.all
|
119
|
+
end
|
120
|
+
private :ole_inner_elements
|
121
|
+
|
122
|
+
def document
|
123
|
+
assert_exists
|
124
|
+
return ole_object
|
125
|
+
end
|
126
|
+
|
127
|
+
# Return the element immediately containing self.
|
128
|
+
def parent
|
129
|
+
assert_exists
|
130
|
+
result = Element.new(ole_object.parentelement)
|
131
|
+
result.set_container self
|
132
|
+
result
|
133
|
+
end
|
134
|
+
|
135
|
+
include Comparable
|
136
|
+
def <=> other
|
137
|
+
assert_exists
|
138
|
+
other.assert_exists
|
139
|
+
ole_object.sourceindex <=> other.ole_object.sourceindex
|
140
|
+
end
|
141
|
+
|
142
|
+
# Return true if self is contained earlier in the html than other.
|
143
|
+
alias :before? :<
|
144
|
+
# Return true if self is contained later in the html than other.
|
145
|
+
alias :after? :>
|
146
|
+
|
147
|
+
def typingspeed
|
148
|
+
@container.typingspeed
|
149
|
+
end
|
150
|
+
|
151
|
+
def activeObjectHighLightColor
|
152
|
+
@container.activeObjectHighLightColor
|
153
|
+
end
|
154
|
+
|
155
|
+
# Return an array with many of the properties, in a format to be used by the to_s method
|
156
|
+
def string_creator
|
157
|
+
n = []
|
158
|
+
n << "type:".ljust(TO_S_SIZE) + self.type
|
159
|
+
n << "id:".ljust(TO_S_SIZE) + self.id.to_s
|
160
|
+
n << "name:".ljust(TO_S_SIZE) + self.name.to_s
|
161
|
+
n << "value:".ljust(TO_S_SIZE) + self.value.to_s
|
162
|
+
n << "disabled:".ljust(TO_S_SIZE) + self.disabled.to_s
|
163
|
+
return n
|
164
|
+
end
|
165
|
+
private :string_creator
|
166
|
+
|
167
|
+
# Display basic details about the object. Sample output for a button is shown.
|
168
|
+
# Raises UnknownObjectException if the object is not found.
|
169
|
+
# name b4
|
170
|
+
# type button
|
171
|
+
# id b5
|
172
|
+
# value Disabled Button
|
173
|
+
# disabled true
|
174
|
+
def to_s
|
175
|
+
assert_exists
|
176
|
+
return string_creator.join("\n")
|
177
|
+
end
|
178
|
+
|
179
|
+
# This method is responsible for setting and clearing the colored highlighting on the currently active element.
|
180
|
+
# use :set to set the highlight
|
181
|
+
# :clear to clear the highlight
|
182
|
+
# TODO: Make this two methods: set_highlight & clear_highlight
|
183
|
+
# TODO: Remove begin/rescue blocks
|
184
|
+
def highlight(set_or_clear)
|
185
|
+
if set_or_clear == :set
|
186
|
+
begin
|
187
|
+
@original_color ||= style.backgroundColor
|
188
|
+
style.backgroundColor = @container.activeObjectHighLightColor
|
189
|
+
rescue
|
190
|
+
@original_color = nil
|
191
|
+
end
|
192
|
+
else # BUG: assumes is :clear, but could actually be anything
|
193
|
+
begin
|
194
|
+
style.backgroundColor = @original_color unless @original_color == nil
|
195
|
+
rescue
|
196
|
+
# we could be here for a number of reasons...
|
197
|
+
# e.g. page may have reloaded and the reference is no longer valid
|
198
|
+
ensure
|
199
|
+
@original_color = nil
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
private :highlight
|
204
|
+
|
205
|
+
# This method clicks the active element.
|
206
|
+
# raises: UnknownObjectException if the object is not found
|
207
|
+
# ObjectDisabledException if the object is currently disabled
|
208
|
+
def click
|
209
|
+
click!
|
210
|
+
@container.wait
|
211
|
+
end
|
212
|
+
|
213
|
+
def click_no_wait
|
214
|
+
assert_enabled
|
215
|
+
|
216
|
+
highlight(:set)
|
217
|
+
object = "#{self.class}.new(self, :unique_number, #{self.unique_number})"
|
218
|
+
@page_container.eval_in_spawned_process(object + ".click!")
|
219
|
+
highlight(:clear)
|
220
|
+
end
|
221
|
+
|
222
|
+
def click!
|
223
|
+
assert_enabled
|
224
|
+
|
225
|
+
highlight(:set)
|
226
|
+
ole_object.click
|
227
|
+
highlight(:clear)
|
228
|
+
end
|
229
|
+
|
230
|
+
# Flash the element the specified number of times.
|
231
|
+
# Defaults to 10 flashes.
|
232
|
+
def flash number=10
|
233
|
+
assert_exists
|
234
|
+
number.times do
|
235
|
+
highlight(:set)
|
236
|
+
sleep 0.05
|
237
|
+
highlight(:clear)
|
238
|
+
sleep 0.05
|
239
|
+
end
|
240
|
+
nil
|
241
|
+
end
|
242
|
+
|
243
|
+
# Executes a user defined "fireEvent" for objects with JavaScript events tied to them such as DHTML menus.
|
244
|
+
# usage: allows a generic way to fire javascript events on page objects such as "onMouseOver", "onClick", etc.
|
245
|
+
# raises: UnknownObjectException if the object is not found
|
246
|
+
# ObjectDisabledException if the object is currently disabled
|
247
|
+
def fire_event(event)
|
248
|
+
assert_enabled
|
249
|
+
|
250
|
+
highlight(:set)
|
251
|
+
ole_object.fireEvent(event)
|
252
|
+
@container.wait
|
253
|
+
highlight(:clear)
|
254
|
+
end
|
255
|
+
|
256
|
+
# This method sets focus on the active element.
|
257
|
+
# raises: UnknownObjectException if the object is not found
|
258
|
+
# ObjectDisabledException if the object is currently disabled
|
259
|
+
def focus
|
260
|
+
assert_enabled
|
261
|
+
ole_object.focus
|
262
|
+
end
|
263
|
+
|
264
|
+
# Returns whether this element actually exists.
|
265
|
+
def exists?
|
266
|
+
begin
|
267
|
+
locate if defined?(locate)
|
268
|
+
rescue WIN32OLERuntimeError
|
269
|
+
@o = nil
|
270
|
+
end
|
271
|
+
@o ? true: false
|
272
|
+
end
|
273
|
+
alias :exist? :exists?
|
274
|
+
|
275
|
+
# Returns true if the element is enabled, false if it isn't.
|
276
|
+
# raises: UnknownObjectException if the object is not found
|
277
|
+
def enabled?
|
278
|
+
assert_exists
|
279
|
+
return ! disabled
|
280
|
+
end
|
281
|
+
|
282
|
+
# Get attribute value for any attribute of the element.
|
283
|
+
# Returns null if attribute doesn't exist.
|
284
|
+
def attribute_value(attribute_name)
|
285
|
+
assert_exists
|
286
|
+
return ole_object.getAttribute(attribute_name)
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
|
291
|
+
class ElementMapper # Still to be used
|
292
|
+
include Container
|
293
|
+
|
294
|
+
def initialize wrapper_class, container, how, what
|
295
|
+
@wrapper_class = wrapper_class
|
296
|
+
set_container
|
297
|
+
@how = how
|
298
|
+
@what = what
|
299
|
+
end
|
300
|
+
|
301
|
+
def method_missing method, *args
|
302
|
+
locate
|
303
|
+
@wrapper_class.new(@o).send(method, *args)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Watir
|
2
|
+
# this class is the super class for the iterator classes (buttons, links, spans etc
|
3
|
+
# it would normally only be accessed by the iterator methods (spans, links etc) of IE
|
4
|
+
class ElementCollections
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
# Super class for all the iteractor classes
|
8
|
+
# * container - an instance of an IE object
|
9
|
+
def initialize(container)
|
10
|
+
@container = container
|
11
|
+
@page_container = container.page_container
|
12
|
+
@length = length # defined by subclasses
|
13
|
+
|
14
|
+
# set up the items we want to display when the show method is used
|
15
|
+
set_show_items
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def set_show_items
|
20
|
+
@show_attributes = AttributeLengthPairs.new("id", 20)
|
21
|
+
@show_attributes.add("name", 20)
|
22
|
+
end
|
23
|
+
|
24
|
+
public
|
25
|
+
def get_length_of_input_objects(object_type)
|
26
|
+
object_types =
|
27
|
+
if object_type.kind_of? Array
|
28
|
+
object_type
|
29
|
+
else
|
30
|
+
[object_type]
|
31
|
+
end
|
32
|
+
|
33
|
+
length = 0
|
34
|
+
objects = @container.document.getElementsByTagName("INPUT")
|
35
|
+
if objects.length > 0
|
36
|
+
objects.each do |o|
|
37
|
+
length += 1 if object_types.include?(o.invoke("type").downcase)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
return length
|
41
|
+
end
|
42
|
+
|
43
|
+
# iterate through each of the elements in the collection in turn
|
44
|
+
def each
|
45
|
+
0.upto(@length-1) { |i| yield iterator_object(i) }
|
46
|
+
end
|
47
|
+
|
48
|
+
# allows access to a specific item in the collection
|
49
|
+
def [](n)
|
50
|
+
return iterator_object(n-1)
|
51
|
+
end
|
52
|
+
|
53
|
+
# this method is the way to show the objects, normally used from irb
|
54
|
+
def show
|
55
|
+
s = "index".ljust(6)
|
56
|
+
@show_attributes.each do |attribute_length_pair|
|
57
|
+
s += attribute_length_pair.attribute.ljust(attribute_length_pair.length)
|
58
|
+
end
|
59
|
+
|
60
|
+
index = 1
|
61
|
+
self.each do |o|
|
62
|
+
s += "\n"
|
63
|
+
s += index.to_s.ljust(6)
|
64
|
+
@show_attributes.each do |attribute_length_pair|
|
65
|
+
begin
|
66
|
+
s += eval('o.ole_object.invoke("#{attribute_length_pair.attribute}")').to_s.ljust(attribute_length_pair.length)
|
67
|
+
rescue => e
|
68
|
+
s += " ".ljust(attribute_length_pair.length)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
index += 1
|
72
|
+
end
|
73
|
+
puts s
|
74
|
+
end
|
75
|
+
|
76
|
+
# this method creates an object of the correct type that the iterators use
|
77
|
+
private
|
78
|
+
def iterator_object(i)
|
79
|
+
element_class.new(@container, :index, i + 1)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/watir/form.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
module Watir
|
2
|
+
|
3
|
+
# Forms
|
4
|
+
|
5
|
+
module FormAccess
|
6
|
+
def name
|
7
|
+
@ole_object.getAttributeNode('name').value
|
8
|
+
end
|
9
|
+
def action
|
10
|
+
@ole_object.action
|
11
|
+
end
|
12
|
+
def method
|
13
|
+
@ole_object.invoke('method')
|
14
|
+
end
|
15
|
+
def id
|
16
|
+
@ole_object.invoke('id')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# wraps around a form OLE object
|
21
|
+
class FormWrapper
|
22
|
+
include FormAccess
|
23
|
+
def initialize(ole_object)
|
24
|
+
@ole_object = ole_object
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Form Factory object
|
29
|
+
class Form < Element
|
30
|
+
include FormAccess
|
31
|
+
include Container
|
32
|
+
|
33
|
+
attr_accessor :form
|
34
|
+
|
35
|
+
# * container - the containing object, normally an instance of IE
|
36
|
+
# * how - symbol - how we access the form (:name, :id, :index, :action, :method)
|
37
|
+
# * what - what we use to access the form
|
38
|
+
def initialize(container, how, what)
|
39
|
+
set_container container
|
40
|
+
@how = how
|
41
|
+
@what = what
|
42
|
+
|
43
|
+
log "Get form how is #{@how} what is #{@what} "
|
44
|
+
|
45
|
+
# Get form using xpath.
|
46
|
+
if @how == :xpath
|
47
|
+
@ole_object = @container.element_by_xpath(@what)
|
48
|
+
else
|
49
|
+
count = 1
|
50
|
+
doc = @container.document
|
51
|
+
doc.forms.each do |thisForm|
|
52
|
+
next unless @ole_object == nil
|
53
|
+
|
54
|
+
wrapped = FormWrapper.new(thisForm)
|
55
|
+
|
56
|
+
log "form on page, name is " + wrapped.name
|
57
|
+
|
58
|
+
@ole_object =
|
59
|
+
case @how
|
60
|
+
when :name, :id, :method, :action
|
61
|
+
@what.matches(wrapped.send(@how)) ? thisForm : nil
|
62
|
+
when :index
|
63
|
+
count == @what ? thisForm : nil
|
64
|
+
else
|
65
|
+
raise MissingWayOfFindingObjectException, "#{how} is an unknown way of finding a form (#{what})"
|
66
|
+
end
|
67
|
+
count = count +1
|
68
|
+
end
|
69
|
+
end
|
70
|
+
super(@ole_object)
|
71
|
+
|
72
|
+
copy_test_config container
|
73
|
+
end
|
74
|
+
|
75
|
+
def exists?
|
76
|
+
@ole_object ? true : false
|
77
|
+
end
|
78
|
+
alias :exist? :exists?
|
79
|
+
|
80
|
+
# Submit the data -- equivalent to pressing Enter or Return to submit a form.
|
81
|
+
def submit # XXX use assert_exists
|
82
|
+
raise UnknownFormException, "Unable to locate a form using #{@how} and #{@what} " if @ole_object == nil
|
83
|
+
@ole_object.submit
|
84
|
+
@container.wait
|
85
|
+
end
|
86
|
+
|
87
|
+
def ole_inner_elements # XXX use assert_exists
|
88
|
+
raise UnknownFormException, "Unable to locate a form using #{@how} and #{@what} " if @ole_object == nil
|
89
|
+
@ole_object.elements
|
90
|
+
end
|
91
|
+
private :ole_inner_elements
|
92
|
+
|
93
|
+
def document
|
94
|
+
return @ole_object
|
95
|
+
end
|
96
|
+
|
97
|
+
def wait(no_sleep=false)
|
98
|
+
@container.wait(no_sleep)
|
99
|
+
end
|
100
|
+
|
101
|
+
# This method is responsible for setting and clearing the colored highlighting on the specified form.
|
102
|
+
# use :set to set the highlight
|
103
|
+
# :clear to clear the highlight
|
104
|
+
def highlight(set_or_clear, element, count)
|
105
|
+
|
106
|
+
if set_or_clear == :set
|
107
|
+
begin
|
108
|
+
original_color = element.style.backgroundColor
|
109
|
+
original_color = "" if original_color==nil
|
110
|
+
element.style.backgroundColor = activeObjectHighLightColor
|
111
|
+
rescue => e
|
112
|
+
puts e
|
113
|
+
puts e.backtrace.join("\n")
|
114
|
+
original_color = ""
|
115
|
+
end
|
116
|
+
@original_styles[count] = original_color
|
117
|
+
else
|
118
|
+
begin
|
119
|
+
element.style.backgroundColor = @original_styles[ count]
|
120
|
+
rescue => e
|
121
|
+
puts e
|
122
|
+
# we could be here for a number of reasons...
|
123
|
+
ensure
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
private :highlight
|
128
|
+
|
129
|
+
# causes the object to flash. Normally used in IRB when creating scripts
|
130
|
+
# Default is 10
|
131
|
+
def flash number=10
|
132
|
+
@original_styles = {}
|
133
|
+
number.times do
|
134
|
+
count = 0
|
135
|
+
@ole_object.elements.each do |element|
|
136
|
+
highlight(:set, element, count)
|
137
|
+
count += 1
|
138
|
+
end
|
139
|
+
sleep 0.05
|
140
|
+
count = 0
|
141
|
+
@ole_object.elements.each do |element|
|
142
|
+
highlight(:clear, element, count)
|
143
|
+
count += 1
|
144
|
+
end
|
145
|
+
sleep 0.05
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end # class Form
|
150
|
+
|
151
|
+
end
|