watir 1.5.2 → 1.5.3

Sign up to get free protection for your applications and to get access to all the features.
data/readme.rb CHANGED
@@ -2,17 +2,25 @@
2
2
 
3
3
  This is Watir - Web Application Testing In Ruby http://wtr.rubyforge.org
4
4
 
5
- To Install Ruby: http://ruby-lang.org
6
- Best is to use Ruby 1.8.2-14 or later.
7
- However, if you are using the Watir::IE#modal_dialog method, you must use Ruby 1.8.2-14 and not a more recent version.
8
- Watir (in general) will not work with Ruby 1.8.1-13. (This version of Ruby has a bad WIN32OLE library.)
9
-
10
- To Install Watir:
11
- Best way to install is to use the gem.
12
- From your command line:
13
- > gem install win32-process --include-dependencies
14
- > gem install watir
15
- This will download and install watir, win32-process and all dependencies.
5
+ Install Ruby http://ruby-lang.org
6
+ First you need to install Ruby using the one-click installer for Windows. We
7
+ recommend Ruby 1.8.5. (Ruby 1.8.6 has problems.)
8
+
9
+ However, if you wish to use Watir's support for the IE showModalDialog then
10
+ you must use Ruby 1.8.2-15 (or 1.8.2-14) and not a more recent version. This
11
+ dialog is the one that is posted with the showModalDialog() JavaScript
12
+ command and is supported with Watir's ie.modal_dialog command.
13
+
14
+ Install Watir
15
+ Watir is packaged as a gem, a Ruby library that can be installed over the
16
+ internet.
17
+
18
+ Watir 1.5 was released in September 2007. To install it, type this at a
19
+ command prompt:
20
+ gem install watir
21
+
22
+ Watir 1.4 was released in August 2005. If you are upgrading from it, see
23
+ these notes: http://wiki.openqa.org/display/WTR/Development+Builds
16
24
 
17
25
  How To Use:
18
26
  This only works on Windows.
@@ -93,7 +101,7 @@ Contacts:
93
101
  Paul Rogers (paul.rogers@shaw.ca)
94
102
  Bret Pettichord (bret@pettichord.com)
95
103
  Charley Baker (charley.baker@gmail.com)
96
- The mailing list: http://rubyforge.org/mail/?group_id=104
104
+ The mailing list: http://groups.google.com/group/watir-general
97
105
 
98
106
  Contributors:
99
107
  Bret Pettichord
@@ -6,6 +6,33 @@ Test page for Tables
6
6
  </head>
7
7
  <body>
8
8
 
9
+ <style type="text/css">
10
+ table.sample {
11
+ border-width: 1px 1px 1px 1px;
12
+ border-spacing: 2px;
13
+ border-style: outset outset outset outset;
14
+ border-color: gray gray gray gray;
15
+ border-collapse: separate;
16
+ background-color: white;
17
+ }
18
+ table.sample th {
19
+ border-width: 1px 1px 1px 1px;
20
+ padding: 1px 1px 1px 1px;
21
+ border-style: inset inset inset inset;
22
+ border-color: gray gray gray gray;
23
+ background-color: white;
24
+ -moz-border-radius: 0px 0px 0px 0px;
25
+ }
26
+ table.sample td {
27
+ border-width: 1px 1px 1px 1px;
28
+ padding: 1px 1px 1px 1px;
29
+ border-style: inset inset inset inset;
30
+ border-color: gray gray gray gray;
31
+ background-color: white;
32
+ -moz-border-radius: 0px 0px 0px 0px;
33
+ }
34
+ </style>
35
+
9
36
  <script language=javascript>
10
37
 
11
38
  function addRow() {
@@ -32,7 +59,7 @@ function addRow() {
32
59
  </script>
33
60
 
34
61
 
35
- CVS Revision: "$Revision: 561 $"
62
+ CVS Revision: "$Revision: 1239 $"
36
63
  <br>
37
64
  <br>
38
65
  <table >
@@ -137,6 +164,19 @@ This text is in the THIRD TBODY.
137
164
 
138
165
 
139
166
 
167
+ <table class="sample">
168
+ <tr>
169
+ <th>Header</th>
170
+ <td>First table with css class</td>
171
+ </tr>
172
+ </table>
173
+
174
+ <table class="sample">
175
+ <tr>
176
+ <td>Second table with css class</td>
177
+ </tr>
178
+ </table>
179
+
140
180
 
141
181
  </body>
142
182
  </html>
@@ -1,9 +1,9 @@
1
1
  # feature tests for Links
2
- # revision: $Revision: 1078 $
2
+ # revision: $Revision: 1277 $
3
3
 
4
4
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..') if $0 == __FILE__
5
5
  require 'unittests/setup'
6
- require 'CGI'
6
+ require 'cgi'
7
7
 
8
8
  class TC_Links < Test::Unit::TestCase
9
9
  include Watir
@@ -1,9 +1,9 @@
1
1
  # feature tests for navigation
2
- # revision: $Revision: 1009 $
2
+ # revision: $Revision: 1277 $
3
3
 
4
4
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..') if $0 == __FILE__
5
5
  require 'unittests/setup'
6
- require 'CGI'
6
+ require 'cgi'
7
7
 
8
8
  class TC_Navigate < Test::Unit::TestCase
9
9
  include Watir
@@ -3,21 +3,6 @@
3
3
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..') if $0 == __FILE__
4
4
  require 'unittests/setup'
5
5
 
6
- # These tests are based on the rails depot application, which requires some
7
- # modifications...
8
-
9
- module Watir
10
- class H3 < NonControlElement
11
- TAG = 'h3'
12
- end
13
- module Container
14
- def h3(how, what)
15
- return H3.new(self, how, what)
16
- end
17
- end
18
- end
19
-
20
-
21
6
  class TC_Relative < Test::Unit::TestCase
22
7
 
23
8
  def setup
@@ -1,5 +1,5 @@
1
1
  # feature tests for Tables
2
- # revision: $Revision: 1076 $
2
+ # revision: $Revision: 1246 $
3
3
 
4
4
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..') if $0 == __FILE__
5
5
  require 'unittests/setup'
@@ -54,7 +54,6 @@ class TC_Tables < Test::Unit::TestCase
54
54
  def test_dynamic_tables
55
55
  t = $ie.table(:id, 't1')
56
56
  assert_equal(5, t.row_count)
57
-
58
57
  $ie.button(:value, 'add row').click
59
58
  assert_equal(6, t.row_count)
60
59
  end
@@ -176,6 +175,10 @@ class TC_Tables < Test::Unit::TestCase
176
175
  def test_table_container
177
176
  assert_nothing_raised { $ie.table(:id, 't1').html }
178
177
  end
178
+
179
+ def test_multiple_selector
180
+ assert( $ie.table(:class => 'sample', :index => 2)[1][1].text, '')
181
+ end
179
182
  end
180
183
 
181
184
  class TC_Tables_Simple < Test::Unit::TestCase
@@ -1,5 +1,5 @@
1
- # feature tests for TextArea Fields
2
- # revision: $Revision: 963 $
1
+ # tests for textarea elements
2
+ # revision: $Revision: 1260 $
3
3
 
4
4
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..') if $0 == __FILE__
5
5
  require 'unittests/setup'
@@ -7,13 +7,15 @@ require 'unittests/setup'
7
7
  class TC_TextArea < Test::Unit::TestCase
8
8
  include Watir
9
9
 
10
- def goto_page
11
- $ie.goto($htmlRoot + "textArea.html")
10
+ def use_page page
11
+ $ie.goto($htmlRoot + page)
12
+ end
13
+
14
+ def setup
15
+ use_page 'textarea.html'
12
16
  end
13
17
 
14
- def test_textarea_field_exists
15
- goto_page
16
- #test for existance of 4 text area
18
+ def test_elements_exist_or_not
17
19
  assert($ie.text_field(:name,"txtMultiLine1").exists?)
18
20
  assert($ie.text_field(:name,"txtMultiLine2").exists?)
19
21
  assert($ie.text_field(:name,"txtMultiLine3").exists?)
@@ -23,59 +25,73 @@ class TC_TextArea < Test::Unit::TestCase
23
25
  assert($ie.text_field(:id,"txtMultiLine2").exists?)
24
26
  assert($ie.text_field(:id,"txtMultiLine3").exists?)
25
27
  assert($ie.text_field(:id,"txtReadOnly").exists?)
26
- #test for missing
28
+
27
29
  assert(!$ie.text_field(:name, "missing").exists?)
28
30
  assert(!$ie.text_field(:name,"txtMultiLine4").exists?)
29
31
  end
30
32
 
31
- def test_textarea_to_s
33
+ def test_to_s_bug
32
34
  # from a bug reported by Zeljko Filipin
33
35
  assert_nothing_raised { $ie.text_field(:id,"txtMultiLine3").to_s }
34
36
  end
35
37
 
36
- def test_textarea_field
37
- goto_page
38
-
39
- # test for read only method
38
+ def test_maxlength_bug
39
+ # from another bug
40
+ assert_nothing_raised { $ie.text_field(:id,"txtMultiLine3").append('foo')}
41
+ end
42
+
43
+ def test_readonly_and_enabled
40
44
  assert(!$ie.text_field(:name, "txtMultiLine1").readonly? )
41
45
  assert($ie.text_field(:name,"txtReadOnly").readonly?)
42
46
 
43
- # test for enabled? method
44
47
  assert(!$ie.text_field(:name, "txtDisabled").enabled? )
45
48
  assert($ie.text_field(:id, "txtMultiLine1").enabled? )
46
-
47
-
49
+ end
50
+
51
+ def test_verify_contains
48
52
  t1 = $ie.text_field(:name, "txtMultiLine1")
49
53
  assert(t1.verify_contains("Hello World") )
50
54
  assert(t1.verify_contains(/el/) )
51
- t2 = $ie.text_field(:name, "txtMultiLine2")
52
- assert(t2.verify_contains(/IE/))
53
- assert_raises(UnknownObjectException , "UnknownObjectException was supposed to be thrown" ) { $ie.text_field(:name, "NoName").verify_contains("No field to get a value of") }
54
- assert_raises(UnknownObjectException , "UnknownObjectException was supposed to be thrown" ) { $ie.text_field(:id, "noID").verify_contains("No field to get a value of") }
55
-
56
- assert_raises(UnknownObjectException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:name, "txtNone").append("Some Text") }
57
-
58
- assert_raises(ObjectReadOnlyException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:id, "txtReadOnly").append("Some Text") }
59
- assert_raises(ObjectDisabledException , "ObjectDisabledException was supposed to be thrown" ) { $ie.text_field(:name, "txtDisabled").append("Some Text") }
60
- assert_raises(UnknownObjectException , "UnknownObjectException was supposed to be thrown" ) { $ie.text_field(:name, "missing_field").append("Some Text") }
61
-
55
+ assert($ie.text_field(:name, "txtMultiLine2").verify_contains(/IE/))
56
+ end
57
+
58
+ def test_no_such_element
59
+ assert_raises(UnknownObjectException) do
60
+ $ie.text_field(:name, "NoName").verify_contains("de nada")
61
+ end
62
+ assert_raises(UnknownObjectException) do
63
+ $ie.text_field(:id, "noID").verify_contains("de nada")
64
+ end
65
+ assert_raises(UnknownObjectException) do
66
+ $ie.text_field(:name, "txtNone").append("de nada")
67
+ end
68
+ end
69
+ def test_readonly_and_disabled_errors
70
+ assert_raises(ObjectReadOnlyException) do
71
+ $ie.text_field(:id, "txtReadOnly").append("de nada")
72
+ end
73
+ assert_raises(ObjectDisabledException) do
74
+ $ie.text_field(:name, "txtDisabled").append("de nada")
75
+ end
76
+ assert_raises(ObjectReadOnlyException) do
77
+ $ie.text_field(:id, "txtReadOnly").append("Some Text")
78
+ end
79
+ assert_raises(ObjectDisabledException) do
80
+ $ie.text_field(:name, "txtDisabled").append("Some Text")
81
+ end
82
+ end
83
+
84
+ def test_append_set_and_clear
62
85
  $ie.text_field(:name, "txtMultiLine1").append(" Some Text")
63
- assert_equal( "Hello World Some Text" , $ie.text_field(:name, "txtMultiLine1").getContents )
64
-
65
- assert_raises(ObjectReadOnlyException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:id, "txtReadOnly").append("Some Text") }
66
- assert_raises(ObjectDisabledException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:name, "txtDisabled").append("Some Text") }
67
- assert_raises(UnknownObjectException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:name, "missing_field").append("Some Text") }
86
+ assert_equal("Hello World Some Text",
87
+ $ie.text_field(:name, "txtMultiLine1").getContents )
68
88
 
69
89
  $ie.text_field(:name, "txtMultiLine1").set("watir IE Controller")
70
- assert_equal( "watir IE Controller" , $ie.text_field(:name, "txtMultiLine1").getContents )
71
-
72
- assert_raises(ObjectReadOnlyException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:id, "txtReadOnly").append("Some Text") }
73
- assert_raises(ObjectDisabledException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:name, "txtDisabled").append("Some Text") }
74
- assert_raises(UnknownObjectException , "ObjectReadOnlyException was supposed to be thrown" ) { $ie.text_field(:name, "missing_field").append("Some Text") }
90
+ assert_equal("watir IE Controller",
91
+ $ie.text_field(:name, "txtMultiLine1").getContents )
75
92
 
76
93
  $ie.text_field(:name, "txtMultiLine2").clear
77
- assert_equal( "" , $ie.text_field(:name, "txtMultiLine2").getContents )
78
-
94
+ assert_equal("" , $ie.text_field(:name, "txtMultiLine2").getContents )
79
95
  end
80
96
 
81
97
  end
@@ -1,5 +1,5 @@
1
1
  # unit tests for iedialog.dll and customized win32ole.so
2
- # revision: $Revision: 1177 $
2
+ # revision: $Revision: 1278 $
3
3
 
4
4
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', '..') if $0 == __FILE__
5
5
  require 'unittests/setup'
@@ -10,7 +10,7 @@ class TC_IEDialog < Test::Unit::TestCase
10
10
  include Watir
11
11
 
12
12
  # this will find the IEDialog.dll file in its build location
13
- @@iedialog_file = (File.expand_path(File.dirname(__FILE__)) + "/../watir/IEDialog/Release/IEDialog.dll").gsub('/', '\\')
13
+ @@iedialog_file = (File.expand_path(File.dirname(__FILE__)) + "/../../watir/IEDialog/Release/IEDialog.dll").gsub('/', '\\')
14
14
 
15
15
  # commented out because it currently requires a manual click
16
16
  # a better idea would be to automate the click...
data/watir.rb CHANGED
@@ -86,6 +86,25 @@ $FAST_SPEED = command_line_flag('-f')
86
86
  # Eat the -s command line switch (deprecated)
87
87
  command_line_flag('-s')
88
88
 
89
+ require 'watir/logger'
90
+ require 'watir/win32'
91
+ require 'watir/container'
92
+ require 'watir/locator'
93
+ require 'watir/page-container'
94
+ require 'watir/ie'
95
+ require 'watir/popup'
96
+ require 'watir/element'
97
+ require 'watir/frame'
98
+ require 'watir/modal_dialog'
99
+ require 'watir/element_collections'
100
+ require 'watir/form'
101
+ require 'watir/non_control_elements'
102
+ require 'watir/input_elements'
103
+ require 'watir/table'
104
+ require 'watir/image'
105
+ require 'watir/link'
106
+ require 'watir/collections'
107
+
89
108
  module Watir
90
109
  include Watir::Exception
91
110
 
@@ -103,4393 +122,8 @@ module Watir
103
122
  ATTACHER.timeout = IE.attach_timeout
104
123
  ATTACHER.wait_until { yield }
105
124
  end
