watir 1.5.2 → 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/readme.rb 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'