watir 1.4.1
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 +211 -0
- data/unittests/WindowLogonExample.rb +30 -0
- data/unittests/WindowLogonExtra.rb +7 -0
- data/unittests/all_tests.rb +10 -0
- data/unittests/all_tests_concurrent.rb +57 -0
- data/unittests/attachToExistingWindow_test.rb +40 -0
- data/unittests/buttons_test.rb +131 -0
- data/unittests/checkbox_test.rb +149 -0
- data/unittests/core_tests.rb +9 -0
- data/unittests/css_test.rb +60 -0
- data/unittests/div_test.rb +179 -0
- data/unittests/errorchecker_test.rb +29 -0
- data/unittests/filefield_test.rb +35 -0
- data/unittests/form_test.rb +279 -0
- data/unittests/frame_test.rb +141 -0
- data/unittests/html/blankpage.html +12 -0
- data/unittests/html/buttons1.html +40 -0
- data/unittests/html/checkboxes1.html +69 -0
- data/unittests/html/complex_table.html +36 -0
- data/unittests/html/cssTest.html +42 -0
- data/unittests/html/div.html +105 -0
- data/unittests/html/fileupload.html +45 -0
- data/unittests/html/formTest1.html +39 -0
- data/unittests/html/forms2.html +45 -0
- data/unittests/html/forms3.html +132 -0
- data/unittests/html/forms4.html +27 -0
- data/unittests/html/frame_buttons.html +4 -0
- data/unittests/html/frame_links.html +4 -0
- data/unittests/html/frame_multi.html +5 -0
- data/unittests/html/iframeTest.html +13 -0
- data/unittests/html/iframeTest1.html +7 -0
- data/unittests/html/iframeTest2.html +6 -0
- data/unittests/html/images/1.gif +0 -0
- data/unittests/html/images/2.GIF +0 -0
- data/unittests/html/images/3.GIF +0 -0
- data/unittests/html/images/button.jpg +0 -0
- data/unittests/html/images/circle.jpg +0 -0
- data/unittests/html/images/minus.GIF +0 -0
- data/unittests/html/images/originaltriangle.jpg +0 -0
- data/unittests/html/images/plus.gif +0 -0
- data/unittests/html/images/square.jpg +0 -0
- data/unittests/html/images/triangle.jpg +0 -0
- data/unittests/html/images1.html +52 -0
- data/unittests/html/javascriptevents.html +39 -0
- data/unittests/html/link_pass.html +11 -0
- data/unittests/html/links1.html +37 -0
- data/unittests/html/links2.html +11 -0
- data/unittests/html/nestedFrames.html +6 -0
- data/unittests/html/pass.html +10 -0
- data/unittests/html/popups1.html +60 -0
- data/unittests/html/radioButtons1.html +71 -0
- data/unittests/html/select_tealeaf.html +54 -0
- data/unittests/html/selectboxes1.html +55 -0
- data/unittests/html/simple_table.html +26 -0
- data/unittests/html/simple_table_buttons.html +104 -0
- data/unittests/html/simple_table_columns.html +76 -0
- data/unittests/html/table1.html +142 -0
- data/unittests/html/textarea.html +30 -0
- data/unittests/html/textfields1.html +87 -0
- data/unittests/html/textsearch.html +44 -0
- data/unittests/ie_mock.rb +93 -0
- data/unittests/ie_test.rb +50 -0
- data/unittests/images_test.rb +179 -0
- data/unittests/iostring.rb +30 -0
- data/unittests/iostring_test.rb +48 -0
- data/unittests/js_events_test.rb +77 -0
- data/unittests/jscriptExtraAlert.rb +6 -0
- data/unittests/jscriptExtraConfirmCancel.rb +7 -0
- data/unittests/jscriptExtraConfirmOk.rb +7 -0
- data/unittests/jscriptPushButton.rb +5 -0
- data/unittests/jscript_test.rb +57 -0
- data/unittests/links_test.rb +169 -0
- data/unittests/minmax_test.rb +31 -0
- data/unittests/navigate_test.rb +56 -0
- data/unittests/non_core_tests.rb +9 -0
- data/unittests/pagecontainstext_test.rb +49 -0
- data/unittests/popups_test.rb +44 -0
- data/unittests/radios_test.rb +164 -0
- data/unittests/screen_capture_test.rb +53 -0
- data/unittests/selectbox_test.rb +197 -0
- data/unittests/send_keys_test.rb +29 -0
- data/unittests/setup.rb +47 -0
- data/unittests/table_test.rb +306 -0
- data/unittests/textAreafields_test.rb +81 -0
- data/unittests/textfields_test.rb +239 -0
- data/watir.rb +3744 -0
- data/watir/AutoItX3.dll +0 -0
- data/watir/WindowHelper.rb +47 -0
- data/watir/camel_case.rb +37 -0
- data/watir/clickJSDialog.rb +19 -0
- data/watir/cookiemanager.rb +53 -0
- data/watir/exceptions.rb +60 -0
- data/watir/screen_capture.rb +115 -0
- data/watir/setFileDialog.rb +16 -0
- data/watir/testUnitAddons.rb +47 -0
- data/watir/watir_simple.rb +475 -0
- data/watir/winClicker.rb +505 -0
- metadata +152 -0
@@ -0,0 +1,239 @@
|
|
1
|
+
# feature tests for Text Fields
|
2
|
+
# revision: $Revision: 1.31 $
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..') if $0 == __FILE__
|
5
|
+
require 'unittests/setup'
|
6
|
+
|
7
|
+
class TC_Fields < Test::Unit::TestCase
|
8
|
+
include Watir
|
9
|
+
|
10
|
+
def setup()
|
11
|
+
$ie.goto($htmlRoot + "textfields1.html")
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_text_field_exists
|
15
|
+
assert($ie.text_field(:name, "text1").exists?)
|
16
|
+
assert_false($ie.text_field(:name, "missing").exists?)
|
17
|
+
|
18
|
+
assert($ie.text_field(:id, "text2").exists?)
|
19
|
+
assert_false($ie.text_field(:id, "alsomissing").exists?)
|
20
|
+
|
21
|
+
assert($ie.text_field(:beforeText , "This Text After").exists? )
|
22
|
+
assert($ie.text_field(:afterText , "This Text Before").exists? )
|
23
|
+
|
24
|
+
assert($ie.text_field(:beforeText , /after/i).exists? )
|
25
|
+
assert($ie.text_field(:afterText , /before/i).exists? )
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_text_field_dragContentsTo
|
29
|
+
$ie.text_field(:name, "text1").dragContentsTo(:id, "text2")
|
30
|
+
assert_equal($ie.text_field(:name, "text1").getContents, "" )
|
31
|
+
assert_equal($ie.text_field(:id, "text2").getContents, "goodbye allHello World" )
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_text_field_VerifyContents
|
35
|
+
assert($ie.text_field(:name, "text1").verify_contains("Hello World") )
|
36
|
+
assert($ie.text_field(:name, "text1").verify_contains(/Hello\sW/ ) )
|
37
|
+
assert_false($ie.text_field(:name, "text1").verify_contains("Ruby") )
|
38
|
+
assert_false($ie.text_field(:name, "text1").verify_contains(/R/) )
|
39
|
+
assert_raises(UnknownObjectException , "UnknownObjectException was supposed to be thrown" ) { $ie.text_field(:name, "NoName").verify_contains("No field to get a value of") }
|
40
|
+
|
41
|
+
assert($ie.text_field(:id, "text2").verify_contains("goodbye all") )
|
42
|
+
assert_raises(UnknownObjectException , "UnknownObjectException was supposed to be thrown" ) { $ie.text_field(:id, "noID").verify_contains("No field to get a value of") }
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_text_field_enabled
|
47
|
+
assert_false($ie.text_field(:name, "disabled").enabled? )
|
48
|
+
assert($ie.text_field(:name, "text1").enabled? )
|
49
|
+
assert($ie.text_field(:id, "text2").enabled? )
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_text_field_readOnly
|
53
|
+
assert_false($ie.text_field(:name, "disabled").readonly? )
|
54
|
+
assert($ie.text_field(:name, "readOnly").readonly? )
|
55
|
+
assert($ie.text_field(:id, "readOnly2").readonly? )
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_text_field_getContents()
|
59
|
+
assert_raises(UnknownObjectException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:name, "missing_field").append("Some Text") }
|
60
|
+
assert_equal( "Hello World" , $ie.text_field(:name, "text1").getContents )
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_TextField_to_s
|
64
|
+
expected = [build_to_s_regex("type", "text"),
|
65
|
+
build_to_s_regex("id", ""),
|
66
|
+
build_to_s_regex("name", "text1"),
|
67
|
+
build_to_s_regex("value", "Hello World"),
|
68
|
+
build_to_s_regex("disabled", "false"),
|
69
|
+
build_to_s_regex("length", "20"),
|
70
|
+
build_to_s_regex("max length", "2147483647"),
|
71
|
+
build_to_s_regex("read only", "false")]
|
72
|
+
items = $ie.text_field(:index, 1).to_s.split(/\n/)
|
73
|
+
expected.each_with_index{|regex, x| assert(regex =~ items[x]) }
|
74
|
+
expected[1] = build_to_s_regex("id", "text2")
|
75
|
+
expected[2] = build_to_s_regex("name", "")
|
76
|
+
expected[3] = build_to_s_regex("value", "goodbye all")
|
77
|
+
items = $ie.text_field(:index, 2).to_s.split(/\n/)
|
78
|
+
expected.each_with_index{|regex, x| assert(regex =~ items[x]) }
|
79
|
+
assert_raises(UnknownObjectException , "UnknownObjectException was supposed to be thrown" ) { $ie.text_field(:index, 999 ).to_s}
|
80
|
+
end
|
81
|
+
|
82
|
+
def build_to_s_regex(lhs, rhs)
|
83
|
+
Regexp.new("^#{lhs}: +#{rhs}$")
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_text_field_Append
|
87
|
+
assert_raises(ObjectReadOnlyException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:id, "readOnly2").append("Some Text") }
|
88
|
+
assert_raises(ObjectDisabledException , "ObjectDisabledException was supposed to be thrown" ) { $ie.text_field(:name, "disabled").append("Some Text") }
|
89
|
+
assert_raises(UnknownObjectException , "UnknownObjectException was supposed to be thrown" ) { $ie.text_field(:name, "missing_field").append("Some Text") }
|
90
|
+
|
91
|
+
$ie.text_field(:name, "text1").append(" Some Text")
|
92
|
+
assert_equal( "Hello World Some Text" , $ie.text_field(:name, "text1").getContents )
|
93
|
+
|
94
|
+
# may need this to see that it really happened
|
95
|
+
#puts "press return to continue"
|
96
|
+
#gets
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
def test_text_field_Clear
|
102
|
+
assert_raises(ObjectReadOnlyException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:id, "readOnly2").append("Some Text") }
|
103
|
+
assert_raises(ObjectDisabledException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:name, "disabled").append("Some Text") }
|
104
|
+
assert_raises(UnknownObjectException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:name, "missing_field").append("Some Text") }
|
105
|
+
|
106
|
+
$ie.text_field(:name, "text1").clear()
|
107
|
+
assert_equal( "" , $ie.text_field(:name, "text1").getContents )
|
108
|
+
|
109
|
+
# may need this to see that it really happened
|
110
|
+
#puts "press return to continue"
|
111
|
+
#gets
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_text_field_Set
|
116
|
+
assert_raises(ObjectReadOnlyException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:id, "readOnly2").append("Some Text") }
|
117
|
+
assert_raises(ObjectDisabledException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:name, "disabled").append("Some Text") }
|
118
|
+
assert_raises(UnknownObjectException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:name, "missing_field").append("Some Text") }
|
119
|
+
|
120
|
+
$ie.text_field(:name, "text1").set("watir IE Controller")
|
121
|
+
assert_equal( "watir IE Controller" , $ie.text_field(:name, "text1").getContents )
|
122
|
+
|
123
|
+
# may need this to see that it really happened
|
124
|
+
#puts "press return to continue"
|
125
|
+
#gets
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_text_field_properties
|
129
|
+
|
130
|
+
assert_raises(UnknownObjectException , "UnknownObjectException was supposed to be thrown" ) { $ie.text_field(:index, 199).value}
|
131
|
+
assert_raises(UnknownObjectException , "UnknownObjectException was supposed to be thrown" ) { $ie.text_field(:index, 199).name }
|
132
|
+
assert_raises(UnknownObjectException , "UnknownObjectException was supposed to be thrown" ) { $ie.text_field(:index, 199).id }
|
133
|
+
assert_raises(UnknownObjectException , "UnknownObjectException was supposed to be thrown" ) { $ie.text_field(:index, 199).disabled }
|
134
|
+
assert_raises(UnknownObjectException , "UnknownObjectException was supposed to be thrown" ) { $ie.text_field(:index, 199).type }
|
135
|
+
|
136
|
+
assert_equal( "Hello World" , $ie.text_field(:index, 1).value )
|
137
|
+
assert_equal( "text" , $ie.text_field(:index, 1).type)
|
138
|
+
assert_equal( "text1" , $ie.text_field(:index, 1).name )
|
139
|
+
assert_equal( "" , $ie.text_field(:index, 1).id )
|
140
|
+
assert_equal( false , $ie.text_field(:index, 1).disabled )
|
141
|
+
|
142
|
+
assert_equal( "" , $ie.text_field(:index, 2).name )
|
143
|
+
assert_equal( "text2" , $ie.text_field(:index, 2).id )
|
144
|
+
|
145
|
+
assert( $ie.text_field(:index, 3).disabled )
|
146
|
+
|
147
|
+
assert_equal( "This used to test :afterText" , $ie.text_field(:name, "aftertest" ).title )
|
148
|
+
assert_equal( "" , $ie.text_field(:index, 1 ).title )
|
149
|
+
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_text_field_iterators
|
154
|
+
|
155
|
+
assert_equal( 12 , $ie.text_fields.length )
|
156
|
+
|
157
|
+
# watir is 1 based, so this is the first text field
|
158
|
+
assert_equal( "Hello World" , $ie.text_fields[1].value )
|
159
|
+
assert_equal( "text1" , $ie.text_fields[1].name )
|
160
|
+
|
161
|
+
assert_equal( "password" , $ie.text_fields[ $ie.text_fields.length ].type)
|
162
|
+
|
163
|
+
|
164
|
+
index = 1
|
165
|
+
$ie.text_fields.each do |t|
|
166
|
+
assert_equal( $ie.text_field(:index, index).value, t.value )
|
167
|
+
assert_equal( $ie.text_field(:index, index).id, t.id )
|
168
|
+
assert_equal( $ie.text_field(:index, index).name, t.name )
|
169
|
+
index +=1
|
170
|
+
end
|
171
|
+
assert_equal( index-1, $ie.text_fields.length)
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_JS_Events
|
176
|
+
$ie.text_field(:name , 'events_tester').set('p')
|
177
|
+
|
178
|
+
# the following line has an extra keypress at the begining, as we mimic the delete key being pressed
|
179
|
+
assert_equal( "keypresskeydownkeypresskeyup" , $ie.text_field(:name , 'events_text').value.gsub("\r\n" , "") )
|
180
|
+
$ie.button(:value , "Clear Events Box").click
|
181
|
+
$ie.text_field(:name , 'events_tester').set('ab')
|
182
|
+
|
183
|
+
# the following line has an extra keypress at the begining, as we mimic the delete key being pressed
|
184
|
+
assert_equal( "keypresskeydownkeypresskeyupkeydownkeypresskeyup" , $ie.text_field(:name , 'events_text').value.gsub("\r\n" , "") )
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_password
|
189
|
+
|
190
|
+
$ie.text_field(:name , "password1").set("secret")
|
191
|
+
assert( 'secret' , $ie.text_field(:name , "password1").value )
|
192
|
+
|
193
|
+
$ie.text_field(:id , "password1").set("top_secret")
|
194
|
+
assert( 'top_secret' , $ie.text_field(:id, "password1").value )
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_labels_iterator
|
198
|
+
|
199
|
+
assert_equal(3, $ie.labels.length)
|
200
|
+
assert_equal('Label For this Field' , $ie.labels[1].innerText.strip )
|
201
|
+
assert_equal('Password With ID ( the text here is a label for it )' , $ie.labels[3].innerText )
|
202
|
+
|
203
|
+
count=0
|
204
|
+
$ie.labels.each do |l|
|
205
|
+
count +=1
|
206
|
+
end
|
207
|
+
assert_equal(count, $ie.labels.length)
|
208
|
+
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_label_properties
|
213
|
+
assert_raises(UnknownObjectException ) { $ie.label(:index,20).innerText }
|
214
|
+
assert_raises(UnknownObjectException ) { $ie.label(:index,20).for }
|
215
|
+
assert_raises(UnknownObjectException ) { $ie.label(:index,20).name }
|
216
|
+
assert_raises(UnknownObjectException ) { $ie.label(:index,20).type }
|
217
|
+
assert_raises(UnknownObjectException ) { $ie.label(:index,20).id }
|
218
|
+
|
219
|
+
assert_false( $ie.label(:index,10).exists? )
|
220
|
+
assert_false( $ie.label(:id,'missing').exists? )
|
221
|
+
assert( $ie.label(:index,1).exists? )
|
222
|
+
|
223
|
+
|
224
|
+
assert_equal( "" , $ie.label(:index,1).id )
|
225
|
+
assert_false( $ie.label(:index,1).disabled )
|
226
|
+
assert( $ie.label(:index,1).enabled?)
|
227
|
+
|
228
|
+
|
229
|
+
assert_equal( "label2" , $ie.label(:index,2).id )
|
230
|
+
assert_equal( "Label" , $ie.label(:index,2).type )
|
231
|
+
|
232
|
+
assert_equal( "Password With ID ( the text here is a label for it )" , $ie.label(:index,3).innerText)
|
233
|
+
assert_equal( "password1" , $ie.label(:index,3).for)
|
234
|
+
end
|
235
|
+
|
236
|
+
|
237
|
+
|
238
|
+
|
239
|
+
end
|
data/watir.rb
ADDED
@@ -0,0 +1,3744 @@
|
|
1
|
+
=begin
|
2
|
+
license
|
3
|
+
---------------------------------------------------------------------------
|
4
|
+
Copyright (c) 2004-2005, Paul Rogers and Bret Pettichord
|
5
|
+
All rights reserved.
|
6
|
+
|
7
|
+
Redistribution and use in source and binary forms, with or without
|
8
|
+
modification, are permitted provided that the following conditions are met:
|
9
|
+
|
10
|
+
1. Redistributions of source code must retain the above copyright notice,
|
11
|
+
this list of conditions and the following disclaimer.
|
12
|
+
|
13
|
+
2. Redistributions in binary form must reproduce the above copyright
|
14
|
+
notice, this list of conditions and the following disclaimer in the
|
15
|
+
documentation and/or other materials provided with the distribution.
|
16
|
+
|
17
|
+
3. Neither the names Paul Rogers, Bret Pettichord nor the names of contributors to
|
18
|
+
this software may be used to endorse or promote products derived from this
|
19
|
+
software without specific prior written permission.
|
20
|
+
|
21
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
22
|
+
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
23
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
24
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
|
25
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
26
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
27
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
28
|
+
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
29
|
+
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
30
|
+
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
31
|
+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32
|
+
--------------------------------------------------------------------------
|
33
|
+
(based on BSD Open Source License)
|
34
|
+
=end
|
35
|
+
|
36
|
+
# This is Watir, Web Application Testing In Ruby
|
37
|
+
# Home page is http://wtr.rubyforge.org
|
38
|
+
#
|
39
|
+
# Version "$Revision: 1.211.2.2 $"
|
40
|
+
#
|
41
|
+
# Typical usage:
|
42
|
+
# # include the controller
|
43
|
+
# require "watir"
|
44
|
+
# # go to the page you want to test
|
45
|
+
# ie = Watir::IE.start("http://myserver/mypage")
|
46
|
+
# # enter "Paul" into an input field named "username"
|
47
|
+
# ie.text_field(:name, "username").set("Paul")
|
48
|
+
# # enter "Ruby Co" into input field with id "company_ID"
|
49
|
+
# ie.text_field(:id ,"company_ID").set("Ruby Co")
|
50
|
+
# # click button that has a caption of "Cancel"
|
51
|
+
# ie.button(:value, "Cancel").click
|
52
|
+
#
|
53
|
+
# The ways that are available to identify an html object depend upon the object type, but include
|
54
|
+
# :id used for an object that has an ID attribute -- this is the best way!
|
55
|
+
# :name used for an object that has a name attribute.
|
56
|
+
# :value value of text fields, captions of buttons
|
57
|
+
# :index finds the nth object of the specified type - eg button(:index , 2) finds the second button. This is 1 based. <br>
|
58
|
+
# :beforeText finds the object immeditaley before the specified text. Doesnt work if the text is in a table cell
|
59
|
+
# :afterText finds the object immeditaley after the specified text. Doesnt work if the text is in a table cell
|
60
|
+
#
|
61
|
+
|
62
|
+
|
63
|
+
# These 2 web sites provide info on Internet Explorer and on the DOM as implemented by Internet Explorer
|
64
|
+
# http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/webbrowser/webbrowser.asp
|
65
|
+
# http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/overview/overview.asp
|
66
|
+
|
67
|
+
# command line options:
|
68
|
+
#
|
69
|
+
# -b (background) Run Internet Explorer invisible
|
70
|
+
# -f (fast) Run tests fast
|
71
|
+
# -x (spinner) Add a spinner that displays when pages are waiting to be loaded.
|
72
|
+
|
73
|
+
require 'win32ole'
|
74
|
+
require 'logger'
|
75
|
+
require 'watir/winClicker'
|
76
|
+
require 'watir/exceptions'
|
77
|
+
|
78
|
+
class String
|
79
|
+
def matches (x)
|
80
|
+
return self == x
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Regexp
|
85
|
+
def matches (x)
|
86
|
+
return self.match(x)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# ARGV needs to be deleted to enable the Test::Unit functionality that grabs
|
91
|
+
# the remaining ARGV as a filter on what tests to run.
|
92
|
+
# Note: this means that watir must be require'd BEFORE test/unit.
|
93
|
+
def command_line_flag(switch)
|
94
|
+
setting = ARGV.include?(switch)
|
95
|
+
ARGV.delete(switch)
|
96
|
+
return setting
|
97
|
+
end
|
98
|
+
|
99
|
+
# Constant to make Internet explorer minimisez. -b stands for background
|
100
|
+
$HIDE_IE = command_line_flag('-b')
|
101
|
+
|
102
|
+
# Constant to enable/disable the spinner
|
103
|
+
$ENABLE_SPINNER = command_line_flag('-x')
|
104
|
+
|
105
|
+
# Constant to set fast speed
|
106
|
+
$FAST_SPEED = command_line_flag('-f')
|
107
|
+
|
108
|
+
# Eat the -s command line switch (deprecated)
|
109
|
+
command_line_flag('-s')
|
110
|
+
|
111
|
+
module Watir
|
112
|
+
include Watir::Exception
|
113
|
+
|
114
|
+
# BUG: this won't work right until the null objects are pulled out
|
115
|
+
def exists?
|
116
|
+
begin
|
117
|
+
yield
|
118
|
+
true
|
119
|
+
rescue
|
120
|
+
false
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class WatirLogger < Logger
|
125
|
+
def initialize( filName , logsToKeep, maxLogSize )
|
126
|
+
super( filName , logsToKeep, maxLogSize )
|
127
|
+
self.level = Logger::DEBUG
|
128
|
+
self.datetime_format = "%d-%b-%Y %H:%M:%S"
|
129
|
+
self.debug("Watir starting")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class DefaultLogger < Logger
|
134
|
+
def initialize()
|
135
|
+
super(STDERR)
|
136
|
+
self.level = Logger::WARN
|
137
|
+
self.datetime_format = "%d-%b-%Y %H:%M:%S"
|
138
|
+
self.info "Log started"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# This class displays the spinner object that appears in the console when a page is being loaded
|
143
|
+
class Spinner
|
144
|
+
|
145
|
+
def initialize(enabled = true)
|
146
|
+
@s = [ "\b/" , "\b|" , "\b\\" , "\b-"]
|
147
|
+
@i=0
|
148
|
+
@enabled = enabled
|
149
|
+
end
|
150
|
+
|
151
|
+
# reverse the direction of spinning
|
152
|
+
def reverse
|
153
|
+
@s.reverse!
|
154
|
+
end
|
155
|
+
|
156
|
+
def spin
|
157
|
+
print self.next if @enabled
|
158
|
+
end
|
159
|
+
|
160
|
+
# get the next character to display
|
161
|
+
def next
|
162
|
+
@i=@i+1
|
163
|
+
@i=0 if @i>@s.length-1
|
164
|
+
return @s[@i]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# This module contains the factory methods that are used to access most html objects
|
169
|
+
#
|
170
|
+
# For example, to access a button on a web page that has the following html
|
171
|
+
# <input type = button name= 'b1' value='Click Me' onClick='javascript:doSomething()'>
|
172
|
+
#
|
173
|
+
# the following watir code could be used
|
174
|
+
#
|
175
|
+
# ie.button(:name, 'b1').click
|
176
|
+
#
|
177
|
+
# or
|
178
|
+
#
|
179
|
+
# ie.button(:value, 'Click Me').to_s
|
180
|
+
#
|
181
|
+
# there are many methods available to the Button object
|
182
|
+
#
|
183
|
+
# Is includable for classes that have @ieController, document and document.body
|
184
|
+
module SupportsSubElements
|
185
|
+
include Watir::Exception
|
186
|
+
|
187
|
+
# this method returns the real Internet Explorer object, allowing access to objects, properties and methods that Watir doesnot support
|
188
|
+
def ie
|
189
|
+
return @ieController
|
190
|
+
end
|
191
|
+
|
192
|
+
# write the specified string to the log, assuming a logger has been setup using IE#set_logger
|
193
|
+
def log ( what )
|
194
|
+
@ieController.logger.debug( what ) if @logger
|
195
|
+
end
|
196
|
+
|
197
|
+
# this method causes Watir to wait until Internet Explorer has finished the action
|
198
|
+
def wait( noSleep = false )
|
199
|
+
@ieController.wait( noSleep )
|
200
|
+
end
|
201
|
+
|
202
|
+
def process_default(default_attribute, how, what)
|
203
|
+
if what == nil
|
204
|
+
what = how
|
205
|
+
how = default_attribute
|
206
|
+
end
|
207
|
+
return how, what
|
208
|
+
end
|
209
|
+
private :process_default
|
210
|
+
|
211
|
+
# this method is the main way of accessing a frame
|
212
|
+
# * how - how the frame is accessed. This can also just be the name of the frame
|
213
|
+
# * what - what we want to access.
|
214
|
+
#
|
215
|
+
# Typical usage:
|
216
|
+
#
|
217
|
+
# ie.frame(:index, 1)
|
218
|
+
# ie.frame(:name , 'main_frame')
|
219
|
+
# ie.frame('main_frame') # in this case, just a name is supplied
|
220
|
+
def frame(how, what=nil)
|
221
|
+
how, what = process_default :name, how, what
|
222
|
+
return Frame.new(self, how, what)
|
223
|
+
end
|
224
|
+
|
225
|
+
# this method is used to access a form.
|
226
|
+
# available ways of accessing it are, :index , :name, :id, :method, :action
|
227
|
+
# * how - symbol - WHat mecahnism we use to find the form, one of the above. NOTE if what is not supplied this parameter is the NAME of the form
|
228
|
+
# * what - String - the text associated with the symbol
|
229
|
+
def form(how, what=nil)
|
230
|
+
how, what = process_default :name, how, what
|
231
|
+
return Form.new(self, how, what)
|
232
|
+
end
|
233
|
+
|
234
|
+
# This method is used to get a table from the page.
|
235
|
+
# :index (1 based counting)and :id are supported.
|
236
|
+
# NOTE :name is not supported, as the table tag does not have a name attribute. It is not part of the DOM.
|
237
|
+
# :index can be used when there are multiple tables on a page.
|
238
|
+
# The first form can be accessed with :index 1, the second :index 2, etc.
|
239
|
+
# * how - symbol - the way we look for the table. Supported values are
|
240
|
+
# - :id
|
241
|
+
# - :index
|
242
|
+
# * what - string the thing we are looking for, ex. id or index of the object we are looking for
|
243
|
+
def table( how, what )
|
244
|
+
return Table.new( self , how, what)
|
245
|
+
end
|
246
|
+
|
247
|
+
# this is the main method for accessing the tables iterator. It returns a Tables object
|
248
|
+
#
|
249
|
+
# Typical usage:
|
250
|
+
#
|
251
|
+
# ie.tables.each { |t| puts t.to_s } # iterate through all the tables on the page
|
252
|
+
# ie.tables[1].to_s # goto the first table on the page
|
253
|
+
# ie.tables.length # show how many tables are on the page. Tables that are nested will be included in this
|
254
|
+
def tables()
|
255
|
+
return Tables.new(self)
|
256
|
+
end
|
257
|
+
|
258
|
+
# this method accesses a table cell.
|
259
|
+
# how - symbol - how we access the cell, :id is supported
|
260
|
+
#
|
261
|
+
# returns a TableCell Object
|
262
|
+
def cell( how, what )
|
263
|
+
return TableCell.new( self, how, what)
|
264
|
+
end
|
265
|
+
|
266
|
+
# this method accesses a table row.
|
267
|
+
# how - symbol - how we access the row, :id is supported
|
268
|
+
#
|
269
|
+
# returns a TableRow object
|
270
|
+
def row( how, what )
|
271
|
+
return TableRow.new( self, how, what)
|
272
|
+
end
|
273
|
+
|
274
|
+
# This is the main method for accessing a button. Often declared as an <input type = submit> tag.
|
275
|
+
# * how - symbol - how we access the button
|
276
|
+
# * what - string, int or re , what we are looking for,
|
277
|
+
# Returns a Button object.
|
278
|
+
#
|
279
|
+
# Valid values for 'how' are
|
280
|
+
#
|
281
|
+
# :index - find the item using the index in the container ( a container can be a document, a TableCell, a Span, a Div or a P
|
282
|
+
# index is 1 based
|
283
|
+
# :name - find the item using the name attribute
|
284
|
+
# :id - find the item using the id attribute
|
285
|
+
# :value - find the item using the value attribute ( in this case the button caption)
|
286
|
+
# :caption - same as value
|
287
|
+
# :beforeText - finds the item immediately before the specified text
|
288
|
+
# :afterText - finds the item immediately after the specified text
|
289
|
+
#
|
290
|
+
# Typical Usage
|
291
|
+
#
|
292
|
+
# ie.button(:id, 'b_1') # access the button with an ID of b_1
|
293
|
+
# ie.button(:name, 'verify_data') # access the button with a name of verify_data
|
294
|
+
# ie.button(:value, 'Login') # access the button with a value (the text displayed on the button) of Login
|
295
|
+
# ie.button(:caption, 'Login') # same as above
|
296
|
+
# ie.button(:value, /Log/) # access the button that has text matching /Log/
|
297
|
+
# ie.button(:index, 2) # access the second button on the page ( 1 based, so the first button is accessed with :index,1)
|
298
|
+
#
|
299
|
+
# if only a single parameter is supplied, then :value is used
|
300
|
+
#
|
301
|
+
# ie.button('Click Me') # access the button with a value of Click Me
|
302
|
+
def button(how, what=nil)
|
303
|
+
how, what = process_default :value, how, what
|
304
|
+
return Button.new(self, how, what)
|
305
|
+
end
|
306
|
+
|
307
|
+
# this is the main method for accessing the buttons iterator. It returns a Buttons object
|
308
|
+
#
|
309
|
+
# Typical usage:
|
310
|
+
#
|
311
|
+
# ie.buttons.each { |b| puts b.to_s } # iterate through all the buttons on the page
|
312
|
+
# ie.buttons[1].to_s # goto the first button on the page
|
313
|
+
# ie.buttons.length # show how many buttons are on the page.
|
314
|
+
def buttons()
|
315
|
+
return Buttons.new(self)
|
316
|
+
end
|
317
|
+
|
318
|
+
|
319
|
+
# This is the main method for accessing a file field. Usually an <input type = file> HTML tag.
|
320
|
+
# * how - symbol - how we access the field , :index, :id, :name etc
|
321
|
+
# * what - string, int or re , what we are looking for,
|
322
|
+
#
|
323
|
+
# returns a FileField object
|
324
|
+
#
|
325
|
+
# Typical Usage
|
326
|
+
#
|
327
|
+
# ie.file_field(:id, 'up_1') # access the file upload field with an ID of up_1
|
328
|
+
# ie.file_field(:name, 'upload') # access the file upload field with a name of upload
|
329
|
+
# ie.file_field(:index, 2) # access the second file upload on the page ( 1 based, so the first field is accessed with :index,1)
|
330
|
+
#
|
331
|
+
def file_field(how , what)
|
332
|
+
return FileField.new(self , how, what)
|
333
|
+
end
|
334
|
+
|
335
|
+
# this is the main method for accessing the file_fields iterator. It returns a FileFields object
|
336
|
+
#
|
337
|
+
# Typical usage:
|
338
|
+
#
|
339
|
+
# ie.file_fields.each { |f| puts f.to_s } # iterate through all the file fields on the page
|
340
|
+
# ie.file_fields[1].to_s # goto the first file field on the page
|
341
|
+
# ie.file_fields.length # show how many file fields are on the page.
|
342
|
+
def file_fields()
|
343
|
+
return FileFields.new(self)
|
344
|
+
end
|
345
|
+
|
346
|
+
# This is the main method for accessing a text field. Usually an <input type = text> HTML tag. or a text area - a <textarea> tag
|
347
|
+
# * how - symbol - how we access the field , :index, :id, :name etc
|
348
|
+
# * what - string, int or re , what we are looking for,
|
349
|
+
#
|
350
|
+
# returns a TextField object
|
351
|
+
#
|
352
|
+
# Valid values for 'how' are
|
353
|
+
#
|
354
|
+
# :index - find the item using the index in the container ( a container can be a document, a TableCell, a Span, a Div or a P
|
355
|
+
# index is 1 based
|
356
|
+
# :name - find the item using the name attribute
|
357
|
+
# :id - find the item using the id attribute
|
358
|
+
# :beforeText - finds the item immediately before the specified text
|
359
|
+
# :afterText - finds the item immediately after the specified text
|
360
|
+
#
|
361
|
+
# Typical Usage
|
362
|
+
#
|
363
|
+
# ie.text_field(:id, 'user_name') # access the text field with an ID of user_name
|
364
|
+
# ie.text_field(:name, 'address') # access the text field with a name of address
|
365
|
+
# ie.text_field(:index, 2) # access the second text field on the page ( 1 based, so the first field is accessed with :index,1)
|
366
|
+
def text_field(how , what=nil)
|
367
|
+
return TextField.new(self, how, what)
|
368
|
+
end
|
369
|
+
|
370
|
+
# this is the method for accessing the text_fields iterator. It returns a Text_Fields object
|
371
|
+
#
|
372
|
+
# Typical usage:
|
373
|
+
#
|
374
|
+
# ie.text_fields.each { |t| puts t.to_s } # iterate through all the text fields on the page
|
375
|
+
# ie.text_fields[1].to_s # goto the first text field on the page
|
376
|
+
# ie.text_fields.length # show how many text field are on the page.
|
377
|
+
def text_fields
|
378
|
+
return TextFields.new(self)
|
379
|
+
end
|
380
|
+
|
381
|
+
# This is the main method for accessing a hidden field. Usually an <input type = hidden> HTML tag
|
382
|
+
# * how - symbol - how we access the field , :index, :id, :name etc
|
383
|
+
# * what - string, int or re , what we are looking for,
|
384
|
+
#
|
385
|
+
# returns a Hidden object
|
386
|
+
#
|
387
|
+
# Typical usage
|
388
|
+
#
|
389
|
+
# ie.hidden(:id, 'session_id') # access the hidden field with an ID of session_id
|
390
|
+
# ie.hidden(:name, 'temp_value') # access the hidden field with a name of temp_value
|
391
|
+
# ie.hidden(:index, 2) # access the second hidden field on the page ( 1 based, so the first field is accessed with :index,1)
|
392
|
+
def hidden( how, what )
|
393
|
+
return Hidden.new(self, how, what)
|
394
|
+
end
|
395
|
+
|
396
|
+
# this is the method for accessing the hiddens iterator. It returns a Hiddens object
|
397
|
+
#
|
398
|
+
# Typical usage:
|
399
|
+
#
|
400
|
+
# ie.hiddens.each { |t| puts t.to_s } # iterate through all the hidden fields on the page
|
401
|
+
# ie.hiddens[1].to_s # goto the first hidden field on the page
|
402
|
+
# ie.hiddens.length # show how many hidden fields are on the page.
|
403
|
+
def hiddens
|
404
|
+
return Hiddens.new(self)
|
405
|
+
end
|
406
|
+
|
407
|
+
# This is the main method for accessing a selection list. Usually a <select> HTML tag.
|
408
|
+
# * how - symbol - how we access the selection list , :index, :id, :name etc
|
409
|
+
# * what - string, int or re , what we are looking for,
|
410
|
+
#
|
411
|
+
# returns a SelectList object
|
412
|
+
#
|
413
|
+
# Valid values for 'how' are
|
414
|
+
#
|
415
|
+
# :index - find the item using the index in the container ( a container can be a document, a TableCell, a Span, a Div or a P
|
416
|
+
# index is 1 based
|
417
|
+
# :name - find the item using the name attribute
|
418
|
+
# :id - find the item using the id attribute
|
419
|
+
# :beforeText - finds the item immediately before the specified text
|
420
|
+
# :afterText - finds the item immediately after the specified text
|
421
|
+
#
|
422
|
+
# Typical usage
|
423
|
+
#
|
424
|
+
# ie.select_list(:id, 'currency') # access the select box with an id of currency
|
425
|
+
# ie.select_list(:name, 'country') # access the select box with a name of country
|
426
|
+
# ie.select_list(:name, /n_/ ) # access the first select box whose name matches n_
|
427
|
+
# ie.select_list(:index, 2) # access the second select box on the page ( 1 based, so the first field is accessed with :index,1)
|
428
|
+
def select_list(how , what=nil)
|
429
|
+
return SelectList.new(self, how, what)
|
430
|
+
end
|
431
|
+
|
432
|
+
# this is the method for accessing the select lists iterator. Returns a SelectLists object
|
433
|
+
#
|
434
|
+
# Typical usage:
|
435
|
+
#
|
436
|
+
# ie.select_lists.each { |s| puts s.to_s } # iterate through all the select boxes on the page
|
437
|
+
# ie.select_lists[1].to_s # goto the first select boxes on the page
|
438
|
+
# ie.select_lists.length # show how many select boxes are on the page.
|
439
|
+
def select_lists()
|
440
|
+
return SelectLists.new(self)
|
441
|
+
end
|
442
|
+
|
443
|
+
# This is the main method for accessing a check box. Usually an <input type = checkbox> HTML tag.
|
444
|
+
#
|
445
|
+
# * how - symbol - how we access the check box , :index, :id, :name etc
|
446
|
+
# * what - string, int or re , what we are looking for,
|
447
|
+
# * value - string - when there are multiple objects with different value attributes, this can be used to find the correct object
|
448
|
+
#
|
449
|
+
# returns a CheckBox object
|
450
|
+
#
|
451
|
+
# Valid values for 'how' are
|
452
|
+
#
|
453
|
+
# :index - find the item using the index in the container ( a container can be a document, a TableCell, a Span, a Div or a P
|
454
|
+
# index is 1 based
|
455
|
+
# :name - find the item using the name attribute
|
456
|
+
# :id - find the item using the id attribute
|
457
|
+
# :beforeText - finds the item immediately before the specified text
|
458
|
+
# :afterText - finds the item immediately after the specified text
|
459
|
+
#
|
460
|
+
# Typical usage
|
461
|
+
#
|
462
|
+
# ie.checkbox(:id, 'send_email') # access the check box with an id of send_mail
|
463
|
+
# ie.checkbox(:name, 'send_copy') # access the check box with a name of send_copy
|
464
|
+
# ie.checkbox(:name, /n_/ ) # access the first check box whose name matches n_
|
465
|
+
# ie.checkbox(:index, 2) # access the second check box on the page ( 1 based, so the first field is accessed with :index,1)
|
466
|
+
#
|
467
|
+
# In many instances, checkboxes on an html page have the same name, but are identified by different values. An example is shown next.
|
468
|
+
#
|
469
|
+
# <input type = checkbox name = email_frequency value = 'daily' > Daily Email
|
470
|
+
# <input type = checkbox name = email_frequency value = 'Weekly'> Weekly Email
|
471
|
+
# <input type = checkbox name = email_frequency value = 'monthly'>Monthly Email
|
472
|
+
#
|
473
|
+
# Watir can access these using the following:
|
474
|
+
#
|
475
|
+
# ie.checkbox(:id, 'day_to_send' , 'monday' ) # access the check box with an id of day_to_send and a value of monday
|
476
|
+
# ie.checkbox(:name ,'email_frequency', 'weekly') # access the check box with a name of email_frequency and a value of 'weekly'
|
477
|
+
def checkbox(how, what=nil ,value=nil)
|
478
|
+
return CheckBox.new(self, how, what, ["checkbox"], value)
|
479
|
+
end
|
480
|
+
|
481
|
+
# this is the method for accessing the check boxes iterator. Returns a CheckBoxes object
|
482
|
+
#
|
483
|
+
# Typical usage:
|
484
|
+
#
|
485
|
+
# ie.checkboxes.each { |c| puts c.to_s } # iterate through all the check boxes on the page
|
486
|
+
# ie.checkboxes[1].to_s # goto the first check box on the page
|
487
|
+
# ie.checkboxes.length # show how many check boxes are on the page.
|
488
|
+
def checkboxes
|
489
|
+
return CheckBoxes.new(self)
|
490
|
+
end
|
491
|
+
|
492
|
+
# This is the main method for accessing a radio button. Usually an <input type = radio> HTML tag.
|
493
|
+
# * how - symbol - how we access the radio button, :index, :id, :name etc
|
494
|
+
# * what - string, int or regexp , what we are looking for,
|
495
|
+
# * value - string - when there are multiple objects with different value attributes, this can be used to find the correct object
|
496
|
+
#
|
497
|
+
# returns a Radio object
|
498
|
+
#
|
499
|
+
# Valid values for 'how' are
|
500
|
+
#
|
501
|
+
# :index - find the item using the index in the container ( a container can be a document, a TableCell, a Span, a Div or a P
|
502
|
+
# index is 1 based
|
503
|
+
# :name - find the item using the name attribute
|
504
|
+
# :id - find the item using the id attribute
|
505
|
+
# :beforeText - finds the item immediately before the specified text
|
506
|
+
# :afterText - finds the item immediately after the specified text
|
507
|
+
#
|
508
|
+
# Typical usage
|
509
|
+
#
|
510
|
+
# ie.radio(:id, 'send_email') # access the radio button with an id of currency
|
511
|
+
# ie.radio(:name, 'send_copy') # access the radio button with a name of country
|
512
|
+
# ie.radio(:name, /n_/ ) # access the first radio button whose name matches n_
|
513
|
+
# ie.radio(:index, 2) # access the second radio button on the page ( 1 based, so the first field is accessed with :index,1)
|
514
|
+
#
|
515
|
+
# In many instances, radio buttons on an html page have the same name, but are identified by different values. An example is shown next.
|
516
|
+
#
|
517
|
+
# <input type = radio name = email_frequency value = 'daily' > Daily Email
|
518
|
+
# <input type = radio name = email_frequency value = 'Weekly'> Weekly Email
|
519
|
+
# <input type = radio name = email_frequency value = 'monthly'>Monthly Email
|
520
|
+
#
|
521
|
+
# Watir can access these using the following:
|
522
|
+
#
|
523
|
+
# ie.radio(:id, 'day_to_send' , 'monday' ) # access the radio button with an id of day_to_send and a value of monday
|
524
|
+
# ie.radio(:name ,'email_frequency', 'weekly') # access the radio button with a name of email_frequency and a value of 'weekly'
|
525
|
+
#
|
526
|
+
def radio(how, what=nil, value=nil)
|
527
|
+
return Radio.new(self, how, what, ["radio"], value)
|
528
|
+
end
|
529
|
+
|
530
|
+
# This is the method for accessing the radio buttons iterator. Returns a Radios object
|
531
|
+
#
|
532
|
+
# Typical usage:
|
533
|
+
#
|
534
|
+
# ie.radios.each { |r| puts r.to_s } # iterate through all the radio buttons on the page
|
535
|
+
# ie.radios[1].to_s # goto the first radio button on the page
|
536
|
+
# ie.radios.length # show how many radio buttons are on the page.
|
537
|
+
#
|
538
|
+
def radios
|
539
|
+
return Radios.new(self)
|
540
|
+
end
|
541
|
+
|
542
|
+
# This is the main method for accessing a link.
|
543
|
+
# * how - symbol - how we access the link, :index, :id, :name , :beforetext, :afterText, :title , :text , :url
|
544
|
+
# * what - string, int or re , what we are looking for
|
545
|
+
#
|
546
|
+
# returns a Link object
|
547
|
+
#
|
548
|
+
# Valid values for 'how' are
|
549
|
+
#
|
550
|
+
# :index - find the item using the index in the container ( a container can be a document, a TableCell, a Span, a Div or a P
|
551
|
+
# index is 1 based
|
552
|
+
# :name - find the item using the name attribute
|
553
|
+
# :id - find the item using the id attribute
|
554
|
+
# :beforeText - finds the item immediately before the specified text
|
555
|
+
# :afterText - finds the item immediately after the specified text
|
556
|
+
# :url - finds the link based on the url. This must be the full path to the link, so is best used with a regular expression
|
557
|
+
# :text - finds a link using the innerText of the link, ie the Text that is displayed to the user
|
558
|
+
# :title - finds the item using the tool tip text
|
559
|
+
#
|
560
|
+
# Typical Usage
|
561
|
+
#
|
562
|
+
# ie.link(:url, /login/) # access the first link whose url matches login. We can use a string in place of the regular expression
|
563
|
+
# # but the complete path must be used, ie.link(:url, 'http://myserver.com/my_path/login.asp')
|
564
|
+
# ie.link(:index,2) # access the second link on the page
|
565
|
+
# ie.link(:title , "Picture") # access a link using the tool tip
|
566
|
+
# ie.link(:text, 'Click Me') # access the link that has Click Me as its text
|
567
|
+
# ie.link(:afterText, 'Click->') # access the link that immediately follows the text Click->
|
568
|
+
#
|
569
|
+
def link(how, what=nil)
|
570
|
+
return Link.new(self, how, what)
|
571
|
+
end
|
572
|
+
|
573
|
+
# This is the main method for accessing the links collection. Returns a Links object
|
574
|
+
#
|
575
|
+
# Typical usage:
|
576
|
+
#
|
577
|
+
# ie.links.each { |l| puts l.to_s } # iterate through all the links on the page
|
578
|
+
# ie.links[1].to_s # goto the first link on the page
|
579
|
+
# ie.links.length # show how many links are on the page.
|
580
|
+
#
|
581
|
+
def links
|
582
|
+
return Links.new(self)
|
583
|
+
end
|
584
|
+
|
585
|
+
# This is the main method for accessing images - normally an <img src="image.gif"> HTML tag.
|
586
|
+
# * how - symbol - how we access the image, :index, :id, :name , :src or :alt are supported
|
587
|
+
# * what - string, int or re , what we are looking for,
|
588
|
+
#
|
589
|
+
# returns an Image object
|
590
|
+
#
|
591
|
+
# Valid values for 'how' are
|
592
|
+
#
|
593
|
+
# :index - find the item using the index in the container ( a container can be a document, a TableCell, a Span, a Div or a P
|
594
|
+
# index is 1 based
|
595
|
+
# :name - find the item using the name attribute
|
596
|
+
# :id - find the item using the id attribute
|
597
|
+
# :alt - finds the item using the tool tip text
|
598
|
+
# :src - finds the item using the src tag. This must be the fully qualified name, so is best used with a regular expression
|
599
|
+
#
|
600
|
+
# Typical Usage
|
601
|
+
#
|
602
|
+
# ie.image(:src, /myPic/) # access the first image that matches myPic. We can use a string in place of the regular expression
|
603
|
+
# # but the complete path must be used, ie.image(:src, 'http://myserver.com/my_path/my_image.jpg')
|
604
|
+
# ie.image(:index,2) # access the second image on the page
|
605
|
+
# ie.image(:alt , "A Picture") # access an image using the alt text
|
606
|
+
#
|
607
|
+
def image( how , what=nil)
|
608
|
+
return Image.new(self, how, what)
|
609
|
+
end
|
610
|
+
|
611
|
+
# This is the main method for accessing the images collection. Returns an Images object
|
612
|
+
#
|
613
|
+
# Typical usage:
|
614
|
+
#
|
615
|
+
# ie.images.each { |i| puts i.to_s } # iterate through all the images on the page
|
616
|
+
# ie.images[1].to_s # goto the first image on the page
|
617
|
+
# ie.images.length # show how many images are on the page.
|
618
|
+
#
|
619
|
+
def images
|
620
|
+
return Images.new(self)
|
621
|
+
end
|
622
|
+
|
623
|
+
# This is the main method for accessing JavaScript popups.
|
624
|
+
# returns a PopUp object
|
625
|
+
def popup
|
626
|
+
return PopUp.new(self )
|
627
|
+
end
|
628
|
+
|
629
|
+
# This is the main method for accessing divs. http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/div.asp?frame=true
|
630
|
+
# * how - symbol - how we access the div, :index, :id, :title
|
631
|
+
# * what - string, integer or re , what we are looking for,
|
632
|
+
#
|
633
|
+
# returns an Div object
|
634
|
+
#
|
635
|
+
# Typical Usage
|
636
|
+
#
|
637
|
+
# ie.div(:id, /list/) # access the first div that matches list.
|
638
|
+
# ie.div(:index,2) # access the second div on the page
|
639
|
+
# ie.div(:title , "A Picture") # access a div using the tooltip text. See http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/title_1.asp?frame=true
|
640
|
+
#
|
641
|
+
def div(how, what)
|
642
|
+
return Div.new(self, how, what)
|
643
|
+
end
|
644
|
+
|
645
|
+
# this is the main method for accessing the divs iterator. Returns a Divs object
|
646
|
+
#
|
647
|
+
# Typical usage:
|
648
|
+
#
|
649
|
+
# ie.divs.each { |d| puts d.to_s } # iterate through all the divs on the page
|
650
|
+
# ie.divs[1].to_s # goto the first div on the page
|
651
|
+
# ie.divs.length # show how many divs are on the page.
|
652
|
+
#
|
653
|
+
def divs
|
654
|
+
return Divs.new(self)
|
655
|
+
end
|
656
|
+
|
657
|
+
# This is the main method for accessing span tags - http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/span.asp?frame=true
|
658
|
+
# * how - symbol - how we access the span, :index, :id, :name
|
659
|
+
# * what - string, integer or re , what we are looking for,
|
660
|
+
#
|
661
|
+
# returns a Span object
|
662
|
+
#
|
663
|
+
# Typical Usage
|
664
|
+
#
|
665
|
+
# ie.span(:id, /list/) # access the first span that matches list.
|
666
|
+
# ie.span(:index,2) # access the second span on the page
|
667
|
+
# ie.span(:title , "A Picture") # access a span using the tooltip text. See http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/title_1.asp?frame=true
|
668
|
+
#
|
669
|
+
def span(how , what)
|
670
|
+
return Span.new(self, how, what)
|
671
|
+
end
|
672
|
+
|
673
|
+
# this is the main method for accessing the spans iterator.
|
674
|
+
#
|
675
|
+
# Returns a Spans object
|
676
|
+
#
|
677
|
+
# Typical usage:
|
678
|
+
#
|
679
|
+
# ie.spans.each { |s| puts s.to_s } # iterate through all the spans on the page
|
680
|
+
# ie.spans[1].to_s # goto the first span on the page
|
681
|
+
# ie.spans.length # show how many spans are on the page.
|
682
|
+
#
|
683
|
+
def spans
|
684
|
+
return Spans.new(self)
|
685
|
+
end
|
686
|
+
|
687
|
+
# This is the main method for accessing p tags - http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/p.asp?frame=true
|
688
|
+
# * how - symbol - how we access the p, :index, :id, :name
|
689
|
+
# * what - string, integer or re , what we are looking for,
|
690
|
+
#
|
691
|
+
# returns a P object
|
692
|
+
#
|
693
|
+
# Typical Usage
|
694
|
+
#
|
695
|
+
# ie.p(:id, /list/) # access the first p tag that matches list.
|
696
|
+
# ie.p(:index,2) # access the second p tag on the page
|
697
|
+
# ie.p(:title , "A Picture") # access a p tag using the tooltip text. See http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/title_1.asp?frame=true
|
698
|
+
#
|
699
|
+
def p(how, what)
|
700
|
+
return P.new(self , how , what)
|
701
|
+
end
|
702
|
+
|
703
|
+
# this is the main method for accessing the ps iterator.
|
704
|
+
#
|
705
|
+
# Returns a Ps object
|
706
|
+
#
|
707
|
+
# Typical usage:
|
708
|
+
#
|
709
|
+
# ie.ps.each { |p| puts p.to_s } # iterate through all the p tags on the page
|
710
|
+
# ie.ps[1].to_s # goto the first p tag on the page
|
711
|
+
# ie.ps.length # show how many p tags are on the page.
|
712
|
+
#
|
713
|
+
def ps
|
714
|
+
return Ps.new(self)
|
715
|
+
end
|
716
|
+
|
717
|
+
# This is the main method for accessing labels. http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/label.asp?frame=true
|
718
|
+
# * how - symbol - how we access the label, :index, :id, :for
|
719
|
+
# * what - string, integer or re , what we are looking for,
|
720
|
+
#
|
721
|
+
# returns a Label object
|
722
|
+
#
|
723
|
+
# Typical Usage
|
724
|
+
#
|
725
|
+
# ie.label(:id, /list/) # access the first span that matches list.
|
726
|
+
# ie.label(:index,2) # access the second label on the page
|
727
|
+
# ie.label(:for, "text_1") # access a the label that is associated with the object that has an id of text_1
|
728
|
+
#
|
729
|
+
def label(how, what)
|
730
|
+
return Label.new(self, how, what)
|
731
|
+
end
|
732
|
+
|
733
|
+
# this is the main method for accessing the labels iterator. It returns a Labels object
|
734
|
+
#
|
735
|
+
# Returns a Labels object
|
736
|
+
#
|
737
|
+
# Typical usage:
|
738
|
+
#
|
739
|
+
# ie.labels.each { |l| puts l.to_s } # iterate through all the labels on the page
|
740
|
+
# ie.labels[1].to_s # goto the first label on the page
|
741
|
+
# ie.labels.length # show how many labels are on the page.
|
742
|
+
#
|
743
|
+
def labels()
|
744
|
+
return Labels.new(self)
|
745
|
+
end
|
746
|
+
|
747
|
+
#--
|
748
|
+
#
|
749
|
+
# Searching for Page Elements
|
750
|
+
# Not for external consumption
|
751
|
+
#
|
752
|
+
#++
|
753
|
+
def getContainerContents()
|
754
|
+
return document.body.all
|
755
|
+
end
|
756
|
+
private :getContainerContents
|
757
|
+
|
758
|
+
# this method is used internally by Watir and should not be used externally.
|
759
|
+
# It cannot be marked as private because of the way mixins and inheritance work in watir.
|
760
|
+
# BUG: This looks wrong: Not everything that includes SupportsSubElements has a document.body!
|
761
|
+
def getContainer()
|
762
|
+
return document.body
|
763
|
+
end
|
764
|
+
|
765
|
+
# This is the main method for finding objects on a web page.
|
766
|
+
#
|
767
|
+
# This method is used internally by Watir and should not be used externally. It cannot be marked as private because of the way mixins and inheritance work in watir
|
768
|
+
#
|
769
|
+
# * how - symbol - the way we look for the object. Supported values are
|
770
|
+
# - :name
|
771
|
+
# - :id
|
772
|
+
# - :index
|
773
|
+
# - :value etc
|
774
|
+
# * what - string that we are looking for, ex. the name, or id tag attribute or index of the object we are looking for.
|
775
|
+
# * types - what object types we will look at. Only used when index is specified as the how.
|
776
|
+
# * value - used for objects that have one name, but many values. ex. radio lists and checkboxes
|
777
|
+
def getObject(how, what, types, value=nil)
|
778
|
+
container = getContainerContents # XXX actually this returns a collection object (not a container)
|
779
|
+
how = :value if how == :caption
|
780
|
+
log "getting object - how is #{how} what is #{what} types = #{types} value = #{value}"
|
781
|
+
|
782
|
+
o = nil
|
783
|
+
if how == :index
|
784
|
+
index = what.to_i
|
785
|
+
log" getting object #{types.to_s} at index( #{index}"
|
786
|
+
|
787
|
+
objectIndex = 1
|
788
|
+
container.each do | thisObject |
|
789
|
+
begin
|
790
|
+
this_type = thisObject.invoke("type")
|
791
|
+
rescue
|
792
|
+
this_type = nil
|
793
|
+
end
|
794
|
+
if types.include?(this_type)
|
795
|
+
if objectIndex == index
|
796
|
+
o = thisObject
|
797
|
+
break
|
798
|
+
end
|
799
|
+
objectIndex += 1
|
800
|
+
end
|
801
|
+
end
|
802
|
+
return o
|
803
|
+
|
804
|
+
else
|
805
|
+
container.each do |object|
|
806
|
+
next unless o == nil
|
807
|
+
|
808
|
+
begin
|
809
|
+
case how
|
810
|
+
when :id
|
811
|
+
attribute = object.invoke("id")
|
812
|
+
when :name
|
813
|
+
attribute = object.invoke("name")
|
814
|
+
when :value
|
815
|
+
attribute = object.value
|
816
|
+
when :alt
|
817
|
+
attribute = object.alt
|
818
|
+
when :src
|
819
|
+
attribute = object.src
|
820
|
+
when :beforeText
|
821
|
+
attribute = object.getAdjacentText("afterEnd").strip
|
822
|
+
when :afterText
|
823
|
+
attribute = object.getAdjacentText("beforeBegin").strip
|
824
|
+
else
|
825
|
+
next
|
826
|
+
end
|
827
|
+
|
828
|
+
if what.matches(attribute) && types.include?(object.invoke("type"))
|
829
|
+
if value
|
830
|
+
log "checking value supplied #{value} ( #{value.class}) actual #{object.value} ( #{object.value.class})"
|
831
|
+
if object.value.to_s == value.to_s
|
832
|
+
o = object
|
833
|
+
end
|
834
|
+
else # no value
|
835
|
+
o = object
|
836
|
+
end
|
837
|
+
end
|
838
|
+
|
839
|
+
rescue => e
|
840
|
+
log 'IE#getObject error ' + e.to_s
|
841
|
+
end
|
842
|
+
|
843
|
+
end
|
844
|
+
end
|
845
|
+
|
846
|
+
return o
|
847
|
+
end
|
848
|
+
|
849
|
+
# This method is used iternally by Watir and should not be used externally. It cannot be marked as private because of the way mixins and inheritance work in watir
|
850
|
+
#
|
851
|
+
# this method finds the specified image
|
852
|
+
# * how - symbol - how to look
|
853
|
+
# * what - string or regexp - what to look ofr
|
854
|
+
def getImage( how, what )
|
855
|
+
|
856
|
+
doc = document
|
857
|
+
count = 1
|
858
|
+
images = doc.all.tags("IMG")
|
859
|
+
o=nil
|
860
|
+
images.each do |img|
|
861
|
+
|
862
|
+
#puts "Image on page: src = #{img.src}"
|
863
|
+
|
864
|
+
next unless o == nil
|
865
|
+
if how == :index
|
866
|
+
o = img if count == what.to_i
|
867
|
+
else
|
868
|
+
case how
|
869
|
+
|
870
|
+
when :src
|
871
|
+
attribute = img.src
|
872
|
+
when :name
|
873
|
+
attribute = img.name
|
874
|
+
when :id
|
875
|
+
attribute = img.invoke("id")
|
876
|
+
when :alt
|
877
|
+
attribute = img.invoke("alt")
|
878
|
+
else
|
879
|
+
next
|
880
|
+
end
|
881
|
+
|
882
|
+
o = img if what.matches(attribute)
|
883
|
+
end
|
884
|
+
count +=1
|
885
|
+
end # do
|
886
|
+
return o
|
887
|
+
|
888
|
+
end
|
889
|
+
|
890
|
+
# This method is used iternally by Watir and should not be used externally. It cannot be marked as private because of the way mixins and inheritance work in watir
|
891
|
+
#
|
892
|
+
# This method gets a link from the document. This is a hyperlink, generally declared in the <a href="http://testsite">test site</a> HTML tag.
|
893
|
+
# * how - symbol - how we get the link Supported types are:
|
894
|
+
# :index - the link at position x , 1 based
|
895
|
+
# :url - get the link that has a url that matches. A regular expression match is performed
|
896
|
+
# :text - get link based on the supplied text. uses either a string or regular expression match
|
897
|
+
# * what - depends on how - an integer for index, a string or regexp for url and text
|
898
|
+
def getLink( how, what )
|
899
|
+
links = document.all.tags("A")
|
900
|
+
|
901
|
+
# Guard ensures watir won't crash if somehow the list of links is nil
|
902
|
+
if (links == nil)
|
903
|
+
raise UnknownObjectException, "Unknown Object in getLink: attempted to click a link when no links present"
|
904
|
+
end
|
905
|
+
|
906
|
+
link = nil
|
907
|
+
case how
|
908
|
+
when :index
|
909
|
+
begin
|
910
|
+
link = links[ (what-1).to_s ]
|
911
|
+
rescue
|
912
|
+
link=nil
|
913
|
+
end
|
914
|
+
|
915
|
+
when :url
|
916
|
+
links.each do |thisLink|
|
917
|
+
if what.matches(thisLink.href)
|
918
|
+
link = thisLink if link == nil
|
919
|
+
end
|
920
|
+
end
|
921
|
+
|
922
|
+
when :text
|
923
|
+
links.each do |thisLink|
|
924
|
+
if what.matches(thisLink.innerText.strip)
|
925
|
+
link = thisLink if link == nil
|
926
|
+
end
|
927
|
+
end
|
928
|
+
|
929
|
+
when :id
|
930
|
+
links.each do |thisLink|
|
931
|
+
if what.matches(thisLink.invoke("id"))
|
932
|
+
link = thisLink if link == nil
|
933
|
+
end
|
934
|
+
end
|
935
|
+
when :name
|
936
|
+
links.each do |thisLink|
|
937
|
+
if what.matches(thisLink.invoke("name"))
|
938
|
+
link = thisLink if link == nil
|
939
|
+
end
|
940
|
+
end
|
941
|
+
|
942
|
+
when :title
|
943
|
+
links.each do |thisLink|
|
944
|
+
if what.matches(thisLink.invoke("title"))
|
945
|
+
link = thisLink if link == nil
|
946
|
+
end
|
947
|
+
end
|
948
|
+
|
949
|
+
when :beforeText
|
950
|
+
links.each do |thisLink|
|
951
|
+
if what.matches(thisLink.getAdjacentText("afterEnd").strip)
|
952
|
+
link = thisLink if link == nil
|
953
|
+
end
|
954
|
+
end
|
955
|
+
|
956
|
+
when :afterText
|
957
|
+
links.each do |thisLink|
|
958
|
+
if what.matches(thisLink.getAdjacentText("beforeBegin").strip)
|
959
|
+
link = thisLink if link == nil
|
960
|
+
end
|
961
|
+
end
|
962
|
+
else
|
963
|
+
raise MissingWayOfFindingObjectException, "#{how.inspect} is an unknown way of finding a link ( #{what} )"
|
964
|
+
end
|
965
|
+
|
966
|
+
# if no link found, link will be a nil. This is OK. Actions taken on links (e.g. "click") should rescue
|
967
|
+
# the nil-related exceptions and provide useful information to the user.
|
968
|
+
return link
|
969
|
+
|
970
|
+
end
|
971
|
+
|
972
|
+
# This method is used iternally by Watir and should not be used externally. It cannot be marked as private because of the way mixins and inheritance work in watir
|
973
|
+
#
|
974
|
+
# This method gets a table row or cell
|
975
|
+
# * how - symbol - how we get the link row or cell types are:
|
976
|
+
# id
|
977
|
+
# * what - a string or regexp
|
978
|
+
def getTablePart( part , how , what )
|
979
|
+
doc = document
|
980
|
+
parts = doc.all.tags( part )
|
981
|
+
n = nil
|
982
|
+
parts.each do | p |
|
983
|
+
next unless n==nil
|
984
|
+
if what.matches( p.invoke("id") )
|
985
|
+
n = p
|
986
|
+
end
|
987
|
+
end
|
988
|
+
return n
|
989
|
+
end
|
990
|
+
|
991
|
+
# This method is used iternally by Watir and should not be used externally. It cannot be marked as private because of the way mixins and inheritance work in watir
|
992
|
+
#
|
993
|
+
# this method is used to get elements like SPAN or DIV
|
994
|
+
def getNonControlObject(part , how, what )
|
995
|
+
|
996
|
+
doc = document
|
997
|
+
parts = doc.all.tags( part )
|
998
|
+
n = nil
|
999
|
+
case how
|
1000
|
+
when :id
|
1001
|
+
attribute = "id"
|
1002
|
+
when :name
|
1003
|
+
attribute = "name"
|
1004
|
+
when :title
|
1005
|
+
attribute = "title"
|
1006
|
+
when :for # only applies to labels
|
1007
|
+
attribute = "htmlFor"
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
if attribute
|
1011
|
+
parts.each do | p |
|
1012
|
+
next unless n==nil
|
1013
|
+
n = p if what.matches( p.invoke(attribute) )
|
1014
|
+
end
|
1015
|
+
elsif how == :index
|
1016
|
+
count = 1
|
1017
|
+
parts.each do | p |
|
1018
|
+
next unless n==nil
|
1019
|
+
n = p if what == count
|
1020
|
+
count +=1
|
1021
|
+
end
|
1022
|
+
else
|
1023
|
+
raise MissingWayOfFindingObjectException, "unknown way of finding a #{ part} ( {what} )"
|
1024
|
+
end
|
1025
|
+
return n
|
1026
|
+
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
|
1032
|
+
# This class is the main Internet Explorer Controller
|
1033
|
+
# An instance of this must be created to access Internet Explorer.
|
1034
|
+
class IE
|
1035
|
+
include Watir::Exception
|
1036
|
+
include SupportsSubElements
|
1037
|
+
|
1038
|
+
# The revision number ( according to CVS )
|
1039
|
+
REVISION = "$Revision: 1.211.2.2 $"
|
1040
|
+
|
1041
|
+
# the Release number
|
1042
|
+
VERSION = "1.4.1"
|
1043
|
+
|
1044
|
+
# Used internally to determine when IE has finished loading a page
|
1045
|
+
READYSTATE_COMPLETE = 4
|
1046
|
+
|
1047
|
+
# The default delay when entering text on a web page.
|
1048
|
+
DEFAULT_TYPING_SPEED = 0.08
|
1049
|
+
|
1050
|
+
# The default time we wait after a page has loaded.
|
1051
|
+
DEFAULT_SLEEP_TIME = 0.1
|
1052
|
+
|
1053
|
+
# The default color for highlighting objects as they are accessed.
|
1054
|
+
DEFAULT_HIGHLIGHT_COLOR = "yellow"
|
1055
|
+
|
1056
|
+
# This is used to change the typing speed when entering text on a page.
|
1057
|
+
attr_accessor :typingspeed
|
1058
|
+
|
1059
|
+
# This is used to change how long after a page has finished loading that we wait for.
|
1060
|
+
attr_accessor :defaultSleepTime
|
1061
|
+
|
1062
|
+
# The color we want to use for the active object. This can be any valid web-friendly color.
|
1063
|
+
attr_accessor :activeObjectHighLightColor
|
1064
|
+
|
1065
|
+
# use this to switch the spinner on and off
|
1066
|
+
attr_accessor :enable_spinner
|
1067
|
+
|
1068
|
+
# use this to get the time for the last page download
|
1069
|
+
attr_reader :down_load_time
|
1070
|
+
|
1071
|
+
# When a new window is created it is stored in newWindow
|
1072
|
+
attr_accessor :newWindow
|
1073
|
+
|
1074
|
+
# Use this to gain access to the 'raw' internet explorer object.
|
1075
|
+
attr_reader :ie
|
1076
|
+
|
1077
|
+
# access to the logger object
|
1078
|
+
attr_accessor :logger
|
1079
|
+
|
1080
|
+
|
1081
|
+
# this contains the list of unique urls that have been visited
|
1082
|
+
attr_reader :url_list
|
1083
|
+
|
1084
|
+
def initialize(suppress_new_window=nil)
|
1085
|
+
unless suppress_new_window
|
1086
|
+
create_browser_window
|
1087
|
+
set_defaults
|
1088
|
+
end
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
# Create a new IE Window, starting at the specified url.
|
1092
|
+
# If no url is given, start empty.
|
1093
|
+
def IE.start( url = nil )
|
1094
|
+
ie = new
|
1095
|
+
ie.goto(url) if url
|
1096
|
+
return ie
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
# Attach to an existing IE window, either by url or title.
|
1100
|
+
# IE.attach(:url, 'http://www.google.com')
|
1101
|
+
# IE.attach(:title, 'Google')
|
1102
|
+
def IE.attach(how, what)
|
1103
|
+
ie = new(true) # don't create window
|
1104
|
+
ie.attach_init(how, what)
|
1105
|
+
return ie
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
# this method is used internally to attach to an existing window
|
1109
|
+
# dont make private
|
1110
|
+
def attach_init( how, what )
|
1111
|
+
attach_browser_window(how, what)
|
1112
|
+
set_defaults
|
1113
|
+
wait
|
1114
|
+
end
|
1115
|
+
|
1116
|
+
def set_defaults
|
1117
|
+
@form = nil
|
1118
|
+
|
1119
|
+
@enable_spinner = $ENABLE_SPINNER
|
1120
|
+
@error_checkers= []
|
1121
|
+
|
1122
|
+
@ie.visible = ! $HIDE_IE
|
1123
|
+
@activeObjectHighLightColor = DEFAULT_HIGHLIGHT_COLOR
|
1124
|
+
if $FAST_SPEED
|
1125
|
+
set_fast_speed
|
1126
|
+
else
|
1127
|
+
set_slow_speed
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
@logger = DefaultLogger.new()
|
1131
|
+
|
1132
|
+
@url_list = []
|
1133
|
+
|
1134
|
+
# add an error checker for http navigation errors, such as 404, 500 etc
|
1135
|
+
navigation_checker=Proc.new{ |ie|
|
1136
|
+
if ie.document.frames.length > 1
|
1137
|
+
1.upto ie.document.frames.length do |i|
|
1138
|
+
check_for_http_error(ie.frame(:index, i) )
|
1139
|
+
end
|
1140
|
+
else
|
1141
|
+
check_for_http_error(ie)
|
1142
|
+
end
|
1143
|
+
}
|
1144
|
+
|
1145
|
+
add_checker( navigation_checker )
|
1146
|
+
|
1147
|
+
end
|
1148
|
+
private :set_defaults
|
1149
|
+
|
1150
|
+
# This method checks the currently displayed page for http errors, 404, 500 etc
|
1151
|
+
# It gets called internally by the wait method, so a user does not need to call it explicitly
|
1152
|
+
def check_for_http_error(ie)
|
1153
|
+
url=ie.document.url
|
1154
|
+
#puts "url is " + url
|
1155
|
+
if /shdoclc.dll/.match(url)
|
1156
|
+
#puts "Match on shdoclc.dll"
|
1157
|
+
m = /id=IEText.*?>(.*?)</i.match(ie.html)
|
1158
|
+
if m
|
1159
|
+
#puts "Error is #{m[1]}"
|
1160
|
+
raise NavigationException , m[1]
|
1161
|
+
end
|
1162
|
+
end
|
1163
|
+
end
|
1164
|
+
|
1165
|
+
def set_fast_speed
|
1166
|
+
@typingspeed = 0
|
1167
|
+
@defaultSleepTime = 0.01
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
def set_slow_speed
|
1171
|
+
@typingspeed = DEFAULT_TYPING_SPEED
|
1172
|
+
@defaultSleepTime = DEFAULT_SLEEP_TIME
|
1173
|
+
end
|
1174
|
+
|
1175
|
+
def create_browser_window
|
1176
|
+
@ie = WIN32OLE.new('InternetExplorer.Application')
|
1177
|
+
end
|
1178
|
+
private :create_browser_window
|
1179
|
+
|
1180
|
+
def attach_browser_window( how, what )
|
1181
|
+
log "Seeking Window with #{how}: #{ what }"
|
1182
|
+
shell = WIN32OLE.new("Shell.Application")
|
1183
|
+
appWindows = shell.Windows()
|
1184
|
+
|
1185
|
+
ieTemp = nil
|
1186
|
+
appWindows.each do |aWin|
|
1187
|
+
log "Found a window: #{aWin}. "
|
1188
|
+
|
1189
|
+
case how
|
1190
|
+
when :url
|
1191
|
+
log " url is: #{aWin.locationURL}\n"
|
1192
|
+
ieTemp = aWin if (what.matches(aWin.locationURL) )
|
1193
|
+
when :title
|
1194
|
+
# normal windows explorer shells do not have document
|
1195
|
+
title = nil
|
1196
|
+
begin
|
1197
|
+
title = aWin.document.title
|
1198
|
+
rescue WIN32OLERuntimeError
|
1199
|
+
end
|
1200
|
+
ieTemp = aWin if (what.matches( title ) )
|
1201
|
+
else
|
1202
|
+
raise ArgumentError
|
1203
|
+
end
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
#if it can not find window
|
1207
|
+
if ieTemp == nil
|
1208
|
+
raise NoMatchingWindowFoundException,
|
1209
|
+
"Unable to locate a window with #{ how} of #{what}"
|
1210
|
+
end
|
1211
|
+
@ie = ieTemp
|
1212
|
+
end
|
1213
|
+
private :attach_browser_window
|
1214
|
+
|
1215
|
+
# deprecated: use logger= instead
|
1216
|
+
def set_logger( logger )
|
1217
|
+
@logger = logger
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
def log ( what )
|
1221
|
+
@logger.debug( what ) if @logger
|
1222
|
+
end
|
1223
|
+
|
1224
|
+
# Deprecated: Use IE#ie instead
|
1225
|
+
# This method returns the Internet Explorer object.
|
1226
|
+
# Methods, properties, etc. that the IE object does not support can be accessed.
|
1227
|
+
def getIE()
|
1228
|
+
return @ie
|
1229
|
+
end
|
1230
|
+
|
1231
|
+
#
|
1232
|
+
# Accessing data outside the document
|
1233
|
+
#
|
1234
|
+
|
1235
|
+
# Return the title of the window
|
1236
|
+
def title
|
1237
|
+
@ie.document.title
|
1238
|
+
end
|
1239
|
+
|
1240
|
+
# Return the status of the window, typically from the status bar at the bottom.
|
1241
|
+
def status
|
1242
|
+
raise NoStatusBarException if !@ie.statusBar
|
1243
|
+
return @ie.statusText()
|
1244
|
+
end
|
1245
|
+
|
1246
|
+
#
|
1247
|
+
# Navigation
|
1248
|
+
#
|
1249
|
+
|
1250
|
+
# Navigate to the specified URL.
|
1251
|
+
# * url - string - the URL to navigate to
|
1252
|
+
def goto( url )
|
1253
|
+
@ie.navigate(url)
|
1254
|
+
wait()
|
1255
|
+
sleep 0.2
|
1256
|
+
return @down_load_time
|
1257
|
+
end
|
1258
|
+
|
1259
|
+
# Go to the previous page - the same as clicking the browsers back button
|
1260
|
+
# an WIN32OLERuntimeError exception is raised if the browser cant go back
|
1261
|
+
def back
|
1262
|
+
@ie.GoBack()
|
1263
|
+
wait
|
1264
|
+
end
|
1265
|
+
|
1266
|
+
# Go to the next page - the same as clicking the browsers forward button
|
1267
|
+
# an WIN32OLERuntimeError exception is raised if the browser cant go forward
|
1268
|
+
def forward
|
1269
|
+
@ie.GoForward()
|
1270
|
+
wait
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
# Refresh the current page - the same as clicking the browsers refresh button
|
1274
|
+
# an WIN32OLERuntimeError exception is raised if the browser cant refresh
|
1275
|
+
def refresh
|
1276
|
+
@ie.refresh2(3)
|
1277
|
+
wait
|
1278
|
+
end
|
1279
|
+
|
1280
|
+
# clear the list of urls that we have visited
|
1281
|
+
def clear_url_list
|
1282
|
+
@url_list.clear
|
1283
|
+
end
|
1284
|
+
|
1285
|
+
# Closes the Browser
|
1286
|
+
def close
|
1287
|
+
@ie.quit
|
1288
|
+
end
|
1289
|
+
|
1290
|
+
# Maximize the window (expands to fill the screen)
|
1291
|
+
def maximize; set_window_state (:SW_MAXIMIZE); end
|
1292
|
+
|
1293
|
+
# Minimize the window (appears as icon on taskbar)
|
1294
|
+
def minimize; set_window_state (:SW_MINIMIZE); end
|
1295
|
+
|
1296
|
+
# Restore the window (after minimizing or maximizing)
|
1297
|
+
def restore; set_window_state (:SW_RESTORE); end
|
1298
|
+
|
1299
|
+
# Make the window come to the front
|
1300
|
+
def bring_to_front
|
1301
|
+
autoit = WIN32OLE.new('AutoItX3.Control')
|
1302
|
+
autoit.WinActivate title, ''
|
1303
|
+
end
|
1304
|
+
|
1305
|
+
def front?
|
1306
|
+
autoit = WIN32OLE.new('AutoItX3.Control')
|
1307
|
+
1 == autoit.WinActive(title, '')
|
1308
|
+
end
|
1309
|
+
|
1310
|
+
def set_window_state (state)
|
1311
|
+
autoit = WIN32OLE.new('AutoItX3.Control')
|
1312
|
+
autoit.WinSetState title, '', autoit.send(state)
|
1313
|
+
end
|
1314
|
+
private :set_window_state
|
1315
|
+
|
1316
|
+
# Send key events to IE window.
|
1317
|
+
# See http://www.autoitscript.com/autoit3/docs/appendix/SendKeys.htm
|
1318
|
+
# for complete documentation on keys supported and syntax.
|
1319
|
+
def send_keys (key_string)
|
1320
|
+
autoit = WIN32OLE.new 'AutoItX3.Control'
|
1321
|
+
autoit.WinActivate title
|
1322
|
+
autoit.Send key_string
|
1323
|
+
end
|
1324
|
+
|
1325
|
+
# used by the popup code only
|
1326
|
+
def dir
|
1327
|
+
return File.expand_path(File.dirname(__FILE__))
|
1328
|
+
end
|
1329
|
+
|
1330
|
+
#
|
1331
|
+
# Document and Document Data
|
1332
|
+
#
|
1333
|
+
|
1334
|
+
# Return the current document
|
1335
|
+
def document
|
1336
|
+
return @ie.document
|
1337
|
+
end
|
1338
|
+
|
1339
|
+
# returns the current url, as displayed in the address bar of the browser
|
1340
|
+
def url
|
1341
|
+
return @ie.LocationURL
|
1342
|
+
end
|
1343
|
+
|
1344
|
+
# Search the current page for specified text or regexp.
|
1345
|
+
# Returns true if the specified text was found.
|
1346
|
+
# Returns matchdata object if the specified regexp was found.
|
1347
|
+
# * text - string or regular expression - the string to look for
|
1348
|
+
def contains_text(text)
|
1349
|
+
returnValue = false
|
1350
|
+
retryCount = 0
|
1351
|
+
begin
|
1352
|
+
retryCount += 1
|
1353
|
+
returnValue =
|
1354
|
+
if text.kind_of? Regexp
|
1355
|
+
document.body.innerText.match(text)
|
1356
|
+
elsif text.kind_of? String
|
1357
|
+
document.body.innerText.index(text)
|
1358
|
+
else
|
1359
|
+
raise MissingWayOfFindingObjectException
|
1360
|
+
end
|
1361
|
+
rescue MissingWayOfFindingObjectException => e
|
1362
|
+
raise e
|
1363
|
+
rescue
|
1364
|
+
retry if retryCount < 2
|
1365
|
+
end
|
1366
|
+
return returnValue
|
1367
|
+
end
|
1368
|
+
|
1369
|
+
#
|
1370
|
+
# Synchronization
|
1371
|
+
#
|
1372
|
+
|
1373
|
+
# This method is used internally to cause an execution to stop until the page has loaded in Internet Explorer.
|
1374
|
+
def wait( noSleep = false )
|
1375
|
+
begin
|
1376
|
+
@down_load_time=0
|
1377
|
+
pageLoadStart = Time.now
|
1378
|
+
@pageHasReloaded= false
|
1379
|
+
|
1380
|
+
s= Spinner.new(@enable_spinner)
|
1381
|
+
while @ie.busy
|
1382
|
+
@pageHasReloaded = true
|
1383
|
+
sleep 0.02
|
1384
|
+
s.spin
|
1385
|
+
end
|
1386
|
+
s.reverse
|
1387
|
+
|
1388
|
+
log "wait: readystate=" + @ie.readyState.to_s
|
1389
|
+
until @ie.readyState == READYSTATE_COMPLETE
|
1390
|
+
@pageHasReloaded = true
|
1391
|
+
sleep 0.02
|
1392
|
+
s.spin
|
1393
|
+
end
|
1394
|
+
sleep 0.02
|
1395
|
+
|
1396
|
+
until @ie.document.readyState == "complete"
|
1397
|
+
sleep 0.02
|
1398
|
+
s.spin
|
1399
|
+
end
|
1400
|
+
|
1401
|
+
|
1402
|
+
if @ie.document.frames.length > 1
|
1403
|
+
begin
|
1404
|
+
0.upto @ie.document.frames.length-1 do |i|
|
1405
|
+
until @ie.document.frames[i.to_s].document.readyState == "complete"
|
1406
|
+
sleep 0.02
|
1407
|
+
s.spin
|
1408
|
+
end
|
1409
|
+
@url_list << @ie.document.frames[i.to_s].document.url unless url_list.include?(@ie.document.frames[i.to_s].document.url)
|
1410
|
+
end
|
1411
|
+
rescue=>e
|
1412
|
+
@logger.warn 'frame error in wait' + e.to_s + "\n" + e.backtrace.join("\n")
|
1413
|
+
end
|
1414
|
+
else
|
1415
|
+
@url_list << @ie.document.url unless @url_list.include?(@ie.document.url)
|
1416
|
+
end
|
1417
|
+
@down_load_time = Time.now - pageLoadStart
|
1418
|
+
|
1419
|
+
run_error_checks
|
1420
|
+
|
1421
|
+
print "\b" unless @enable_spinner == false
|
1422
|
+
|
1423
|
+
s=nil
|
1424
|
+
rescue WIN32OLERuntimeError => e
|
1425
|
+
@logger.info "runtime error in wait: #{e}\n#{e.backtrace.join("\\\n")}"
|
1426
|
+
end
|
1427
|
+
sleep 0.01
|
1428
|
+
sleep @defaultSleepTime unless noSleep == true
|
1429
|
+
end
|
1430
|
+
|
1431
|
+
# Error checkers
|
1432
|
+
|
1433
|
+
# this method runs the predefined error checks
|
1434
|
+
def run_error_checks
|
1435
|
+
@error_checkers.each do |e|
|
1436
|
+
e.call(self)
|
1437
|
+
end
|
1438
|
+
end
|
1439
|
+
|
1440
|
+
# this method is used to add an error checker that gets executed on every page load
|
1441
|
+
# * checker Proc Object, that contains the code to be run
|
1442
|
+
def add_checker( checker)
|
1443
|
+
@error_checkers << checker
|
1444
|
+
end
|
1445
|
+
|
1446
|
+
# this allows a checker to be disabled
|
1447
|
+
# * checker Proc Object, the checker that is to be disabled
|
1448
|
+
def disable_checker( checker )
|
1449
|
+
@error_checkers.delete(checker)
|
1450
|
+
end
|
1451
|
+
|
1452
|
+
# The HTML of the current page
|
1453
|
+
def html
|
1454
|
+
return document.body.outerHTML
|
1455
|
+
end
|
1456
|
+
|
1457
|
+
# The text of the current document
|
1458
|
+
def text
|
1459
|
+
return document.body.innerText.strip
|
1460
|
+
end
|
1461
|
+
|
1462
|
+
#
|
1463
|
+
# Show me state
|
1464
|
+
#
|
1465
|
+
|
1466
|
+
# This method is used to display the available html frames that Internet Explorer currently has loaded.
|
1467
|
+
# This method is usually only used for debugging test scripts.
|
1468
|
+
def show_frames
|
1469
|
+
if allFrames = document.frames
|
1470
|
+
count = allFrames.length
|
1471
|
+
puts "there are #{count} frames"
|
1472
|
+
for i in 0..count-1 do
|
1473
|
+
begin
|
1474
|
+
fname = allFrames[i.to_s].name.to_s
|
1475
|
+
puts "frame index: #{i+1} name: #{fname}"
|
1476
|
+
rescue => e
|
1477
|
+
puts "frame index: #{i+1} --Access Denied--" if e.to_s.match(/Access is denied/)
|
1478
|
+
end
|
1479
|
+
end
|
1480
|
+
else
|
1481
|
+
puts "no frames"
|
1482
|
+
end
|
1483
|
+
end
|
1484
|
+
|
1485
|
+
# Show all forms displays all the forms that are on a web page.
|
1486
|
+
def show_forms
|
1487
|
+
if allForms = document.forms
|
1488
|
+
count = allForms.length
|
1489
|
+
puts "There are #{count} forms"
|
1490
|
+
for i in 0..count-1 do
|
1491
|
+
wrapped = FormWrapper.new(allForms.item(i))
|
1492
|
+
puts "Form name: #{wrapped.name}"
|
1493
|
+
puts " id: #{wrapped.id}"
|
1494
|
+
puts " method: #{wrapped.method}"
|
1495
|
+
puts " action: #{wrapped.action}"
|
1496
|
+
end
|
1497
|
+
else
|
1498
|
+
puts "No forms"
|
1499
|
+
end
|
1500
|
+
end
|
1501
|
+
|
1502
|
+
# this method shows all the images availble in the document
|
1503
|
+
def show_images
|
1504
|
+
doc = document
|
1505
|
+
index=1
|
1506
|
+
doc.images.each do |l|
|
1507
|
+
puts "image: name: #{l.name}"
|
1508
|
+
puts " id: #{l.invoke("id")}"
|
1509
|
+
puts " src: #{l.src}"
|
1510
|
+
puts " index: #{index}"
|
1511
|
+
index+=1
|
1512
|
+
end
|
1513
|
+
end
|
1514
|
+
|
1515
|
+
# this method shows all the links availble in the document
|
1516
|
+
def show_links
|
1517
|
+
|
1518
|
+
props= ["name" ,"id" , "href" ]
|
1519
|
+
print_sizes= [12 , 12, 60]
|
1520
|
+
doc = document
|
1521
|
+
index=0
|
1522
|
+
text_size = 60
|
1523
|
+
# draw the table header
|
1524
|
+
s = "index".ljust(6)
|
1525
|
+
props.each_with_index do |p,i|
|
1526
|
+
s=s+ p.ljust(print_sizes[i])
|
1527
|
+
end
|
1528
|
+
s=s + "text/src".ljust(text_size)
|
1529
|
+
s=s+"\n"
|
1530
|
+
|
1531
|
+
# now get the details of the links
|
1532
|
+
doc.links.each do |n|
|
1533
|
+
index+=1
|
1534
|
+
s = s + index.to_s.ljust(6)
|
1535
|
+
props.each_with_index do |prop,i|
|
1536
|
+
printsize=print_sizes[i]
|
1537
|
+
begin
|
1538
|
+
p = n.invoke(prop)
|
1539
|
+
temp_var = "#{p}".to_s.ljust(printsize)
|
1540
|
+
rescue
|
1541
|
+
# this object probably doesnt have this property
|
1542
|
+
temp_var = "".to_s.ljust(printsize)
|
1543
|
+
end
|
1544
|
+
s =s+ temp_var
|
1545
|
+
end
|
1546
|
+
s=s+ n.innerText
|
1547
|
+
if n.getElementsByTagName("IMG").length > 0
|
1548
|
+
s=s+ " / " + n.getElementsByTagName("IMG")[0.to_s].src
|
1549
|
+
end
|
1550
|
+
s=s+"\n"
|
1551
|
+
end
|
1552
|
+
puts s
|
1553
|
+
end
|
1554
|
+
|
1555
|
+
# this method shows the name, id etc of the object that is currently active - ie the element that has focus
|
1556
|
+
# its mostly used in irb when creating a script
|
1557
|
+
def show_active
|
1558
|
+
s = ""
|
1559
|
+
|
1560
|
+
current = document.activeElement
|
1561
|
+
begin
|
1562
|
+
s=s+current.invoke("type").to_s.ljust(16)
|
1563
|
+
rescue
|
1564
|
+
end
|
1565
|
+
props=["name", "id", "value", "alt", "src", "innerText", "href"]
|
1566
|
+
props.each do |prop|
|
1567
|
+
begin
|
1568
|
+
p = current.invoke(prop)
|
1569
|
+
s =s+ " " + "#{prop}=#{p}".to_s.ljust(18)
|
1570
|
+
rescue
|
1571
|
+
#this object probably doesnt have this property
|
1572
|
+
end
|
1573
|
+
end
|
1574
|
+
s=s+"\n"
|
1575
|
+
end
|
1576
|
+
|
1577
|
+
# This method shows the available objects on the current page.
|
1578
|
+
# This is usually only used for debugging or writing new test scripts.
|
1579
|
+
# This is a nice feature to help find out what HTML objects are on a page
|
1580
|
+
# when developing a test case using Watir.
|
1581
|
+
def show_all_objects
|
1582
|
+
puts "-----------Objects in page -------------"
|
1583
|
+
doc = document
|
1584
|
+
s = ""
|
1585
|
+
props=["name" ,"id" , "value" , "alt" , "src"]
|
1586
|
+
doc.all.each do |n|
|
1587
|
+
begin
|
1588
|
+
s=s+n.invoke("type").to_s.ljust(16)
|
1589
|
+
rescue
|
1590
|
+
next
|
1591
|
+
end
|
1592
|
+
props.each do |prop|
|
1593
|
+
begin
|
1594
|
+
p = n.invoke(prop)
|
1595
|
+
s =s+ " " + "#{prop}=#{p}".to_s.ljust(18)
|
1596
|
+
rescue
|
1597
|
+
# this object probably doesnt have this property
|
1598
|
+
end
|
1599
|
+
end
|
1600
|
+
s=s+"\n"
|
1601
|
+
end
|
1602
|
+
puts s+"\n\n\n"
|
1603
|
+
end
|
1604
|
+
|
1605
|
+
# this method shows all the divs availble in the document
|
1606
|
+
def show_divs
|
1607
|
+
divs = document.getElementsByTagName("DIV")
|
1608
|
+
puts "Found #{divs.length} div tags"
|
1609
|
+
index=1
|
1610
|
+
divs.each do |d|
|
1611
|
+
puts "#{index} id=#{d.invoke('id')} class=#{d.invoke("className")}"
|
1612
|
+
index+=1
|
1613
|
+
end
|
1614
|
+
end
|
1615
|
+
|
1616
|
+
# this method is used to show all the tables that are available
|
1617
|
+
def show_tables
|
1618
|
+
tables = document.getElementsByTagName("TABLE")
|
1619
|
+
puts "Found #{tables.length} tables"
|
1620
|
+
index=1
|
1621
|
+
tables.each do |d|
|
1622
|
+
puts "#{index} id=#{d.invoke('id')} rows=#{d.rows.length} columns=#{d.rows["0"].cells.length }"
|
1623
|
+
index+=1
|
1624
|
+
end
|
1625
|
+
end
|
1626
|
+
|
1627
|
+
# this method shows all the spans availble in the document
|
1628
|
+
def show_spans
|
1629
|
+
spans = document.getElementsByTagName("SPAN")
|
1630
|
+
puts "Found #{spans.length} span tags"
|
1631
|
+
index=1
|
1632
|
+
spans.each do |d|
|
1633
|
+
puts "#{index} id=#{d.invoke('id')} class=#{d.invoke("className")}"
|
1634
|
+
index+=1
|
1635
|
+
end
|
1636
|
+
end
|
1637
|
+
|
1638
|
+
def show_labels
|
1639
|
+
labels = document.getElementsByTagName("LABEL")
|
1640
|
+
puts "Found #{labels.length} label tags"
|
1641
|
+
index=1
|
1642
|
+
labels.each do |d|
|
1643
|
+
puts "#{index} text=#{d.invoke('innerText')} class=#{d.invoke("className")} for=#{d.invoke("htmlFor")}"
|
1644
|
+
index+=1
|
1645
|
+
end
|
1646
|
+
end
|
1647
|
+
|
1648
|
+
#
|
1649
|
+
# This method gives focus to the frame
|
1650
|
+
# It may be removed and become part of the frame object
|
1651
|
+
def focus
|
1652
|
+
document.activeElement.blur
|
1653
|
+
document.focus
|
1654
|
+
end
|
1655
|
+
|
1656
|
+
end # class IE
|
1657
|
+
|
1658
|
+
#
|
1659
|
+
# MOVETO: watir/popup.rb
|
1660
|
+
# Module Watir::Popup
|
1661
|
+
#
|
1662
|
+
|
1663
|
+
# POPUP object
|
1664
|
+
class PopUp
|
1665
|
+
def initialize( ieController )
|
1666
|
+
@ieController = ieController
|
1667
|
+
end
|
1668
|
+
|
1669
|
+
def button( caption )
|
1670
|
+
return JSButton.new( @ieController.getIE.hwnd , caption )
|
1671
|
+
end
|
1672
|
+
end
|
1673
|
+
|
1674
|
+
class JSButton
|
1675
|
+
def initialize( hWnd , caption )
|
1676
|
+
@hWnd = hWnd
|
1677
|
+
@caption = caption
|
1678
|
+
end
|
1679
|
+
|
1680
|
+
def startClicker( waitTime = 3 )
|
1681
|
+
clicker = WinClicker.new
|
1682
|
+
clicker.clickJSDialog_Thread
|
1683
|
+
# clickerThread = Thread.new( @caption ) {
|
1684
|
+
# sleep waitTime
|
1685
|
+
# puts "After the wait time in startClicker"
|
1686
|
+
# clickWindowsButton_hwnd(hwnd , buttonCaption )
|
1687
|
+
#}
|
1688
|
+
end
|
1689
|
+
end
|
1690
|
+
|
1691
|
+
#
|
1692
|
+
# Module Watir::Control or Watir::BrowserDriver
|
1693
|
+
#
|
1694
|
+
|
1695
|
+
class Frame < IE
|
1696
|
+
|
1697
|
+
def initialize(container, how, what)
|
1698
|
+
@container = container
|
1699
|
+
@frame = nil
|
1700
|
+
|
1701
|
+
frames = @container.document.frames
|
1702
|
+
|
1703
|
+
for i in 0 .. frames.length-1
|
1704
|
+
next unless @frame == nil
|
1705
|
+
this_frame = frames.item(i)
|
1706
|
+
if how == :index
|
1707
|
+
if i+1 == what
|
1708
|
+
@frame = this_frame
|
1709
|
+
end
|
1710
|
+
elsif how == :name
|
1711
|
+
begin
|
1712
|
+
if what.matches(this_frame.name)
|
1713
|
+
@frame = this_frame
|
1714
|
+
end
|
1715
|
+
rescue # access denied?
|
1716
|
+
end
|
1717
|
+
elsif how == :id
|
1718
|
+
# BUG: Won't work for IFRAMES
|
1719
|
+
if what.matches(@container.document.getElementsByTagName("FRAME").item(i).invoke("id"))
|
1720
|
+
@frame = this_frame
|
1721
|
+
end
|
1722
|
+
else
|
1723
|
+
raise ArgumentError, "Argument #{how} not supported"
|
1724
|
+
end
|
1725
|
+
end
|
1726
|
+
|
1727
|
+
unless @frame
|
1728
|
+
raise UnknownFrameException , "Unable to locate a frame with name #{ what} "
|
1729
|
+
end
|
1730
|
+
|
1731
|
+
@typingspeed = container.typingspeed
|
1732
|
+
@activeObjectHighLightColor = container.activeObjectHighLightColor
|
1733
|
+
end
|
1734
|
+
|
1735
|
+
def ie
|
1736
|
+
return @frame
|
1737
|
+
end
|
1738
|
+
|
1739
|
+
def document
|
1740
|
+
@frame.document
|
1741
|
+
end
|
1742
|
+
|
1743
|
+
def wait(no_sleep = false)
|
1744
|
+
@container.wait(no_sleep)
|
1745
|
+
end
|
1746
|
+
end
|
1747
|
+
|
1748
|
+
|
1749
|
+
# Forms
|
1750
|
+
|
1751
|
+
module FormAccess
|
1752
|
+
def name
|
1753
|
+
@form.getAttributeNode('name').value
|
1754
|
+
end
|
1755
|
+
def action
|
1756
|
+
@form.action
|
1757
|
+
end
|
1758
|
+
def method
|
1759
|
+
@form.invoke('method')
|
1760
|
+
end
|
1761
|
+
def id
|
1762
|
+
@form.invoke("id").to_s
|
1763
|
+
end
|
1764
|
+
end
|
1765
|
+
|
1766
|
+
# wraps around a form OLE object
|
1767
|
+
class FormWrapper
|
1768
|
+
include FormAccess
|
1769
|
+
def initialize ( ole_object )
|
1770
|
+
@form = ole_object
|
1771
|
+
end
|
1772
|
+
end
|
1773
|
+
|
1774
|
+
# Form Factory object
|
1775
|
+
class Form < IE
|
1776
|
+
include FormAccess
|
1777
|
+
|
1778
|
+
attr_accessor :form
|
1779
|
+
|
1780
|
+
|
1781
|
+
# * container - the containing object, normally an instance of IE
|
1782
|
+
# * how - symbol - how we access the form (:name, :id, :index, :action, :method)
|
1783
|
+
# * what - what we use to access the form
|
1784
|
+
def initialize( container, how, what )
|
1785
|
+
@container = container
|
1786
|
+
@formHow = how
|
1787
|
+
@formName = what
|
1788
|
+
|
1789
|
+
log "Get form formHow is #{@formHow} formName is #{@formName} "
|
1790
|
+
count = 1
|
1791
|
+
doc = @container.document
|
1792
|
+
doc.forms.each do |thisForm|
|
1793
|
+
next unless @form == nil
|
1794
|
+
|
1795
|
+
wrapped = FormWrapper.new(thisForm)
|
1796
|
+
|
1797
|
+
log "form on page, name is " + wrapped.name
|
1798
|
+
|
1799
|
+
@form =
|
1800
|
+
case @formHow
|
1801
|
+
when :name
|
1802
|
+
wrapped.name == @formName ? thisForm : nil
|
1803
|
+
when :id
|
1804
|
+
wrapped.id == @formName.to_s ? thisForm : nil
|
1805
|
+
when :index
|
1806
|
+
count == @formName.to_i ? thisForm : nil
|
1807
|
+
when :method
|
1808
|
+
wrapped.method.downcase == @formName.downcase ? thisForm : nil
|
1809
|
+
when :action
|
1810
|
+
@formName.matches(wrapped.action) ? thisForm : nil
|
1811
|
+
else
|
1812
|
+
raise MissingWayOfFindingObjectException
|
1813
|
+
end
|
1814
|
+
count = count +1
|
1815
|
+
end
|
1816
|
+
|
1817
|
+
@typingspeed = @container.typingspeed
|
1818
|
+
@activeObjectHighLightColor = @container.activeObjectHighLightColor
|
1819
|
+
end
|
1820
|
+
|
1821
|
+
def exists?
|
1822
|
+
@form ? true : false
|
1823
|
+
end
|
1824
|
+
|
1825
|
+
# Submit the data -- equivalent to pressing Enter or Return to submit a form.
|
1826
|
+
def submit
|
1827
|
+
raise UnknownFormException , "Unable to locate a form using #{@formHow} and #{@formName} " if @form == nil
|
1828
|
+
@form.submit
|
1829
|
+
@container.wait
|
1830
|
+
end
|
1831
|
+
|
1832
|
+
def getContainerContents
|
1833
|
+
raise UnknownFormException , "Unable to locate a form using #{@formHow} and #{@formName} " if @form == nil
|
1834
|
+
@form.elements.all
|
1835
|
+
end
|
1836
|
+
private :getContainerContents
|
1837
|
+
|
1838
|
+
def getContainer
|
1839
|
+
return @form
|
1840
|
+
end
|
1841
|
+
|
1842
|
+
def wait(no_sleep = false)
|
1843
|
+
@container.wait(no_sleep)
|
1844
|
+
end
|
1845
|
+
|
1846
|
+
# This method is responsible for setting and clearing the colored highlighting on the specified form.
|
1847
|
+
# use :set to set the highlight
|
1848
|
+
# :clear to clear the highlight
|
1849
|
+
def highLight( setOrClear , element , count)
|
1850
|
+
|
1851
|
+
if setOrClear == :set
|
1852
|
+
begin
|
1853
|
+
original_color = element.style.backgroundColor
|
1854
|
+
original_color = "" if original_color== nil
|
1855
|
+
element.style.backgroundColor = activeObjectHighLightColor
|
1856
|
+
rescue => e
|
1857
|
+
puts e
|
1858
|
+
puts e.backtrace.join("\n")
|
1859
|
+
original_color = ""
|
1860
|
+
end
|
1861
|
+
@original_styles[ count ] = original_color
|
1862
|
+
else
|
1863
|
+
begin
|
1864
|
+
element.style.backgroundColor = @original_styles[ count]
|
1865
|
+
rescue => e
|
1866
|
+
puts e
|
1867
|
+
# we could be here for a number of reasons...
|
1868
|
+
ensure
|
1869
|
+
end
|
1870
|
+
end
|
1871
|
+
end
|
1872
|
+
private :highLight
|
1873
|
+
|
1874
|
+
# causes the object to flash. Normally used in IRB when creating scripts
|
1875
|
+
def flash
|
1876
|
+
@original_styles = {}
|
1877
|
+
10.times do
|
1878
|
+
count=0
|
1879
|
+
@form.elements.each do |element|
|
1880
|
+
highLight(:set , element , count)
|
1881
|
+
count +=1
|
1882
|
+
end
|
1883
|
+
sleep 0.05
|
1884
|
+
count = 0
|
1885
|
+
@form.elements.each do |element|
|
1886
|
+
highLight(:clear , element , count)
|
1887
|
+
count +=1
|
1888
|
+
end
|
1889
|
+
sleep 0.05
|
1890
|
+
end
|
1891
|
+
end
|
1892
|
+
|
1893
|
+
end # class Form
|
1894
|
+
|
1895
|
+
# Base class for most elements.
|
1896
|
+
# This is not a class that users would normally access.
|
1897
|
+
class Element
|
1898
|
+
include Watir::Exception
|
1899
|
+
|
1900
|
+
# number of spaces that seperate the property from the value in the to_s method
|
1901
|
+
TO_S_SIZE = 14
|
1902
|
+
|
1903
|
+
# o - the ole object for the element being wrapped
|
1904
|
+
def initialize( o )
|
1905
|
+
@o = o
|
1906
|
+
@originalColor = nil
|
1907
|
+
end
|
1908
|
+
|
1909
|
+
private
|
1910
|
+
def self.def_wrap(method_name)
|
1911
|
+
class_eval "def #{method_name}
|
1912
|
+
assert_exists
|
1913
|
+
@o.invoke('#{method_name}')
|
1914
|
+
end"
|
1915
|
+
end
|
1916
|
+
def self.def_wrap_guard(method_name)
|
1917
|
+
class_eval "def #{method_name}
|
1918
|
+
assert_exists
|
1919
|
+
begin
|
1920
|
+
@o.invoke('#{method_name}')
|
1921
|
+
rescue
|
1922
|
+
''
|
1923
|
+
end
|
1924
|
+
end"
|
1925
|
+
end
|
1926
|
+
def assert_exists
|
1927
|
+
unless @o
|
1928
|
+
raise UnknownObjectException.new("Unable to locate object, using #{@how} and #{@what}")
|
1929
|
+
end
|
1930
|
+
end
|
1931
|
+
def assert_enabled
|
1932
|
+
unless enabled?
|
1933
|
+
raise ObjectDisabledException, "object #{@how} and #{@what} is disabled"
|
1934
|
+
end
|
1935
|
+
end
|
1936
|
+
|
1937
|
+
public
|
1938
|
+
def_wrap_guard :type
|
1939
|
+
def_wrap_guard :name
|
1940
|
+
def_wrap :id
|
1941
|
+
def_wrap :disabled
|
1942
|
+
def_wrap_guard :value
|
1943
|
+
def_wrap_guard :title
|
1944
|
+
|
1945
|
+
# returns the Object in its OLE form, allowing any methods of the DOM that Watir doesnt support to be used
|
1946
|
+
#--
|
1947
|
+
# BUG: should be renamed appropriately and then use an attribute reader
|
1948
|
+
#++
|
1949
|
+
def getOLEObject
|
1950
|
+
return @o
|
1951
|
+
end
|
1952
|
+
|
1953
|
+
# returns the outer html of the object - see http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/outerhtml.asp?frame=true
|
1954
|
+
def html
|
1955
|
+
assert_exists
|
1956
|
+
return @o.outerHTML
|
1957
|
+
end
|
1958
|
+
|
1959
|
+
# Returns an array with many of the properties, in a format to be used by the to_s method
|
1960
|
+
def string_creator
|
1961
|
+
n = []
|
1962
|
+
n << "type:".ljust(TO_S_SIZE) + self.type
|
1963
|
+
n << "id:".ljust(TO_S_SIZE) + self.id.to_s
|
1964
|
+
n << "name:".ljust(TO_S_SIZE) + self.name.to_s
|
1965
|
+
n << "value:".ljust(TO_S_SIZE) + self.value.to_s
|
1966
|
+
n << "disabled:".ljust(TO_S_SIZE) + self.disabled.to_s
|
1967
|
+
return n
|
1968
|
+
end
|
1969
|
+
|
1970
|
+
# This method displays basic details about the object. Sample output for a button is shown.
|
1971
|
+
# Raises UnknownObjectException if the object is not found.
|
1972
|
+
# name b4
|
1973
|
+
# type button
|
1974
|
+
# id b5
|
1975
|
+
# value Disabled Button
|
1976
|
+
# disabled true
|
1977
|
+
def to_s
|
1978
|
+
assert_exists
|
1979
|
+
return string_creator.join("\n")
|
1980
|
+
end
|
1981
|
+
|
1982
|
+
# This method is responsible for setting and clearing the colored highlighting on the currently active element.
|
1983
|
+
# use :set to set the highlight
|
1984
|
+
# :clear to clear the highlight
|
1985
|
+
def highLight( setOrClear )
|
1986
|
+
if setOrClear == :set
|
1987
|
+
begin
|
1988
|
+
@originalColor = @o.style.backgroundColor
|
1989
|
+
@o.style.backgroundColor = @ieController.activeObjectHighLightColor
|
1990
|
+
rescue
|
1991
|
+
@originalColor = nil
|
1992
|
+
end
|
1993
|
+
else # BUG: assumes is :clear, but could actually be anything
|
1994
|
+
begin
|
1995
|
+
@o.style.backgroundColor = @originalColor unless @originalColor == nil
|
1996
|
+
rescue
|
1997
|
+
# we could be here for a number of reasons...
|
1998
|
+
ensure
|
1999
|
+
@originalColor = nil
|
2000
|
+
end
|
2001
|
+
end
|
2002
|
+
end
|
2003
|
+
private :highLight
|
2004
|
+
|
2005
|
+
# This method clicks the active element.
|
2006
|
+
# raises: UnknownObjectException if the object is not found
|
2007
|
+
# ObjectDisabledException if the object is currently disabled
|
2008
|
+
def click
|
2009
|
+
assert_exists
|
2010
|
+
assert_enabled
|
2011
|
+
|
2012
|
+
highLight(:set)
|
2013
|
+
@o.click()
|
2014
|
+
@ieController.wait()
|
2015
|
+
highLight(:clear)
|
2016
|
+
end
|
2017
|
+
|
2018
|
+
# causes the object to flash. Normally used in IRB when creating scripts
|
2019
|
+
def flash
|
2020
|
+
assert_exists
|
2021
|
+
10.times do
|
2022
|
+
highLight(:set)
|
2023
|
+
sleep 0.05
|
2024
|
+
highLight(:clear)
|
2025
|
+
sleep 0.05
|
2026
|
+
end
|
2027
|
+
nil
|
2028
|
+
end
|
2029
|
+
|
2030
|
+
# This method executes a user defined "fireEvent" for objects with JavaScript events tied to them such as DHTML menus.
|
2031
|
+
# usage: allows a generic way to fire javascript events on page objects such as "onMouseOver", "onClick", etc.
|
2032
|
+
# raises: UnknownObjectException if the object is not found
|
2033
|
+
# ObjectDisabledException if the object is currently disabled
|
2034
|
+
def fireEvent(event)
|
2035
|
+
assert_exists
|
2036
|
+
assert_enabled
|
2037
|
+
|
2038
|
+
highLight(:set)
|
2039
|
+
@o.fireEvent(event)
|
2040
|
+
@ieController.wait()
|
2041
|
+
highLight(:clear)
|
2042
|
+
end
|
2043
|
+
alias fire_event fireEvent
|
2044
|
+
|
2045
|
+
# This method sets focus on the active element.
|
2046
|
+
# raises: UnknownObjectException if the object is not found
|
2047
|
+
# ObjectDisabledException if the object is currently disabled
|
2048
|
+
def focus()
|
2049
|
+
assert_exists
|
2050
|
+
assert_enabled
|
2051
|
+
@o.focus()
|
2052
|
+
end
|
2053
|
+
|
2054
|
+
# This methods checks to see if the current element actually exists.
|
2055
|
+
def exists?
|
2056
|
+
@o? true: false
|
2057
|
+
end
|
2058
|
+
|
2059
|
+
# Returns true if the element is enabled, false if it isn't.
|
2060
|
+
# raises: UnknownObjectException if the object is not found
|
2061
|
+
def enabled?
|
2062
|
+
assert_exists
|
2063
|
+
return ! @o.invoke("disabled")
|
2064
|
+
end
|
2065
|
+
end
|
2066
|
+
|
2067
|
+
|
2068
|
+
# this class is the super class for the iterator classes ( buttons, links, spans etc
|
2069
|
+
# it would normally only be accessed by the iterator methods ( spans , links etc) of IE
|
2070
|
+
class ElementCollections
|
2071
|
+
include Enumerable
|
2072
|
+
|
2073
|
+
# Super class for all the iteractor classes
|
2074
|
+
# * ieController - an instance of an IE object
|
2075
|
+
def initialize( ieController)
|
2076
|
+
@ieController = ieController
|
2077
|
+
@length = length() # defined by subclasses
|
2078
|
+
|
2079
|
+
# set up the items we want to display when the show method s used
|
2080
|
+
set_show_items
|
2081
|
+
end
|
2082
|
+
|
2083
|
+
def set_show_items
|
2084
|
+
@show_attributes = AttributeLengthPairs.new( "id" , 20)
|
2085
|
+
@show_attributes.add( "name" , 20)
|
2086
|
+
end
|
2087
|
+
|
2088
|
+
def get_length_of_input_objects(object_type)
|
2089
|
+
object_types =
|
2090
|
+
if object_type.kind_of? Array
|
2091
|
+
object_type
|
2092
|
+
else
|
2093
|
+
[ object_type ]
|
2094
|
+
end
|
2095
|
+
|
2096
|
+
length = 0
|
2097
|
+
objects = @ieController.getContainer.getElementsByTagName("INPUT")
|
2098
|
+
if objects.length > 0
|
2099
|
+
objects.each do |o|
|
2100
|
+
length += 1 if object_types.include?(o.invoke("type").downcase )
|
2101
|
+
end
|
2102
|
+
end
|
2103
|
+
return length
|
2104
|
+
end
|
2105
|
+
|
2106
|
+
# iterate through each of the elements in the collection in turn
|
2107
|
+
def each
|
2108
|
+
0.upto( @length-1 ) { |i | yield iterator_object(i) }
|
2109
|
+
end
|
2110
|
+
|
2111
|
+
# allows access to a specific item in the collection
|
2112
|
+
def [](n)
|
2113
|
+
return iterator_object(n-1)
|
2114
|
+
end
|
2115
|
+
|
2116
|
+
# this method is the way to show the objects, normally used from irb
|
2117
|
+
def show
|
2118
|
+
s="index".ljust(6)
|
2119
|
+
@show_attributes.each do |attribute_length_pair|
|
2120
|
+
s=s + attribute_length_pair.attribute.ljust(attribute_length_pair.length)
|
2121
|
+
end
|
2122
|
+
|
2123
|
+
index = 1
|
2124
|
+
self.each do |o|
|
2125
|
+
s= s+"\n"
|
2126
|
+
s=s + index.to_s.ljust(6)
|
2127
|
+
@show_attributes.each do |attribute_length_pair|
|
2128
|
+
begin
|
2129
|
+
s=s + eval( 'o.getOLEObject.invoke("#{attribute_length_pair.attribute}")').to_s.ljust( attribute_length_pair.length )
|
2130
|
+
rescue=>e
|
2131
|
+
s=s+ " ".ljust( attribute_length_pair.length )
|
2132
|
+
end
|
2133
|
+
end
|
2134
|
+
index+=1
|
2135
|
+
end
|
2136
|
+
puts s
|
2137
|
+
end
|
2138
|
+
|
2139
|
+
# this method creates an object of the correct type that the iterators use
|
2140
|
+
private
|
2141
|
+
def iterator_object(i)
|
2142
|
+
element_class.new(@ieController, :index, i+1)
|
2143
|
+
end
|
2144
|
+
end
|
2145
|
+
|
2146
|
+
# this class contains items that are common between the span and div objects
|
2147
|
+
# it would not normally be used directly
|
2148
|
+
#
|
2149
|
+
# many of the methods available to this object are inherited from the Element class
|
2150
|
+
#
|
2151
|
+
class SpanDivCommon < Element
|
2152
|
+
include Watir::Exception
|
2153
|
+
include SupportsSubElements
|
2154
|
+
|
2155
|
+
attr_reader :typingspeed
|
2156
|
+
|
2157
|
+
def initialize( ieController, how , what )
|
2158
|
+
@ieController = ieController
|
2159
|
+
@how = how
|
2160
|
+
@what = what
|
2161
|
+
@o = @ieController.getNonControlObject(tag , @how, @what )
|
2162
|
+
super( @o )
|
2163
|
+
@typingspeed = @ieController.typingspeed
|
2164
|
+
@activeObjectHighLightColor = @ieController.activeObjectHighLightColor
|
2165
|
+
end
|
2166
|
+
|
2167
|
+
def getContainerContents()
|
2168
|
+
return @o.all
|
2169
|
+
end
|
2170
|
+
private :getContainerContents
|
2171
|
+
|
2172
|
+
def getContainer()
|
2173
|
+
return @o
|
2174
|
+
end
|
2175
|
+
|
2176
|
+
# this method returns the innerText of the object
|
2177
|
+
# raises an ObjectNotFound exception if the object cannot be found
|
2178
|
+
def text
|
2179
|
+
assert_exists
|
2180
|
+
return @o.innerText.strip
|
2181
|
+
end
|
2182
|
+
|
2183
|
+
# returns the class name of the span or div is using
|
2184
|
+
# raises an ObjectNotFound exception if the object cannot be found
|
2185
|
+
def class_name
|
2186
|
+
assert_exists
|
2187
|
+
return @o.invoke("className")
|
2188
|
+
end
|
2189
|
+
|
2190
|
+
# this method returns the type of object
|
2191
|
+
# raises an ObjectNotFound exception if the object cannot be found
|
2192
|
+
def type
|
2193
|
+
assert_exists
|
2194
|
+
return self.class.name[self.class.name.index("::")+2 .. self.class.name.length ]
|
2195
|
+
end
|
2196
|
+
|
2197
|
+
# this method is used to populate the properties in the to_s method
|
2198
|
+
def span_div_string_creator
|
2199
|
+
n = []
|
2200
|
+
n << "class:".ljust(TO_S_SIZE) + self.class_name
|
2201
|
+
n << "text:".ljust(TO_S_SIZE) + self.text
|
2202
|
+
return n
|
2203
|
+
end
|
2204
|
+
private :span_div_string_creator
|
2205
|
+
|
2206
|
+
# returns the properties of the object in a string
|
2207
|
+
# raises an ObjectNotFound exception if the object cannot be found
|
2208
|
+
def to_s
|
2209
|
+
assert_exists
|
2210
|
+
r = string_creator
|
2211
|
+
r=r + span_div_string_creator
|
2212
|
+
return r.join("\n")
|
2213
|
+
end
|
2214
|
+
end
|
2215
|
+
|
2216
|
+
class P < SpanDivCommon
|
2217
|
+
TAG = 'P'
|
2218
|
+
def tag; TAG; end
|
2219
|
+
def self.tag; TAG; end
|
2220
|
+
end
|
2221
|
+
|
2222
|
+
# this class is used to deal with Div tags in the html page. http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/div.asp?frame=true
|
2223
|
+
# It would not normally be created by users
|
2224
|
+
class Div < SpanDivCommon
|
2225
|
+
TAG = 'DIV'
|
2226
|
+
def tag; TAG; end
|
2227
|
+
def self.tag; TAG; end
|
2228
|
+
end
|
2229
|
+
|
2230
|
+
# this class is used to deal with Span tags in the html page. It would not normally be created by users
|
2231
|
+
class Span < SpanDivCommon
|
2232
|
+
TAG = 'SPAN'
|
2233
|
+
def tag; TAG; end
|
2234
|
+
def self.tag; TAG; end
|
2235
|
+
end
|
2236
|
+
|
2237
|
+
# this class is used to access a label object on the html page - http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/label.asp?frame=true
|
2238
|
+
#
|
2239
|
+
# many of the methods available to this object are inherited from the Element class
|
2240
|
+
#
|
2241
|
+
class Label < Element
|
2242
|
+
def initialize( ieController , how, what)
|
2243
|
+
@ieController = ieController
|
2244
|
+
@how = how
|
2245
|
+
@what = what
|
2246
|
+
@o = @ieController.getNonControlObject("LABEL" , @how, @what )
|
2247
|
+
super( @o )
|
2248
|
+
end
|
2249
|
+
|
2250
|
+
# return the type of this object
|
2251
|
+
def type
|
2252
|
+
assert_exists
|
2253
|
+
return "Label"
|
2254
|
+
end
|
2255
|
+
|
2256
|
+
# return the ID of the control that this label is associated with
|
2257
|
+
def for
|
2258
|
+
assert_exists
|
2259
|
+
return @o.htmlFor
|
2260
|
+
end
|
2261
|
+
|
2262
|
+
def text
|
2263
|
+
assert_exists
|
2264
|
+
return @o.innerText.strip
|
2265
|
+
end
|
2266
|
+
alias innerText :text
|
2267
|
+
|
2268
|
+
# this method is used to populate the properties in the to_s method
|
2269
|
+
def label_string_creator
|
2270
|
+
n = []
|
2271
|
+
n << "for:".ljust(TO_S_SIZE) + self.for
|
2272
|
+
n << "inner text:".ljust(TO_S_SIZE) + self.innerText
|
2273
|
+
return n
|
2274
|
+
end
|
2275
|
+
private :label_string_creator
|
2276
|
+
|
2277
|
+
# returns the properties of the object in a string
|
2278
|
+
# raises an ObjectNotFound exception if the object cannot be found
|
2279
|
+
def to_s
|
2280
|
+
assert_exists
|
2281
|
+
r = string_creator
|
2282
|
+
r=r + label_string_creator
|
2283
|
+
return r.join("\n")
|
2284
|
+
end
|
2285
|
+
|
2286
|
+
end
|
2287
|
+
|
2288
|
+
# This class is used for dealing with tables.
|
2289
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#table method
|
2290
|
+
#
|
2291
|
+
# many of the methods available to this object are inherited from the Element class
|
2292
|
+
#
|
2293
|
+
class Table < Element
|
2294
|
+
|
2295
|
+
# Returns an initialized instance of the table object to wich anElement belongs
|
2296
|
+
# * ieController - an instance of an IE object
|
2297
|
+
# * anElement - a Watir object (TextField, Button, etc.)
|
2298
|
+
def Table.create_from_element(ieController,anElement)
|
2299
|
+
o = anElement.getOLEObject.parentElement
|
2300
|
+
while(o && o.tagName != 'TABLE')
|
2301
|
+
o = o.parentElement
|
2302
|
+
end
|
2303
|
+
return Table.new(ieController,:from_object,o)
|
2304
|
+
end
|
2305
|
+
|
2306
|
+
# Returns an initialized instance of a table object
|
2307
|
+
# * parent - an instance of an IEController ( or a frame etc )
|
2308
|
+
# * how - symbol - how we access the table
|
2309
|
+
# * what - what we use to access the table - id, name index etc
|
2310
|
+
def initialize( parent, how , what )
|
2311
|
+
@ieController = parent
|
2312
|
+
@how = how
|
2313
|
+
@what = what
|
2314
|
+
|
2315
|
+
table = nil
|
2316
|
+
|
2317
|
+
if(@how != :from_object) then
|
2318
|
+
table=get_table
|
2319
|
+
else
|
2320
|
+
table = @what
|
2321
|
+
end
|
2322
|
+
|
2323
|
+
parent.log "table - #{@what}, #{@how} Not found " if table == nil
|
2324
|
+
@o = table
|
2325
|
+
super( @o )
|
2326
|
+
end
|
2327
|
+
|
2328
|
+
# ---
|
2329
|
+
# BUG: should be private
|
2330
|
+
# +++
|
2331
|
+
# this method finds the specified table on the page
|
2332
|
+
def get_table
|
2333
|
+
allTables = @ieController.document.getElementsByTagName("TABLE")
|
2334
|
+
@ieController.log "There are #{ allTables.length } tables"
|
2335
|
+
tableIndex = 1
|
2336
|
+
table=nil
|
2337
|
+
allTables.each do |t|
|
2338
|
+
next unless table == nil
|
2339
|
+
case @how
|
2340
|
+
when :id
|
2341
|
+
if @what.matches( t.invoke("id").to_s )
|
2342
|
+
table = t
|
2343
|
+
end
|
2344
|
+
when :index
|
2345
|
+
if tableIndex == @what.to_i
|
2346
|
+
table = t
|
2347
|
+
end
|
2348
|
+
end
|
2349
|
+
tableIndex = tableIndex + 1
|
2350
|
+
end
|
2351
|
+
return table
|
2352
|
+
end
|
2353
|
+
|
2354
|
+
|
2355
|
+
# override the highlight method, as if the tables rows are set to have a background color,
|
2356
|
+
# this will override the table background color, and the normal flsh method wont work
|
2357
|
+
def highLight(setOrClear )
|
2358
|
+
|
2359
|
+
if setOrClear == :set
|
2360
|
+
begin
|
2361
|
+
@original_border = @o.border.to_i
|
2362
|
+
if @o.border.to_i==1
|
2363
|
+
@o.border = 2
|
2364
|
+
else
|
2365
|
+
@o.border=1
|
2366
|
+
end
|
2367
|
+
rescue
|
2368
|
+
@original_border = nil
|
2369
|
+
end
|
2370
|
+
else
|
2371
|
+
begin
|
2372
|
+
@o.border= @original_border unless @original_border == nil
|
2373
|
+
@original_border = nil
|
2374
|
+
rescue
|
2375
|
+
# we could be here for a number of reasons...
|
2376
|
+
ensure
|
2377
|
+
@original_border = nil
|
2378
|
+
end
|
2379
|
+
end
|
2380
|
+
super
|
2381
|
+
end
|
2382
|
+
|
2383
|
+
# this method is used to ppulate the properties in the to_s method
|
2384
|
+
def table_string_creator
|
2385
|
+
n = []
|
2386
|
+
n << "rows:".ljust(TO_S_SIZE) + self.row_count.to_s
|
2387
|
+
n << "cols:".ljust(TO_S_SIZE) + self.column_count.to_s
|
2388
|
+
return n
|
2389
|
+
end
|
2390
|
+
private :table_string_creator
|
2391
|
+
|
2392
|
+
# returns the properties of the object in a string
|
2393
|
+
# raises an ObjectNotFound exception if the object cannot be found
|
2394
|
+
def to_s
|
2395
|
+
assert_exists
|
2396
|
+
r = string_creator
|
2397
|
+
r=r + table_string_creator
|
2398
|
+
return r.join("\n")
|
2399
|
+
end
|
2400
|
+
|
2401
|
+
# iterates through the rows in the table. Yields a TableRow object
|
2402
|
+
def each
|
2403
|
+
assert_exists
|
2404
|
+
1.upto( @o.getElementsByTagName("TR").length ) { |i | yield TableRow.new(@ieController ,:direct, row(i) ) }
|
2405
|
+
end
|
2406
|
+
|
2407
|
+
# Returns a row in the table
|
2408
|
+
# * index - the index of the row
|
2409
|
+
def [](index)
|
2410
|
+
raise UnknownTableException , "Unable to locate a table using #{@how} and #{@what} " if @o == nil
|
2411
|
+
return TableRow.new(@ieController ,:direct, row(index) )
|
2412
|
+
end
|
2413
|
+
|
2414
|
+
# This method returns the number of rows in the table.
|
2415
|
+
# Raises an UnknownTableException if the table doesnt exist.
|
2416
|
+
def row_count
|
2417
|
+
raise UnknownTableException , "Unable to locate a table using #{@how} and #{@what} " if @o == nil
|
2418
|
+
#return table_body.children.length
|
2419
|
+
return @o.getElementsByTagName("TR").length
|
2420
|
+
end
|
2421
|
+
|
2422
|
+
# This method returns the number of columns in a row of the table.
|
2423
|
+
# Raises an UnknownTableException if the table doesn't exist.
|
2424
|
+
# * index - the index of the row
|
2425
|
+
def column_count(index=1)
|
2426
|
+
raise UnknownTableException , "Unable to locate a table using #{@how} and #{@what} " if @o == nil
|
2427
|
+
row(index).cells.length
|
2428
|
+
end
|
2429
|
+
|
2430
|
+
# This method returns the table as a 2 dimensional array. Dont expect too much if there are nested tables, colspan etc.
|
2431
|
+
# Raises an UnknownTableException if the table doesn't exist.
|
2432
|
+
def to_a
|
2433
|
+
raise UnknownTableException , "Unable to locate a table using #{@how} and #{@what} " if @o == nil
|
2434
|
+
y = []
|
2435
|
+
table_rows = @o.getElementsByTagName("TR")
|
2436
|
+
for row in table_rows
|
2437
|
+
x = []
|
2438
|
+
for td in row.getElementsbyTagName("TD")
|
2439
|
+
x << td.innerText.strip
|
2440
|
+
end
|
2441
|
+
y << x
|
2442
|
+
end
|
2443
|
+
return y
|
2444
|
+
|
2445
|
+
end
|
2446
|
+
|
2447
|
+
def table_body(index=1)
|
2448
|
+
return @o.getElementsByTagName('TBODY')[index]
|
2449
|
+
end
|
2450
|
+
private :table_body
|
2451
|
+
|
2452
|
+
def body( how , what )
|
2453
|
+
return TableBody.new( @ieController, how, what , self)
|
2454
|
+
end
|
2455
|
+
|
2456
|
+
def bodies
|
2457
|
+
return TableBodies.new(@ieController, :direct , @o)
|
2458
|
+
end
|
2459
|
+
|
2460
|
+
def row(index)
|
2461
|
+
return @o.invoke("rows")[(index-1).to_s]
|
2462
|
+
end
|
2463
|
+
private :row
|
2464
|
+
|
2465
|
+
# Returns an array containing all the text values in the specified column
|
2466
|
+
# Raises an UnknownCellException if the specified column does not exist in every
|
2467
|
+
# Raises an UnknownTableException if the table doesn't exist.
|
2468
|
+
# row of the table
|
2469
|
+
# * columnnumber - column index to extract values from
|
2470
|
+
def column_values(columnnumber)
|
2471
|
+
return (1..row_count).collect {|idx| self[idx][columnnumber].text}
|
2472
|
+
end
|
2473
|
+
|
2474
|
+
# Returns an array containing all the text values in the specified row
|
2475
|
+
# Raises an UnknownTableException if the table doesn't exist.
|
2476
|
+
# * rownumber - row index to extract values from
|
2477
|
+
def row_values(rownumber)
|
2478
|
+
return (1..column_count(rownumber)).collect {|idx| self[rownumber][idx].text}
|
2479
|
+
end
|
2480
|
+
|
2481
|
+
end
|
2482
|
+
|
2483
|
+
|
2484
|
+
# this class is a collection of the table body objects that exist in the table
|
2485
|
+
# it wouldnt normally be created by a user, but gets returned by the bodies method of the Table object
|
2486
|
+
# many of the methods available to this object are inherited from the Element class
|
2487
|
+
#
|
2488
|
+
class TableBodies<Element
|
2489
|
+
def initialize(ieController, how, what )
|
2490
|
+
@ieController = ieController
|
2491
|
+
@o= nil
|
2492
|
+
if how == :direct
|
2493
|
+
@o = what # in this case, @o is the parent table
|
2494
|
+
end
|
2495
|
+
end
|
2496
|
+
|
2497
|
+
# returns the number of TableBodies that exist in the table
|
2498
|
+
def length
|
2499
|
+
assert_exists
|
2500
|
+
return @o.tBodies.length
|
2501
|
+
end
|
2502
|
+
|
2503
|
+
# returns the n'th Body as a Watir TableBody object
|
2504
|
+
def []n
|
2505
|
+
assert_exists
|
2506
|
+
return TableBody.new( @ieController , :direct , @o.tBodies[(n-1).to_s] )
|
2507
|
+
end
|
2508
|
+
|
2509
|
+
def get_IE_table_body_at_index( n )
|
2510
|
+
return @o.tBodies[(n-1).to_s]
|
2511
|
+
end
|
2512
|
+
|
2513
|
+
# iterates through each of the TableBodies in the Table. Yields a TableBody object
|
2514
|
+
def each
|
2515
|
+
0.upto( @o.tBodies.length-1 ) { |i | yield TableBody.new( @ieController , :direct , @o.tBodies[i.to_s] ) }
|
2516
|
+
end
|
2517
|
+
|
2518
|
+
end
|
2519
|
+
|
2520
|
+
|
2521
|
+
# this class is a table body
|
2522
|
+
class TableBody<Element
|
2523
|
+
def initialize(ieController, how, what, parent_table=nil )
|
2524
|
+
@ieController = ieController
|
2525
|
+
@o= nil
|
2526
|
+
if how == :direct
|
2527
|
+
@o = what # in this case, @o is the table body
|
2528
|
+
elsif how == :index
|
2529
|
+
@o=parent_table.bodies.get_IE_table_body_at_index( what )
|
2530
|
+
end
|
2531
|
+
@rows = []
|
2532
|
+
update_rows
|
2533
|
+
super(@o)
|
2534
|
+
end
|
2535
|
+
|
2536
|
+
# This method updates the internal representation of the table. It can be used on dynamic tables to update the watir representation
|
2537
|
+
# after the table has changed
|
2538
|
+
# BUG: Remove
|
2539
|
+
def update_rows
|
2540
|
+
if @o
|
2541
|
+
@o.rows.each do |oo|
|
2542
|
+
@rows << TableRow.new(@ieController, :direct, oo)
|
2543
|
+
end
|
2544
|
+
end
|
2545
|
+
end
|
2546
|
+
|
2547
|
+
# returns the specified row as a TableRow object
|
2548
|
+
def []n
|
2549
|
+
assert_exists
|
2550
|
+
return TableRow.new( @ieController , :direct , @rows[n-1] )
|
2551
|
+
end
|
2552
|
+
|
2553
|
+
# iterates through all the rows in the table body
|
2554
|
+
def each
|
2555
|
+
0.upto( @rows.length-1 ) { |i | yield @rows[i] }
|
2556
|
+
end
|
2557
|
+
|
2558
|
+
# returns the number of rows in this table body.
|
2559
|
+
def length
|
2560
|
+
return @rows.length
|
2561
|
+
end
|
2562
|
+
end
|
2563
|
+
|
2564
|
+
|
2565
|
+
# this class is a table row
|
2566
|
+
class TableRow < Element
|
2567
|
+
|
2568
|
+
# Returns an initialized instance of a table row
|
2569
|
+
# * o - the object contained in the row
|
2570
|
+
# * ieController - an instance of an IE object
|
2571
|
+
# * how - symbol - how we access the row
|
2572
|
+
# * what - what we use to access the row - id, index etc. If how is :direct then what is a Internet Explorer Raw Row
|
2573
|
+
def initialize(ieController , how, what)
|
2574
|
+
@ieController = ieController
|
2575
|
+
@how = how
|
2576
|
+
@what = what
|
2577
|
+
@o=nil
|
2578
|
+
if how == :direct
|
2579
|
+
@o = what
|
2580
|
+
else
|
2581
|
+
@o = ieController.getTablePart( "TR" , how , what )
|
2582
|
+
end
|
2583
|
+
update_row_cells
|
2584
|
+
super( @o )
|
2585
|
+
end
|
2586
|
+
|
2587
|
+
|
2588
|
+
# this method updates the internal list of cells.
|
2589
|
+
def update_row_cells
|
2590
|
+
if @o # cant call the assert_exists here, as an exists? method call will fail
|
2591
|
+
@cells=[]
|
2592
|
+
@o.cells.each do |oo|
|
2593
|
+
@cells << TableCell.new(@ieController, :direct, oo)
|
2594
|
+
end
|
2595
|
+
end
|
2596
|
+
end
|
2597
|
+
|
2598
|
+
# this method iterates through each of the cells in the row. Yields a TableCell object
|
2599
|
+
def each
|
2600
|
+
0.upto( @cells.length-1 ) { |i | yield @cells[i] }
|
2601
|
+
end
|
2602
|
+
|
2603
|
+
# Returns an element from the row as a TableCell object
|
2604
|
+
def [](index)
|
2605
|
+
assert_exists
|
2606
|
+
raise UnknownCellException , "Unable to locate a cell at index #{index}" if @cells.length < index
|
2607
|
+
return @cells[(index-1)]
|
2608
|
+
end
|
2609
|
+
|
2610
|
+
#defaults all missing methods to the array of elements, to be able to
|
2611
|
+
# use the row as an array
|
2612
|
+
def method_missing(aSymbol,*args)
|
2613
|
+
return @o.send(aSymbol,*args)
|
2614
|
+
end
|
2615
|
+
|
2616
|
+
def column_count
|
2617
|
+
@cells.length
|
2618
|
+
end
|
2619
|
+
end
|
2620
|
+
|
2621
|
+
# this class is a table cell - when called via the Table object
|
2622
|
+
class TableCell <Element
|
2623
|
+
include Watir::Exception
|
2624
|
+
include SupportsSubElements
|
2625
|
+
|
2626
|
+
attr_reader :typingspeed
|
2627
|
+
attr_reader :activeObjectHighLightColor
|
2628
|
+
|
2629
|
+
# Returns an initialized instance of a table cell
|
2630
|
+
# * ieController - an IE object
|
2631
|
+
# * how - symbol - how we access the cell
|
2632
|
+
# * what - what we use to access the cell - id, name index etc
|
2633
|
+
def initialize( ieController, how , what )
|
2634
|
+
@ieController = ieController
|
2635
|
+
#puts "How = #{how}"
|
2636
|
+
if how == :direct
|
2637
|
+
@o = what
|
2638
|
+
#puts "@o.class=#{@o.class}"
|
2639
|
+
else
|
2640
|
+
@o = ieController.getTablePart( "TD" , how , what )
|
2641
|
+
end
|
2642
|
+
super( @o )
|
2643
|
+
@how = how
|
2644
|
+
@what = what
|
2645
|
+
@typingspeed = @ieController.typingspeed
|
2646
|
+
@activeObjectHighLightColor = @ieController.activeObjectHighLightColor
|
2647
|
+
end
|
2648
|
+
|
2649
|
+
def getContainerContents
|
2650
|
+
return @o.all
|
2651
|
+
end
|
2652
|
+
private :getContainerContents
|
2653
|
+
|
2654
|
+
def getContainer
|
2655
|
+
return @o
|
2656
|
+
end
|
2657
|
+
|
2658
|
+
def document
|
2659
|
+
return @o
|
2660
|
+
end
|
2661
|
+
|
2662
|
+
# returns the contents of the cell as text
|
2663
|
+
def text
|
2664
|
+
raise UnknownObjectException , "Unable to locate table cell with #{@how} of #{@what}" if @o == nil
|
2665
|
+
return @o.innerText.strip
|
2666
|
+
end
|
2667
|
+
alias to_s text
|
2668
|
+
|
2669
|
+
def colspan
|
2670
|
+
@o.colSpan
|
2671
|
+
end
|
2672
|
+
|
2673
|
+
end
|
2674
|
+
|
2675
|
+
# This class is the means of accessing an image on a page.
|
2676
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#image method
|
2677
|
+
#
|
2678
|
+
# many of the methods available to this object are inherited from the Element class
|
2679
|
+
#
|
2680
|
+
class Image < Element
|
2681
|
+
|
2682
|
+
# Returns an initialized instance of a image object
|
2683
|
+
# * ieController - an instance of an IEController
|
2684
|
+
# * how - symbol - how we access the image
|
2685
|
+
# * what - what we use to access the image, name, src, index, id or alt
|
2686
|
+
def initialize( ieController, how , what )
|
2687
|
+
@ieController = ieController
|
2688
|
+
@how = how
|
2689
|
+
@what = what
|
2690
|
+
@o = @ieController.getImage(@how, @what)
|
2691
|
+
super( @o )
|
2692
|
+
end
|
2693
|
+
|
2694
|
+
# this method produces the properties for an image as an array
|
2695
|
+
def image_string_creator
|
2696
|
+
n = []
|
2697
|
+
n << "src:".ljust(TO_S_SIZE) + self.src.to_s
|
2698
|
+
n << "file date:".ljust(TO_S_SIZE) + self.fileCreatedDate.to_s
|
2699
|
+
n << "file size:".ljust(TO_S_SIZE) + self.fileSize.to_s
|
2700
|
+
n << "width:".ljust(TO_S_SIZE) + self.width.to_s
|
2701
|
+
n << "height:".ljust(TO_S_SIZE) + self.height.to_s
|
2702
|
+
n << "alt:".ljust(TO_S_SIZE) + self.alt.to_s
|
2703
|
+
return n
|
2704
|
+
end
|
2705
|
+
private :image_string_creator
|
2706
|
+
|
2707
|
+
# returns a string representation of the object
|
2708
|
+
def to_s
|
2709
|
+
assert_exists
|
2710
|
+
r = string_creator
|
2711
|
+
r=r + image_string_creator
|
2712
|
+
return r.join("\n")
|
2713
|
+
end
|
2714
|
+
|
2715
|
+
def_wrap :src
|
2716
|
+
|
2717
|
+
# this method returns the file created date of the image
|
2718
|
+
def fileCreatedDate
|
2719
|
+
assert_exists
|
2720
|
+
return @o.invoke("fileCreatedDate")
|
2721
|
+
end
|
2722
|
+
|
2723
|
+
# this method returns the filesize of the image
|
2724
|
+
def fileSize
|
2725
|
+
assert_exists
|
2726
|
+
return @o.invoke("fileSize").to_s
|
2727
|
+
end
|
2728
|
+
|
2729
|
+
# returns the width in pixels of the image, as a string
|
2730
|
+
def width
|
2731
|
+
assert_exists
|
2732
|
+
return @o.invoke("width").to_s
|
2733
|
+
end
|
2734
|
+
|
2735
|
+
# returns the alt text of the image
|
2736
|
+
def alt
|
2737
|
+
assert_exists
|
2738
|
+
return @o.invoke("alt").to_s
|
2739
|
+
end
|
2740
|
+
|
2741
|
+
|
2742
|
+
# returns the height in pixels of the image, as a string
|
2743
|
+
def height
|
2744
|
+
assert_exists
|
2745
|
+
return @o.invoke("height").to_s
|
2746
|
+
end
|
2747
|
+
|
2748
|
+
# returns the type of the object - 'image'
|
2749
|
+
def type
|
2750
|
+
assert_exists
|
2751
|
+
return "image"
|
2752
|
+
end
|
2753
|
+
|
2754
|
+
# This method attempts to find out if the image was actually loaded by the web browser.
|
2755
|
+
# If the image was not loaded, the browser is unable to determine some of the properties.
|
2756
|
+
# We look for these missing properties to see if the image is really there or not.
|
2757
|
+
# If the Disk cache is full ( tools menu -> Internet options -> Temporary Internet Files) , it may produce incorrect responses.
|
2758
|
+
def hasLoaded?
|
2759
|
+
raise UnknownObjectException , "Unable to locate image using #{@how} and #{@what} " if @o==nil
|
2760
|
+
return false if @o.fileCreatedDate == "" and @o.fileSize.to_i == -1
|
2761
|
+
return true
|
2762
|
+
end
|
2763
|
+
|
2764
|
+
# this method highlights the image ( in fact it adds or removes a border around the image)
|
2765
|
+
# * setOrClear - symbol - :set to set the border, :clear to remove it
|
2766
|
+
def highLight( setOrClear )
|
2767
|
+
if setOrClear == :set
|
2768
|
+
begin
|
2769
|
+
@original_border = @o.border
|
2770
|
+
@o.border = 1
|
2771
|
+
rescue
|
2772
|
+
@original_border = nil
|
2773
|
+
end
|
2774
|
+
else
|
2775
|
+
begin
|
2776
|
+
@o.border = @original_border
|
2777
|
+
@original_border = nil
|
2778
|
+
rescue
|
2779
|
+
# we could be here for a number of reasons...
|
2780
|
+
ensure
|
2781
|
+
@original_border = nil
|
2782
|
+
end
|
2783
|
+
end
|
2784
|
+
end
|
2785
|
+
private :highLight
|
2786
|
+
|
2787
|
+
# This method saves the image to the file path that is given. The
|
2788
|
+
# path must be in windows format (c:\\dirname\\somename.gif). This method
|
2789
|
+
# will not overwrite a previously existing image. If an image already
|
2790
|
+
# exists at the given path then a dialog will be displayed prompting
|
2791
|
+
# for overwrite.
|
2792
|
+
# Raises a WatirException if AutoIt is not correctly installed
|
2793
|
+
# path - directory path and file name of where image should be saved
|
2794
|
+
def save(path)
|
2795
|
+
require 'watir/windowhelper'
|
2796
|
+
WindowHelper.check_autoit_installed
|
2797
|
+
@ieController.goto(src)
|
2798
|
+
begin
|
2799
|
+
thrd = fill_save_image_dialog(path)
|
2800
|
+
@ieController.document.execCommand("SaveAs")
|
2801
|
+
thrd.join(5)
|
2802
|
+
ensure
|
2803
|
+
@ieController.back
|
2804
|
+
end
|
2805
|
+
end
|
2806
|
+
|
2807
|
+
def fill_save_image_dialog(path)
|
2808
|
+
Thread.new do
|
2809
|
+
system("ruby -e \"require 'win32ole'; @autoit = WIN32OLE.new('AutoItX3.Control'); waitresult = @autoit.WinWait 'Save Picture', '', 15; if waitresult == 1\" -e \"@autoit.ControlSetText 'Save Picture', '', '1148', '#{path}'; @autoit.ControlSend 'Save Picture', '', '1', '{ENTER}';\" -e \"end\"")
|
2810
|
+
end
|
2811
|
+
end
|
2812
|
+
private :fill_save_image_dialog
|
2813
|
+
end
|
2814
|
+
|
2815
|
+
|
2816
|
+
# This class is the means of accessing a link on a page
|
2817
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#link method
|
2818
|
+
# many of the methods available to this object are inherited from the Element class
|
2819
|
+
#
|
2820
|
+
class Link < Element
|
2821
|
+
# Returns an initialized instance of a link object
|
2822
|
+
# * ieController - an instance of an IEController
|
2823
|
+
# * how - symbol - how we access the link
|
2824
|
+
# * what - what we use to access the link, text, url, index etc
|
2825
|
+
def initialize( ieController, how , what )
|
2826
|
+
@ieController = ieController
|
2827
|
+
@how = how
|
2828
|
+
@what = what
|
2829
|
+
begin
|
2830
|
+
@o = @ieController.getLink( @how, @what )
|
2831
|
+
rescue UnknownObjectException
|
2832
|
+
@o = nil
|
2833
|
+
end
|
2834
|
+
super( @o )
|
2835
|
+
end
|
2836
|
+
|
2837
|
+
# returns 'link' as the object type
|
2838
|
+
def type
|
2839
|
+
assert_exists
|
2840
|
+
return "link"
|
2841
|
+
end
|
2842
|
+
|
2843
|
+
# returns the text displayed by the link
|
2844
|
+
def innerText
|
2845
|
+
assert_exists
|
2846
|
+
return @o.innerText.strip
|
2847
|
+
end
|
2848
|
+
alias text innerText
|
2849
|
+
|
2850
|
+
# returns the url the link points to
|
2851
|
+
def_wrap :href
|
2852
|
+
|
2853
|
+
# if an image is used as part of the link, this will return true
|
2854
|
+
def link_has_image
|
2855
|
+
return true if @o.getElementsByTagName("IMG").length > 0
|
2856
|
+
return false
|
2857
|
+
end
|
2858
|
+
|
2859
|
+
# this method returns the src of an image, if an image is used as part of the link
|
2860
|
+
def src
|
2861
|
+
if @o.getElementsByTagName("IMG").length > 0
|
2862
|
+
return @o.getElementsByTagName("IMG")[0.to_s].src
|
2863
|
+
else
|
2864
|
+
return ""
|
2865
|
+
end
|
2866
|
+
end
|
2867
|
+
|
2868
|
+
def link_string_creator
|
2869
|
+
n = []
|
2870
|
+
n << "href:".ljust(TO_S_SIZE) + self.href
|
2871
|
+
n << "inner text:".ljust(TO_S_SIZE) + self.innerText
|
2872
|
+
n << "img src:".ljust(TO_S_SIZE) + self.src if self.link_has_image
|
2873
|
+
return n
|
2874
|
+
end
|
2875
|
+
|
2876
|
+
# returns a textual description of the link
|
2877
|
+
def to_s
|
2878
|
+
assert_exists
|
2879
|
+
r = string_creator
|
2880
|
+
r=r + link_string_creator
|
2881
|
+
return r.join("\n")
|
2882
|
+
end
|
2883
|
+
end
|
2884
|
+
|
2885
|
+
# This class is the way in which select boxes are manipulated.
|
2886
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#select_list method
|
2887
|
+
#
|
2888
|
+
# many of the methods available to this object are inherited from the Element class
|
2889
|
+
#
|
2890
|
+
class SelectList < Element
|
2891
|
+
# returns an initialized instance of a SelectList object
|
2892
|
+
# * ieController - an instance of an IEController
|
2893
|
+
# * how - symbol - how we access the select box
|
2894
|
+
# * what - what we use to access the select box, name, id etc
|
2895
|
+
def initialize( ieController, how , what )
|
2896
|
+
@ieController = ieController
|
2897
|
+
@how = how
|
2898
|
+
@what = what
|
2899
|
+
@o = @ieController.getObject(@how, @what, ["select-one", "select-multiple"])
|
2900
|
+
super( @o )
|
2901
|
+
end
|
2902
|
+
|
2903
|
+
attr :o
|
2904
|
+
|
2905
|
+
# This method clears the selected items in the select box
|
2906
|
+
def clearSelection
|
2907
|
+
assert_exists
|
2908
|
+
highLight( :set)
|
2909
|
+
wait = false
|
2910
|
+
@o.each do |selectBoxItem|
|
2911
|
+
if selectBoxItem.selected
|
2912
|
+
selectBoxItem.selected = false
|
2913
|
+
wait = true
|
2914
|
+
end
|
2915
|
+
end
|
2916
|
+
@ieController.wait if wait
|
2917
|
+
highLight( :clear)
|
2918
|
+
end
|
2919
|
+
# private :clearSelection
|
2920
|
+
|
2921
|
+
# This method selects an item, or items in a select box, by text.
|
2922
|
+
# Raises NoValueFoundException if the specified value is not found.
|
2923
|
+
# * item - the thing to select, string, reg exp or an array of string and reg exps
|
2924
|
+
def select( item )
|
2925
|
+
select_item_in_select_list( :text , item )
|
2926
|
+
end
|
2927
|
+
|
2928
|
+
# Selects an item, or items in a select box, by value.
|
2929
|
+
# Raises NoValueFoundException if the specified value is not found.
|
2930
|
+
# * item - the value of the thing to select, string, reg exp or an array of string and reg exps
|
2931
|
+
def select_value( item )
|
2932
|
+
select_item_in_select_list( :value , item )
|
2933
|
+
end
|
2934
|
+
|
2935
|
+
# BUG: Should be private
|
2936
|
+
# Selects something from the select box
|
2937
|
+
# * name - symbol :value or :text - how we find an item in the select box
|
2938
|
+
# * item - string or reg exp - what we are looking for
|
2939
|
+
def select_item_in_select_list( attribute, value )
|
2940
|
+
assert_exists
|
2941
|
+
highLight( :set )
|
2942
|
+
doBreak = false
|
2943
|
+
@ieController.log "Setting box #{@o.name} to #{attribute} #{value} "
|
2944
|
+
@o.each do |option| # items in the list
|
2945
|
+
if value.matches( option.invoke(attribute.to_s))
|
2946
|
+
if option.selected
|
2947
|
+
doBreak = true
|
2948
|
+
break
|
2949
|
+
else
|
2950
|
+
option.selected = true
|
2951
|
+
@o.fireEvent("onChange")
|
2952
|
+
@ieController.wait
|
2953
|
+
doBreak = true
|
2954
|
+
break
|
2955
|
+
end
|
2956
|
+
end
|
2957
|
+
end
|
2958
|
+
unless doBreak
|
2959
|
+
raise NoValueFoundException,
|
2960
|
+
"No option with #{attribute.to_s} of #{value} in this select element"
|
2961
|
+
end
|
2962
|
+
highLight( :clear )
|
2963
|
+
end
|
2964
|
+
|
2965
|
+
# Returns all the items in the select list as an array.
|
2966
|
+
# An empty array is returned if the select box has no contents.
|
2967
|
+
# Raises UnknownObjectException if the select box is not found
|
2968
|
+
def getAllContents()
|
2969
|
+
assert_exists
|
2970
|
+
@ieController.log "There are #{@o.length} items"
|
2971
|
+
returnArray = []
|
2972
|
+
@o.each { |thisItem| returnArray << thisItem.text }
|
2973
|
+
return returnArray
|
2974
|
+
end
|
2975
|
+
|
2976
|
+
# Returns the selected items as an array.
|
2977
|
+
# Raises UnknownObjectException if the select box is not found.
|
2978
|
+
def getSelectedItems
|
2979
|
+
assert_exists
|
2980
|
+
returnArray = []
|
2981
|
+
@ieController.log "There are #{@o.length} items"
|
2982
|
+
@o.each do |thisItem|
|
2983
|
+
if thisItem.selected
|
2984
|
+
@ieController.log "Item ( #{thisItem.text} ) is selected"
|
2985
|
+
returnArray << thisItem.text
|
2986
|
+
end
|
2987
|
+
end
|
2988
|
+
return returnArray
|
2989
|
+
end
|
2990
|
+
|
2991
|
+
def option (attribute, value)
|
2992
|
+
Option.new(self, attribute, value)
|
2993
|
+
end
|
2994
|
+
end
|
2995
|
+
|
2996
|
+
module OptionAccess
|
2997
|
+
def text
|
2998
|
+
@option.text
|
2999
|
+
end
|
3000
|
+
def value
|
3001
|
+
@option.value
|
3002
|
+
end
|
3003
|
+
def selected
|
3004
|
+
@option.selected
|
3005
|
+
end
|
3006
|
+
end
|
3007
|
+
|
3008
|
+
class OptionWrapper
|
3009
|
+
include OptionAccess
|
3010
|
+
def initialize (option)
|
3011
|
+
@option = option
|
3012
|
+
end
|
3013
|
+
end
|
3014
|
+
|
3015
|
+
# An item in a select list
|
3016
|
+
class Option
|
3017
|
+
include OptionAccess
|
3018
|
+
include Watir::Exception
|
3019
|
+
def initialize (select_list, attribute, value)
|
3020
|
+
@select_list = select_list
|
3021
|
+
@how = attribute
|
3022
|
+
@what = value
|
3023
|
+
@option = nil
|
3024
|
+
|
3025
|
+
unless [:text, :value].include? attribute
|
3026
|
+
raise MissingWayOfFindingObjectException,
|
3027
|
+
"Option does not support attribute #{@how}"
|
3028
|
+
end
|
3029
|
+
@select_list.o.each do |option| # items in the list
|
3030
|
+
if value.matches( option.invoke(attribute.to_s))
|
3031
|
+
@option = option
|
3032
|
+
break
|
3033
|
+
end
|
3034
|
+
end
|
3035
|
+
|
3036
|
+
end
|
3037
|
+
def assert_exists
|
3038
|
+
unless @option
|
3039
|
+
raise UnknownObjectException,
|
3040
|
+
"Unable to locate an option using #{@how} and #{@what}"
|
3041
|
+
end
|
3042
|
+
end
|
3043
|
+
private :assert_exists
|
3044
|
+
def select
|
3045
|
+
assert_exists
|
3046
|
+
@select_list.select_item_in_select_list(@how, @what)
|
3047
|
+
end
|
3048
|
+
end
|
3049
|
+
|
3050
|
+
# This is the main class for accessing buttons.
|
3051
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#button method
|
3052
|
+
#
|
3053
|
+
# most of the methods available to Button objects are inherited from the Element class
|
3054
|
+
#
|
3055
|
+
class Button < Element
|
3056
|
+
def initialize( ieController, how , what )
|
3057
|
+
@ieController = ieController
|
3058
|
+
@how = how
|
3059
|
+
@what = what
|
3060
|
+
if(how == :from_object) then
|
3061
|
+
@o = what
|
3062
|
+
else
|
3063
|
+
@o = @ieController.getObject( @how, @what , object_types)
|
3064
|
+
end
|
3065
|
+
super( @o )
|
3066
|
+
end
|
3067
|
+
|
3068
|
+
def object_types
|
3069
|
+
return ["button" , "submit" , "image" , "reset" ]
|
3070
|
+
end
|
3071
|
+
|
3072
|
+
end
|
3073
|
+
|
3074
|
+
|
3075
|
+
# File dialog
|
3076
|
+
class FileField < Element
|
3077
|
+
# Create an instance of the file object
|
3078
|
+
def initialize( ieController, how , what )
|
3079
|
+
@ieController = ieController
|
3080
|
+
@how = how
|
3081
|
+
@what = what
|
3082
|
+
super( @o )
|
3083
|
+
@o = @ieController.getObject( @how, @what , ["file"] )
|
3084
|
+
|
3085
|
+
end
|
3086
|
+
|
3087
|
+
def set(setPath)
|
3088
|
+
assert_exists
|
3089
|
+
Thread.new {
|
3090
|
+
clicker = WinClicker.new
|
3091
|
+
clicker.setFileRequesterFileName_newProcess(setPath)
|
3092
|
+
}
|
3093
|
+
# may need to experiment with this value. if it takes longer than this
|
3094
|
+
# to open the new external Ruby process, the current thread may become
|
3095
|
+
# blocked by the file chooser.
|
3096
|
+
sleep(1)
|
3097
|
+
self.click
|
3098
|
+
end
|
3099
|
+
end
|
3100
|
+
|
3101
|
+
# This class is the class for radio buttons and check boxes.
|
3102
|
+
# It contains methods common to both.
|
3103
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#checkbox or Watir::SupportsSubElements#radio methods
|
3104
|
+
#
|
3105
|
+
# most of the methods available to this element are inherited from the Element class
|
3106
|
+
#
|
3107
|
+
class RadioCheckCommon < Element
|
3108
|
+
|
3109
|
+
def initialize( ieController, how , what , type, value=nil )
|
3110
|
+
@ieController = ieController
|
3111
|
+
@how = how
|
3112
|
+
@what = what
|
3113
|
+
@type = type
|
3114
|
+
@value = value
|
3115
|
+
@o = @ieController.getObject(@how, @what, @type, @value)
|
3116
|
+
super( @o )
|
3117
|
+
end
|
3118
|
+
|
3119
|
+
# This method determines if a radio button or check box is set.
|
3120
|
+
# Returns true is set/checked or false if not set/checked.
|
3121
|
+
# Raises UnknownObjectException if its unable to locate an object.
|
3122
|
+
def isSet?
|
3123
|
+
assert_exists
|
3124
|
+
return @o.checked
|
3125
|
+
end
|
3126
|
+
alias getState isSet?
|
3127
|
+
alias checked? isSet?
|
3128
|
+
|
3129
|
+
# This method clears a radio button or check box. Note, with radio buttons one of them will almost always be set.
|
3130
|
+
# Returns true if set or false if not set.
|
3131
|
+
# Raises UnknownObjectException if its unable to locate an object
|
3132
|
+
# ObjectDisabledException IF THE OBJECT IS DISABLED
|
3133
|
+
def clear
|
3134
|
+
assert_exists
|
3135
|
+
assert_enabled
|
3136
|
+
highLight( :set)
|
3137
|
+
set_clear_item( false )
|
3138
|
+
highLight( :clear )
|
3139
|
+
end
|
3140
|
+
|
3141
|
+
# This method sets the radio list item or check box.
|
3142
|
+
# Raises UnknownObjectException if its unable to locate an object
|
3143
|
+
# ObjectDisabledException if the object is disabled
|
3144
|
+
def set
|
3145
|
+
assert_exists
|
3146
|
+
assert_enabled
|
3147
|
+
highLight( :set)
|
3148
|
+
set_clear_item( true )
|
3149
|
+
highLight( :clear )
|
3150
|
+
end
|
3151
|
+
|
3152
|
+
# This method is the common code for setting or clearing checkboxes and radio. A user would normalyy not access this, but use Checkbox#set etc
|
3153
|
+
def set_clear_item( set )
|
3154
|
+
@o.checked = set
|
3155
|
+
@o.fireEvent("onClick")
|
3156
|
+
@ieController.wait
|
3157
|
+
end
|
3158
|
+
private :set_clear_item
|
3159
|
+
|
3160
|
+
end
|
3161
|
+
|
3162
|
+
#--
|
3163
|
+
# this class is only used to change the name of the class that radio buttons use to something more meaningful
|
3164
|
+
# and to make the docs better
|
3165
|
+
#++
|
3166
|
+
# This class is the watir representation of a radio button.
|
3167
|
+
class Radio < RadioCheckCommon
|
3168
|
+
|
3169
|
+
end
|
3170
|
+
|
3171
|
+
|
3172
|
+
# This class is the watir representation of a check box.
|
3173
|
+
class CheckBox < RadioCheckCommon
|
3174
|
+
|
3175
|
+
# This method, with no arguments supplied, sets the check box.
|
3176
|
+
# If the optional set_or_clear is supplied, the checkbox is set, when its true and cleared when its false
|
3177
|
+
# Raises UnknownObjectException if its unable to locate an object
|
3178
|
+
# ObjectDisabledException if the object is disabled
|
3179
|
+
def set( set_or_clear=true )
|
3180
|
+
assert_exists
|
3181
|
+
assert_enabled
|
3182
|
+
highLight( :set)
|
3183
|
+
|
3184
|
+
if set_or_clear == true
|
3185
|
+
if @o.checked == false
|
3186
|
+
set_clear_item( true )
|
3187
|
+
end
|
3188
|
+
else
|
3189
|
+
self.clear
|
3190
|
+
end
|
3191
|
+
highLight( :clear )
|
3192
|
+
end
|
3193
|
+
|
3194
|
+
# This method clears a check box.
|
3195
|
+
# Returns true if set or false if not set.
|
3196
|
+
# Raises UnknownObjectException if its unable to locate an object
|
3197
|
+
# ObjectDisabledException if the object is disabled
|
3198
|
+
def clear
|
3199
|
+
assert_exists
|
3200
|
+
assert_enabled
|
3201
|
+
highLight( :set)
|
3202
|
+
if @o.checked == true
|
3203
|
+
set_clear_item( false )
|
3204
|
+
end
|
3205
|
+
highLight( :clear)
|
3206
|
+
end
|
3207
|
+
|
3208
|
+
|
3209
|
+
end
|
3210
|
+
|
3211
|
+
|
3212
|
+
# This class is the main class for Text Fields
|
3213
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#text_field method
|
3214
|
+
#
|
3215
|
+
# most of the methods available to this element are inherited from the Element class
|
3216
|
+
#
|
3217
|
+
class TextField < Element
|
3218
|
+
|
3219
|
+
def initialize( ieController, how , what )
|
3220
|
+
@ieController = ieController
|
3221
|
+
@how = how
|
3222
|
+
@what = what
|
3223
|
+
|
3224
|
+
if(how != :from_object) then
|
3225
|
+
@o = @ieController.getObject(@how, @what, supported_types)
|
3226
|
+
else
|
3227
|
+
@o = what
|
3228
|
+
end
|
3229
|
+
super( @o )
|
3230
|
+
end
|
3231
|
+
|
3232
|
+
def supported_types
|
3233
|
+
return ["text" , "password", "textarea"]
|
3234
|
+
end
|
3235
|
+
private :supported_types
|
3236
|
+
|
3237
|
+
def size
|
3238
|
+
assert_exists
|
3239
|
+
begin
|
3240
|
+
s=@o.size
|
3241
|
+
rescue
|
3242
|
+
# TextArea does not support size
|
3243
|
+
s=""
|
3244
|
+
end
|
3245
|
+
return s
|
3246
|
+
|
3247
|
+
end
|
3248
|
+
|
3249
|
+
def maxLength
|
3250
|
+
assert_exists
|
3251
|
+
begin
|
3252
|
+
s=@o.maxlength
|
3253
|
+
rescue
|
3254
|
+
# TextArea does not support maxLength
|
3255
|
+
s=""
|
3256
|
+
end
|
3257
|
+
return s
|
3258
|
+
end
|
3259
|
+
|
3260
|
+
def text_string_creator
|
3261
|
+
n = []
|
3262
|
+
n << "length:".ljust(TO_S_SIZE) + self.size.to_s
|
3263
|
+
n << "max length:".ljust(TO_S_SIZE) + self.maxLength.to_s
|
3264
|
+
n << "read only:".ljust(TO_S_SIZE) + self.readonly?.to_s
|
3265
|
+
|
3266
|
+
return n
|
3267
|
+
end
|
3268
|
+
|
3269
|
+
def to_s
|
3270
|
+
assert_exists
|
3271
|
+
r = string_creator
|
3272
|
+
r=r + text_string_creator
|
3273
|
+
return r.join("\n")
|
3274
|
+
end
|
3275
|
+
|
3276
|
+
# This method returns true or false if the text field is read only.
|
3277
|
+
# Raises UnknownObjectException if the object can't be found.
|
3278
|
+
def readonly?
|
3279
|
+
assert_exists
|
3280
|
+
return @o.readOnly
|
3281
|
+
end
|
3282
|
+
alias readOnly? :readonly?
|
3283
|
+
|
3284
|
+
def assert_not_readonly
|
3285
|
+
raise ObjectReadOnlyException , "Textfield #{@how} and #{@what} is read only" if self.readonly?
|
3286
|
+
end
|
3287
|
+
#--
|
3288
|
+
# BUG: rename me
|
3289
|
+
#++
|
3290
|
+
# This method returns the current contents of the text field as a string.
|
3291
|
+
# Raises UnknownObjectException if the object can't be found
|
3292
|
+
def getContents()
|
3293
|
+
assert_exists
|
3294
|
+
return self.value
|
3295
|
+
end
|
3296
|
+
|
3297
|
+
# This method returns true orfalse if the text field contents is either a string match
|
3298
|
+
# or a regular expression match to the supplied value.
|
3299
|
+
# Raises UnknownObjectException if the object can't be found
|
3300
|
+
# * containsThis - string or reg exp - the text to verify
|
3301
|
+
def verify_contains( containsThis )
|
3302
|
+
assert_exists
|
3303
|
+
if containsThis.kind_of? String
|
3304
|
+
return true if self.value == containsThis
|
3305
|
+
elsif containsThis.kind_of? Regexp
|
3306
|
+
return true if self.value.match(containsThis) != nil
|
3307
|
+
end
|
3308
|
+
return false
|
3309
|
+
end
|
3310
|
+
|
3311
|
+
# this method is used to drag the entire contents of the text field to another text field
|
3312
|
+
# 19 Jan 2005 - It is added as prototype functionality, and may change
|
3313
|
+
# * destination_how - symbol, :id, :name how we identify the drop target
|
3314
|
+
# * destination_what - string or regular expression, the name, id, etc of the text field that will be the drop target
|
3315
|
+
def dragContentsTo( destination_how , destination_what)
|
3316
|
+
assert_exists
|
3317
|
+
destination = @ieController.textField(destination_how , destination_what)
|
3318
|
+
|
3319
|
+
raise UnknownObjectException , "Unable to locate destination using #{destination_how } and #{destination_what } " if destination.exists? == false
|
3320
|
+
|
3321
|
+
@o.focus
|
3322
|
+
@o.select()
|
3323
|
+
value = self.value
|
3324
|
+
|
3325
|
+
@o.fireEvent("onSelect")
|
3326
|
+
@o.fireEvent("ondragstart")
|
3327
|
+
@o.fireEvent("ondrag")
|
3328
|
+
destination.fireEvent("onDragEnter")
|
3329
|
+
destination.fireEvent("onDragOver")
|
3330
|
+
destination.fireEvent("ondrop")
|
3331
|
+
|
3332
|
+
@o.fireEvent("ondragend")
|
3333
|
+
destination.value= ( destination.value + value.to_s )
|
3334
|
+
self.value = ""
|
3335
|
+
end
|
3336
|
+
|
3337
|
+
# This method clears the contents of the text box.
|
3338
|
+
# Raises UnknownObjectException if the object can't be found
|
3339
|
+
# Raises ObjectDisabledException if the object is disabled
|
3340
|
+
# Raises ObjectReadOnlyException if the object is read only
|
3341
|
+
def clear
|
3342
|
+
assert_exists
|
3343
|
+
assert_enabled
|
3344
|
+
assert_not_readonly
|
3345
|
+
|
3346
|
+
highLight(:set)
|
3347
|
+
|
3348
|
+
@o.scrollIntoView
|
3349
|
+
@o.focus
|
3350
|
+
@o.select()
|
3351
|
+
@o.fireEvent("onSelect")
|
3352
|
+
@o.value = ""
|
3353
|
+
@o.fireEvent("onKeyPress")
|
3354
|
+
@o.fireEvent("onChange")
|
3355
|
+
@ieController.wait()
|
3356
|
+
highLight(:clear)
|
3357
|
+
end
|
3358
|
+
|
3359
|
+
# This method appens the supplied text to the contents of the text box.
|
3360
|
+
# Raises UnknownObjectException if the object cant be found
|
3361
|
+
# Raises ObjectDisabledException if the object is disabled
|
3362
|
+
# Raises ObjectReadOnlyException if the object is read only
|
3363
|
+
# * setThis - string - the text to append
|
3364
|
+
def append( setThis)
|
3365
|
+
assert_exists
|
3366
|
+
assert_enabled
|
3367
|
+
assert_not_readonly
|
3368
|
+
|
3369
|
+
highLight(:set)
|
3370
|
+
@o.scrollIntoView
|
3371
|
+
@o.focus
|
3372
|
+
doKeyPress( setThis )
|
3373
|
+
highLight(:clear)
|
3374
|
+
end
|
3375
|
+
|
3376
|
+
# This method sets the contents of the text box to the supplied text
|
3377
|
+
# Raises UnknownObjectException if the object cant be found
|
3378
|
+
# Raises ObjectDisabledException if the object is disabled
|
3379
|
+
# Raises ObjectReadOnlyException if the object is read only
|
3380
|
+
# * setThis - string - the text to set
|
3381
|
+
def set( setThis )
|
3382
|
+
assert_exists
|
3383
|
+
assert_enabled
|
3384
|
+
assert_not_readonly
|
3385
|
+
|
3386
|
+
highLight(:set)
|
3387
|
+
@o.scrollIntoView
|
3388
|
+
@o.focus
|
3389
|
+
@o.select()
|
3390
|
+
@o.fireEvent("onSelect")
|
3391
|
+
@o.value = ""
|
3392
|
+
@o.fireEvent("onKeyPress")
|
3393
|
+
doKeyPress( setThis )
|
3394
|
+
highLight(:clear)
|
3395
|
+
@o.fireEvent("onChange")
|
3396
|
+
@o.fireEvent("onBlur")
|
3397
|
+
end
|
3398
|
+
|
3399
|
+
# this method sets the value of the text field directly. It causes no events to be fired or exceptions to be raised, so generally shouldnt be used
|
3400
|
+
# it is preffered to use the set method.
|
3401
|
+
def value=(v)
|
3402
|
+
assert_exists
|
3403
|
+
@o.value = v.to_s
|
3404
|
+
end
|
3405
|
+
|
3406
|
+
def fire_key_events
|
3407
|
+
@o.fireEvent("onKeyDown")
|
3408
|
+
@o.fireEvent("onKeyPress")
|
3409
|
+
@o.fireEvent("onKeyUp")
|
3410
|
+
end
|
3411
|
+
private :fire_key_events
|
3412
|
+
|
3413
|
+
# This method is used internally by setText and appendText
|
3414
|
+
# It should not be used externally.
|
3415
|
+
# * value - string - The string to enter into the text field
|
3416
|
+
def doKeyPress( value )
|
3417
|
+
begin
|
3418
|
+
maxLength = @o.maxLength
|
3419
|
+
if value.length > maxLength
|
3420
|
+
value = suppliedValue[0 .. maxLength ]
|
3421
|
+
@ieController.log " Supplied string is #{suppliedValue.length} chars, which exceeds the max length (#{maxLength}) of the field. Using value: #{value}"
|
3422
|
+
end
|
3423
|
+
rescue
|
3424
|
+
# probably a text area - so it doesnt have a max Length
|
3425
|
+
maxLength = -1
|
3426
|
+
end
|
3427
|
+
for i in 0 .. value.length-1
|
3428
|
+
sleep @ieController.typingspeed # typing speed
|
3429
|
+
c = value[i,1]
|
3430
|
+
#@ieController.log " adding c.chr " + c #.chr.to_s
|
3431
|
+
@o.value = @o.value.to_s + c #c.chr
|
3432
|
+
fire_key_events
|
3433
|
+
end
|
3434
|
+
|
3435
|
+
end
|
3436
|
+
private :doKeyPress
|
3437
|
+
end
|
3438
|
+
|
3439
|
+
# this class can be used to access hidden field objects
|
3440
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#hidden method
|
3441
|
+
#
|
3442
|
+
# most of the methods available to this element are inherited from the Element class
|
3443
|
+
#
|
3444
|
+
class Hidden < TextField
|
3445
|
+
|
3446
|
+
def initialize( ieController, how , what )
|
3447
|
+
super
|
3448
|
+
end
|
3449
|
+
|
3450
|
+
def supported_types
|
3451
|
+
return ["hidden"]
|
3452
|
+
end
|
3453
|
+
|
3454
|
+
|
3455
|
+
# set is overriden in this class, as there is no way to set focus to a hidden field
|
3456
|
+
def set(n)
|
3457
|
+
self.value=n
|
3458
|
+
end
|
3459
|
+
|
3460
|
+
# override the append method, so that focus isnt set to the hidden object
|
3461
|
+
def append(n)
|
3462
|
+
self.value = self.value.to_s + n.to_s
|
3463
|
+
end
|
3464
|
+
|
3465
|
+
# override the clear method, so that focus isnt set to the hidden object
|
3466
|
+
def clear
|
3467
|
+
self.value = ""
|
3468
|
+
end
|
3469
|
+
|
3470
|
+
# this method will do nothing, as you cant set focus to a hidden field
|
3471
|
+
def focus
|
3472
|
+
# do nothing!
|
3473
|
+
end
|
3474
|
+
|
3475
|
+
end
|
3476
|
+
|
3477
|
+
#--
|
3478
|
+
# These classes are not for public consumption, so we switch off rdoc
|
3479
|
+
|
3480
|
+
|
3481
|
+
# presumes element_class or element_tag is defined
|
3482
|
+
# for subclasses of ElementCollections
|
3483
|
+
module CommonCollection
|
3484
|
+
def element_tag
|
3485
|
+
element_class.tag
|
3486
|
+
end
|
3487
|
+
def length
|
3488
|
+
@ieController.getContainer.getElementsByTagName(element_tag).length
|
3489
|
+
end
|
3490
|
+
end
|
3491
|
+
|
3492
|
+
# This class is used as part of the .show method of the iterators class
|
3493
|
+
# it would not normally be used by a user
|
3494
|
+
class AttributeLengthPairs
|
3495
|
+
|
3496
|
+
# This class is used as part of the .show method of the iterators class
|
3497
|
+
# it would not normally be used by a user
|
3498
|
+
class AttributeLengthHolder
|
3499
|
+
attr_accessor :attribute
|
3500
|
+
attr_accessor :length
|
3501
|
+
|
3502
|
+
def initialize( attrib, length)
|
3503
|
+
@attribute = attrib
|
3504
|
+
@length = length
|
3505
|
+
end
|
3506
|
+
end
|
3507
|
+
|
3508
|
+
def initialize( attrib=nil , length=nil)
|
3509
|
+
@attr=[]
|
3510
|
+
add( attrib , length ) if attrib
|
3511
|
+
@index_counter=0
|
3512
|
+
end
|
3513
|
+
|
3514
|
+
# BUG: Untested. (Null implementation passes all tests.)
|
3515
|
+
def add( attrib , length)
|
3516
|
+
@attr << AttributeLengthHolder.new( attrib , length )
|
3517
|
+
end
|
3518
|
+
|
3519
|
+
def delete(attrib)
|
3520
|
+
item_to_delete=nil
|
3521
|
+
@attr.each_with_index do |e,i|
|
3522
|
+
item_to_delete = i if e.attribute==attrib
|
3523
|
+
end
|
3524
|
+
@attr.delete_at(item_to_delete ) unless item_to_delete == nil
|
3525
|
+
end
|
3526
|
+
|
3527
|
+
def next
|
3528
|
+
temp = @attr[@index_counter]
|
3529
|
+
@index_counter +=1
|
3530
|
+
return temp
|
3531
|
+
end
|
3532
|
+
|
3533
|
+
def each
|
3534
|
+
0.upto( @attr.length-1 ) { |i | yield @attr[i] }
|
3535
|
+
end
|
3536
|
+
end
|
3537
|
+
|
3538
|
+
# resume rdoc
|
3539
|
+
#++
|
3540
|
+
|
3541
|
+
|
3542
|
+
# this class accesses the buttons in the document as a collection
|
3543
|
+
# it would normally only be accessed by the Watir::SupportsSubElements#buttons method
|
3544
|
+
#
|
3545
|
+
class Buttons < ElementCollections
|
3546
|
+
def element_class; Button; end
|
3547
|
+
def length
|
3548
|
+
get_length_of_input_objects(["button", "submit", "image"])
|
3549
|
+
end
|
3550
|
+
|
3551
|
+
def set_show_items
|
3552
|
+
super
|
3553
|
+
@show_attributes.add( "disabled" , 9)
|
3554
|
+
@show_attributes.add( "value" , 20)
|
3555
|
+
end
|
3556
|
+
end
|
3557
|
+
|
3558
|
+
|
3559
|
+
# this class accesses the file fields in the document as a collection
|
3560
|
+
# it would normally only be accessed by the Watir::SupportsSubElements#file_fields method
|
3561
|
+
#
|
3562
|
+
class FileFields< ElementCollections
|
3563
|
+
def element_class; FileField; end
|
3564
|
+
def length
|
3565
|
+
get_length_of_input_objects(["file"])
|
3566
|
+
end
|
3567
|
+
|
3568
|
+
def set_show_items
|
3569
|
+
super
|
3570
|
+
@show_attributes.add( "disabled" , 9)
|
3571
|
+
@show_attributes.add( "value" , 20)
|
3572
|
+
end
|
3573
|
+
end
|
3574
|
+
|
3575
|
+
|
3576
|
+
# this class accesses the check boxes in the document as a collection
|
3577
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#checkboxes method
|
3578
|
+
#
|
3579
|
+
class CheckBoxes < ElementCollections
|
3580
|
+
def element_class; CheckBox; end
|
3581
|
+
def length
|
3582
|
+
get_length_of_input_objects("checkbox")
|
3583
|
+
end
|
3584
|
+
# this method creates an object of the correct type that the iterators use
|
3585
|
+
private
|
3586
|
+
def iterator_object(i)
|
3587
|
+
@ieController.checkbox(:index, i+1)
|
3588
|
+
end
|
3589
|
+
end
|
3590
|
+
|
3591
|
+
# this class accesses the radio buttons in the document as a collection
|
3592
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#radios method
|
3593
|
+
#
|
3594
|
+
class Radios < ElementCollections
|
3595
|
+
def element_class; Radio; end
|
3596
|
+
def length
|
3597
|
+
get_length_of_input_objects("radio")
|
3598
|
+
end
|
3599
|
+
# this method creates an object of the correct type that the iterators use
|
3600
|
+
private
|
3601
|
+
def iterator_object(i)
|
3602
|
+
@ieController.radio(:index, i+1)
|
3603
|
+
end
|
3604
|
+
end
|
3605
|
+
|
3606
|
+
# this class accesses the select boxes in the document as a collection
|
3607
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#select_lists method
|
3608
|
+
#
|
3609
|
+
class SelectLists < ElementCollections
|
3610
|
+
include CommonCollection
|
3611
|
+
def element_class; SelectList; end
|
3612
|
+
def element_tag; 'SELECT'; end
|
3613
|
+
end
|
3614
|
+
|
3615
|
+
# this class accesses the links in the document as a collection
|
3616
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#links method
|
3617
|
+
#
|
3618
|
+
class Links < ElementCollections
|
3619
|
+
include CommonCollection
|
3620
|
+
def element_class; Link; end
|
3621
|
+
def element_tag; 'A'; end
|
3622
|
+
|
3623
|
+
def set_show_items
|
3624
|
+
super
|
3625
|
+
@show_attributes.add("href", 60)
|
3626
|
+
@show_attributes.add("innerText" , 60)
|
3627
|
+
end
|
3628
|
+
|
3629
|
+
end
|
3630
|
+
|
3631
|
+
# this class accesses the imnages in the document as a collection
|
3632
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#images method
|
3633
|
+
#
|
3634
|
+
class Images < ElementCollections
|
3635
|
+
def element_class; Image; end
|
3636
|
+
def length
|
3637
|
+
@ieController.document.images.length
|
3638
|
+
end
|
3639
|
+
|
3640
|
+
def set_show_items
|
3641
|
+
super
|
3642
|
+
@show_attributes.add("src", 60)
|
3643
|
+
@show_attributes.add("alt", 30)
|
3644
|
+
end
|
3645
|
+
|
3646
|
+
end
|
3647
|
+
|
3648
|
+
# this class accesses the text fields in the document as a collection
|
3649
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#text_fields method
|
3650
|
+
#
|
3651
|
+
class TextFields < ElementCollections
|
3652
|
+
def element_class; TextField; end
|
3653
|
+
def length
|
3654
|
+
# text areas are also included inthe Text_filds, but we need to get them seperately
|
3655
|
+
get_length_of_input_objects( ["text" , "password"] ) +
|
3656
|
+
@ieController.ie.document.body.getElementsByTagName("textarea").length
|
3657
|
+
end
|
3658
|
+
end
|
3659
|
+
|
3660
|
+
# this class accesses the hidden fields in the document as a collection
|
3661
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#hiddens method
|
3662
|
+
class Hiddens < ElementCollections
|
3663
|
+
def element_class; Hidden; end
|
3664
|
+
def length
|
3665
|
+
get_length_of_input_objects("hidden")
|
3666
|
+
end
|
3667
|
+
end
|
3668
|
+
|
3669
|
+
# this class accesses the text fields in the document as a collection
|
3670
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#tables method
|
3671
|
+
#
|
3672
|
+
class Tables < ElementCollections
|
3673
|
+
include CommonCollection
|
3674
|
+
def element_class; Table; end
|
3675
|
+
def element_tag; 'TABLE'; end
|
3676
|
+
|
3677
|
+
def set_show_items
|
3678
|
+
super
|
3679
|
+
@show_attributes.delete( "name")
|
3680
|
+
end
|
3681
|
+
end
|
3682
|
+
|
3683
|
+
# this class accesses the labels in the document as a collection
|
3684
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#labels method
|
3685
|
+
#
|
3686
|
+
class Labels < ElementCollections
|
3687
|
+
include CommonCollection
|
3688
|
+
def element_class; Label; end
|
3689
|
+
def element_tag; 'LABEL'; end
|
3690
|
+
|
3691
|
+
def set_show_items
|
3692
|
+
super
|
3693
|
+
@show_attributes.add("htmlFor", 20)
|
3694
|
+
end
|
3695
|
+
end
|
3696
|
+
|
3697
|
+
# this class accesses the p tags in the document as a collection
|
3698
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#ps method
|
3699
|
+
#
|
3700
|
+
class Ps < ElementCollections
|
3701
|
+
include CommonCollection
|
3702
|
+
def element_class; P; end
|
3703
|
+
|
3704
|
+
def set_show_items
|
3705
|
+
super
|
3706
|
+
@show_attributes.delete( "name")
|
3707
|
+
@show_attributes.add( "className" , 20)
|
3708
|
+
end
|
3709
|
+
|
3710
|
+
end
|
3711
|
+
|
3712
|
+
# this class accesses the spans in the document as a collection
|
3713
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#spans method
|
3714
|
+
#
|
3715
|
+
class Spans < ElementCollections
|
3716
|
+
include CommonCollection
|
3717
|
+
def element_class; Span; end
|
3718
|
+
|
3719
|
+
def set_show_items
|
3720
|
+
super
|
3721
|
+
@show_attributes.delete( "name")
|
3722
|
+
@show_attributes.add( "className" , 20)
|
3723
|
+
end
|
3724
|
+
|
3725
|
+
end
|
3726
|
+
|
3727
|
+
# this class accesses the divs in the document as a collection
|
3728
|
+
# Normally a user would not need to create this object as it is returned by the Watir::SupportsSubElements#divs method
|
3729
|
+
#
|
3730
|
+
class Divs < ElementCollections
|
3731
|
+
include CommonCollection
|
3732
|
+
def element_class; Div; end
|
3733
|
+
|
3734
|
+
def set_show_items
|
3735
|
+
super
|
3736
|
+
@show_attributes.delete( "name")
|
3737
|
+
@show_attributes.add( "className" , 20)
|
3738
|
+
end
|
3739
|
+
|
3740
|
+
end
|
3741
|
+
|
3742
|
+
end
|
3743
|
+
|
3744
|
+
require 'watir/camel_case'
|