106
-
107
- class WatirLogger < Logger
108
- def initialize(filName, logsToKeep, maxLogSize)
109
- super(filName, logsToKeep, maxLogSize)
110
- self.level = Logger::DEBUG
111
- self.datetime_format = "%d-%b-%Y %H:%M:%S"
112
- self.debug("Watir starting")
113
- end
114
- end
115
-
116
- class DefaultLogger < Logger
117
- def initialize
118
- super(STDERR)
119
- self.level = Logger::WARN
120
- self.datetime_format = "%d-%b-%Y %H:%M:%S"
121
- self.info "Log started"
122
- end
123
- end
124
-
125
- module Win32
126
- # this will find the IEDialog.dll file in its build location
127
- @@iedialog_file = (File.expand_path(File.dirname(__FILE__)) + "/watir/IEDialog/Release/IEDialog.dll").gsub('/', '\\')
128
-
129
- GetUnknown = Win32API.new(@@iedialog_file, 'GetUnknown', ['l', 'p'], 'v')
130
- User32 = DL.dlopen('user32')
131
- FindWindowEx = User32['FindWindowEx', 'LLLpp']
132
- # method for this found in wet-winobj/wet/winobjects/WinUtils.rb
133
- GetWindow = User32['GetWindow', 'ILL']
134
-
135
- ## GetWindows Constants
136
- GW_HWNDFIRST = 0
137
- GW_HWNDLAST = 1
138
- GW_HWNDNEXT = 2
139
- GW_HWNDPREV = 3
140
- GW_OWNER = 4
141
- GW_CHILD = 5
142
- GW_ENABLEDPOPUP = 6
143
- GW_MAX = 6
144
-
145
- IsWindow = User32['IsWindow', 'II']
146
- # Does the window with the specified window handle (hwnd) exist?
147
- def self.window_exists? hwnd
148
- rtn, junk = IsWindow[hwnd]
149
- rtn == 1
150
- end
151
- end
152
-
153
- # This module contains the factory methods that are used to access most html objects
154
- #
155
- # For example, to access a button on a web page that has the following html
156
- # <input type = button name= 'b1' value='Click Me' onClick='javascript:doSomething()'>
157
- #
158
- # the following watir code could be used
159
- #
160
- # ie.button(:name, 'b1').click
161
- #
162
- # or
163
- #
164
- # ie.button(:value, 'Click Me').to_s
165
- #
166
- # there are many methods available to the Button object
167
- #
168
- # Is includable for classes that have @container, document and ole_inner_elements
169
- module Container
170
- include Watir::Exception
171
-
172
- # Note: @container is the container of this object, i.e. the container
173
- # of this container.
174
- # In other words, for ie.table().this_thing().text_field().set,
175
- # container of this_thing is the table.
176
-
177
- # This is used to change the typing speed when entering text on a page.
178
- attr_accessor :typingspeed
179
- # The color we want to use for the active object. This can be any valid web-friendly color.
180
- attr_accessor :activeObjectHighLightColor
181
- # The PageContainer object containing this element
182
- attr_accessor :page_container
183
-
184
- def copy_test_config(container) # only used by form and frame
185
- @typingspeed = container.typingspeed
186
- @activeObjectHighLightColor = container.activeObjectHighLightColor
187
- end
188
- private :copy_test_config
189
-
190
- # Write the specified string to the log.
191
- def log(what)
192
- @container.logger.debug(what) if @logger
193
- end
194
-
195
- # Wait until Internet Explorer has finished loading the page.
196
- def wait(no_sleep=false)
197
- @container.wait(no_sleep)
198
- end
199
-
200
- # Determine the how and what when defaults are possible.
201
- def process_default(default_attribute, how, what)
202
- if how.class == String && what == nil
203
- what = how
204
- how = default_attribute
205
- end
206
- return how, what
207
- end
208
- private :process_default
209
-
210
- def set_container container
211
- @container = container
212
- @page_container = container.page_container
213
- end
214
-
215
- private
216
- def self.def_creator(method_name, klass_name=nil)
217
- klass_name ||= method_name.to_s.capitalize
218
- class_eval "def #{method_name}(how, what=nil)
219
- #{klass_name}.new(self, how, what)
220
- end"
221
- end
222
-
223
- def self.def_creator_with_default(method_name, default_symbol)
224
- klass_name = method_name.to_s.capitalize
225
- class_eval "def #{method_name}(how, what=nil)
226
- how, what = process_default :#{default_symbol}, how, what
227
- #{klass_name}.new(self, how, what)
228
- end"
229
- end
230
-
231
- #
232
- # Factory Methods
233
- #
234
-
235
- # this method is the main way of accessing a frame
236
- # * how - how the frame is accessed. This can also just be the name of the frame.
237
- # * what - what we want to access.
238
- #
239
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
240
- #
241
- # returns a Frame object
242
- #
243
- # Typical usage:
244
- #
245
- # ie.frame(:index, 1)
246
- # ie.frame(:name, 'main_frame')
247
- # ie.frame('main_frame') # in this case, just a name is supplied
248
- public
249
- def frame(how, what=nil)
250
- how, what = process_default :name, how, what
251
- Frame.new(self, how, what)
252
- end
253
-
254
- # this method is used to access a form.
255
- # available ways of accessing it are, :index, :name, :id, :method, :action, :xpath
256
- # * how - symbol - What mecahnism we use to find the form, one of
257
- # the above. NOTE if what is not supplied this parameter is the NAME of the form
258
- # * what - String - the text associated with the symbol
259
- #
260
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
261
- #
262
- # returns a Form object
263
- def form(how, what=nil)
264
- how, what = process_default :name, how, what
265
- Form.new(self, how, what)
266
- end
267
-
268
- # This method is used to get a table from the page.
269
- # :index (1 based counting) and :id are supported.
270
- # NOTE :name is not supported, as the table tag does not have a name attribute. It is not part of the DOM.
271
- # :index can be used when there are multiple tables on a page.
272
- # :xpath can be used to select table using XPath query.
273
- # The first form can be accessed with :index 1, the second :index 2, etc.
274
- # * how - symbol - how we access the table, :index, :id, :xpath etc
275
- # * what - string the thing we are looking for, ex. id, index or xpath query, of the object we are looking for
276
- #
277
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
278
- #
279
- # returns a Table object
280
- def table(how, what=nil)
281
- Table.new(self, how, what)
282
- end
283
-
284
- # this is the main method for accessing the tables iterator. It returns a Tables object
285
- #
286
- # Typical usage:
287
- #
288
- # ie.tables.each { |t| puts t.to_s } # iterate through all the tables on the page
289
- # ie.tables[1].to_s # goto the first table on the page
290
- # ie.tables.length # show how many tables are on the page. Tables that are nested will be included in this
291
- def tables
292
- Tables.new(self)
293
- end
294
-
295
- # this method accesses a table cell.
296
- # how - symbol - how we access the cell, valid values are
297
- # :id - find the table cell with given id.
298
- # :xpath - find the table cell using xpath query.
299
- #
300
- # returns a TableCell Object
301
- def cell(how, what=nil)
302
- TableCell.new(self, how, what)
303
- end
304
- def cells
305
- TableCells.new(self)
306
- end
307
-
308
- # this method accesses a table row.
309
- # how - symbol - how we access the row, valid values are
310
- # :id - find the table row with given id.
311
- # :xpath - find the table row using xpath query.
312
- #
313
- # returns a TableRow object
314
- def row(how, what=nil)
315
- TableRow.new(self, how, what)
316
- end
317
- def rows
318
- TableRows.new(self)
319
- end
320
-
321
- # Access a modal web dialog, which is a PageContainer, like IE or Frame.
322
- # Returns a ModalDialog object.
323
- #
324
- # Typical Usage
325
- # ie.modal_dialog # access the modal dialog of ie
326
- # ie.modal_dialog(:title, 'Title') # access the modal dialog by title
327
- # ie.modal_dialog.modal_dialog # access a modal dialog's modal dialog XXX untested!
328
- #
329
- # This method will not work when
330
- # Watir/Ruby is run under a service (instead of a user).
331
- # Note: unlike Watir.attach, this returns before the page is assured to have
332
- # loaded.
333
-
334
- def modal_dialog(how=nil, what=nil)
335
- ModalDialog.new(self, how, what)
336
- end
337
-
338
- # This is the main method for accessing a button. Often declared as an <input type = submit> tag.
339
- # * how - symbol - how we access the button, :index, :id, :name etc
340
- # * what - string, integer or regular expression - what we are looking for,
341
- #
342
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
343
- #
344
- # Returns a Button object.
345
- #
346
- # Typical usage
347
- #
348
- # ie.button(:id, 'b_1') # access the button with an ID of b_1
349
- # ie.button(:name, 'verify_data') # access the button with a name of verify_data
350
- # ie.button(:value, 'Login') # access the button with a value (the text displayed on the button) of Login
351
- # ie.button(:caption, 'Login') # same as above
352
- # ie.button(:value, /Log/) # access the button that has text matching /Log/
353
- # ie.button(:index, 2) # access the second button on the page (1 based, so the first button is accessed with :index,1)
354
- # ie.button(:class, 'my_custom_button_class') # access the button with a class of my_custom_button_class
355
- # ie.button(:xpath, "//input[@value='Click Me']/") # access the button with a value of Click Me
356
- #
357
- # Accessing a Button nested within another element
358
- # ie.div(:class, 'xyz').button(:index, 2) # access a div of class xyz, and the 2nd button within that div
359
- #
360
- # If only a single parameter is supplied, then :value is used
361
- # ie.button('Click Me') # access the button with a value of Click Me
362
- def button(how, what=nil)
363
- how, what = process_default :value, how, what
364
- Button.new(self, how, what)
365
- end
366
-
367
- # this is the main method for accessing the buttons iterator. It returns a Buttons object
368
- #
369
- # Typical usage:
370
- #
371
- # ie.buttons.each { |b| puts b.to_s } # iterate through all the buttons on the page
372
- # ie.buttons[1].to_s # goto the first button on the page
373
- # ie.buttons.length # show how many buttons are on the page.
374
- def buttons
375
- Buttons.new(self)
376
- end
377
-
378
- # This is the main method for accessing a file field. Usually an <input type = file> HTML tag.
379
- # * how - symbol - how we access the field, valid values are
380
- # :index - find the file field using index
381
- # :id - find the file field using id attribute
382
- # :name - find the file field using name attribute
383
- # :xpath - find the file field using xpath query
384
- # * what - string, integer, regular expression, or xpath query - what we are looking for,
385
- #
386
- # returns a FileField object
387
- #
388
- # Typical Usage
389
- #
390
- # ie.file_field(:id, 'up_1') # access the file upload field with an ID of up_1
391
- # ie.file_field(:name, 'upload') # access the file upload field with a name of upload
392
- # ie.file_field(:index, 2) # access the second file upload on the page (1 based, so the first field is accessed with :index,1)
393
- #
394
- def file_field(how, what=nil)
395
- FileField.new(self, how, what)
396
- end
397
-
398
- # this is the main method for accessing the file_fields iterator. It returns a FileFields object
399
- #
400
- # Typical usage:
401
- #
402
- # ie.file_fields.each { |f| puts f.to_s } # iterate through all the file fields on the page
403
- # ie.file_fields[1].to_s # goto the first file field on the page
404
- # ie.file_fields.length # show how many file fields are on the page.
405
- def file_fields
406
- FileFields.new(self)
407
- end
408
-
409
- # This is the main method for accessing a text field. Usually an <input type = text> HTML tag. or a text area - a <textarea> tag
410
- # * how - symbol - how we access the field, :index, :id, :name etc
411
- # * what - string, integer or regular expression - what we are looking for,
412
- #
413
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
414
- #
415
- # returns a TextField object
416
- #
417
- # Typical Usage
418
- #
419
- # ie.text_field(:id, 'user_name') # access the text field with an ID of user_name
420
- # ie.text_field(:name, 'address') # access the text field with a name of address
421
- # ie.text_field(:index, 2) # access the second text field on the page (1 based, so the first field is accessed with :index,1)
422
- # ie.text_field(:xpath, "//textarea[@id='user_name']/") # access the text field with an ID of user_name
423
- def text_field(how, what=nil)
424
- TextField.new(self, how, what)
425
- end
426
-
427
- # this is the method for accessing the text_fields iterator. It returns a Text_Fields object
428
- #
429
- # Typical usage:
430
- #
431
- # ie.text_fields.each { |t| puts t.to_s } # iterate through all the text fields on the page
432
- # ie.text_fields[1].to_s # goto the first text field on the page
433
- # ie.text_fields.length # show how many text field are on the page.
434
- def text_fields
435
- TextFields.new(self)
436
- end
437
-
438
- # This is the main method for accessing a hidden field. Usually an <input type = hidden> HTML tag
439
- #
440
- # * how - symbol - how we access the hidden field, :index, :id, :name etc
441
- # * what - string, integer or regular expression - what we are looking for,
442
- #
443
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
444
- #
445
- # returns a Hidden object
446
- #
447
- # Typical usage
448
- #
449
- # ie.hidden(:id, 'session_id') # access the hidden field with an ID of session_id
450
- # ie.hidden(:name, 'temp_value') # access the hidden field with a name of temp_value
451
- # ie.hidden(:index, 2) # access the second hidden field on the page (1 based, so the first field is accessed with :index,1)
452
- # ie.hidden(:xpath, "//input[@type='hidden' and @id='session_value']/") # access the hidden field with an ID of session_id
453
- def hidden(how, what=nil)
454
- Hidden.new(self, how, what)
455
- end
456
-
457
- # this is the method for accessing the hiddens iterator. It returns a Hiddens object
458
- #
459
- # Typical usage:
460
- #
461
- # ie.hiddens.each { |t| puts t.to_s } # iterate through all the hidden fields on the page
462
- # ie.hiddens[1].to_s # goto the first hidden field on the page
463
- # ie.hiddens.length # show how many hidden fields are on the page.
464
- def hiddens
465
- Hiddens.new(self)
466
- end
467
-
468
- # This is the main method for accessing a selection list. Usually a <select> HTML tag.
469
- # * how - symbol - how we access the selection list, :index, :id, :name etc
470
- # * what - string, integer or regular expression - what we are looking for,
471
- #
472
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
473
- #
474
- # returns a SelectList object
475
- #
476
- # Typical usage
477
- #
478
- # ie.select_list(:id, 'currency') # access the select box with an id of currency
479
- # ie.select_list(:name, 'country') # access the select box with a name of country
480
- # ie.select_list(:name, /n_/) # access the first select box whose name matches n_
481
- # ie.select_list(:index, 2) # access the second select box on the page (1 based, so the first field is accessed with :index,1)
482
- # ie.select(:xpath, "//select[@id='currency']/") # access the select box with an id of currency
483
- def select_list(how, what)
484
- SelectList.new(self, how, what)
485
- end
486
-
487
- # this is the method for accessing the select lists iterator. Returns a SelectLists object
488
- #
489
- # Typical usage:
490
- #
491
- # ie.select_lists.each { |s| puts s.to_s } # iterate through all the select boxes on the page
492
- # ie.select_lists[1].to_s # goto the first select boxes on the page
493
- # ie.select_lists.length # show how many select boxes are on the page.
494
- def select_lists
495
- SelectLists.new(self)
496
- end
497
-
498
- # This is the main method for accessing a check box. Usually an <input type = checkbox> HTML tag.
499
- #
500
- # * how - symbol - how we access the check box - :index, :id, :name etc
501
- # * what - string, integer or regular expression - what we are looking for,
502
- # * value - string - when there are multiple objects with different value attributes, this can be used to find the correct object
503
- #
504
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
505
- #
506
- # returns a CheckBox object
507
- #
508
- # Typical usage
509
- #
510
- # ie.checkbox(:id, 'send_email') # access the check box with an id of send_mail
511
- # ie.checkbox(:name, 'send_copy') # access the check box with a name of send_copy
512
- # ie.checkbox(:name, /n_/) # access the first check box whose name matches n_
513
- # ie.checkbox(:index, 2) # access the second check box on the page (1 based, so the first field is accessed with :index,1)
514
- #
515
- # In many instances, checkboxes on an html page have the same name, but are identified by different values. An example is shown next.
516
- #
517
- # <input type = checkbox name = email_frequency value = 'daily' > Daily Email
518
- # <input type = checkbox name = email_frequency value = 'Weekly'> Weekly Email
519
- # <input type = checkbox name = email_frequency value = 'monthly'>Monthly Email
520
- #
521
- # Watir can access these using the following:
522
- #
523
- # ie.checkbox(:id, 'day_to_send', 'monday') # access the check box with an id of day_to_send and a value of monday
524
- # ie.checkbox(:name,'email_frequency', 'weekly') # access the check box with a name of email_frequency and a value of 'weekly'
525
- # ie.checkbox(:xpath, "//input[@name='email_frequency' and @value='daily']/") # access the checkbox with a name of email_frequency and a value of 'daily'
526
- def checkbox(how, what, value=nil)
527
- CheckBox.new(self, how, what, ["checkbox"], value)
528
- end
529
-
530
- # this is the method for accessing the check boxes iterator. Returns a CheckBoxes object
531
- #
532
- # Typical usage:
533
- #
534
- # ie.checkboxes.each { |c| puts c.to_s } # iterate through all the check boxes on the page
535
- # ie.checkboxes[1].to_s # goto the first check box on the page
536
- # ie.checkboxes.length # show how many check boxes are on the page.
537
- def checkboxes
538
- CheckBoxes.new(self)
539
- end
540
-
541
- # This is the main method for accessing a radio button. Usually an <input type = radio> HTML tag.
542
- # * how - symbol - how we access the radio button, :index, :id, :name etc
543
- # * what - string, integer or regular expression - what we are looking for,
544
- # * value - string - when there are multiple objects with different value attributes, this can be used to find the correct object
545
- #
546
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
547
- #
548
- # returns a Radio object
549
- #
550
- # Typical usage
551
- #
552
- # ie.radio(:id, 'send_email') # access the radio button with an id of currency
553
- # ie.radio(:name, 'send_copy') # access the radio button with a name of country
554
- # ie.radio(:name, /n_/) # access the first radio button whose name matches n_
555
- # ie.radio(:index, 2) # access the second radio button on the page (1 based, so the first field is accessed with :index,1)
556
- #
557
- # In many instances, radio buttons on an html page have the same name, but are identified by different values. An example is shown next.
558
- #
559
- # <input type="radio" name="email_frequency" value="daily">Daily Email</input>
560
- # <input type="radio" name="email_frequency" value="weekly">Weekly Email</input>
561
- # <input type="radio" name="email_frequency" value="monthly">Monthly Email</input>
562
- #
563
- # Watir can access these using the following:
564
- #
565
- # ie.radio(:id, 'day_to_send', 'monday') # access the radio button with an id of day_to_send and a value of monday
566
- # ie.radio(:name,'email_frequency', 'weekly') # access the radio button with a name of email_frequency and a value of 'weekly'
567
- # ie.radio(:xpath, "//input[@name='email_frequency' and @value='daily']/") # access the radio button with a name of email_frequency and a value of 'daily'
568
- def radio(how, what, value=nil)
569
- Radio.new(self, how, what, ["radio"], value)
570
- end
571
-
572
- # This is the method for accessing the radio buttons iterator. Returns a Radios object
573
- #
574
- # Typical usage:
575
- #
576
- # ie.radios.each { |r| puts r.to_s } # iterate through all the radio buttons on the page
577
- # ie.radios[1].to_s # goto the first radio button on the page
578
- # ie.radios.length # show how many radio buttons are on the page.
579
- #
580
- def radios
581
- Radios.new(self)
582
- end
583
-
584
- # This is the main method for accessing a link.
585
- # * how - symbol - how we access the link, :index, :id, :name, :title, :text, :url
586
- # * what - string, integer or regular expression - what we are looking for,
587
- #
588
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
589
- #
590
- # returns a Link object
591
- #
592
- # Typical Usage
593
- #
594
- # ie.link(:url, /login/) # access the first link whose url matches login. We can use a string in place of the regular expression
595
- # # but the complete path must be used, ie.link(:url, 'http://myserver.com/my_path/login.asp')
596
- # ie.link(:index,2) # access the second link on the page
597
- # ie.link(:title, "Picture") # access a link using the tool tip
598
- # ie.link(:text, 'Click Me') # access the link that has Click Me as its text
599
- # ie.link(:xpath, "//a[contains(.,'Click Me')]/") # access the link with Click Me as its text
600
- def link(how, what=nil)
601
- Link.new(self, how, what)
602
- end
603
-
604
- # This is the main method for accessing the links collection. Returns a Links object
605
- #
606
- # Typical usage:
607
- #
608
- # ie.links.each { |l| puts l.to_s } # iterate through all the links on the page
609
- # ie.links[1].to_s # goto the first link on the page
610
- # ie.links.length # show how many links are on the page.
611
- #
612
- def links
613
- Links.new(self)
614
- end
615
-
616
- # This is the main method for accessing li tags - http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/map.asp?frame=true
617
- # * how - symbol - how we access the li,
618
- # * what - string, integer or regular expression - what we are looking for,
619
- #
620
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
621
- #
622
- # returns a li object
623
- #
624
- # Typical Usage
625
- #
626
- # ie.li(:id, /list/) # access the first li that matches list.
627
- # ie.li(:index,2) # access the second li on the page
628
- # ie.li(:title, "A Picture") # access a li using the tooltip text. See http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/title_1.asp?frame=true
629
- #
630
- def li(how, what)
631
- return Li.new(self, how, what)
632
- end
633
-
634
- # this is the main method for accessing the lis iterator.
635
- #
636
- # Returns a lis object
637
- #
638
- # Typical usage:
639
- #
640
- # ie.lis.each { |s| puts s.to_s } # iterate through all the lis on the page
641
- # ie.lis[1].to_s # goto the first li on the page
642
- # ie.lis.length # show how many lis are on the page.
643
- #
644
- def lis
645
- return Lis.new(self)
646
- end
647
-
648
-
649
- # This is the main method for accessing map tags - http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/map.asp?frame=true
650
- # * how - symbol - how we access the map,
651
- # * what - string, integer or regular expression - what we are looking for,
652
- #
653
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
654
- #
655
- # returns a map object
656
- #
657
- # Typical Usage
658
- #
659
- # ie.map(:id, /list/) # access the first map that matches list.
660
- # ie.map(:index,2) # access the second map on the page
661
- # ie.map(:title, "A Picture") # access a map using the tooltip text. See http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/title_1.asp?frame=true
662
- #
663
- def map(how, what)
664
- return Map.new(self, how, what)
665
- end
666
-
667
- # this is the main method for accessing the maps iterator.
668
- #
669
- # Returns a maps object
670
- #
671
- # Typical usage:
672
- #
673
- # ie.maps.each { |s| puts s.to_s } # iterate through all the maps on the page
674
- # ie.maps[1].to_s # goto the first map on the page
675
- # ie.maps.length # show how many maps are on the page.
676
- #
677
- def maps
678
- return Maps.new(self)
679
- end
680
-
681
- # This is the main method for accessing area tags - http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/area.asp?frame=true
682
- # * how - symbol - how we access the area
683
- # * what - string, integer or regular expression - what we are looking for,
684
- #
685
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
686
- #
687
- # returns a area object
688
- #
689
- # Typical Usage
690
- #
691
- # ie.area(:id, /list/) # access the first area that matches list.
692
- # ie.area(:index,2) # access the second area on the page
693
- # ie.area(:title, "A Picture") # access a area using the tooltip text. See http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/title_1.asp?frame=true
694
- #
695
- def area(how, what)
696
- return Area.new(self, how, what)
697
- end
698
-
699
- # this is the main method for accessing the areas iterator.
700
- #
701
- # Returns a areas object
702
- #
703
- # Typical usage:
704
- #
705
- # ie.areas.each { |s| puts s.to_s } # iterate through all the areas on the page
706
- # ie.areas[1].to_s # goto the first area on the page
707
- # ie.areas.length # show how many areas are on the page.
708
- #
709
- def areas
710
- return Areas.new(self)
711
- end
712
-
713
- # This is the main method for accessing images - normally an <img src="image.gif"> HTML tag.
714
- # * how - symbol - how we access the image, :index, :id, :name, :src, :title or :alt are supported
715
- # * what - string, integer or regular expression - what we are looking for,
716
- #
717
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
718
- #
719
- # returns an Image object
720
- #
721
- # Typical Usage
722
- #
723
- # ie.image(:src, /myPic/) # access the first image that matches myPic. We can use a string in place of the regular expression
724
- # # but the complete path must be used, ie.image(:src, 'http://myserver.com/my_path/my_image.jpg')
725
- # ie.image(:index,2) # access the second image on the page
726
- # ie.image(:alt, "A Picture") # access an image using the alt text
727
- # ie.image(:xpath, "//img[@alt='A Picture']/") # access an image using the alt text
728
- #
729
- def image(how,what=nil)
730
- Image.new(self, how, what)
731
- end
732
-
733
- # This is the main method for accessing the images collection. Returns an Images object
734
- #
735
- # Typical usage:
736
- #
737
- # ie.images.each { |i| puts i.to_s } # iterate through all the images on the page
738
- # ie.images[1].to_s # goto the first image on the page
739
- # ie.images.length # show how many images are on the page.
740
- #
741
- def images
742
- Images.new(self)
743
- end
744
-
745
- # This is the main method for accessing JavaScript popups.
746
- # returns a PopUp object
747
- def popup # BUG this should not be on the container object!
748
- PopUp.new(self)
749
- end
750
-
751
- # This is the main method for accessing divs. http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/div.asp?frame=true
752
- # * how - symbol - how we access the div
753
- # * what - string, integer, regular expression or xpath query - what we are looking for,
754
- #
755
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
756
- #
757
- # returns an Div object
758
- #
759
- # Typical Usage
760
- #
761
- # ie.div(:id, /list/) # access the first div that matches list.
762
- # ie.div(:index,2) # access the second div on the page
763
- # 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
764
- # ie.div(:xpath, "//div[@id='list']/") # access the first div whose id is 'list'
765
- #
766
- def div(how, what=nil)
767
- Div.new(self, how, what)
768
- end
769
-
770
- # this is the main method for accessing the divs iterator. Returns a Divs collection
771
- #
772
- # Typical usage:
773
- #
774
- # ie.divs.each { |d| puts d.to_s } # iterate through all the divs on the page
775
- # ie.divs[1].to_s # goto the first div on the page
776
- # ie.divs.length # show how many divs are on the page.
777
- #
778
- def divs
779
- Divs.new(self)
780
- end
781
-
782
- # This is the main method for accessing span tags - http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/span.asp?frame=true
783
- # * how - symbol - how we access the span,
784
- # * what - string, integer or regular expression - what we are looking for,
785
- #
786
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
787
- #
788
- # returns a Span object
789
- #
790
- # Typical Usage
791
- #
792
- # ie.span(:id, /list/) # access the first span that matches list.
793
- # ie.span(:index,2) # access the second span on the page
794
- # 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
795
- #
796
- def span(how, what=nil)
797
- Span.new(self, how, what)
798
- end
799
-
800
- # this is the main method for accessing the spans iterator.
801
- #
802
- # Returns a Spans object
803
- #
804
- # Typical usage:
805
- #
806
- # ie.spans.each { |s| puts s.to_s } # iterate through all the spans on the page
807
- # ie.spans[1].to_s # goto the first span on the page
808
- # ie.spans.length # show how many spans are on the page.
809
- #
810
- def spans
811
- Spans.new(self)
812
- end
813
-
814
- # This is the main method for accessing p tags - http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/p.asp?frame=true
815
- # * how - symbol - how we access the p,
816
- # * what - string, integer or regular expression - what we are looking for,
817
- #
818
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
819
- #
820
- # returns a P object
821
- #
822
- # Typical Usage
823
- #
824
- # ie.p(:id, /list/) # access the first p tag that matches list.
825
- # ie.p(:index,2) # access the second p tag on the page
826
- # 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
827
- #
828
- def p(how, what=nil)
829
- P.new(self, how, what)
830
- end
831
-
832
- # this is the main method for accessing the ps iterator.
833
- #
834
- # Returns a Ps object
835
- #
836
- # Typical usage:
837
- #
838
- # ie.ps.each { |p| puts p.to_s } # iterate through all the p tags on the page
839
- # ie.ps[1].to_s # goto the first p tag on the page
840
- # ie.ps.length # show how many p tags are on the page.
841
- #
842
- def ps
843
- Ps.new(self)
844
- end
845
-
846
- # This is the main method for accessing pre tags - http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/pre.asp?frame=true
847
- # * how - symbol - how we access the pre, valid values are
848
- # :index - finds the item using its index
849
- # :id - finds the item using its id attribute
850
- # :name - finds the item using its name attribute
851
- # * what - string, integer or re, what we are looking for,
852
- #
853
- # returns a Pre object
854
- #
855
- # Typical Usage
856
- #
857
- # ie.pre(:id, /list/) # access the first pre tag that matches list.
858
- # ie.pre(:index,2) # access the second pre tag on the page
859
- # ie.pre(:title, "A Picture") # access a pre tag using the tooltip text. See http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/title_1.asp?frame=true
860
- #
861
- def pre(how, what=nil)
862
- Pre.new(self, how, what)
863
- end
864
-
865
- # this is the main method for accessing the ps iterator.
866
- #
867
- # Returns a Pres object
868
- #
869
- # Typical usage:
870
- #
871
- # ie.pres.each { |pre| puts pre.to_s } # iterate through all the pre tags on the page
872
- # ie.pres[1].to_s # goto the first pre tag on the page
873
- # ie.pres.length # show how many pre tags are on the page.
874
- #
875
- def pres
876
- Pres.new(self)
877
- end
878
-
879
- # This is the main method for accessing labels. http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/label.asp?frame=true
880
- # * how - symbol - how we access the label,
881
- # * what - string, integer or regular expression - what we are looking for,
882
- #
883
- # Valid values for 'how' are listed in the Watir Wiki - http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
884
- #
885
- # returns a Label object
886
- #
887
- # Typical Usage
888
- #
889
- # ie.label(:id, /list/) # access the first span that matches list.
890
- # ie.label(:index,2) # access the second label on the page
891
- # ie.label(:for, "text_1") # access a the label that is associated with the object that has an id of text_1
892
- #
893
- def label(how, what=nil)
894
- Label.new(self, how, what)
895
- end
896
-
897
- # this is the main method for accessing the labels iterator. It returns a Labels object
898
- #
899
- # Returns a Labels object
900
- #
901
- # Typical usage:
902
- #
903
- # ie.labels.each { |l| puts l.to_s } # iterate through all the labels on the page
904
- # ie.labels[1].to_s # goto the first label on the page
905
- # ie.labels.length # show how many labels are on the page.
906
- #
907
- def labels
908
- Labels.new(self)
909
- end
910
-
911
- #--
912
- #
913
- # Searching for Page Elements
914
- # Not for external consumption
915
- #
916
- #++
917
- def ole_inner_elements
918
- return document.body.all
919
- end
920
- private :ole_inner_elements
921
-
922
- # This method shows the available objects on the current page.
923
- # This is usually only used for debugging or writing new test scripts.
924
- # This is a nice feature to help find out what HTML objects are on a page
925
- # when developing a test case using Watir.
926
- def show_all_objects
927
- puts "-----------Objects in page -------------"
928
- doc = document
929
- s = ""
930
- props = ["name", "id", "value", "alt", "src"]
931
- doc.all.each do |n|
932
- begin
933
- s += n.invoke("type").to_s.ljust(16)
934
- rescue
935
- next
936
- end
937
- props.each do |prop|
938
- begin
939
- p = n.invoke(prop)
940
- s += " " + "#{prop}=#{p}".to_s.ljust(18)
941
- rescue
942
- # this object probably doesnt have this property
943
- end
944
- end
945
- s += "\n"
946
- end
947
- puts s
948
- end
949
-
950
- #
951
- # Locator Methods
952
- #
953
-
954
- # Returns the specified ole object for input elements on a web page.
955
- #
956
- # 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
957
- #
958
- # * how - symbol - the way we look for the object. Supported values are
959
- # - :name
960
- # - :id
961
- # - :index
962
- # - :value etc
963
- # * what - string that we are looking for, ex. the name, or id tag attribute or index of the object we are looking for.
964
- # * types - what object types we will look at.
965
- # * value - used for objects that have one name, but many values. ex. radio lists and checkboxes
966
- def locate_input_element(how, what, types, value=nil)
967
- elements = nil
968
- # Searching through all elements returned by ole_inner_elements
969
- # is *significantly* slower than IE's getElementById() and
970
- # getElementsByName() calls when how is :id or :name. However
971
- # IE doesn't match Regexps, so first we make sure what is a String.
972
- # In addition, IE's getElementById() will also return an element
973
- # where the :name matches, so we will only return the results of
974
- # getElementById() if the matching element actually HAS a matching
975
- # :id.
976
- begin
977
- if what.class == String # Only use fast calls with String what.
978
- if how == :id
979
- element = document.getElementById(what)
980
- # Return if our fast match really HAS a matching :id
981
- return element if element.nil? or element.invoke('id') == what
982
- elsif how == :name
983
- elements = document.getElementsByName(what)
984
- end
985
- end
986
- rescue
987
- end
988
- # Use slow methods if the faster methods didn't match
989
- elements = ole_inner_elements if elements.nil?
990
-
991
- how = :value if how == :caption
992
- how = :class_name if how == :class
993
- what = what.to_i if how == :index
994
- value = value.to_s if value unless value.class == String
995
- log "getting object - how is #{how} what is #{what} types = #{types} value = #{value}"
996
-
997
- object_index = 1
998
- elements.each do |object|
999
- element = Element.new(object)
1000
- if types.include?(element.type)
1001
- if how == :index
1002
- attribute = object_index
1003
- else
1004
- begin
1005
- attribute = element.send(how)
1006
- rescue NoMethodError
1007
- raise MissingWayOfFindingObjectException,
1008
- "#{how} is an unknown way of finding an <INPUT> element (#{what})"
1009
- end
1010
- end
1011
- if what.matches(attribute)
1012
- if value
1013
- if element.value == value
1014
- return object
1015
- end
1016
- else
1017
- return object
1018
- end
1019
- end
1020
- object_index += 1
1021
- end
1022
- end
1023
- return nil
1024
- end
1025
-
1026
- # returns the ole object for the specified element
1027
- def locate_tagged_element(tag, how, what)
1028
- locator = TaggedElementLocator.new(self, tag)
1029
- locator.set_specifier(how, what)
1030
- locator.locate
1031
- end
1032
-
1033
- end # module
1034
-
1035
- class TaggedElementLocator
1036
- include Watir
1037
- include Watir::Exception
1038
-
1039
- def initialize(container, tag)
1040
- @container = container
1041
- @tag = tag
1042
- end
1043
-
1044
- def set_specifier(how, what)
1045
- if how.class == Hash and what.nil?
1046
- specifiers = how
1047
- else
1048
- specifiers = {how => what}
1049
- end
1050
-
1051
- @specifiers = {:index => 1} # default if not specified
1052
-
1053
- specifiers.each do |how, what|
1054
- what = what.to_i if how == :index
1055
- how = :href if how == :url
1056
- how = :class_name if how == :class
1057
-
1058
- @specifiers[how] = what
1059
- end
1060
-
1061
- end
1062
-
1063
- def each_element tag
1064
- @container.document.getElementsByTagName(tag).each do |ole_element|
1065
- yield Element.new(ole_element)
1066
- end
1067
- end
1068
-
1069
- def locate
1070
- index_target = @specifiers[:index]
1071
-
1072
- count = 0
1073
- each_element(@tag) do |element|
1074
-
1075
- catch :next_element do
1076
- @specifiers.each do |how, what|
1077
- next if how == :index
1078
- unless match? element, how, what
1079
- throw :next_element
1080
- end
1081
- end
1082
- count += 1
1083
- unless index_target == count
1084
- throw :next_element
1085
- end
1086
- return element.ole_object
1087
- end
1088
-
1089
- end # elements
1090
- nil
1091
- end
1092
-
1093
- def match?(element, how, what)
1094
- begin
1095
- method = element.method(how)
1096
- rescue NameError
1097
- raise MissingWayOfFindingObjectException,
1098
- "#{how} is an unknown way of finding a <#{@tag}> element (#{what})"
1099
- end
1100
- case method.arity
1101
- when 0
1102
- what.matches element.send(how)
1103
- when 1
1104
- element.send(how, what)
1105
- else
1106
- raise MissingWayOfFindingObjectException,
1107
- "#{how} is an unknown way of finding a <#{@tag}> element (#{what})"
1108
- end
1109
- end
1110
-
1111
- end
1112
-
1113
- # A PageContainer contains an HTML Document. In other words, it is a
1114
- # JavaScript Window.
1115
- module PageContainer
1116
- include Watir::Exception
1117
-
1118
- # This method checks the currently displayed page for http errors, 404, 500 etc
1119
- # It gets called internally by the wait method, so a user does not need to call it explicitly
1120
-
1121
- def check_for_http_error
1122
- # check for IE7
1123
- n = self.document.invoke('parentWindow').navigator.appVersion
1124
- m=/MSIE\s(.*?);/.match( n )
1125
- if m and m[1] =='7.0'
1126
- if m=/HTTP (\d\d\d.*)/.match( self.title )
1127
- raise NavigationException, m[1]
1128
- end
1129
- else
1130
- # assume its IE6
1131
- url = self.document.url
1132
- if /shdoclc.dll/.match(url)
1133
- m = /id=IEText.*?>(.*?)</i.match(self.html)
1134
- raise NavigationException, m[1] if m
1135
- end
1136
- end
1137
- false
1138
- end
1139
-
1140
- # The HTML Page
1141
- def page
1142
- document.documentelement
1143
- end
1144
- private :page
1145
-
1146
- # The HTML of the current page
1147
- def html
1148
- page.outerhtml
1149
- end
1150
-
1151
- # The url of the page object.
1152
- def url
1153
- page.document.location.href
1154
- end
1155
-
1156
- # The text of the current page
1157
- def text
1158
- page.innertext.strip
1159
- end
1160
-
1161
- def eval_in_spawned_process(command)
1162
- command.strip!
1163
- load_path_code = _code_that_copies_readonly_array($LOAD_PATH, '$LOAD_PATH')
1164
- ruby_code = "require 'watir'; "
1165
- # ruby_code = "$HIDE_IE = #{$HIDE_IE};" # This prevents attaching to a window from setting it visible. However modal dialogs cannot be attached to when not visible.
1166
- ruby_code << "pc = #{attach_command}; " # pc = page container
1167
- # IDEA: consider changing this to not use instance_eval (it makes the code hard to understand)
1168
- ruby_code << "pc.instance_eval(#{command.inspect})"
1169
- exec_string = "start rubyw -e #{(load_path_code + '; ' + ruby_code).inspect}"
1170
- system(exec_string)
1171
- end
1172
-
1173
- def set_container container
1174
- @container = container
1175
- @page_container = self
1176
- end
1177
-
1178
- # This method is used to display the available html frames that Internet Explorer currently has loaded.
1179
- # This method is usually only used for debugging test scripts.
1180
- def show_frames
1181
- if allFrames = document.frames
1182
- count = allFrames.length
1183
- puts "there are #{count} frames"
1184
- for i in 0..count-1 do
1185
- begin
1186
- fname = allFrames[i.to_s].name.to_s
1187
- puts "frame index: #{i + 1} name: #{fname}"
1188
- rescue => e
1189
- puts "frame index: #{i + 1} Access Denied, see http://wiki.openqa.org/display/WTR/FAQ#access-denied" if e.to_s.match(/Access is denied/)
1190
- end
1191
- end
1192
- else
1193
- puts "no frames"
1194
- end
1195
- end
1196
-
1197
- # Search the current page for specified text or regexp.
1198
- # Returns the index if the specified text was found.
1199
- # Returns matchdata object if the specified regexp was found.
1200
- #
1201
- # *Deprecated*
1202
- # Instead use
1203
- # IE#text.include? target
1204
- # or
1205
- # IE#text.match target
1206
- def contains_text(target)
1207
- if target.kind_of? Regexp
1208
- self.text.match(target)
1209
- elsif target.kind_of? String
1210
- self.text.index(target)
1211
- else
1212
- raise ArgumentError, "Argument #{target} should be a string or regexp."
1213
- end
1214
- end
1215
-
1216
- end # module
1217
-
1218
- =begin rdoc
1219
- This is Watir, Web Application Testing In Ruby
1220
- http://wtr.rubyforge.org
1221
-
1222
- Version "$Revision: 1234 $"
1223
-
1224
- Example:
1225
-
1226
- # Load the Watir library.
1227
- require "watir"
1228
-
1229
- # Go to the page you want to test.
1230
- ie = Watir::IE.start("http://myserver/mypage")
1231
-
1232
- # Enter "Paul" in a text input field named "username".
1233
- ie.text_field(:name, "username").set("Paul")
1234
-
1235
- # Enter "Ruby Co" in the text input field whose "id" is "company_ID".
1236
- ie.text_field(:id, "company_ID").set("Ruby Co")
1237
-
1238
- # Click on a link that includes the word "green".
1239
- ie.link(:text, /green/)
1240
-
1241
- # Click button that is labelled "Cancel".
1242
- ie.button(:value, "Cancel").click
1243
-
1244
- The Watir::IE class allows your test to read and interact with HTML
1245
- elements on a page, including their attributes and contents.
1246
- The class includes many methods for accessing HTML elements, including the
1247
- following:
1248
-
1249
- #button:: <input> tags with type=button, submit, image or reset
1250
- #check_box:: <input> tags with type=checkbox
1251
- #div:: <div> tags
1252
- #form:: <form> tags
1253
- #frame:: frames, including both the <frame> elements and the
1254
- corresponding pages.
1255
- #hidden:: <input> tags with type=hidden
1256
- #image:: <img> tags
1257
- #label:: <label> tags (including "for" attribute)
1258
- #link:: <a> (anchor) tags
1259
- #p:: <p> (paragraph) tags
1260
- #radio:: <input> tags with the type=radio; known as radio buttons
1261
- #select_list:: <select> tags, known as drop-downs or drop-down lists
1262
- #span:: <span> tags
1263
- #table:: <table> tags, including +row+ and +cell+ methods for accessing
1264
- nested elements.
1265
- #text_field <input> tags with the type=text (single-line), type=textarea
1266
- (multi-line), and type=password
1267
- #map:: <map> tags
1268
- #area:: <area> tags
1269
- #li:: <li> tags
1270
-
1271
- In general, there are several ways to identify a specific object. WATIR's
1272
- syntax is in the form (how, what), where "how" is a means of identifying
1273
- the object, and "what" is the specific string or regular expression
1274
- that WATIR will seek, as shown in the examples above. Available "how"
1275
- options depend upon the type of object, but here are a few examples:
1276
-
1277
- How Description
1278
- ============ ===============================================================
1279
- :id Used to find an object that has an "id=" attribute. Since each
1280
- id should be unique, according to the XHTML specification,
1281
- this is recommended as the most reliable method to find an
1282
- object.
1283
- :name Used to find an object that has a "name=" attribute. This is
1284
- useful for older versions of HTML, but "name" is deprecated
1285
- in XHTML.
1286
- :value Used to find a text field with a given default value, or a
1287
- button with a given caption
1288
- :index Used to find the nth object of the specified type on a page.
1289
- For example, button(:index, 2) finds the second button.
1290
- Current versions of WATIR use 1-based indexing, but future
1291
- versions will use 0-based indexing.
1292
- :xpath Uses xpath (see separate doc)
1293
-
1294
- Note that the XHTML specification requires that tags and their attributes be
1295
- in lower case. WATIR doesn't enforce this; WATIR will find tags and
1296
- attributes whether they're in upper, lower, or mixed case. This is either
1297
- a bug or a feature.
1298
-
1299
- WATIR uses Microsoft's Document Object Model (DOM) as implemented by Internet
1300
- Explorer. For further information on Internet Explorer and on the DOM, go to
1301
- the following Web pages:
1302
-
1303
- http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/webbrowser/webbrowser.asp
1304
- http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/overview/overview.asp
1305
-
1306
- WATIR supports command-line options:
1307
-
1308
- -b (background) Run Internet Explorer invisibly
1309
- -f (fast) By default, WATIR types slowly and pauses briefly between
1310
- actions. This switch removes the delays and sets WATIR
1311
- to run at full speed. The set_fast_speed method of the
1312
- IE object performs the same function; set_slow_speed
1313
- returns WATIR to its default behaviour.
1314
- =end
1315
- class IE
1316
- include Watir::Exception
1317
- include Container
1318
- include PageContainer
1319
-
1320
- def self.quit
1321
- end
1322
-
1323
- # Maximum number of seconds to wait when attaching to a window
1324
- def self.reset_attach_timeout
1325
- @@attach_timeout = 2.0
1326
- end
1327
- reset_attach_timeout
1328
- def self.attach_timeout
1329
- @@attach_timeout
1330
- end
1331
- def self.attach_timeout=(timeout)
1332
- @@attach_timeout = timeout
1333
- end
1334
-
1335
- # The revision number (according to Subversion)
1336
- REVISION_STRING = '$Revision: 1234 $'
1337
- REVISION_STRING.scan(/Revision: (\d*)/)
1338
- REVISION = $1 or 'unknown'
1339
-
1340
- # The Release number
1341
- VERSION_SHORT = '1.5.2'
1342
- VERSION = VERSION_SHORT + '.' + REVISION
1343
-
1344
- # Used internally to determine when IE has finished loading a page
1345
- READYSTATE_COMPLETE = 4
1346
-
1347
- # TODO: the following constants should be able to be specified by object (not class)
1348
-
1349
- # The delay when entering text on a web page when speed = :slow.
1350
- DEFAULT_TYPING_SPEED = 0.08
1351
-
1352
- # The default time we wait after a page has loaded when speed = :slow.
1353
- DEFAULT_SLEEP_TIME = 0.1
1354
-
1355
- # The default color for highlighting objects as they are accessed.
1356
- HIGHLIGHT_COLOR = 'yellow'
1357
-
1358
- # IE inserts some element whose tagName is empty and just acts as block level element
1359
- # Probably some IE method of cleaning things
1360
- # To pass the same to REXML we need to give some name to empty tagName
1361
- EMPTY_TAG_NAME = "DUMMY"
1362
-
1363
- # The time, in seconds, it took for the new page to load after executing the
1364
- # the last command
1365
- attr_reader :down_load_time
1366
-
1367
- # Whether the speed is :fast or :slow
1368
- attr_reader :speed
1369
-
1370
- # the OLE Internet Explorer object
1371
- attr_accessor :ie
1372
-
1373
- # access to the logger object
1374
- attr_accessor :logger
1375
-
1376
- # this contains the list of unique urls that have been visited
1377
- attr_reader :url_list
1378
-
1379
- # Create a new IE window. Works just like IE.new in Watir 1.4.
1380
- def self.new_window
1381
- ie = new true
1382
- ie._new_window_init
1383
- ie
1384
- end
1385
-
1386
- # Create an IE browser.
1387
- def initialize suppress_new_window=nil
1388
- _new_window_init unless suppress_new_window
1389
- end
1390
-
1391
- def _new_window_init
1392
- create_browser_window
1393
- set_defaults
1394
- goto 'about:blank' # this avoids numerous problems caused by lack of a document
1395
- end
1396
-
1397
- # Create a new IE Window, starting at the specified url.
1398
- # If no url is given, start empty.
1399
- def self.start url=nil
1400
- start_window url
1401
- end
1402
-
1403
- # Create a new IE window, starting at the specified url.
1404
- # If no url is given, start empty. Works like IE.start in Watir 1.4.
1405
- def self.start_window url=nil
1406
- ie = new_window
1407
- ie.goto url if url
1408
- ie
1409
- end
1410
-
1411
- # Create a new IE window in a new process.
1412
- # This method will not work when
1413
- # Watir/Ruby is run under a service (instead of a user).
1414
- def self.new_process
1415
- ie = new true
1416
- ie._new_process_init
1417
- ie
1418
- end
1419
-
1420
- def _new_process_init
1421
- iep = Process.start
1422
- @ie = iep.window
1423
- @process_id = iep.process_id
1424
- set_defaults
1425
- goto 'about:blank'
1426
- end
1427
-
1428
- # Create a new IE window in a new process, starting at the specified URL.
1429
- # Same as IE.start.
1430
- def self.start_process url=nil
1431
- ie = new_process
1432
- ie.goto url if url
1433
- ie
1434
- end
1435
-
1436
- # Return a Watir::IE object for an existing IE window. Window can be
1437
- # referenced by url, title, or window handle.
1438
- # Second argument can be either a string or a regular expression in the
1439
- # case of of :url or :title.
1440
- # IE.attach(:url, 'http://www.google.com')
1441
- # IE.attach(:title, 'Google')
1442
- # IE.attach(:hwnd, 528140)
1443
- # This method will not work when
1444
- # Watir/Ruby is run under a service (instead of a user).
1445
- def self.attach how, what
1446
- ie = new true # don't create window
1447
- ie._attach_init(how, what)
1448
- ie
1449
- end
1450
-
1451
- # this method is used internally to attach to an existing window
1452
- def _attach_init how, what
1453
- attach_browser_window how, what
1454
- set_defaults
1455
- wait
1456
- end
1457
-
1458
- # Return an IE object that wraps the given window, typically obtained from
1459
- # Shell.Application.windows.
1460
- def self.bind window
1461
- ie = new true
1462
- ie.ie = window
1463
- ie.set_defaults
1464
- ie
1465
- end
1466
-
1467
- def create_browser_window
1468
- @ie = WIN32OLE.new('InternetExplorer.Application')
1469
- end
1470
- private :create_browser_window
1471
-
1472
- def set_defaults
1473
- self.visible = ! $HIDE_IE
1474
- @ole_object = nil
1475
- @page_container = self
1476
- @error_checkers = []
1477
- @activeObjectHighLightColor = HIGHLIGHT_COLOR
1478
-
1479
- if $FAST_SPEED
1480
- set_fast_speed
1481
- else
1482
- set_slow_speed
1483
- end
1484
-
1485
- @logger = DefaultLogger.new
1486
- @url_list = []
1487
- end
1488
-
1489
- def speed= how_fast
1490
- case how_fast
1491
- when :fast : set_fast_speed
1492
- when :slow : set_slow_speed
1493
- else
1494
- raise ArgumentError, "Invalid speed: #{how_fast}"
1495
- end
1496
- end
1497
-
1498
- # deprecated: use speed = :fast instead
1499
- def set_fast_speed
1500
- @typingspeed = 0
1501
- @defaultSleepTime = 0.01
1502
- @speed = :fast
1503
- end
1504
-
1505
- # deprecated: use speed = :slow instead
1506
- def set_slow_speed
1507
- @typingspeed = DEFAULT_TYPING_SPEED
1508
- @defaultSleepTime = DEFAULT_SLEEP_TIME
1509
- @speed = :slow
1510
- end
1511
-
1512
- def visible
1513
- @ie.visible
1514
- end
1515
- def visible=(boolean)
1516
- @ie.visible = boolean if boolean != @ie.visible
1517
- end
1518
-
1519
- # Yields successively to each IE window on the current desktop. Takes a block.
1520
- # This method will not work when
1521
- # Watir/Ruby is run under a service (instead of a user).
1522
- # Yields to the window and its hwnd.
1523
- def self.each
1524
- shell = WIN32OLE.new('Shell.Application')
1525
- shell.Windows.each do |window|
1526
- next unless (window.path =~ /Internet Explorer/ rescue false)
1527
- next unless (hwnd = window.hwnd rescue false)
1528
- ie = IE.bind(window)
1529
- ie.hwnd = hwnd
1530
- yield ie
1531
- end
1532
- end
1533
-
1534
- # return internet explorer instance as specified. if none is found,
1535
- # return nil.
1536
- # arguments:
1537
- # :url, url -- the URL of the IE browser window
1538
- # :title, title -- the title of the browser page
1539
- # :hwnd, hwnd -- the window handle of the browser window.
1540
- # This method will not work when
1541
- # Watir/Ruby is run under a service (instead of a user).
1542
- def self.find(how, what)
1543
- ie_ole = IE._find(how, what)
1544
- IE.bind ie_ole if ie_ole
1545
- end
1546
-
1547
- def self._find(how, what)
1548
- ieTemp = nil
1549
- IE.each do |ie|
1550
- window = ie.ie
1551
-
1552
- case how
1553
- when :url
1554
- ieTemp = window if (what.matches(window.locationURL))
1555
- when :title
1556
- # normal windows explorer shells do not have document
1557
- # note window.document will fail for "new" browsers
1558
- begin
1559
- title = window.locationname
1560
- title = window.document.title
1561
- rescue WIN32OLERuntimeError
1562
- end
1563
- ieTemp = window if what.matches(title)
1564
- when :hwnd
1565
- begin
1566
- ieTemp = window if what == window.HWND
1567
- rescue WIN32OLERuntimeError
1568
- end
1569
- else
1570
- raise ArgumentError
1571
- end
1572
- end
1573
- return ieTemp
1574
- end
1575
-
1576
- def attach_browser_window how, what
1577
- log "Seeking Window with #{how}: #{what}"
1578
- ieTemp = nil
1579
- begin
1580
- Watir::until_with_timeout do
1581
- ieTemp = IE._find how, what
1582
- end
1583
- rescue TimeOutException
1584
- raise NoMatchingWindowFoundException,
1585
- "Unable to locate a window with #{how} of #{what}"
1586
- end
1587
- @ie = ieTemp
1588
- end
1589
- private :attach_browser_window
1590
-
1591
- # Return the current window handle
1592
- def hwnd
1593
- raise "Not attached to a browser" if @ie.nil?
1594
- @hwnd ||= @ie.hwnd
1595
- end
1596
- attr_writer :hwnd
1597
-
1598
- include Watir::Win32
1599
-
1600
- # Are we attached to an open browser?
1601
- def exists?
1602
- return false if @closing
1603
- begin
1604
- @ie.name =~ /Internet Explorer/
1605
- rescue WIN32OLERuntimeError
1606
- false
1607
- end
1608
- end
1609
- alias :exist? :exists?
1610
-
1611
- # deprecated: use logger= instead
1612
- def set_logger(logger)
1613
- @logger = logger
1614
- end
1615
-
1616
- def log(what)
1617
- @logger.debug(what) if @logger
1618
- end
1619
-
1620
- #
1621
- # Accessing data outside the document
1622
- #
1623
-
1624
- # Return the title of the document
1625
- def title
1626
- @ie.document.title
1627
- end
1628
-
1629
- # Return the status of the window, typically from the status bar at the bottom.
1630
- def status
1631
- raise NoStatusBarException if !@ie.statusBar
1632
- return @ie.statusText
1633
- end
1634
-
1635
- #
1636
- # Navigation
1637
- #
1638
-
1639
- # Navigate to the specified URL.
1640
- # * url - string - the URL to navigate to
1641
- def goto(url)
1642
- @ie.navigate(url)
1643
- wait
1644
- return @down_load_time
1645
- end
1646
-
1647
- # Go to the previous page - the same as clicking the browsers back button
1648
- # an WIN32OLERuntimeError exception is raised if the browser cant go back
1649
- def back
1650
- @ie.GoBack
1651
- wait
1652
- end
1653
-
1654
- # Go to the next page - the same as clicking the browsers forward button
1655
- # an WIN32OLERuntimeError exception is raised if the browser cant go forward
1656
- def forward
1657
- @ie.GoForward
1658
- wait
1659
- end
1660
-
1661
- # Refresh the current page - the same as clicking the browsers refresh button
1662
- # an WIN32OLERuntimeError exception is raised if the browser cant refresh
1663
- def refresh
1664
- @ie.refresh2(3)
1665
- wait
1666
- end
1667
-
1668
- # clear the list of urls that we have visited
1669
- def clear_url_list
1670
- @url_list.clear
1671
- end
1672
-
1673
- # Closes the Browser
1674
- def close
1675
- @closing = true
1676
- @ie.quit
1677
- end
1678
-
1679
- # Maximize the window (expands to fill the screen)
1680
- def maximize
1681
- set_window_state :SW_MAXIMIZE
1682
- end
1683
-
1684
- # Minimize the window (appears as icon on taskbar)
1685
- def minimize
1686
- set_window_state :SW_MINIMIZE
1687
- end
1688
-
1689
- # Restore the window (after minimizing or maximizing)
1690
- def restore
1691
- set_window_state :SW_RESTORE
1692
- end
1693
-
1694
- # Make the window come to the front
1695
- def bring_to_front
1696
- autoit.WinActivate title, ''
1697
- end
1698
-
1699
- def front?
1700
- 1 == autoit.WinActive(title, '')
1701
- end
1702
-
1703
- private
1704
- def set_window_state(state)
1705
- autoit.WinSetState title, '', autoit.send(state)
1706
- end
1707
- def autoit
1708
- Watir::autoit
1709
- end
1710
- public
1711
-
1712
- # Send key events to IE window.
1713
- # See http://www.autoitscript.com/autoit3/docs/appendix/SendKeys.htm
1714
- # for complete documentation on keys supported and syntax.
1715
- def send_keys(key_string)
1716
- autoit.WinActivate title
1717
- autoit.Send key_string
1718
- end
1719
-
1720
- def dir
1721
- return File.expand_path(File.dirname(__FILE__))
1722
- end
1723
-
1724
- #
1725
- # Document and Document Data
1726
- #
1727
-
1728
- # Return the current document
1729
- def document
1730
- return @ie.document
1731
- end
1732
-
1733
- # returns the current url, as displayed in the address bar of the browser
1734
- def url
1735
- return @ie.LocationURL
1736
- end
1737
-
1738
- #
1739
- # Synchronization
1740
- #
1741
- include Watir::Utils
1742
-
1743
- # Block execution until the page has loaded.
1744
- # =nodoc
1745
- # Note: This code needs to be prepared for the ie object to be closed at
1746
- # any moment!
1747
- def wait(no_sleep=false)
1748
- @rexmlDomobject = nil
1749
- @down_load_time = 0.0
1750
- a_moment = 0.2 # seconds
1751
- start_load_time = Time.now
1752
125
 
1753
- begin
1754
- while @ie.busy # XXX need to add time out
1755
- sleep a_moment
1756
- end
1757
- until @ie.readyState == READYSTATE_COMPLETE do
1758
- sleep a_moment
1759
- end
1760
- sleep a_moment
1761
- until @ie.document do
1762
- sleep a_moment
1763
- end
1764
-
1765
- documents_to_wait_for = [@ie.document]
1766
-
1767
- rescue WIN32OLERuntimeError # IE window must have been closed
1768
- @down_load_time = Time.now - start_load_time
1769
- sleep @defaultSleepTime unless no_sleep
1770
- return @down_load_time
1771
- end
1772
126
 
1773
- while doc = documents_to_wait_for.shift
1774
- begin
1775
- until doc.readyState == "complete" do
1776
- sleep a_moment
1777
- end
1778
- @url_list << doc.url unless @url_list.include?(doc.url)
1779
- doc.frames.length.times do |n|
1780
- begin
1781
- documents_to_wait_for << doc.frames[n.to_s].document
1782
- rescue WIN32OLERuntimeError
1783
- end
1784
- end
1785
- rescue WIN32OLERuntimeError
1786
- end
1787
- end
1788
-
1789
- @down_load_time = Time.now - start_load_time
1790
- run_error_checks
1791
- sleep @defaultSleepTime unless no_sleep
1792
- @down_load_time
1793
- end
1794
-
1795
- # Error checkers
1796
-
1797
- # this method runs the predefined error checks
1798
- def run_error_checks
1799
- @error_checkers.each { |e| e.call(self) }
1800
- end
1801
-
1802
- # this method is used to add an error checker that gets executed on every page load
1803
- # * checker Proc Object, that contains the code to be run
1804
- def add_checker(checker)
1805
- @error_checkers << checker
1806
- end
1807
-
1808
- # this allows a checker to be disabled
1809
- # * checker Proc Object, the checker that is to be disabled
1810
- def disable_checker(checker)
1811
- @error_checkers.delete(checker)
1812
- end
1813
-
1814
- #
1815
- # Show me state
1816
- #
1817
-
1818
- # Show all forms displays all the forms that are on a web page.
1819
- def show_forms
1820
- if allForms = document.forms
1821
- count = allForms.length
1822
- puts "There are #{count} forms"
1823
- for i in 0..count-1 do
1824
- wrapped = FormWrapper.new(allForms.item(i))
1825
- puts "Form name: #{wrapped.name}"
1826
- puts " id: #{wrapped.id}"
1827
- puts " method: #{wrapped.method}"
1828
- puts " action: #{wrapped.action}"
1829
- end
1830
- else
1831
- puts "No forms"
1832
- end
1833
- end
1834
-
1835
- # this method shows all the images availble in the document
1836
- def show_images
1837
- doc = document
1838
- index = 1
1839
- doc.images.each do |l|
1840
- puts "image: name: #{l.name}"
1841
- puts " id: #{l.invoke("id")}"
1842
- puts " src: #{l.src}"
1843
- puts " index: #{index}"
1844
- index += 1
1845
- end
1846
- end
1847
-
1848
- # this method shows all the links availble in the document
1849
- def show_links
1850
- props = ["name", "id", "href"]
1851
- print_sizes = [12, 12, 60]
1852
- doc = document
1853
- index = 0
1854
- text_size = 60
1855
- # draw the table header
1856
- s = "index".ljust(6)
1857
- props.each_with_index do |p, i|
1858
- s += p.ljust(print_sizes[i])
1859
- end
1860
- s += "text/src".ljust(text_size)
1861
- s += "\n"
1862
-
1863
- # now get the details of the links
1864
- doc.links.each do |n|
1865
- index += 1
1866
- s = s + index.to_s.ljust(6)
1867
- props.each_with_index do |prop, i|
1868
- printsize = print_sizes[i]
1869
- begin
1870
- p = n.invoke(prop)
1871
- temp_var = "#{p}".to_s.ljust(printsize)
1872
- rescue
1873
- # this object probably doesnt have this property
1874
- temp_var = "".to_s.ljust(printsize)
1875
- end
1876
- s += temp_var
1877
- end
1878
- s += n.innerText
1879
- if n.getElementsByTagName("IMG").length > 0
1880
- s += " / " + n.getElementsByTagName("IMG")[0.to_s].src
1881
- end
1882
- s += "\n"
1883
- end
1884
- puts s
1885
- end
1886
-
1887
- # this method shows the name, id etc of the object that is currently active - ie the element that has focus
1888
- # its mostly used in irb when creating a script
1889
- def show_active
1890
- s = ""
1891
-
1892
- current = document.activeElement
1893
- begin
1894
- s += current.invoke("type").to_s.ljust(16)
1895
- rescue
1896
- end
1897
- props = ["name", "id", "value", "alt", "src", "innerText", "href"]
1898
- props.each do |prop|
1899
- begin
1900
- p = current.invoke(prop)
1901
- s += " " + "#{prop}=#{p}".to_s.ljust(18)
1902
- rescue
1903
- #this object probably doesnt have this property
1904
- end
1905
- end
1906
- s += "\n"
1907
- end
1908
-
1909
- # this method shows all the divs availble in the document
1910
- def show_divs
1911
- divs = document.getElementsByTagName("DIV")
1912
- puts "Found #{divs.length} div tags"
1913
- index = 1
1914
- divs.each do |d|
1915
- puts "#{index} id=#{d.invoke('id')} class=#{d.invoke("className")}"
1916
- index += 1
1917
- end
1918
- end
1919
-
1920
- # this method is used to show all the tables that are available
1921
- def show_tables
1922
- tables = document.getElementsByTagName("TABLE")
1923
- puts "Found #{tables.length} tables"
1924
- index = 1
1925
- tables.each do |d|
1926
- puts "#{index} id=#{d.invoke('id')} rows=#{d.rows.length} columns=#{begin d.rows["0"].cells.length; rescue; end}"
1927
- index += 1
1928
- end
1929
- end
1930
-
1931
- def show_pres
1932
- pres = document.getElementsByTagName("PRE")
1933
- puts "Found #{ pres.length } pre tags"
1934
- index = 1
1935
- pres.each do |d|
1936
- puts "#{index} id=#{d.invoke('id')} class=#{d.invoke("className")}"
1937
- index+=1
1938
- end
1939
- end
1940
-
1941
- # this method shows all the spans availble in the document
1942
- def show_spans
1943
- spans = document.getElementsByTagName("SPAN")
1944
- puts "Found #{spans.length} span tags"
1945
- index = 1
1946
- spans.each do |d|
1947
- puts "#{index} id=#{d.invoke('id')} class=#{d.invoke("className")}"
1948
- index += 1
1949
- end
1950
- end
1951
-
1952
- def show_labels
1953
- labels = document.getElementsByTagName("LABEL")
1954
- puts "Found #{labels.length} label tags"
1955
- index = 1
1956
- labels.each do |d|
1957
- puts "#{index} text=#{d.invoke('innerText')} class=#{d.invoke("className")} for=#{d.invoke("htmlFor")}"
1958
- index += 1
1959
- end
1960
- end
1961
-
1962
- # Gives focus to the frame
1963
- def focus
1964
- document.activeElement.blur
1965
- document.focus
1966
- end
1967
-
1968
- #
1969
- # Functions written for using xpath for getting the elements.
1970
- #
1971
-
1972
- # Get the Rexml object.
1973
- def rexml_document_object
1974
- #puts "Value of rexmlDomobject is : #{@rexmlDomobject}"
1975
- if @rexmlDomobject == nil
1976
- create_rexml_document_object
1977
- end
1978
- return @rexmlDomobject
1979
- end
1980
-
1981
- # Create the Rexml object if it is nil. This method is private so can be called only
1982
- # from rexml_document_object method.
1983
- def create_rexml_document_object
1984
- # Use our modified rexml libraries
1985
- require 'rexml/document'
1986
- unless REXML::Version >= '3.1.4'
1987
- raise "Requires REXML version of at least 3.1.4. Actual: #{REXML::Version}"
1988
- end
1989
- if @rexmlDomobject == nil
1990
- htmlSource ="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<HTML>\n"
1991
- htmlSource = html_source(document.body,htmlSource," ")
1992
- htmlSource += "\n</HTML>\n"
1993
- # Angrez: Resolving Jira issue WTR-114
1994
- htmlSource = htmlSource.gsub(/&nbsp;/, '&#160;')
1995
- begin
1996
- @rexmlDomobject = REXML::Document.new(htmlSource)
1997
- rescue => e
1998
- output_rexml_document("error.xml", htmlSource)
1999
- raise e
2000
- end
2001
- end
2002
- end
2003
- private :create_rexml_document_object
2004
-
2005
- def output_rexml_document(name, text)
2006
- file = File.open(name,"w")
2007
- file.print(text)
2008
- file.close
2009
- end
2010
- private :output_rexml_document
2011
-
2012
- #Function Tokenizes the tag line and returns array of tokens.
2013
- #Token could be either tagName or "=" or attribute name or attribute value
2014
- #Attribute value could be either quoted string or single word
2015
- def tokenize_tagline(outerHtml)
2016
- outerHtml = outerHtml.gsub(/\n|\r/," ")
2017
- #removing "< symbol", opening of current tag
2018
- outerHtml =~ /^\s*<(.*)$/
2019
- outerHtml = $1
2020
- tokens = Array.new
2021
- i = startOffset = 0
2022
- length = outerHtml.length
2023
- #puts outerHtml
2024
- parsingValue = false
2025
- while i < length do
2026
- i +=1 while (i < length && outerHtml[i,1] =~ /\s/)
2027
- next if i == length
2028
- currentToken = outerHtml[i,1]
2029
-
2030
- #Either current tag has been closed or user has not closed the tag >
2031
- # and we have received the opening of next element
2032
- break if currentToken =~ /<|>/
2033
-
2034
- #parse quoted value
2035
- if(currentToken == "\"" || currentToken == "'")
2036
- parsingValue = false
2037
- quote = currentToken
2038
- startOffset = i
2039
- i += 1
2040
- i += 1 while (i < length && (outerHtml[i,1] != quote || outerHtml[i-1,1] == "\\"))
2041
- if i == length
2042
- tokens.push quote + outerHtml[startOffset..i-1]
2043
- else
2044
- tokens.push outerHtml[startOffset..i]
2045
- end
2046
- elsif currentToken == "="
2047
- tokens.push "="
2048
- parsingValue = true
2049
- else
2050
- startOffset = i
2051
- i += 1 while (i < length && !(outerHtml[i,1] =~ /\s|=|<|>/)) if !parsingValue
2052
- i += 1 while (i < length && !(outerHtml[i,1] =~ /\s|<|>/)) if parsingValue
2053
- parsingValue = false
2054
- i -= 1
2055
- tokens.push outerHtml[startOffset..i]
2056
- end
2057
- i += 1
2058
- end
2059
- return tokens
2060
- end
2061
- private :tokenize_tagline
2062
-
2063
- # This function get and clean all the attributes of the tag.
2064
- def all_tag_attributes(outerHtml)
2065
- tokens = tokenize_tagline(outerHtml)
2066
- #puts tokens
2067
- tagLine = ""
2068
- count = 1
2069
- tokensLength = tokens.length
2070
- expectedEqualityOP= false
2071
- while count < tokensLength do
2072
- if expectedEqualityOP == false
2073
- #print Attribute Name
2074
- # If attribute name is valid. Refer: http://www.w3.org/TR/REC-xml/#NT-Name
2075
- if tokens[count] =~ /^(\w|_|:)(.*)$/
2076
- tagLine += " #{tokens[count]}"
2077
- expectedEqualityOP = true
2078
- end
2079
- elsif tokens[count] == "="
2080
- count += 1
2081
- if count == tokensLength
2082
- tagLine += "=\"\""
2083
- elsif(tokens[count][0,1] == "\"" || tokens[count][0,1] == "'")
2084
- tagLine += "=#{tokens[count]}"
2085
- else
2086
- tagLine += "=\"#{tokens[count]}\""
2087
- end
2088
- expectedEqualityOP = false
2089
- else
2090
- #Opps! equality was expected but its not there.
2091
- #Set value same as the attribute name e.g. selected="selected"
2092
- tagLine += "=\"#{tokens[count-1]}\""
2093
- expectedEqualityOP = false
2094
- next
2095
- end
2096
- count += 1
2097
- end
2098
- tagLine += "=\"#{tokens[count-1]}\" " if expectedEqualityOP == true
2099
- #puts tagLine
2100
- return tagLine
2101
- end
2102
- private :all_tag_attributes
2103
-
2104
- # This function is used to escape the characters that are not valid XML data.
2105
- def xml_escape(str)
2106
- str = str.gsub(/&/,'&amp;')
2107
- str = str.gsub(/</,'&lt;')
2108
- str = str.gsub(/>/,'&gt;')
2109
- str = str.gsub(/"/, '&quot;')
2110
- str
2111
- end
2112
- private :xml_escape
2113
-
2114
- # Returns HTML Source
2115
- # Traverse the DOM tree rooted at body element
2116
- # and generate the HTML source.
2117
- # element: Represent Current element
2118
- # htmlString:HTML Source
2119
- # spaces:(Used for debugging). Helps in indentation
2120
- def html_source(element, htmlString, spaceString)
2121
- begin
2122
- tagLine = ""
2123
- outerHtml = ""
2124
- tagName = ""
2125
- begin
2126
- tagName = element.tagName.downcase
2127
- tagName = EMPTY_TAG_NAME if tagName == ""
2128
- # If tag is a mismatched tag.
2129
- if !(tagName =~ /^(\w|_|:)(.*)$/)
2130
- return htmlString
2131
- end
2132
- rescue
2133
- #handling text nodes
2134
- htmlString += xml_escape(element.toString)
2135
- return htmlString
2136
- end
2137
- #puts tagName
2138
- #Skip comment and script tag
2139
- if tagName =~ /^!/ || tagName== "script" || tagName =="style"
2140
- return htmlString
2141
- end
2142
- #tagLine += spaceString
2143
- outerHtml = all_tag_attributes(element.outerHtml) if tagName != EMPTY_TAG_NAME
2144
- tagLine += "<#{tagName} #{outerHtml}"
2145
-
2146
- canHaveChildren = element.canHaveChildren
2147
- if canHaveChildren
2148
- tagLine += ">"
2149
- else
2150
- tagLine += "/>" #self closing tag
2151
- end
2152
- #spaceString += spaceString
2153
- htmlString += tagLine
2154
- childElements = element.childnodes
2155
- childElements.each do |child|
2156
- htmlString = html_source(child,htmlString,spaceString)
2157
- end
2158
- if canHaveChildren
2159
- #tagLine += spaceString
2160
- tagLine ="</" + tagName + ">"
2161
- htmlString += tagLine
2162
- end
2163
- return htmlString
2164
- rescue => e
2165
- puts e.to_s
2166
- end
2167
- return htmlString
2168
- end
2169
- private :html_source
2170
-
2171
- # return the first element that matches the xpath
2172
- def element_by_xpath(xpath)
2173
- temp = elements_by_xpath(xpath)
2174
- temp = temp[0] if temp
2175
- return temp
2176
- end
2177
-
2178
- # execute xpath and return an array of elements
2179
- def elements_by_xpath(xpath)
2180
- doc = rexml_document_object
2181
- modifiedXpath = ""
2182
- selectedElements = Array.new
2183
- doc.elements.each(xpath) do |element|
2184
- modifiedXpath = element.xpath # element = a REXML element
2185
- # puts "modified xpath: #{modifiedXpath}"
2186
- # puts "text: #{element.text}"
2187
- # puts "class: #{element.attributes['class']}"
2188
- # require 'breakpoint'; breakpoint
2189
- temp = element_by_absolute_xpath(modifiedXpath) # temp = a DOM/COM element
2190
- selectedElements << temp if temp != nil
2191
- end
2192
- #puts selectedElements.length
2193
- if selectedElements.length == 0
2194
- return nil
2195
- else
2196
- return selectedElements
2197
- end
2198
- end
2199
-
2200
- # Method that iterates over IE DOM object and get the elements for the given
2201
- # xpath.
2202
- def element_by_absolute_xpath(xpath)
2203
- curElem = nil
2204
-
2205
- #puts "Hello; Given xpath is : #{xpath}"
2206
- doc = document
2207
- curElem = doc.getElementsByTagName("body")["0"]
2208
- xpath =~ /^.*\/body\[?\d*\]?\/(.*)/
2209
- xpath = $1
2210
-
2211
- if xpath == nil
2212
- puts "Function Requires absolute XPath."
2213
- return
2214
- end
2215
-
2216
- arr = xpath.split(/\//)
2217
- return nil if arr.length == 0
2218
-
2219
- lastTagName = arr[arr.length-1].to_s.upcase
2220
-
2221
- # lastTagName is like tagName[number] or just tagName. For the first case we need to
2222
- # separate tagName and number.
2223
- lastTagName =~ /(\w*)\[?\d*\]?/
2224
- lastTagName = $1
2225
- #puts lastTagName
2226
-
2227
- for element in arr do
2228
- element =~ /(\w*)\[?(\d*)\]?/
2229
- tagname = $1
2230
- tagname = tagname.upcase
2231
-
2232
- if $2 != nil && $2 != ""
2233
- index = $2
2234
- index = "#{index}".to_i - 1
2235
- else
2236
- index = 0
2237
- end
2238
-
2239
- #puts "#{element} #{tagname} #{index}"
2240
- allElemns = curElem.childnodes
2241
- if allElemns == nil || allElemns.length == 0
2242
- puts "#{element} is null"
2243
- next # Go to next element
2244
- end
2245
-
2246
- #puts "Current element is : #{curElem.tagName}"
2247
- allElemns.each do |child|
2248
- gotIt = false
2249
- begin
2250
- curTag = child.tagName
2251
- curTag = EMPTY_TAG_NAME if curTag == ""
2252
- rescue
2253
- next
2254
- end
2255
- #puts child.tagName
2256
- if curTag == tagname
2257
- index-=1
2258
- if index < 0
2259
- curElem = child
2260
- break
2261
- end
2262
- end
2263
- end
2264
-
2265
- #puts "Node selected at index #{index.to_s} : #{curElem.tagName}"
2266
- end
2267
- begin
2268
- if curElem.tagName == lastTagName
2269
- #puts curElem.tagName
2270
- return curElem
2271
- else
2272
- return nil
2273
- end
2274
- rescue
2275
- return nil
2276
- end
2277
- end
2278
- private :element_by_absolute_xpath
2279
-
2280
- def attach_command
2281
- "Watir::IE.attach(:hwnd, #{hwnd})"
2282
- end
2283
-
2284
-
2285
- end # class IE
2286
-
2287
- #
2288
- # MOVETO: watir/popup.rb
2289
- # Module Watir::Popup
2290
- #
2291
-
2292
- # POPUP object
2293
- class PopUp
2294
- def initialize(container)
2295
- @container = container
2296
- @page_container = container.page_container
2297
- end
2298
-
2299
- def button(caption)
2300
- return JSButton.new(@container.getIE.hwnd, caption)
2301
- end
2302
- end
2303
-
2304
- class JSButton
2305
- def initialize(hWnd, caption)
2306
- @hWnd = hWnd
2307
- @caption = caption
2308
- end
2309
-
2310
- def startClicker(waitTime=3)
2311
- clicker = WinClicker.new
2312
- clicker.clickJSDialog_Thread
2313
- # clickerThread = Thread.new(@caption) {
2314
- # sleep waitTime
2315
- # puts "After the wait time in startClicker"
2316
- # clickWindowsButton_hwnd(hwnd, buttonCaption)
2317
- #}
2318
- end
2319
- end
2320
-
2321
- # Base class for html elements.
2322
- # This is not a class that users would normally access.
2323
- class Element # Wrapper
2324
- include Watir::Exception
2325
- include Container # presumes @container is defined
2326
- attr_accessor :container
2327
-
2328
- # number of spaces that separate the property from the value in the to_s method
2329
- TO_S_SIZE = 14
2330
-
2331
- # ole_object - the ole object for the element being wrapped
2332
- def initialize(ole_object)
2333
- @o = ole_object
2334
- @original_color = nil
2335
- end
2336
-
2337
- # Return the ole object, allowing any methods of the DOM that Watir doesn't support to be used.
2338
- def ole_object # BUG: should use an attribute reader and rename the instance variable
2339
- return @o
2340
- end
2341
- def ole_object=(o)
2342
- @o = o
2343
- end
2344
-
2345
- private
2346
- def self.def_wrap(ruby_method_name, ole_method_name=nil)
2347
- ole_method_name = ruby_method_name unless ole_method_name
2348
- class_eval "def #{ruby_method_name}
2349
- assert_exists
2350
- ole_object.invoke('#{ole_method_name}')
2351
- end"
2352
- end
2353
- def self.def_wrap_guard(method_name)
2354
- class_eval "def #{method_name}
2355
- assert_exists
2356
- begin
2357
- ole_object.invoke('#{method_name}')
2358
- rescue
2359
- ''
2360
- end
2361
- end"
2362
- end
2363
-
2364
- public
2365
- def assert_exists
2366
- locate if defined?(locate)
2367
- unless ole_object
2368
- raise UnknownObjectException.new("Unable to locate object, using #{@how} and #{@what}")
2369
- end
2370
- end
2371
- def assert_enabled
2372
- unless enabled?
2373
- raise ObjectDisabledException, "object #{@how} and #{@what} is disabled"
2374
- end
2375
- end
2376
-
2377
- # return the name of the element (as defined in html)
2378
- def_wrap_guard :name
2379
- # return the id of the element
2380
- def_wrap_guard :id
2381
- # return whether the element is disabled
2382
- def_wrap :disabled
2383
- alias disabled? disabled
2384
- # return the value of the element
2385
- def_wrap_guard :value
2386
- # return the title of the element
2387
- def_wrap_guard :title
2388
- # return the style of the element
2389
- def_wrap_guard :style
2390
-
2391
- def_wrap_guard :alt
2392
- def_wrap_guard :src
2393
-
2394
- # return the type of the element
2395
- def_wrap_guard :type # input elements only
2396
- # return the url the link points to
2397
- def_wrap :href # link only
2398
- # return the ID of the control that this label is associated with
2399
- def_wrap :for, :htmlFor # label only
2400
- # return the class name of the element
2401
- # raise an ObjectNotFound exception if the object cannot be found
2402
- def_wrap :class_name, :className
2403
- # return the unique COM number for the element
2404
- def_wrap :unique_number, :uniqueNumber
2405
- # Return the outer html of the object - see http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/outerhtml.asp?frame=true
2406
- def_wrap :html, :outerHTML
2407
-
2408
- # return the text before the element
2409
- def before_text # label only
2410
- assert_exists
2411
- begin
2412
- ole_object.getAdjacentText("afterEnd").strip
2413
- rescue
2414
- ''
2415
- end
2416
- end
2417
-
2418
- # return the text after the element
2419
- def after_text # label only
2420
- assert_exists
2421
- begin
2422
- ole_object.getAdjacentText("beforeBegin").strip
2423
- rescue
2424
- ''
2425
- end
2426
- end
2427
-
2428
- # Return the innerText of the object
2429
- # Raise an ObjectNotFound exception if the object cannot be found
2430
- def text
2431
- assert_exists
2432
- return ole_object.innerText.strip
2433
- end
2434
-
2435
- def ole_inner_elements
2436
- assert_exists
2437
- return ole_object.all
2438
- end
2439
- private :ole_inner_elements
2440
-
2441
- def document
2442
- assert_exists
2443
- return ole_object
2444
- end
2445
-
2446
- # Return the element immediately containing self.
2447
- def parent
2448
- assert_exists
2449
- result = Element.new(ole_object.parentelement)
2450
- result.set_container self
2451
- result
2452
- end
2453
-
2454
- include Comparable
2455
- def <=> other
2456
- assert_exists
2457
- other.assert_exists
2458
- ole_object.sourceindex <=> other.ole_object.sourceindex
2459
- end
2460
-
2461
- # Return true if self is contained earlier in the html than other.
2462
- alias :before? :<
2463
- # Return true if self is contained later in the html than other.
2464
- alias :after? :>
2465
-
2466
- def typingspeed
2467
- @container.typingspeed
2468
- end
2469
-
2470
- def activeObjectHighLightColor
2471
- @container.activeObjectHighLightColor
2472
- end
2473
-
2474
- # Return an array with many of the properties, in a format to be used by the to_s method
2475
- def string_creator
2476
- n = []
2477
- n << "type:".ljust(TO_S_SIZE) + self.type
2478
- n << "id:".ljust(TO_S_SIZE) + self.id.to_s
2479
- n << "name:".ljust(TO_S_SIZE) + self.name.to_s
2480
- n << "value:".ljust(TO_S_SIZE) + self.value.to_s
2481
- n << "disabled:".ljust(TO_S_SIZE) + self.disabled.to_s
2482
- return n
2483
- end
2484
- private :string_creator
2485
-
2486
- # Display basic details about the object. Sample output for a button is shown.
2487
- # Raises UnknownObjectException if the object is not found.
2488
- # name b4
2489
- # type button
2490
- # id b5
2491
- # value Disabled Button
2492
- # disabled true
2493
- def to_s
2494
- assert_exists
2495
- return string_creator.join("\n")
2496
- end
2497
-
2498
- # This method is responsible for setting and clearing the colored highlighting on the currently active element.
2499
- # use :set to set the highlight
2500
- # :clear to clear the highlight
2501
- # TODO: Make this two methods: set_highlight & clear_highlight
2502
- # TODO: Remove begin/rescue blocks
2503
- def highlight(set_or_clear)
2504
- if set_or_clear == :set
2505
- begin
2506
- @original_color ||= style.backgroundColor
2507
- style.backgroundColor = @container.activeObjectHighLightColor
2508
- rescue
2509
- @original_color = nil
2510
- end
2511
- else # BUG: assumes is :clear, but could actually be anything
2512
- begin
2513
- style.backgroundColor = @original_color unless @original_color == nil
2514
- rescue
2515
- # we could be here for a number of reasons...
2516
- # e.g. page may have reloaded and the reference is no longer valid
2517
- ensure
2518
- @original_color = nil
2519
- end
2520
- end
2521
- end
2522
- private :highlight
2523
-
2524
- # This method clicks the active element.
2525
- # raises: UnknownObjectException if the object is not found
2526
- # ObjectDisabledException if the object is currently disabled
2527
- def click
2528
- click!
2529
- @container.wait
2530
- end
2531
-
2532
- def click_no_wait
2533
- assert_enabled
2534
-
2535
- highlight(:set)
2536
- object = "#{self.class}.new(self, :unique_number, #{self.unique_number})"
2537
- @page_container.eval_in_spawned_process(object + ".click!")
2538
- highlight(:clear)
2539
- end
2540
-
2541
- def click!
2542
- assert_enabled
2543
-
2544
- highlight(:set)
2545
- ole_object.click
2546
- highlight(:clear)
2547
- end
2548
-
2549
- # Flash the element the specified number of times.
2550
- # Defaults to 10 flashes.
2551
- def flash number=10
2552
- assert_exists
2553
- number.times do
2554
- highlight(:set)
2555
- sleep 0.05
2556
- highlight(:clear)
2557
- sleep 0.05
2558
- end
2559
- nil
2560
- end
2561
-
2562
- # Executes a user defined "fireEvent" for objects with JavaScript events tied to them such as DHTML menus.
2563
- # usage: allows a generic way to fire javascript events on page objects such as "onMouseOver", "onClick", etc.
2564
- # raises: UnknownObjectException if the object is not found
2565
- # ObjectDisabledException if the object is currently disabled
2566
- def fire_event(event)
2567
- assert_enabled
2568
-
2569
- highlight(:set)
2570
- ole_object.fireEvent(event)
2571
- @container.wait
2572
- highlight(:clear)
2573
- end
2574
-
2575
- # This method sets focus on the active element.
2576
- # raises: UnknownObjectException if the object is not found
2577
- # ObjectDisabledException if the object is currently disabled
2578
- def focus
2579
- assert_enabled
2580
- ole_object.focus
2581
- end
2582
-
2583
- # Returns whether this element actually exists.
2584
- def exists?
2585
- begin
2586
- locate if defined?(locate)
2587
- rescue WIN32OLERuntimeError
2588
- @o = nil
2589
- end
2590
- @o ? true: false
2591
- end
2592
- alias :exist? :exists?
2593
-
2594
- # Returns true if the element is enabled, false if it isn't.
2595
- # raises: UnknownObjectException if the object is not found
2596
- def enabled?
2597
- assert_exists
2598
- return ! disabled
2599
- end
2600
-
2601
- # Get attribute value for any attribute of the element.
2602
- # Returns null if attribute doesn't exist.
2603
- def attribute_value(attribute_name)
2604
- assert_exists
2605
- return ole_object.getAttribute(attribute_name)
2606
- end
2607
-
2608
- end
2609
-
2610
- class ElementMapper # Still to be used
2611
- include Container
2612
-
2613
- def initialize wrapper_class, container, how, what
2614
- @wrapper_class = wrapper_class
2615
- set_container
2616
- @how = how
2617
- @what = what
2618
- end
2619
-
2620
- def method_missing method, *args
2621
- locate
2622
- @wrapper_class.new(@o).send(method, *args)
2623
- end
2624
- end
2625
-
2626
- class Frame
2627
- include Container
2628
- include PageContainer
2629
-
2630
- # Find the frame denoted by how and what in the container and return its ole_object
2631
- def locate
2632
- how = @how
2633
- what = @what
2634
- frames = @container.document.frames
2635
- target = nil
2636
-
2637
- for i in 0..(frames.length - 1)
2638
- this_frame = frames.item(i)
2639
- case how
2640
- when :index
2641
- index = i + 1
2642
- return this_frame if index == what
2643
- when :name
2644
- begin
2645
- return this_frame if what.matches(this_frame.name)
2646
- rescue # access denied?
2647
- end
2648
- when :id
2649
- # We assume that pages contain frames or iframes, but not both.
2650
- this_frame_tag = @container.document.getElementsByTagName("FRAME").item(i)
2651
- return this_frame if this_frame_tag and what.matches(this_frame_tag.invoke("id"))
2652
- this_iframe_tag = @container.document.getElementsByTagName("IFRAME").item(i)
2653
- return this_frame if this_iframe_tag and what.matches(this_iframe_tag.invoke("id"))
2654
- when :src
2655
- this_frame_tag = @container.document.getElementsByTagName("FRAME").item(i)
2656
- return this_frame if this_frame_tag and what.matches(this_frame_tag.src)
2657
- this_iframe_tag = @container.document.getElementsByTagName("IFRAME").item(i)
2658
- return this_frame if this_iframe_tag and what.matches(this_iframe_tag.src)
2659
- else
2660
- raise ArgumentError, "Argument #{how} not supported"
2661
- end
2662
- end
2663
-
2664
- raise UnknownFrameException, "Unable to locate a frame with #{how.to_s} #{what}"
2665
- end
2666
-
2667
- def initialize(container, how, what)
2668
- set_container container
2669
- @how = how
2670
- @what = what
2671
- @o = locate
2672
- copy_test_config container
2673
- end
2674
-
2675
- def document
2676
- @o.document
2677
- end
2678
-
2679
- def attach_command
2680
- @container.page_container.attach_command + ".frame(#{@how.inspect}, #{@what.inspect})"
2681
- end
2682
-
2683
- end
2684
-
2685
- class ModalDialog
2686
- include Container
2687
- include PageContainer
2688
- include Win32
2689
-
2690
- # Return the current window handle
2691
- attr_reader :hwnd
2692
-
2693
- def find_modal_from_window
2694
- # Use handle of our parent window to see if we have any currently
2695
- # enabled popup.
2696
- hwnd = @container.hwnd
2697
- hwnd_modal = 0
2698
- begin
2699
- Watir::until_with_timeout do
2700
- hwnd_modal, arr = GetWindow.call(hwnd, GW_ENABLEDPOPUP) # GW_ENABLEDPOPUP = 6
2701
- hwnd_modal > 0
2702
- end
2703
- rescue TimeOutException
2704
- return nil
2705
- end
2706
- if hwnd_modal == hwnd || hwnd_modal == 0
2707
- hwnd_modal = nil
2708
- end
2709
- @hwnd = hwnd_modal
2710
- end
2711
- private :find_modal_from_window
2712
-
2713
- def locate
2714
- how = @how
2715
- what = @what
2716
-
2717
- case how
2718
- when nil
2719
- unless find_modal_from_window
2720
- raise NoMatchingWindowFoundException,
2721
- "Modal Dialog not found. Timeout = #{Watir::IE.attach_timeout}"
2722
- end
2723
- when :title
2724
- case what.class.to_s
2725
- # TODO: re-write like WET's so we can select on regular expressions too.
2726
- when "String"
2727
- begin
2728
- Watir::until_with_timeout do
2729
- title = "#{what} -- Web Page Dialog"
2730
- @hwnd, arr = FindWindowEx.call(0, 0, nil, title)
2731
- @hwnd > 0
2732
- end
2733
- rescue TimeOutException
2734
- raise NoMatchingWindowFoundException,
2735
- "Modal Dialog with title #{what} not found. Timeout = #{Watir::IE.attach_timeout}"
2736
- end
2737
- else
2738
- raise ArgumentError, "Title value must be String"
2739
- end
2740
- else
2741
- raise ArgumentError, "Only null and :title methods are supported"
2742
- end
2743
-
2744
- intUnknown = 0
2745
- begin
2746
- Watir::until_with_timeout do
2747
- intPointer = " " * 4 # will contain the int value of the IUnknown*
2748
- GetUnknown.call(@hwnd, intPointer)
2749
- intArray = intPointer.unpack('L')
2750
- intUnknown = intArray.first
2751
- intUnknown > 0
2752
- end
2753
- rescue TimeOutException => e
2754
- raise NoMatchingWindowFoundException,
2755
- "Unable to attach to Modal Window #{what.inspect} after #{e.duration} seconds."
2756
- end
2757
-
2758
- copy_test_config @parent_container
2759
- @document = WIN32OLE.connect_unknown(intUnknown)
2760
- end
2761
-
2762
- def initialize(container, how, what=nil)
2763
- set_container container
2764
- @how = how
2765
- @what = what
2766
- @parent_container = container
2767
- # locate our modal dialog's Document object and save it
2768
- begin
2769
- locate
2770
- rescue NoMethodError => e
2771
- message =
2772
- "IE#modal_dialog not supported with the current version of Ruby (#{RUBY_VERSION}).\n" +
2773
- "See http://jira.openqa.org/browse/WTR-2 for details.\n" +
2774
- e.message
2775
- raise NoMethodError.new(message)
2776
- end
2777
- end
2778
-
2779
- def document
2780
- @document
2781
- end
2782
-
2783
- # Return the title of the document
2784
- def title
2785
- document.title
2786
- end
2787
-
2788
- def close
2789
- document.parentWindow.close
2790
- end
2791
-
2792
- def attach_command
2793
- "Watir::IE.find(:hwnd, #{@container.hwnd}).modal_dialog"
2794
- end
2795
-
2796
- def wait(no_sleep=false)
2797
- end
2798
-
2799
- # Return true if the modal exists. Mostly this is useful for testing whether
2800
- # a modal has closed.
2801
- def exists?
2802
- Watir::Win32::window_exists? @hwnd
2803
- end
2804
- alias :exist? :exists?
2805
- end
2806
-
2807
- # this class is the super class for the iterator classes (buttons, links, spans etc
2808
- # it would normally only be accessed by the iterator methods (spans, links etc) of IE
2809
- class ElementCollections
2810
- include Enumerable
2811
-
2812
- # Super class for all the iteractor classes
2813
- # * container - an instance of an IE object
2814
- def initialize(container)
2815
- @container = container
2816
- @page_container = container.page_container
2817
- @length = length # defined by subclasses
2818
-
2819
- # set up the items we want to display when the show method is used
2820
- set_show_items
2821
- end
2822
-
2823
- private
2824
- def set_show_items
2825
- @show_attributes = AttributeLengthPairs.new("id", 20)
2826
- @show_attributes.add("name", 20)
2827
- end
2828
-
2829
- public
2830
- def get_length_of_input_objects(object_type)
2831
- object_types =
2832
- if object_type.kind_of? Array
2833
- object_type
2834
- else
2835
- [object_type]
2836
- end
2837
-
2838
- length = 0
2839
- objects = @container.document.getElementsByTagName("INPUT")
2840
- if objects.length > 0
2841
- objects.each do |o|
2842
- length += 1 if object_types.include?(o.invoke("type").downcase)
2843
- end
2844
- end
2845
- return length
2846
- end
2847
-
2848
- # iterate through each of the elements in the collection in turn
2849
- def each
2850
- 0.upto(@length-1) { |i| yield iterator_object(i) }
2851
- end
2852
-
2853
- # allows access to a specific item in the collection
2854
- def [](n)
2855
- return iterator_object(n-1)
2856
- end
2857
-
2858
- # this method is the way to show the objects, normally used from irb
2859
- def show
2860
- s = "index".ljust(6)
2861
- @show_attributes.each do |attribute_length_pair|
2862
- s += attribute_length_pair.attribute.ljust(attribute_length_pair.length)
2863
- end
2864
-
2865
- index = 1
2866
- self.each do |o|
2867
- s += "\n"
2868
- s += index.to_s.ljust(6)
2869
- @show_attributes.each do |attribute_length_pair|
2870
- begin
2871
- s += eval('o.ole_object.invoke("#{attribute_length_pair.attribute}")').to_s.ljust(attribute_length_pair.length)
2872
- rescue => e
2873
- s += " ".ljust(attribute_length_pair.length)
2874
- end
2875
- end
2876
- index += 1
2877
- end
2878
- puts s
2879
- end
2880
-
2881
- # this method creates an object of the correct type that the iterators use
2882
- private
2883
- def iterator_object(i)
2884
- element_class.new(@container, :index, i + 1)
2885
- end
2886
- end
2887
-
2888
-
2889
- # Forms
2890
-
2891
- module FormAccess
2892
- def name
2893
- @ole_object.getAttributeNode('name').value
2894
- end
2895
- def action
2896
- @ole_object.action
2897
- end
2898
- def method
2899
- @ole_object.invoke('method')
2900
- end
2901
- def id
2902
- @ole_object.invoke('id')
2903
- end
2904
- end
2905
-
2906
- # wraps around a form OLE object
2907
- class FormWrapper
2908
- include FormAccess
2909
- def initialize(ole_object)
2910
- @ole_object = ole_object
2911
- end
2912
- end
2913
-
2914
- # Form Factory object
2915
- class Form < Element
2916
- include FormAccess
2917
- include Container
2918
-
2919
- attr_accessor :form
2920
-
2921
- # * container - the containing object, normally an instance of IE
2922
- # * how - symbol - how we access the form (:name, :id, :index, :action, :method)
2923
- # * what - what we use to access the form
2924
- def initialize(container, how, what)
2925
- set_container container
2926
- @how = how
2927
- @what = what
2928
-
2929
- log "Get form how is #{@how} what is #{@what} "
2930
-
2931
- # Get form using xpath.
2932
- if @how == :xpath
2933
- @ole_object = @container.element_by_xpath(@what)
2934
- else
2935
- count = 1
2936
- doc = @container.document
2937
- doc.forms.each do |thisForm|
2938
- next unless @ole_object == nil
2939
-
2940
- wrapped = FormWrapper.new(thisForm)
2941
-
2942
- log "form on page, name is " + wrapped.name
2943
-
2944
- @ole_object =
2945
- case @how
2946
- when :name, :id, :method, :action
2947
- @what.matches(wrapped.send(@how)) ? thisForm : nil
2948
- when :index
2949
- count == @what ? thisForm : nil
2950
- else
2951
- raise MissingWayOfFindingObjectException, "#{how} is an unknown way of finding a form (#{what})"
2952
- end
2953
- count = count +1
2954
- end
2955
- end
2956
- super(@ole_object)
2957
-
2958
- copy_test_config container
2959
- end
2960
-
2961
- def exists?
2962
- @ole_object ? true : false
2963
- end
2964
- alias :exist? :exists?
2965
-
2966
- # Submit the data -- equivalent to pressing Enter or Return to submit a form.
2967
- def submit # XXX use assert_exists
2968
- raise UnknownFormException, "Unable to locate a form using #{@how} and #{@what} " if @ole_object == nil
2969
- @ole_object.submit
2970
- @container.wait
2971
- end
2972
-
2973
- def ole_inner_elements # XXX use assert_exists
2974
- raise UnknownFormException, "Unable to locate a form using #{@how} and #{@what} " if @ole_object == nil
2975
- @ole_object.elements
2976
- end
2977
- private :ole_inner_elements
2978
-
2979
- def document
2980
- return @ole_object
2981
- end
2982
-
2983
- def wait(no_sleep=false)
2984
- @container.wait(no_sleep)
2985
- end
2986
-
2987
- # This method is responsible for setting and clearing the colored highlighting on the specified form.
2988
- # use :set to set the highlight
2989
- # :clear to clear the highlight
2990
- def highlight(set_or_clear, element, count)
2991
-
2992
- if set_or_clear == :set
2993
- begin
2994
- original_color = element.style.backgroundColor
2995
- original_color = "" if original_color==nil
2996
- element.style.backgroundColor = activeObjectHighLightColor
2997
- rescue => e
2998
- puts e
2999
- puts e.backtrace.join("\n")
3000
- original_color = ""
3001
- end
3002
- @original_styles[count] = original_color
3003
- else
3004
- begin
3005
- element.style.backgroundColor = @original_styles[ count]
3006
- rescue => e
3007
- puts e
3008
- # we could be here for a number of reasons...
3009
- ensure
3010
- end
3011
- end
3012
- end
3013
- private :highlight
3014
-
3015
- # causes the object to flash. Normally used in IRB when creating scripts
3016
- # Default is 10
3017
- def flash number=10
3018
- @original_styles = {}
3019
- number.times do
3020
- count = 0
3021
- @ole_object.elements.each do |element|
3022
- highlight(:set, element, count)
3023
- count += 1
3024
- end
3025
- sleep 0.05
3026
- count = 0
3027
- @ole_object.elements.each do |element|
3028
- highlight(:clear, element, count)
3029
- count += 1
3030
- end
3031
- sleep 0.05
3032
- end
3033
- end
3034
-
3035
- end # class Form
3036
-
3037
- # this class contains items that are common between the span, div, and pre objects
3038
- # it would not normally be used directly
3039
- #
3040
- # many of the methods available to this object are inherited from the Element class
3041
- #
3042
- class NonControlElement < Element
3043
- include Watir::Exception
3044
-
3045
- def locate
3046
- if @how == :xpath
3047
- @o = @container.element_by_xpath(@what)
3048
- else
3049
- @o = @container.locate_tagged_element(self.class::TAG, @how, @what)
3050
- end
3051
- end
3052
-
3053
- def initialize(container, how, what)
3054
- set_container container
3055
- @how = how
3056
- @what = what
3057
- super nil
3058
- end
3059
-
3060
- # this method is used to populate the properties in the to_s method
3061
- def span_div_string_creator
3062
- n = []
3063
- n << "class:".ljust(TO_S_SIZE) + self.class_name
3064
- n << "text:".ljust(TO_S_SIZE) + self.text
3065
- return n
3066
- end
3067
- private :span_div_string_creator
3068
-
3069
- # returns the properties of the object in a string
3070
- # raises an ObjectNotFound exception if the object cannot be found
3071
- def to_s
3072
- assert_exists
3073
- r = string_creator
3074
- r += span_div_string_creator
3075
- return r.join("\n")
3076
- end
3077
- end
3078
-
3079
- class Pre < NonControlElement
3080
- TAG = 'PRE'
3081
- end
3082
-
3083
- class P < NonControlElement
3084
- TAG = 'P'
3085
- end
3086
-
3087
- # 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
3088
- # It would not normally be created by users
3089
- class Div < NonControlElement
3090
- TAG = 'DIV'
3091
- end
3092
-
3093
- # this class is used to deal with Span tags in the html page. It would not normally be created by users
3094
- class Span < NonControlElement
3095
- TAG = 'SPAN'
3096
- end
3097
-
3098
- # Accesses Label element on the html page - http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/label.asp?frame=true
3099
- class Label < NonControlElement
3100
- TAG = 'LABEL'
3101
-
3102
- # this method is used to populate the properties in the to_s method
3103
- def label_string_creator
3104
- n = []
3105
- n << "for:".ljust(TO_S_SIZE) + self.for
3106
- n << "text:".ljust(TO_S_SIZE) + self.text
3107
- return n
3108
- end
3109
- private :label_string_creator
3110
-
3111
- # returns the properties of the object in a string
3112
- # raises an ObjectNotFound exception if the object cannot be found
3113
- def to_s
3114
- assert_exists
3115
- r = string_creator
3116
- r += label_string_creator
3117
- return r.join("\n")
3118
- end
3119
- end
3120
-
3121
- class Li < NonControlElement
3122
- TAG = 'LI'
3123
- end
3124
-
3125
- # This class is used for dealing with tables.
3126
- # Normally a user would not need to create this object as it is returned by the Watir::Container#table method
3127
- #
3128
- # many of the methods available to this object are inherited from the Element class
3129
- #
3130
- class Table < Element
3131
- include Container
3132
-
3133
- # Returns the table object containing anElement
3134
- # * container - an instance of an IE object
3135
- # * anElement - a Watir object (TextField, Button, etc.)
3136
- def Table.create_from_element(container, anElement)
3137
- anElement.locate if defined?(anElement.locate)
3138
- o = anElement.ole_object.parentElement
3139
- o = o.parentElement until o.tagName == 'TABLE'
3140
- new container, :ole_object, o
3141
- end
3142
-
3143
- # Returns an initialized instance of a table object
3144
- # * container - the container
3145
- # * how - symbol - how we access the table
3146
- # * what - what we use to access the table - id, name index etc
3147
- def initialize(container, how, what)
3148
- set_container container
3149
- @how = how
3150
- @what = what
3151
- super nil
3152
- end
3153
-
3154
- def locate
3155
- if @how == :xpath
3156
- @o = @container.element_by_xpath(@what)
3157
- elsif @how == :ole_object
3158
- @o = @what
3159
- else
3160
- @o = @container.locate_tagged_element('TABLE', @how, @what)
3161
- end
3162
- end
3163
-
3164
- # override the highlight method, as if the tables rows are set to have a background color,
3165
- # this will override the table background color, and the normal flash method won't work
3166
- def highlight(set_or_clear)
3167
-
3168
- if set_or_clear == :set
3169
- begin
3170
- @original_border = @o.border.to_i
3171
- if @o.border.to_i==1
3172
- @o.border = 2
3173
- else
3174
- @o.border = 1
3175
- end
3176
- rescue
3177
- @original_border = nil
3178
- end
3179
- else
3180
- begin
3181
- @o.border= @original_border unless @original_border == nil
3182
- @original_border = nil
3183
- rescue
3184
- # we could be here for a number of reasons...
3185
- ensure
3186
- @original_border = nil
3187
- end
3188
- end
3189
- super
3190
- end
3191
-
3192
- # this method is used to populate the properties in the to_s method
3193
- def table_string_creator
3194
- n = []
3195
- n << "rows:".ljust(TO_S_SIZE) + self.row_count.to_s
3196
- n << "cols:".ljust(TO_S_SIZE) + self.column_count.to_s
3197
- return n
3198
- end
3199
- private :table_string_creator
3200
-
3201
- # returns the properties of the object in a string
3202
- # raises an ObjectNotFound exception if the object cannot be found
3203
- def to_s
3204
- assert_exists
3205
- r = string_creator
3206
- r += table_string_creator
3207
- return r.join("\n")
3208
- end
3209
-
3210
- # iterates through the rows in the table. Yields a TableRow object
3211
- def each
3212
- assert_exists
3213
- 1.upto(@o.getElementsByTagName("TR").length) { |i| yield TableRow.new(@container, :ole_object, row(i)) }
3214
- end
3215
-
3216
- # Returns a row in the table
3217
- # * index - the index of the row
3218
- def [](index)
3219
- assert_exists
3220
- return TableRow.new(@container, :ole_object, row(index))
3221
- end
3222
-
3223
- # This method returns the number of rows in the table.
3224
- # Raises an UnknownObjectException if the table doesnt exist.
3225
- def row_count
3226
- assert_exists
3227
- #return table_body.children.length
3228
- return @o.getElementsByTagName("TR").length
3229
- end
3230
-
3231
- # This method returns the number of columns in a row of the table.
3232
- # Raises an UnknownObjectException if the table doesn't exist.
3233
- # * index - the index of the row
3234
- def column_count(index=1)
3235
- assert_exists
3236
- row(index).cells.length
3237
- end
3238
-
3239
- # This method returns the table as a 2 dimensional array. Dont expect too much if there are nested tables, colspan etc.
3240
- # Raises an UnknownObjectException if the table doesn't exist.
3241
- # http://www.w3.org/TR/html4/struct/tables.html
3242
- def to_a
3243
- assert_exists
3244
- y = []
3245
- table_rows = @o.getElementsByTagName("TR")
3246
- for row in table_rows
3247
- x = []
3248
- for td in row.getElementsbyTagName("TD")
3249
- x << td.innerText.strip
3250
- end
3251
- y << x
3252
- end
3253
- return y
3254
- end
3255
-
3256
- def table_body(index=1)
3257
- return @o.getElementsByTagName('TBODY')[index]
3258
- end
3259
- private :table_body
3260
-
3261
- # returns a watir object
3262
- def body(how, what)
3263
- return TableBody.new(@container, how, what, self)
3264
- end
3265
-
3266
- # returns a watir object
3267
- def bodies
3268
- assert_exists
3269
- return TableBodies.new(@container, @o)
3270
- end
3271
-
3272
- # returns an ole object
3273
- def row(index)
3274
- return @o.invoke("rows")[(index-1).to_s]
3275
- end
3276
- private :row
3277
-
3278
- # Returns an array containing all the text values in the specified column
3279
- # Raises an UnknownCellException if the specified column does not exist in every
3280
- # Raises an UnknownObjectException if the table doesn't exist.
3281
- # row of the table
3282
- # * columnnumber - column index to extract values from
3283
- def column_values(columnnumber)
3284
-
3285
- return(1..row_count).collect {|idx| self[idx][columnnumber].text}
3286
- end
3287
-
3288
- # Returns an array containing all the text values in the specified row
3289
- # Raises an UnknownObjectException if the table doesn't exist.
3290
- # * rownumber - row index to extract values from
3291
- def row_values(rownumber)
3292
- return(1..column_count(rownumber)).collect {|idx| self[rownumber][idx].text}
3293
- end
3294
-
3295
- end
3296
-
3297
- # this class is a collection of the table body objects that exist in the table
3298
- # it wouldnt normally be created by a user, but gets returned by the bodies method of the Table object
3299
- # many of the methods available to this object are inherited from the Element class
3300
- #
3301
- class TableBodies < Element
3302
- def initialize(container, parent_table)
3303
- set_container container
3304
- @o = parent_table # in this case, @o is the parent table
3305
- end
3306
-
3307
- # returns the number of TableBodies that exist in the table
3308
- def length
3309
- assert_exists
3310
- return @o.tBodies.length
3311
- end
3312
-
3313
- # returns the n'th Body as a Watir TableBody object
3314
- def []n
3315
- assert_exists
3316
- return TableBody.new(@container, :ole_object, ole_table_body_at_index(n))
3317
- end
3318
-
3319
- # returns an ole table body
3320
- def ole_table_body_at_index(n)
3321
- return @o.tBodies[(n-1).to_s]
3322
- end
3323
-
3324
- # iterates through each of the TableBodies in the Table. Yields a TableBody object
3325
- def each
3326
- 1.upto(@o.tBodies.length) { |i| yield TableBody.new(@container, :ole_object, ole_table_body_at_index(i)) }
3327
- end
3328
-
3329
- end
3330
-
3331
- # this class is a table body
3332
- class TableBody < Element
3333
- def locate
3334
- @o = nil
3335
- if @how == :ole_object
3336
- @o = @what # in this case, @o is the table body
3337
- elsif @how == :index
3338
- @o = @parent_table.bodies.ole_table_body_at_index(@what)
3339
- end
3340
- @rows = []
3341
- if @o
3342
- @o.rows.each do |oo|
3343
- @rows << TableRow.new(@container, :ole_object, oo)
3344
- end
3345
- end
3346
- end
3347
-
3348
- def initialize(container, how, what, parent_table=nil)
3349
- set_container container
3350
- @how = how
3351
- @what = what
3352
- @parent_table = parent_table
3353
- super nil
3354
- end
3355
-
3356
- # returns the specified row as a TableRow object
3357
- def [](n)
3358
- assert_exists
3359
- return @rows[n - 1]
3360
- end
3361
-
3362
- # iterates through all the rows in the table body
3363
- def each
3364
- locate
3365
- 0.upto(@rows.length - 1) { |i| yield @rows[i] }
3366
- end
3367
-
3368
- # returns the number of rows in this table body.
3369
- def length
3370
- return @rows.length
3371
- end
3372
- end
3373
-
3374
-
3375
- # this class is a table row
3376
- class TableRow < Element
3377
-
3378
- def locate
3379
- @o = nil
3380
- if @how == :ole_object
3381
- @o = @what
3382
- elsif @how == :xpath
3383
- @o = @container.element_by_xpath(@what)
3384
- else
3385
- @o = @container.locate_tagged_element("TR", @how, @what)
3386
- end
3387
- if @o # cant call the assert_exists here, as an exists? method call will fail
3388
- @cells = []
3389
- @o.cells.each do |oo|
3390
- @cells << TableCell.new(@container, :ole_object, oo)
3391
- end
3392
- end
3393
- end
3394
-
3395
- # Returns an initialized instance of a table row
3396
- # * o - the object contained in the row
3397
- # * container - an instance of an IE object
3398
- # * how - symbol - how we access the row
3399
- # * what - what we use to access the row - id, index etc. If how is :ole_object then what is a Internet Explorer Raw Row
3400
- def initialize(container, how, what)
3401
- set_container container
3402
- @how = how
3403
- @what = what
3404
- super nil
3405
- end
3406
-
3407
- # this method iterates through each of the cells in the row. Yields a TableCell object
3408
- def each
3409
- locate
3410
- 0.upto(@cells.length-1) { |i| yield @cells[i] }
3411
- end
3412
-
3413
- # Returns an element from the row as a TableCell object
3414
- def [](index)
3415
- assert_exists
3416
- raise UnknownCellException, "Unable to locate a cell at index #{index}" if @cells.length < index
3417
- return @cells[(index - 1)]
3418
- end
3419
-
3420
- # defaults all missing methods to the array of elements, to be able to
3421
- # use the row as an array
3422
- # def method_missing(aSymbol, *args)
3423
- # return @o.send(aSymbol, *args)
3424
- # end
3425
-
3426
- def column_count
3427
- locate
3428
- @cells.length
3429
- end
3430
- end
3431
-
3432
- # this class is a table cell - when called via the Table object
3433
- class TableCell < Element
3434
- include Watir::Exception
3435
- include Container
3436
-
3437
- def locate
3438
- if @how == :xpath
3439
- @o = @container.element_by_xpath(@what)
3440
- elsif @how == :ole_object
3441
- @o = @what
3442
- else
3443
- @o = @container.locate_tagged_element("TD", @how, @what)
3444
- end
3445
- end
3446
-
3447
- # Returns an initialized instance of a table cell
3448
- # * container - an IE object
3449
- # * how - symbol - how we access the cell
3450
- # * what - what we use to access the cell - id, name index etc
3451
- def initialize(container, how, what)
3452
- set_container container
3453
- @how = how
3454
- @what = what
3455
- super nil
3456
- end
3457
-
3458
- def ole_inner_elements
3459
- locate
3460
- return @o.all
3461
- end
3462
- private :ole_inner_elements
3463
-
3464
- def document
3465
- locate
3466
- return @o
3467
- end
3468
-
3469
- alias to_s text
3470
-
3471
- def colspan
3472
- locate
3473
- @o.colSpan
3474
- end
3475
-
3476
- end
3477
-
3478
- # This class is the means of accessing an image on a page.
3479
- # Normally a user would not need to create this object as it is returned by the Watir::Container#image method
3480
- #
3481
- # many of the methods available to this object are inherited from the Element class
3482
- #
3483
- class Image < Element
3484
- def initialize(container, how, what)
3485
- set_container container
3486
- @how = how
3487
- @what = what
3488
- super nil
3489
- end
3490
-
3491
- def locate
3492
- if @how == :xpath
3493
- @o = @container.element_by_xpath(@what)
3494
- else
3495
- @o = @container.locate_tagged_element('IMG', @how, @what)
3496
- end
3497
- end
3498
-
3499
- # this method produces the properties for an image as an array
3500
- def image_string_creator
3501
- n = []
3502
- n << "src:".ljust(TO_S_SIZE) + self.src.to_s
3503
- n << "file date:".ljust(TO_S_SIZE) + self.fileCreatedDate.to_s
3504
- n << "file size:".ljust(TO_S_SIZE) + self.fileSize.to_s
3505
- n << "width:".ljust(TO_S_SIZE) + self.width.to_s
3506
- n << "height:".ljust(TO_S_SIZE) + self.height.to_s
3507
- n << "alt:".ljust(TO_S_SIZE) + self.alt.to_s
3508
- return n
3509
- end
3510
- private :image_string_creator
3511
-
3512
- # returns a string representation of the object
3513
- def to_s
3514
- assert_exists
3515
- r = string_creator
3516
- r += image_string_creator
3517
- return r.join("\n")
3518
- end
3519
-
3520
- # this method returns the file created date of the image
3521
- def fileCreatedDate
3522
- assert_exists
3523
- return @o.invoke("fileCreatedDate")
3524
- end
3525
-
3526
- # this method returns the filesize of the image
3527
- def fileSize
3528
- assert_exists
3529
- return @o.invoke("fileSize").to_s
3530
- end
3531
-
3532
- # returns the width in pixels of the image, as a string
3533
- def width
3534
- assert_exists
3535
- return @o.invoke("width").to_s
3536
- end
3537
-
3538
- # returns the height in pixels of the image, as a string
3539
- def height
3540
- assert_exists
3541
- return @o.invoke("height").to_s
3542
- end
3543
-
3544
- # This method attempts to find out if the image was actually loaded by the web browser.
3545
- # If the image was not loaded, the browser is unable to determine some of the properties.
3546
- # We look for these missing properties to see if the image is really there or not.
3547
- # If the Disk cache is full (tools menu -> Internet options -> Temporary Internet Files), it may produce incorrect responses.
3548
- def hasLoaded?
3549
- locate
3550
- raise UnknownObjectException, "Unable to locate image using #{@how} and #{@what}" if @o == nil
3551
- return false if @o.fileCreatedDate == "" and @o.fileSize.to_i == -1
3552
- return true
3553
- end
3554
-
3555
- # this method highlights the image (in fact it adds or removes a border around the image)
3556
- # * set_or_clear - symbol - :set to set the border, :clear to remove it
3557
- def highlight(set_or_clear)
3558
- if set_or_clear == :set
3559
- begin
3560
- @original_border = @o.border
3561
- @o.border = 1
3562
- rescue
3563
- @original_border = nil
3564
- end
3565
- else
3566
- begin
3567
- @o.border = @original_border
3568
- @original_border = nil
3569
- rescue
3570
- # we could be here for a number of reasons...
3571
- ensure
3572
- @original_border = nil
3573
- end
3574
- end
3575
- end
3576
- private :highlight
3577
-
3578
- # This method saves the image to the file path that is given. The
3579
- # path must be in windows format (c:\\dirname\\somename.gif). This method
3580
- # will not overwrite a previously existing image. If an image already
3581
- # exists at the given path then a dialog will be displayed prompting
3582
- # for overwrite.
3583
- # Raises a WatirException if AutoIt is not correctly installed
3584
- # path - directory path and file name of where image should be saved
3585
- def save(path)
3586
- require 'watir/windowhelper'
3587
- WindowHelper.check_autoit_installed
3588
- @container.goto(src)
3589
- begin
3590
- thrd = fill_save_image_dialog(path)
3591
- @container.document.execCommand("SaveAs")
3592
- thrd.join(5)
3593
- ensure
3594
- @container.back
3595
- end
3596
- end
3597
-
3598
- def fill_save_image_dialog(path)
3599
- Thread.new do
3600
- 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\"")
3601
- end
3602
- end
3603
- private :fill_save_image_dialog
3604
- end
3605
-
3606
-
3607
- # This class is the means of accessing a link on a page
3608
- # Normally a user would not need to create this object as it is returned by the Watir::Container#link method
3609
- # many of the methods available to this object are inherited from the Element class
3610
- #
3611
- class Link < Element
3612
- # Returns an initialized instance of a link object
3613
- # * container - an instance of a container
3614
- # * how - symbol - how we access the link
3615
- # * what - what we use to access the link, text, url, index etc
3616
- def initialize(container, how, what)
3617
- set_container container
3618
- @how = how
3619
- @what = what
3620
- super(nil)
3621
- end
3622
-
3623
- def locate
3624
- if @how == :xpath
3625
- @o = @container.element_by_xpath(@what)
3626
- else
3627
- begin
3628
- @o = @container.locate_tagged_element('A', @how, @what)
3629
- rescue UnknownObjectException
3630
- @o = nil
3631
- end
3632
- end
3633
- end
3634
-
3635
- # if an image is used as part of the link, this will return true
3636
- def link_has_image
3637
- assert_exists
3638
- return true if @o.getElementsByTagName("IMG").length > 0
3639
- return false
3640
- end
3641
-
3642
- # this method returns the src of an image, if an image is used as part of the link
3643
- def src # BUG?
3644
- assert_exists
3645
- if @o.getElementsByTagName("IMG").length > 0
3646
- return @o.getElementsByTagName("IMG")[0.to_s].src
3647
- else
3648
- return ""
3649
- end
3650
- end
3651
-
3652
- def link_string_creator
3653
- n = []
3654
- n << "href:".ljust(TO_S_SIZE) + self.href
3655
- n << "inner text:".ljust(TO_S_SIZE) + self.text
3656
- n << "img src:".ljust(TO_S_SIZE) + self.src if self.link_has_image
3657
- return n
3658
- end
3659
-
3660
- # returns a textual description of the link
3661
- def to_s
3662
- assert_exists
3663
- r = string_creator
3664
- r = r + link_string_creator
3665
- return r.join("\n")
3666
- end
3667
- end
3668
-
3669
- class InputElement < Element
3670
- def locate
3671
- if @how == :xpath
3672
- @o = @container.element_by_xpath(@what)
3673
- elsif @how == :ole_object
3674
- @o = @what
3675
- else
3676
- @o = @container.locate_input_element(@how, @what, self.class::INPUT_TYPES)
3677
- end
3678
- end
3679
- def initialize(container, how, what)
3680
- set_container container
3681
- @how = how
3682
- @what = what
3683
- super(nil)
3684
- end
3685
- end
3686
-
3687
- # This class is the way in which select boxes are manipulated.
3688
- # Normally a user would not need to create this object as it is returned by the Watir::Container#select_list method
3689
- class SelectList < InputElement
3690
- INPUT_TYPES = ["select-one", "select-multiple"]
3691
-
3692
- attr_accessor :o
3693
-
3694
- # This method clears the selected items in the select box
3695
- def clearSelection
3696
- assert_exists
3697
- highlight(:set)
3698
- wait = false
3699
- @o.each do |selectBoxItem|
3700
- if selectBoxItem.selected
3701
- selectBoxItem.selected = false
3702
- wait = true
3703
- end
3704
- end
3705
- @container.wait if wait
3706
- highlight(:clear)
3707
- end
3708
- # private :clearSelection
3709
-
3710
- # This method selects an item, or items in a select box, by text.
3711
- # Raises NoValueFoundException if the specified value is not found.
3712
- # * item - the thing to select, string or reg exp
3713
- def select(item)
3714
- select_item_in_select_list(:text, item)
3715
- end
3716
- alias :set :select
3717
-
3718
- # Selects an item, or items in a select box, by value.
3719
- # Raises NoValueFoundException if the specified value is not found.
3720
- # * item - the value of the thing to select, string, reg exp or an array of string and reg exps
3721
- def select_value(item)
3722
- select_item_in_select_list(:value, item)
3723
- end
3724
-
3725
- # BUG: Should be private
3726
- # Selects something from the select box
3727
- # * name - symbol :value or :text - how we find an item in the select box
3728
- # * item - string or reg exp - what we are looking for
3729
- def select_item_in_select_list(attribute, value)
3730
- assert_exists
3731
- highlight(:set)
3732
- doBreak = false
3733
- @container.log "Setting box #{@o.name} to #{attribute} #{value} "
3734
- @o.each do |option| # items in the list
3735
- if value.matches(option.invoke(attribute.to_s))
3736
- if option.selected
3737
- doBreak = true
3738
- break
3739
- else
3740
- option.selected = true
3741
- @o.fireEvent("onChange")
3742
- @container.wait
3743
- doBreak = true
3744
- break
3745
- end
3746
- end
3747
- end
3748
- unless doBreak
3749
- raise NoValueFoundException,
3750
- "No option with #{attribute.to_s} of #{value} in this select element"
3751
- end
3752
- highlight(:clear)
3753
- end
3754
-
3755
- # Returns all the items in the select list as an array.
3756
- # An empty array is returned if the select box has no contents.
3757
- # Raises UnknownObjectException if the select box is not found
3758
- def getAllContents # BUG: camel_case.rb
3759
- assert_exists
3760
- @container.log "There are #{@o.length} items"
3761
- returnArray = []
3762
- @o.each { |thisItem| returnArray << thisItem.text }
3763
- return returnArray
3764
- end
3765
-
3766
- # Returns the selected items as an array.
3767
- # Raises UnknownObjectException if the select box is not found.
3768
- def getSelectedItems
3769
- assert_exists
3770
- returnArray = []
3771
- @container.log "There are #{@o.length} items"
3772
- @o.each do |thisItem|
3773
- if thisItem.selected
3774
- @container.log "Item (#{thisItem.text}) is selected"
3775
- returnArray << thisItem.text
3776
- end
3777
- end
3778
- return returnArray
3779
- end
3780
-
3781
- # Does the SelectList include the specified option (text)?
3782
- def includes? text
3783
- getAllContents.include? text
3784
- end
3785
-
3786
- # Is the specified option (text) selected? Raises exception of option does not exist.
3787
- def selected? text
3788
- unless includes? text
3789
- raise UnknownObjectException, "Option #{text} not found."
3790
- end
3791
- getSelectedItems.include? text
3792
- end
3793
-
3794
- def option(attribute, value)
3795
- assert_exists
3796
- Option.new(self, attribute, value)
3797
- end
3798
- end
3799
-
3800
- module OptionAccess
3801
- def text
3802
- @option.text
3803
- end
3804
- def value
3805
- @option.value
3806
- end
3807
- def selected
3808
- @option.selected
3809
- end
3810
- end
3811
-
3812
- class OptionWrapper
3813
- include OptionAccess
3814
- def initialize(option)
3815
- @option = option
3816
- end
3817
- end
3818
-
3819
- # An item in a select list
3820
- class Option
3821
- include OptionAccess
3822
- include Watir::Exception
3823
- def initialize(select_list, attribute, value)
3824
- @select_list = select_list
3825
- @how = attribute
3826
- @what = value
3827
- @option = nil
3828
-
3829
- unless [:text, :value].include? attribute
3830
- raise MissingWayOfFindingObjectException,
3831
- "Option does not support attribute #{@how}"
3832
- end
3833
- @select_list.o.each do |option| # items in the list
3834
- if value.matches(option.invoke(attribute.to_s))
3835
- @option = option
3836
- break
3837
- end
3838
- end
3839
-
3840
- end
3841
- def assert_exists
3842
- unless @option
3843
- raise UnknownObjectException,
3844
- "Unable to locate an option using #{@how} and #{@what}"
3845
- end
3846
- end
3847
- private :assert_exists
3848
- def select
3849
- assert_exists
3850
- @select_list.select_item_in_select_list(@how, @what)
3851
- end
3852
- end
3853
-
3854
- # This is the main class for accessing buttons.
3855
- # Normally a user would not need to create this object as it is
3856
- # returned by the Watir::Container#button method
3857
- class Button < InputElement
3858
- INPUT_TYPES = ["button", "submit", "image", "reset"]
3859
- end
3860
-
3861
- # This class is the main class for Text Fields
3862
- # Normally a user would not need to create this object as it is returned by the Watir::Container#text_field method
3863
- class TextField < InputElement
3864
- INPUT_TYPES = ["text", "password", "textarea"]
3865
-
3866
- def_wrap_guard :size
3867
- def_wrap_guard :maxlength
3868
-
3869
- # Returns true or false if the text field is read only.
3870
- # Raises UnknownObjectException if the object can't be found.
3871
- def_wrap :readonly?, :readOnly
3872
-
3873
- def text_string_creator
3874
- n = []
3875
- n << "length:".ljust(TO_S_SIZE) + self.size.to_s
3876
- n << "max length:".ljust(TO_S_SIZE) + self.maxlength.to_s
3877
- n << "read only:".ljust(TO_S_SIZE) + self.readonly?.to_s
3878
-
3879
- return n
3880
- end
3881
- private :text_string_creator
3882
-
3883
- def to_s
3884
- assert_exists
3885
- r = string_creator
3886
- r += text_string_creator
3887
- return r.join("\n")
3888
- end
3889
-
3890
- def assert_not_readonly
3891
- raise ObjectReadOnlyException, "Textfield #{@how} and #{@what} is read only." if self.readonly?
3892
- end
3893
-
3894
- # This method returns true or false if the text field contents is either a string match
3895
- # or a regular expression match to the supplied value.
3896
- # Raises UnknownObjectException if the object can't be found
3897
- # * containsThis - string or reg exp - the text to verify
3898
- def verify_contains(containsThis) # FIXME: verify_contains should have same name and semantics as IE#contains_text (prolly make this work for all elements)
3899
- assert_exists
3900
- if containsThis.kind_of? String
3901
- return true if self.value == containsThis
3902
- elsif containsThis.kind_of? Regexp
3903
- return true if self.value.match(containsThis) != nil
3904
- end
3905
- return false
3906
- end
3907
-
3908
- # this method is used to drag the entire contents of the text field to another text field
3909
- # 19 Jan 2005 - It is added as prototype functionality, and may change
3910
- # * destination_how - symbol, :id, :name how we identify the drop target
3911
- # * destination_what - string or regular expression, the name, id, etc of the text field that will be the drop target
3912
- def dragContentsTo(destination_how, destination_what)
3913
- assert_exists
3914
- destination = @container.text_field(destination_how, destination_what)
3915
- raise UnknownObjectException, "Unable to locate destination using #{destination_how } and #{destination_what } " if destination.exists? == false
3916
-
3917
- @o.focus
3918
- @o.select
3919
- value = self.value
3920
-
3921
- @o.fireEvent("onSelect")
3922
- @o.fireEvent("ondragstart")
3923
- @o.fireEvent("ondrag")
3924
- destination.fireEvent("onDragEnter")
3925
- destination.fireEvent("onDragOver")
3926
- destination.fireEvent("ondrop")
3927
-
3928
- @o.fireEvent("ondragend")
3929
- destination.value = destination.value + value.to_s
3930
- self.value = ""
3931
- end
3932
-
3933
- # This method clears the contents of the text box.
3934
- # Raises UnknownObjectException if the object can't be found
3935
- # Raises ObjectDisabledException if the object is disabled
3936
- # Raises ObjectReadOnlyException if the object is read only
3937
- def clear
3938
- assert_enabled
3939
- assert_not_readonly
3940
-
3941
- highlight(:set)
3942
-
3943
- @o.scrollIntoView
3944
- @o.focus
3945
- @o.select
3946
- @o.fireEvent("onSelect")
3947
- @o.value = ""
3948
- @o.fireEvent("onKeyPress")
3949
- @o.fireEvent("onChange")
3950
- @container.wait
3951
- highlight(:clear)
3952
- end
3953
-
3954
- # This method appens the supplied text to the contents of the text box.
3955
- # Raises UnknownObjectException if the object cant be found
3956
- # Raises ObjectDisabledException if the object is disabled
3957
- # Raises ObjectReadOnlyException if the object is read only
3958
- # * setThis - string - the text to append
3959
- def append(setThis)
3960
- assert_enabled
3961
- assert_not_readonly
3962
-
3963
- highlight(:set)
3964
- @o.scrollIntoView
3965
- @o.focus
3966
- doKeyPress(setThis)
3967
- highlight(:clear)
3968
- end
3969
-
3970
- # This method sets the contents of the text box to the supplied text
3971
- # Raises UnknownObjectException if the object cant be found
3972
- # Raises ObjectDisabledException if the object is disabled
3973
- # Raises ObjectReadOnlyException if the object is read only
3974
- # * setThis - string - the text to set
3975
- def set(setThis)
3976
- assert_enabled
3977
- assert_not_readonly
3978
-
3979
- highlight(:set)
3980
- @o.scrollIntoView
3981
- @o.focus
3982
- @o.select
3983
- @o.fireEvent("onSelect")
3984
- @o.value = ""
3985
- @o.fireEvent("onKeyPress")
3986
- doKeyPress(setThis)
3987
- highlight(:clear)
3988
- @o.fireEvent("onChange")
3989
- @o.fireEvent("onBlur")
3990
- end
3991
-
3992
- # 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
3993
- # it is preffered to use the set method.
3994
- def value=(v)
3995
- assert_exists
3996
- @o.value = v.to_s
3997
- end
3998
-
3999
- # This method is used internally by setText and appendText
4000
- # It should not be used externally.
4001
- # * value - string - The string to enter into the text field
4002
- def doKeyPress(value)
4003
- begin
4004
- maxLength = @o.maxLength
4005
- if value.length > maxLength
4006
- original_value = value
4007
- value = original_value[0 .. maxLength-1 ]
4008
- @container.log " Supplied string is #{original_value.length} chars, which exceeds the max length (#{maxLength}) of the field. Using value: #{value}"
4009
- end
4010
- rescue WIN32OLERuntimeError => e
4011
- # probably a text area - so it doesnt have a max Length
4012
- raise e unless /unknown property or method .*?maxLength/.match( e.message )
4013
- maxLength = -1
4014
- end
4015
- for i in 0 .. value.length-1
4016
- sleep @container.typingspeed
4017
- c = value[i,1]
4018
- #@container.log " adding c.chr " + c
4019
- @o.value = @o.value.to_s + c
4020
- @o.fireEvent("onKeyDown")
4021
- @o.fireEvent("onKeyPress")
4022
- @o.fireEvent("onKeyUp")
4023
- end
4024
-
4025
- end
4026
- private :doKeyPress
4027
- end
4028
-
4029
- # this class can be used to access hidden field objects
4030
- # Normally a user would not need to create this object as it is returned by the Watir::Container#hidden method
4031
- class Hidden < TextField
4032
- INPUT_TYPES = ["hidden"]
4033
-
4034
- # set is overriden in this class, as there is no way to set focus to a hidden field
4035
- def set(n)
4036
- self.value = n
4037
- end
4038
-
4039
- # override the append method, so that focus isnt set to the hidden object
4040
- def append(n)
4041
- self.value = self.value.to_s + n.to_s
4042
- end
4043
-
4044
- # override the clear method, so that focus isnt set to the hidden object
4045
- def clear
4046
- self.value = ""
4047
- end
4048
-
4049
- # this method will do nothing, as you cant set focus to a hidden field
4050
- def focus
4051
- end
4052
-
4053
- end
4054
-
4055
- # This class is the class for fields that accept file uploads
4056
- # Windows dialog is opened and handled in this case by autoit
4057
- # launching into a new process.
4058
- class FileField < InputElement
4059
- INPUT_TYPES = ["file"]
4060
-
4061
- # set the file location in the Choose file dialog in a new process
4062
- # will raise a Watir Exception if AutoIt is not correctly installed
4063
- def set(setPath)
4064
- assert_exists
4065
- require 'watir/windowhelper'
4066
- WindowHelper.check_autoit_installed
4067
- begin
4068
- thrd = Thread.new do
4069
- system("rubyw -e \"require 'win32ole'; @autoit=WIN32OLE.new('AutoItX3.Control'); waitresult=@autoit.WinWait 'Choose file', '', 15; if waitresult == 1\" -e \"@autoit.ControlSetText 'Choose file', '', 'Edit1', '#{setPath}'; @autoit.ControlSend 'Choose file', '', 'Button2', '{ENTER}';\" -e \"end\"")
4070
- end
4071
- thrd.join(1)
4072
- rescue
4073
- raise Watir::Exception::WatirException, "Problem accessing Choose file dialog"
4074
- end
4075
- click
4076
- end
4077
- end
4078
-
4079
- # This class is the class for radio buttons and check boxes.
4080
- # It contains methods common to both.
4081
- # Normally a user would not need to create this object as it is returned by the Watir::Container#checkbox or Watir::Container#radio methods
4082
- #
4083
- # most of the methods available to this element are inherited from the Element class
4084
- #
4085
- class RadioCheckCommon < Element
4086
- def locate
4087
- if @how == :xpath
4088
- @o = @container.element_by_xpath(@what)
4089
- else
4090
- @o = @container.locate_input_element(@how, @what, @type, @value)
4091
- end
4092
- end
4093
- def initialize(container, how, what, type, value=nil)
4094
- set_container container
4095
- @how = how
4096
- @what = what
4097
- @type = type
4098
- @value = value
4099
- super(nil)
4100
- end
4101
-
4102
- # BUG: rename me
4103
- # This method determines if a radio button or check box is set.
4104
- # Returns true is set/checked or false if not set/checked.
4105
- # Raises UnknownObjectException if its unable to locate an object.
4106
- def isSet?
4107
- assert_exists
4108
- return @o.checked
4109
- end
4110
- alias getState isSet?
4111
- alias checked? isSet?
4112
-
4113
- # This method clears a radio button or check box. Note, with radio buttons one of them will almost always be set.
4114
- # Returns true if set or false if not set.
4115
- # Raises UnknownObjectException if its unable to locate an object
4116
- # ObjectDisabledException IF THE OBJECT IS DISABLED
4117
- def clear
4118
- assert_enabled
4119
- highlight(:set)
4120
- set_clear_item(false)
4121
- highlight(:clear)
4122
- end
4123
-
4124
- # This method sets the radio list item or check box.
4125
- # Raises UnknownObjectException if it's unable to locate an object
4126
- # ObjectDisabledException if the object is disabled
4127
- def set
4128
- assert_enabled
4129
- highlight(:set)
4130
- set_clear_item(true)
4131
- highlight(:clear)
4132
- end
4133
-
4134
- # This method is the common code for setting or clearing checkboxes and radio.
4135
- def set_clear_item(set)
4136
- @o.checked = set
4137
- @o.fireEvent("onClick")
4138
- @container.wait
4139
- end
4140
- private :set_clear_item
4141
-
4142
- end
4143
-
4144
- #--
4145
- # this class makes the docs better
4146
- #++
4147
- # This class is the watir representation of a radio button.
4148
- class Radio < RadioCheckCommon
4149
- end
4150
-
4151
- # This class is the watir representation of a check box.
4152
- class CheckBox < RadioCheckCommon
4153
-
4154
- # With no arguments supplied, sets the check box.
4155
- # If the optional value is supplied, the checkbox is set, when its true and
4156
- # cleared when its false
4157
- # Raises UnknownObjectException if it's unable to locate an object
4158
- # ObjectDisabledException if the object is disabled
4159
- def set(value=true)
4160
- assert_enabled
4161
- highlight :set
4162
- unless @o.checked == value
4163
- set_clear_item value
4164
- end
4165
- highlight :clear
4166
- end
4167
-
4168
- # Clears a check box.
4169
- # Raises UnknownObjectException if its unable to locate an object
4170
- # ObjectDisabledException if the object is disabled
4171
- def clear
4172
- set false
4173
- end
4174
-
4175
- end
4176
-
4177
- #--
4178
- # These classes are not for public consumption, so we switch off rdoc
4179
-
4180
-
4181
- # presumes element_class or element_tag is defined
4182
- # for subclasses of ElementCollections
4183
- module CommonCollection
4184
- def element_tag
4185
- element_class::TAG
4186
- end
4187
- def length
4188
- @container.document.getElementsByTagName(element_tag).length
4189
- end
4190
- end
4191
-
4192
- # This class is used as part of the .show method of the iterators class
4193
- # it would not normally be used by a user
4194
- class AttributeLengthPairs
4195
-
4196
- # This class is used as part of the .show method of the iterators class
4197
- # it would not normally be used by a user
4198
- class AttributeLengthHolder
4199
- attr_accessor :attribute
4200
- attr_accessor :length
4201
-
4202
- def initialize(attrib, length)
4203
- @attribute = attrib
4204
- @length = length
4205
- end
4206
- end
4207
-
4208
- def initialize(attrib=nil, length=nil)
4209
- @attr=[]
4210
- add(attrib, length) if attrib
4211
- @index_counter = 0
4212
- end
4213
-
4214
- # BUG: Untested. (Null implementation passes all tests.)
4215
- def add(attrib, length)
4216
- @attr << AttributeLengthHolder.new(attrib, length)
4217
- end
4218
-
4219
- def delete(attrib)
4220
- item_to_delete = nil
4221
- @attr.each_with_index do |e,i|
4222
- item_to_delete = i if e.attribute == attrib
4223
- end
4224
- @attr.delete_at(item_to_delete) unless item_to_delete == nil
4225
- end
4226
-
4227
- def next
4228
- temp = @attr[@index_counter]
4229
- @index_counter += 1
4230
- return temp
4231
- end
4232
-
4233
- def each
4234
- 0.upto(@attr.length-1) { |i | yield @attr[i] }
4235
- end
4236
- end
4237
-
4238
- # resume rdoc
4239
- #++
4240
-
4241
- # this class accesses the buttons in the document as a collection
4242
- # it would normally only be accessed by the Watir::Container#buttons method
4243
- class Buttons < ElementCollections
4244
- def element_class; Button; end
4245
- def length
4246
- get_length_of_input_objects(["button", "submit", "image"])
4247
- end
4248
-
4249
- private
4250
- def set_show_items
4251
- super
4252
- @show_attributes.add("disabled", 9)
4253
- @show_attributes.add("value", 20)
4254
- end
4255
- end
4256
-
4257
- # this class accesses the file fields in the document as a collection
4258
- # normal access is via the Container#file_fields method
4259
- class FileFields < ElementCollections
4260
- def element_class; FileField; end
4261
- def length
4262
- get_length_of_input_objects(["file"])
4263
- end
4264
-
4265
- private
4266
- def set_show_items
4267
- super
4268
- @show_attributes.add("disabled", 9)
4269
- @show_attributes.add("value", 20)
4270
- end
4271
- end
4272
-
4273
- # this class accesses the check boxes in the document as a collection
4274
- # Normally a user would not need to create this object as it is returned by the Watir::Container#checkboxes method
4275
- class CheckBoxes < ElementCollections
4276
- def element_class; CheckBox; end
4277
- def length
4278
- get_length_of_input_objects("checkbox")
4279
- end
4280
-
4281
- private
4282
- def iterator_object(i)
4283
- @container.checkbox(:index, i + 1)
4284
- end
4285
- end
4286
-
4287
- # this class accesses the radio buttons in the document as a collection
4288
- # Normally a user would not need to create this object as it is returned by the Watir::Container#radios method
4289
- class Radios < ElementCollections
4290
- def element_class; Radio; end
4291
- def length
4292
- get_length_of_input_objects("radio")
4293
- end
4294
-
4295
- private
4296
- def iterator_object(i)
4297
- @container.radio(:index, i + 1)
4298
- end
4299
- end
4300
-
4301
- # this class accesses the select boxes in the document as a collection
4302
- # Normally a user would not need to create this object as it is returned by the Watir::Container#select_lists method
4303
- class SelectLists < ElementCollections
4304
- include CommonCollection
4305
- def element_class; SelectList; end
4306
- def element_tag; 'SELECT'; end
4307
- end
4308
-
4309
- # this class accesses the links in the document as a collection
4310
- # Normally a user would not need to create this object as it is returned by the Watir::Container#links method
4311
- class Links < ElementCollections
4312
- include CommonCollection
4313
- def element_class; Link; end
4314
- def element_tag; 'A'; end
4315
-
4316
- private
4317
- def set_show_items
4318
- super
4319
- @show_attributes.add("href", 60)
4320
- @show_attributes.add("innerText", 60)
4321
- end
4322
- end
4323
-
4324
- class Lis < ElementCollections
4325
- include Watir::CommonCollection
4326
- def element_class; Li; end
4327
-
4328
- def set_show_items
4329
- super
4330
- @show_attributes.delete( "name")
4331
- @show_attributes.add( "className" , 20)
4332
- end
4333
- end
4334
-
4335
- class Map < NonControlElement
4336
- TAG = 'MAP'
4337
- end
4338
-
4339
- class Area < NonControlElement
4340
- TAG = 'AREA'
4341
- end
4342
-
4343
- # this class accesses the maps in the document as a collection
4344
- # Normally a user would not need to create this object as it is returned by the Watir::Container#maps method
4345
- class Maps < ElementCollections
4346
- include CommonCollection
4347
- def element_class; Map; end
4348
- def element_tag; 'MAP'; end
4349
- end
4350
-
4351
-
4352
- # this class accesses the areas in the document as a collection
4353
- # Normally a user would not need to create this object as it is returned by the Watir::Container#areas method
4354
- class Areas < ElementCollections
4355
- include CommonCollection
4356
- def element_class; Area; end
4357
- def element_tag; 'AREA'; end
4358
- end
4359
-
4360
- # this class accesses the imnages in the document as a collection
4361
- # Normally a user would not need to create this object as it is returned by the Watir::Container#images method
4362
- class Images < ElementCollections
4363
- def element_class; Image; end
4364
- def length
4365
- @container.document.images.length
4366
- end
4367
-
4368
- private
4369
- def set_show_items
4370
- super
4371
- @show_attributes.add("src", 60)
4372
- @show_attributes.add("alt", 30)
4373
- end
4374
- end
4375
-
4376
- # this class accesses the text fields in the document as a collection
4377
- # Normally a user would not need to create this object as it is returned by the Watir::Container#text_fields method
4378
- class TextFields < ElementCollections
4379
- def element_class; TextField; end
4380
- def length
4381
- # text areas are also included in the TextFields, but we need to get them seperately
4382
- get_length_of_input_objects(["text", "password"]) +
4383
- @container.document.getElementsByTagName("textarea").length
4384
- end
4385
- end
4386
-
4387
- # this class accesses the hidden fields in the document as a collection
4388
- # Normally a user would not need to create this object as it is returned by the Watir::Container#hiddens method
4389
- class Hiddens < ElementCollections
4390
- def element_class; Hidden; end
4391
- def length
4392
- get_length_of_input_objects("hidden")
4393
- end
4394
- end
4395
-
4396
- # this class accesses the text fields in the document as a collection
4397
- # Normally a user would not need to create this object as it is returned by the Watir::Container#tables method
4398
- class Tables < ElementCollections
4399
- include CommonCollection
4400
- def element_class; Table; end
4401
- def element_tag; 'TABLE'; end
4402
-
4403
- private
4404
- def set_show_items
4405
- super
4406
- @show_attributes.delete("name")
4407
- end
4408
- end
4409
- # this class accesses the table rows in the document as a collection
4410
- # Normally a user would not need to create this object as it is returned by the Watir::Container#rows method
4411
- class TableRows < ElementCollections
4412
- include CommonCollection
4413
- def element_class; TableRow; end
4414
- def element_tag; 'TR'; end
4415
- end
4416
- # this class accesses the table cells in the document as a collection
4417
- # Normally a user would not need to create this object as it is returned by the Watir::Container#cells method
4418
- class TableCells < ElementCollections
4419
- include CommonCollection
4420
- def element_class; TableCell; end
4421
- def element_tag; 'TD'; end
4422
- end
4423
- # this class accesses the labels in the document as a collection
4424
- # Normally a user would not need to create this object as it is returned by the Watir::Container#labels method
4425
- class Labels < ElementCollections
4426
- include CommonCollection
4427
- def element_class; Label; end
4428
- def element_tag; 'LABEL'; end
4429
-
4430
- private
4431
- def set_show_items
4432
- super
4433
- @show_attributes.add("htmlFor", 20)
4434
- end
4435
- end
4436
-
4437
- # this class accesses the pre tags in the document as a collection
4438
- # Normally a user would not need to create this object as it is returned by the Watir::Container#pres method
4439
- class Pres < ElementCollections
4440
- include CommonCollection
4441
- def element_class; Pre; end
4442
-
4443
- private
4444
- def set_show_items
4445
- super
4446
- @show_attributes.delete("name")
4447
- @show_attributes.add("className", 20)
4448
- end
4449
- end
4450
-
4451
- # this class accesses the p tags in the document as a collection
4452
- # Normally a user would not need to create this object as it is returned by the Watir::Container#ps method
4453
- class Ps < ElementCollections
4454
- include CommonCollection
4455
- def element_class; P; end
4456
-
4457
- private
4458
- def set_show_items
4459
- super
4460
- @show_attributes.delete("name")
4461
- @show_attributes.add("className", 20)
4462
- end
4463
-
4464
- end
4465
- # this class accesses the spans in the document as a collection
4466
- # Normally a user would not need to create this object as it is returned by the Watir::Container#spans method
4467
- class Spans < ElementCollections
4468
- include CommonCollection
4469
- def element_class; Span; end
4470
-
4471
- private
4472
- def set_show_items
4473
- super
4474
- @show_attributes.delete("name")
4475
- @show_attributes.add("className", 20)
4476
- end
4477
- end
4478
-
4479
- # this class accesses the divs in the document as a collection
4480
- # Normally a user would not need to create this object as it is returned by the Watir::Container#divs method
4481
- class Divs < ElementCollections
4482
- include CommonCollection
4483
- def element_class; Div; end
4484
-
4485
- private
4486
- def set_show_items
4487
- super
4488
- @show_attributes.delete("name")
4489
- @show_attributes.add("className", 20)
4490
- end
4491
- end
4492
-
4493
127
  # Move to Watir::Utils
4494
128
 
4495
129
  @@autoit = nil
@@ -4520,4 +154,4 @@ def _code_that_copies_readonly_array(array, name)
4520
154
  end
4521
155
 
4522
156
  require 'watir/camel_case'
4523
- require 'watir/elements'
157
+ require 'watir/bonus-elements'