watir 1.6.5 → 1.6.6.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (186) hide show
  1. data/CHANGES +461 -326
  2. data/VERSION +1 -0
  3. data/bin/watir-console +6 -6
  4. data/lib/changes.rb +3 -3
  5. data/lib/license.rb +38 -38
  6. data/lib/readme.rb +140 -140
  7. data/lib/watir/WindowHelper.rb +49 -49
  8. data/lib/watir/camel_case.rb +66 -66
  9. data/lib/watir/clickJSDialog.rb +19 -19
  10. data/lib/watir/close_all.rb +37 -37
  11. data/lib/watir/collections.rb +392 -344
  12. data/lib/watir/container.rb +857 -815
  13. data/lib/watir/contrib/enabled_popup.rb +20 -20
  14. data/lib/watir/contrib/ie-new-process.rb +27 -27
  15. data/lib/watir/contrib/page_checker.rb +29 -29
  16. data/lib/watir/cookiemanager.rb +55 -55
  17. data/lib/watir/core.rb +28 -0
  18. data/lib/watir/core_ext.rb +17 -17
  19. data/lib/watir/datahandler.rb +107 -107
  20. data/lib/watir/dialog.rb +46 -46
  21. data/lib/watir/element.rb +351 -343
  22. data/lib/watir/element_collections.rb +97 -97
  23. data/lib/watir/form.rb +170 -170
  24. data/lib/watir/frame.rb +59 -59
  25. data/lib/watir/html_element.rb +22 -0
  26. data/lib/watir/ie-class.rb +1006 -1009
  27. data/lib/watir/ie-process.rb +39 -39
  28. data/lib/watir/ie.rb +70 -133
  29. data/lib/watir/image.rb +130 -130
  30. data/lib/watir/input_elements.rb +614 -572
  31. data/lib/watir/irb-history.rb +30 -30
  32. data/lib/watir/link.rb +64 -64
  33. data/lib/watir/locator.rb +200 -176
  34. data/lib/watir/logger.rb +19 -19
  35. data/lib/watir/modal_dialog.rb +122 -122
  36. data/lib/watir/module.rb +37 -0
  37. data/lib/watir/non_control_elements.rb +145 -145
  38. data/lib/watir/page-container.rb +116 -107
  39. data/lib/watir/popup.rb +29 -29
  40. data/lib/watir/process.rb +19 -19
  41. data/lib/watir/screen_capture.rb +115 -115
  42. data/lib/watir/setFileDialog.rb +16 -16
  43. data/lib/watir/table.rb +395 -362
  44. data/lib/watir/watir_simple.rb +475 -475
  45. data/lib/watir/win32.rb +35 -35
  46. data/lib/watir/win32ole.rb +14 -14
  47. data/lib/watir/winClicker.rb +496 -496
  48. data/rakefile.rb +70 -0
  49. data/unittests/all_tests.rb +10 -10
  50. data/unittests/buttons_xpath_test.rb +69 -69
  51. data/unittests/checkbox_test.rb +179 -179
  52. data/unittests/checkbox_xpath_test.rb +107 -107
  53. data/unittests/click_no_wait_test.rb +21 -0
  54. data/unittests/core_tests.rb +17 -17
  55. data/unittests/css_test.rb +42 -35
  56. data/unittests/defer_test.rb +46 -46
  57. data/unittests/dialog_test.rb +77 -77
  58. data/unittests/div2_xpath_test.rb +21 -21
  59. data/unittests/div_test.rb +188 -188
  60. data/unittests/div_xpath_test.rb +96 -96
  61. data/unittests/element_test.rb +49 -0
  62. data/unittests/errorchecker_test.rb +32 -22
  63. data/unittests/filefield_test.rb +39 -39
  64. data/unittests/filefield_xpath_test.rb +33 -33
  65. data/unittests/form_test.rb +280 -280
  66. data/unittests/form_xpath_test.rb +252 -252
  67. data/unittests/frame_test.rb +155 -155
  68. data/unittests/google_form_test.rb +15 -15
  69. data/unittests/html/JavascriptClick.html +39 -39
  70. data/unittests/html/blankpage.html +11 -11
  71. data/unittests/html/buttons1.html +40 -40
  72. data/unittests/html/checkboxes1.html +89 -89
  73. data/unittests/html/click_no_wait.html +14 -0
  74. data/unittests/html/complex_table.html +36 -36
  75. data/unittests/html/cssTest.html +42 -42
  76. data/unittests/html/depot_store.html +59 -59
  77. data/unittests/html/div.html +93 -93
  78. data/unittests/html/div_xml.html +20 -20
  79. data/unittests/html/fileupload.html +45 -45
  80. data/unittests/html/formTest1.html +38 -38
  81. data/unittests/html/forms2.html +44 -44
  82. data/unittests/html/forms3.html +131 -131
  83. data/unittests/html/forms4.html +27 -27
  84. data/unittests/html/frame_buttons.html +3 -3
  85. data/unittests/html/frame_links.html +3 -3
  86. data/unittests/html/frame_multi.html +4 -4
  87. data/unittests/html/google_india.html +119 -119
  88. data/unittests/html/iframeTest.html +12 -12
  89. data/unittests/html/iframeTest1.html +6 -6
  90. data/unittests/html/iframeTest2.html +5 -5
  91. data/unittests/html/images1.html +66 -66
  92. data/unittests/html/javascriptevents.html +35 -35
  93. data/unittests/html/link_pass.html +10 -10
  94. data/unittests/html/links1.html +38 -38
  95. data/unittests/html/links2.html +10 -10
  96. data/unittests/html/links_multi.html +14 -14
  97. data/unittests/html/list_matters.html +720 -720
  98. data/unittests/html/lists.html +17 -17
  99. data/unittests/html/map_test.html +31 -31
  100. data/unittests/html/modal_dialog.html +10 -10
  101. data/unittests/html/modal_dialog_launcher.html +11 -11
  102. data/unittests/html/nestedFrames.html +6 -6
  103. data/unittests/html/new_browser.html +16 -16
  104. data/unittests/html/pass.html +12 -12
  105. data/unittests/html/popups1.html +59 -59
  106. data/unittests/html/pre.html +27 -27
  107. data/unittests/html/radioButtons1.html +71 -71
  108. data/unittests/html/select_tealeaf.html +54 -54
  109. data/unittests/html/selectboxes1.html +52 -52
  110. data/unittests/html/simple_table.html +26 -26
  111. data/unittests/html/simple_table_buttons.html +104 -104
  112. data/unittests/html/simple_table_columns.html +76 -76
  113. data/unittests/html/table1.html +181 -181
  114. data/unittests/html/tableCell_using_xpath.html +19 -19
  115. data/unittests/html/table_and_tablerow_to_a.html +174 -0
  116. data/unittests/html/textarea.html +30 -30
  117. data/unittests/html/textfields1.html +88 -88
  118. data/unittests/html/textsearch.html +44 -44
  119. data/unittests/html/wallofcheckboxes.html +1003 -1003
  120. data/unittests/html/xpath_nbsp.html +12 -12
  121. data/unittests/ie_exists_test.rb +33 -33
  122. data/unittests/ie_mock.rb +94 -94
  123. data/unittests/ie_test.rb +51 -51
  124. data/unittests/images_test.rb +157 -157
  125. data/unittests/images_xpath_test.rb +91 -91
  126. data/unittests/links_multi_test.rb +48 -48
  127. data/unittests/links_test.rb +175 -175
  128. data/unittests/links_xpath_test.rb +39 -39
  129. data/unittests/lists_test.rb +32 -32
  130. data/unittests/map_test.rb +98 -98
  131. data/unittests/minmax_test.rb +31 -31
  132. data/unittests/navigate_test.rb +39 -39
  133. data/unittests/nbsp_xpath_test.rb +16 -16
  134. data/unittests/non_core_tests.rb +12 -12
  135. data/unittests/other/WindowLogonExample.rb +27 -27
  136. data/unittests/other/WindowLogonExtra.rb +6 -6
  137. data/unittests/other/all_tests_concurrent.rb +57 -57
  138. data/unittests/other/jscriptExtraAlert.rb +6 -6
  139. data/unittests/other/jscriptExtraConfirmCancel.rb +6 -6
  140. data/unittests/other/jscriptExtraConfirmOk.rb +6 -6
  141. data/unittests/other/jscriptPushButton.rb +6 -6
  142. data/unittests/other/jscript_test.rb +63 -63
  143. data/unittests/other/navigate_exception_test.rb +24 -24
  144. data/unittests/other/rexml_unit_test.rb +27 -27
  145. data/unittests/other/screen_capture_test.rb +54 -54
  146. data/unittests/other/testcase_method_order_test.rb +35 -35
  147. data/unittests/other/testcase_verify_test.rb +24 -24
  148. data/unittests/other/wait_until_test.rb +99 -99
  149. data/unittests/pagecontainstext_test.rb +69 -69
  150. data/unittests/parent_child_test.rb +43 -43
  151. data/unittests/perf_test.rb +20 -20
  152. data/unittests/popups_test.rb +43 -43
  153. data/unittests/pre_test.rb +53 -53
  154. data/unittests/radios_test.rb +212 -212
  155. data/unittests/radios_xpath_test.rb +101 -101
  156. data/unittests/security_setting_test.rb +23 -23
  157. data/unittests/selectbox_test.rb +148 -148
  158. data/unittests/selectbox_xpath_test.rb +113 -113
  159. data/unittests/setup.rb +87 -77
  160. data/unittests/speed_settings_test.rb +67 -67
  161. data/unittests/table_and_tablerow_to_a_test.rb +117 -0
  162. data/unittests/table_cell_using_xpath_test.rb +35 -35
  163. data/unittests/table_test.rb +376 -376
  164. data/unittests/table_xpath_test.rb +110 -110
  165. data/unittests/test_tests.rb +9 -9
  166. data/unittests/textarea_test.rb +92 -92
  167. data/unittests/textarea_xpath_test.rb +78 -78
  168. data/unittests/textfield_for_ch_char_test.rb +31 -31
  169. data/unittests/textfields_test.rb +218 -218
  170. data/unittests/textfields_xpath_test.rb +111 -111
  171. data/unittests/window_tests.rb +10 -10
  172. data/unittests/windows/attach_to_existing_window_test.rb +53 -53
  173. data/unittests/windows/attach_to_new_window_test.rb +83 -83
  174. data/unittests/windows/close_window_test.rb +20 -20
  175. data/unittests/windows/frame_links_test.rb +25 -25
  176. data/unittests/windows/ie-each_test.rb +47 -47
  177. data/unittests/windows/iedialog_test.rb +54 -54
  178. data/unittests/windows/js_events_test.rb +42 -55
  179. data/unittests/windows/modal_dialog_test.rb +128 -128
  180. data/unittests/windows/new_test.rb +57 -57
  181. data/unittests/windows/open_close_test.rb +18 -18
  182. data/unittests/windows/send_keys_test.rb +33 -33
  183. data/unittests/xpath_tests.rb +10 -10
  184. metadata +85 -31
  185. data/lib/watir/utils.rb +0 -20
  186. data/lib/watir/version.rb +0 -5
@@ -1,60 +1,60 @@
1
- module Watir
2
- class Frame
3
- include Container
4
- include PageContainer
5
-
6
- # Find the frame denoted by how and what in the container and return its ole_object
7
- def locate
8
- how = @how
9
- what = @what
10
- frames = @container.document.frames
11
- target = nil
12
-
13
- for i in 0..(frames.length - 1)
14
- this_frame = frames.item(i)
15
- case how
16
- when :index
17
- index = i + 1
18
- return this_frame if index == what
19
- when :name
20
- begin
21
- return this_frame if what.matches(this_frame.name)
22
- rescue # access denied?
23
- end
24
- when :id
25
- # We assume that pages contain frames or iframes, but not both.
26
- this_frame_tag = @container.document.getElementsByTagName("FRAME").item(i)
27
- return this_frame if this_frame_tag and what.matches(this_frame_tag.invoke("id"))
28
- this_iframe_tag = @container.document.getElementsByTagName("IFRAME").item(i)
29
- return this_frame if this_iframe_tag and what.matches(this_iframe_tag.invoke("id"))
30
- when :src
31
- this_frame_tag = @container.document.getElementsByTagName("FRAME").item(i)
32
- return this_frame if this_frame_tag and what.matches(this_frame_tag.src)
33
- this_iframe_tag = @container.document.getElementsByTagName("IFRAME").item(i)
34
- return this_frame if this_iframe_tag and what.matches(this_iframe_tag.src)
35
- else
36
- raise ArgumentError, "Argument #{how} not supported"
37
- end
38
- end
39
-
40
- raise UnknownFrameException, "Unable to locate a frame with #{how.to_s} #{what}"
41
- end
42
-
43
- def initialize(container, how, what)
44
- set_container container
45
- @how = how
46
- @what = what
47
- @o = locate
48
- copy_test_config container
49
- end
50
-
51
- def document
52
- @o.document
53
- end
54
-
55
- def attach_command
56
- @container.page_container.attach_command + ".frame(#{@how.inspect}, #{@what.inspect})"
57
- end
58
-
59
- end
1
+ module Watir
2
+ class Frame
3
+ include Container
4
+ include PageContainer
5
+
6
+ # Find the frame denoted by how and what in the container and return its ole_object
7
+ def locate
8
+ how = @how
9
+ what = @what
10
+ frames = @container.document.frames
11
+ target = nil
12
+
13
+ for i in 0..(frames.length - 1)
14
+ this_frame = frames.item(i)
15
+ case how
16
+ when :index
17
+ index = i + 1
18
+ return this_frame if index == what
19
+ when :name
20
+ begin
21
+ return this_frame if what.matches(this_frame.name)
22
+ rescue # access denied?
23
+ end
24
+ when :id
25
+ # We assume that pages contain frames or iframes, but not both.
26
+ this_frame_tag = @container.document.getElementsByTagName("FRAME").item(i)
27
+ return this_frame if this_frame_tag and what.matches(this_frame_tag.invoke("id"))
28
+ this_iframe_tag = @container.document.getElementsByTagName("IFRAME").item(i)
29
+ return this_frame if this_iframe_tag and what.matches(this_iframe_tag.invoke("id"))
30
+ when :src
31
+ this_frame_tag = @container.document.getElementsByTagName("FRAME").item(i)
32
+ return this_frame if this_frame_tag and what.matches(this_frame_tag.src)
33
+ this_iframe_tag = @container.document.getElementsByTagName("IFRAME").item(i)
34
+ return this_frame if this_iframe_tag and what.matches(this_iframe_tag.src)
35
+ else
36
+ raise ArgumentError, "Argument #{how} not supported"
37
+ end
38
+ end
39
+
40
+ raise UnknownFrameException, "Unable to locate a frame with #{how.to_s} #{what}"
41
+ end
42
+
43
+ def initialize(container, how, what)
44
+ set_container container
45
+ @how = how
46
+ @what = what
47
+ @o = locate
48
+ copy_test_config container
49
+ end
50
+
51
+ def document
52
+ @o.document
53
+ end
54
+
55
+ def attach_command
56
+ @container.page_container.attach_command + ".frame(#{@how.inspect}, #{@what.inspect})"
57
+ end
58
+
59
+ end
60
60
  end
@@ -0,0 +1,22 @@
1
+ # This is a generic HTML Element that is used to
2
+ # locate all elements that share an attribute. The
3
+ # most common example would be finding elements that
4
+ # all share the same class.
5
+ module Watir
6
+ class HTMLElement < Element
7
+ def initialize(container, how, what)
8
+ set_container container
9
+ @how = how
10
+ @what = what
11
+ if how == :index
12
+ raise MissingWayOfFindingObjectException,
13
+ "#{self.class} does not support attribute #{@how}"
14
+ end
15
+ super nil
16
+ end
17
+
18
+ def locate
19
+ @o = @container.locate_tagged_element('*', @how, @what)
20
+ end
21
+ end
22
+ end
@@ -1,1009 +1,1006 @@
1
- module Watir
2
- class IE
3
- include Watir::Exception
4
- include Container
5
- include PageContainer
6
-
7
- # Maximum number of seconds to wait when attaching to a window
8
- @@attach_timeout = 2.0 # default value
9
- def self.attach_timeout
10
- @@attach_timeout
11
- end
12
- def self.attach_timeout=(timeout)
13
- @@attach_timeout = timeout
14
- end
15
-
16
- # Return the options used when creating new instances of IE.
17
- # BUG: this interface invites misunderstanding/misuse such as IE.options[:speed] = :zippy]
18
- def self.options
19
- {:speed => self.speed, :visible => self.visible, :attach_timeout => self.attach_timeout}
20
- end
21
- # set values for options used when creating new instances of IE.
22
- def self.set_options options
23
- options.each do |name, value|
24
- send "#{name}=", value
25
- end
26
- end
27
- # The globals $FAST_SPEED and $HIDE_IE are checked both at initialization
28
- # and later, because they
29
- # might be set after initialization. Setting them beforehand (e.g. from
30
- # the command line) will affect the class, otherwise it is only a temporary
31
- # effect
32
- @@speed = $FAST_SPEED ? :fast : :slow
33
- def self.speed
34
- return :fast if $FAST_SPEED
35
- @@speed
36
- end
37
- def self.speed= x
38
- $FAST_SPEED = nil
39
- @@speed = x
40
- end
41
- @@visible = $HIDE_IE ? false : true
42
- def self.visible
43
- return false if $HIDE_IE
44
- @@visible
45
- end
46
- def self.visible= x
47
- $HIDE_IE = nil
48
- @@visible = x
49
- end
50
-
51
- # Used internally to determine when IE has finished loading a page
52
- READYSTATE_COMPLETE = 4
53
-
54
- # The default color for highlighting objects as they are accessed.
55
- HIGHLIGHT_COLOR = 'yellow'
56
-
57
- # IE inserts some element whose tagName is empty and just acts as block level element
58
- # Probably some IE method of cleaning things
59
- # To pass the same to the xml parser we need to give some name to empty tagName
60
- EMPTY_TAG_NAME = "DUMMY"
61
-
62
- # The time, in seconds, it took for the new page to load after executing the
63
- # the last command
64
- attr_reader :down_load_time
65
-
66
- # the OLE Internet Explorer object
67
- attr_accessor :ie
68
-
69
- # access to the logger object
70
- attr_accessor :logger
71
-
72
- # this contains the list of unique urls that have been visited
73
- attr_reader :url_list
74
-
75
- # Create a new IE window. Works just like IE.new in Watir 1.4.
76
- def self.new_window
77
- ie = new true
78
- ie._new_window_init
79
- ie
80
- end
81
-
82
- # Create an IE browser.
83
- def initialize suppress_new_window=nil
84
- _new_window_init unless suppress_new_window
85
- end
86
-
87
- def _new_window_init
88
- create_browser_window
89
- initialize_options
90
- goto 'about:blank' # this avoids numerous problems caused by lack of a document
91
- end
92
-
93
- # Create a new IE Window, starting at the specified url.
94
- # If no url is given, start empty.
95
- def self.start url=nil
96
- start_window url
97
- end
98
-
99
- # Create a new IE window, starting at the specified url.
100
- # If no url is given, start empty. Works like IE.start in Watir 1.4.
101
- def self.start_window url=nil
102
- ie = new_window
103
- ie.goto url if url
104
- ie
105
- end
106
-
107
- # Create a new IE window in a new process.
108
- # This method will not work when
109
- # Watir/Ruby is run under a service (instead of a user).
110
- def self.new_process
111
- ie = new true
112
- ie._new_process_init
113
- ie
114
- end
115
-
116
- def _new_process_init
117
- iep = Process.start
118
- @ie = iep.window
119
- @process_id = iep.process_id
120
- initialize_options
121
- goto 'about:blank'
122
- end
123
-
124
- # Create a new IE window in a new process, starting at the specified URL.
125
- # Same as IE.start.
126
- def self.start_process url=nil
127
- ie = new_process
128
- ie.goto url if url
129
- ie
130
- end
131
-
132
- # Return a Watir::IE object for an existing IE window. Window can be
133
- # referenced by url, title, or window handle.
134
- # Second argument can be either a string or a regular expression in the
135
- # case of of :url or :title.
136
- # IE.attach(:url, 'http://www.google.com')
137
- # IE.attach(:title, 'Google')
138
- # IE.attach(:hwnd, 528140)
139
- # This method will not work when
140
- # Watir/Ruby is run under a service (instead of a user).
141
- def self.attach how, what
142
- ie = new true # don't create window
143
- ie._attach_init(how, what)
144
- ie
145
- end
146
-
147
- # this method is used internally to attach to an existing window
148
- def _attach_init how, what
149
- attach_browser_window how, what
150
- initialize_options
151
- wait
152
- end
153
-
154
- # Return an IE object that wraps the given window, typically obtained from
155
- # Shell.Application.windows.
156
- def self.bind window
157
- ie = new true
158
- ie.ie = window
159
- ie.initialize_options
160
- ie
161
- end
162
-
163
- def create_browser_window
164
- @ie = WIN32OLE.new('InternetExplorer.Application')
165
- end
166
- private :create_browser_window
167
-
168
- def initialize_options
169
- self.visible = IE.visible
170
- self.speed = IE.speed
171
-
172
- @ole_object = nil
173
- @page_container = self
174
- @error_checkers = []
175
- @activeObjectHighLightColor = HIGHLIGHT_COLOR
176
-
177
-
178
- @logger = DefaultLogger.new
179
- @url_list = []
180
- end
181
-
182
- # Specifies the speed that commands will be executed at. Choices are:
183
- # * :slow (default)
184
- # * :fast
185
- # * :zippy
186
- # With IE#speed= :zippy, text fields will be entered at once, instead of
187
- # character by character (default).
188
- def speed= how_fast
189
- case how_fast
190
- when :zippy then
191
- @typingspeed = 0
192
- @pause_after_wait = 0.01
193
- @type_keys = false
194
- @speed = :fast
195
- when :fast then
196
- @typingspeed = 0
197
- @pause_after_wait = 0.01
198
- @type_keys = true
199
- @speed = :fast
200
- when :slow then
201
- @typingspeed = 0.08
202
- @pause_after_wait = 0.1
203
- @type_keys = true
204
- @speed = :slow
205
- else
206
- raise ArgumentError, "Invalid speed: #{how_fast}"
207
- end
208
- end
209
-
210
- def speed
211
- return @speed if @speed == :slow
212
- return @type_keys ? :fast : :zippy
213
- end
214
-
215
- # deprecated: use speed = :fast instead
216
- def set_fast_speed
217
- self.speed = :fast
218
- end
219
-
220
- # deprecated: use speed = :slow instead
221
- def set_slow_speed
222
- self.speed = :slow
223
- end
224
-
225
- def visible
226
- @ie.visible
227
- end
228
- def visible=(boolean)
229
- @ie.visible = boolean if boolean != @ie.visible
230
- end
231
-
232
- # Yields successively to each IE window on the current desktop. Takes a block.
233
- # This method will not work when
234
- # Watir/Ruby is run under a service (instead of a user).
235
- # Yields to the window and its hwnd.
236
- def self.each
237
- shell = WIN32OLE.new('Shell.Application')
238
- shell.Windows.each do |window|
239
- next unless (window.path =~ /Internet Explorer/ rescue false)
240
- next unless (hwnd = window.hwnd rescue false)
241
- ie = IE.bind(window)
242
- ie.hwnd = hwnd
243
- yield ie
244
- end
245
- end
246
-
247
- # return internet explorer instance as specified. if none is found,
248
- # return nil.
249
- # arguments:
250
- # :url, url -- the URL of the IE browser window
251
- # :title, title -- the title of the browser page
252
- # :hwnd, hwnd -- the window handle of the browser window.
253
- # This method will not work when
254
- # Watir/Ruby is run under a service (instead of a user).
255
- def self.find(how, what)
256
- ie_ole = IE._find(how, what)
257
- IE.bind ie_ole if ie_ole
258
- end
259
-
260
- def self._find(how, what)
261
- ieTemp = nil
262
- IE.each do |ie|
263
- window = ie.ie
264
-
265
- case how
266
- when :url
267
- ieTemp = window if (what.matches(window.locationURL))
268
- when :title
269
- # normal windows explorer shells do not have document
270
- # note window.document will fail for "new" browsers
271
- begin
272
- title = window.locationname
273
- title = window.document.title
274
- rescue WIN32OLERuntimeError
275
- end
276
- ieTemp = window if what.matches(title)
277
- when :hwnd
278
- begin
279
- ieTemp = window if what == window.HWND
280
- rescue WIN32OLERuntimeError
281
- end
282
- else
283
- raise ArgumentError
284
- end
285
- end
286
- return ieTemp
287
- end
288
-
289
- def attach_browser_window how, what
290
- log "Seeking Window with #{how}: #{what}"
291
- ieTemp = nil
292
- begin
293
- Watir::until_with_timeout do
294
- ieTemp = IE._find how, what
295
- end
296
- rescue TimeOutException
297
- raise NoMatchingWindowFoundException,
298
- "Unable to locate a window with #{how} of #{what}"
299
- end
300
- @ie = ieTemp
301
- end
302
- private :attach_browser_window
303
-
304
- # Return the current window handle
305
- def hwnd
306
- raise "Not attached to a browser" if @ie.nil?
307
- @hwnd ||= @ie.hwnd
308
- end
309
- attr_writer :hwnd
310
-
311
- include Watir::Win32
312
-
313
- # Are we attached to an open browser?
314
- def exists?
315
- return false if @closing
316
- begin
317
- @ie.name =~ /Internet Explorer/
318
- rescue WIN32OLERuntimeError
319
- false
320
- end
321
- end
322
- alias :exist? :exists?
323
-
324
- # deprecated: use logger= instead
325
- def set_logger(logger)
326
- @logger = logger
327
- end
328
-
329
- def log(what)
330
- @logger.debug(what) if @logger
331
- end
332
-
333
- #
334
- # Accessing data outside the document
335
- #
336
-
337
- # Return the title of the document
338
- def title
339
- @ie.document.title
340
- end
341
-
342
- # Return the status of the window, typically from the status bar at the bottom.
343
- def status
344
- return @ie.statusText
345
- end
346
-
347
- #
348
- # Navigation
349
- #
350
-
351
- # Navigate to the specified URL.
352
- # * url - string - the URL to navigate to
353
- def goto(url)
354
- @ie.navigate(url)
355
- wait
356
- return @down_load_time
357
- end
358
-
359
- # Go to the previous page - the same as clicking the browsers back button
360
- # an WIN32OLERuntimeError exception is raised if the browser cant go back
361
- def back
362
- @ie.GoBack
363
- wait
364
- end
365
-
366
- # Go to the next page - the same as clicking the browsers forward button
367
- # an WIN32OLERuntimeError exception is raised if the browser cant go forward
368
- def forward
369
- @ie.GoForward
370
- wait
371
- end
372
-
373
- # Refresh the current page - the same as clicking the browsers refresh button
374
- # an WIN32OLERuntimeError exception is raised if the browser cant refresh
375
- def refresh
376
- @ie.refresh2(3)
377
- wait
378
- end
379
-
380
- def inspect
381
- '#<%s:0x%x url=%s title=%s>' % [self.class, hash*2, url.inspect, title.inspect]
382
- end
383
-
384
- # Execute the given JavaScript string
385
- def execute_script(source)
386
- document.parentWindow.eval(source.to_s)
387
- rescue WIN32OLERuntimeError
388
- document.parentWindow.execScript(source.to_s)
389
- end
390
-
391
- # clear the list of urls that we have visited
392
- def clear_url_list
393
- @url_list.clear
394
- end
395
-
396
- # Closes the Browser
397
- def close
398
- return unless exists?
399
- @closing = true
400
- @ie.stop
401
- wait
402
- chwnd = @ie.hwnd.to_i
403
- @ie.quit
404
- while Win32API.new("user32","IsWindow", 'L', 'L').Call(chwnd) == 1
405
- sleep 0.3
406
- end
407
- end
408
-
409
- # Maximize the window (expands to fill the screen)
410
- def maximize
411
- set_window_state :SW_MAXIMIZE
412
- end
413
-
414
- # Minimize the window (appears as icon on taskbar)
415
- def minimize
416
- set_window_state :SW_MINIMIZE
417
- end
418
-
419
- # Restore the window (after minimizing or maximizing)
420
- def restore
421
- set_window_state :SW_RESTORE
422
- end
423
-
424
- # Make the window come to the front
425
- def bring_to_front
426
- autoit.WinActivate title, ''
427
- end
428
-
429
- def front?
430
- 1 == autoit.WinActive(title, '')
431
- end
432
-
433
- private
434
- def set_window_state(state)
435
- autoit.WinSetState title, '', autoit.send(state)
436
- end
437
- def autoit
438
- Watir::autoit
439
- end
440
- public
441
-
442
- # Send key events to IE window.
443
- # See http://www.autoitscript.com/autoit3/docs/appendix/SendKeys.htm
444
- # for complete documentation on keys supported and syntax.
445
- def send_keys(key_string)
446
- autoit.WinActivate title
447
- autoit.Send key_string
448
- end
449
-
450
- def dir
451
- return File.expand_path(File.dirname(__FILE__))
452
- end
453
-
454
- #
455
- # Document and Document Data
456
- #
457
-
458
- # Return the current document
459
- def document
460
- return @ie.document
461
- end
462
-
463
- # returns the current url, as displayed in the address bar of the browser
464
- def url
465
- return @ie.LocationURL
466
- end
467
-
468
- #
469
- # Synchronization
470
- #
471
- include Watir::Utils
472
-
473
- # Block execution until the page has loaded.
474
- # =nodoc
475
- # Note: This code needs to be prepared for the ie object to be closed at
476
- # any moment!
477
- def wait(no_sleep=false)
478
- @xml_parser_doc = nil
479
- @down_load_time = 0.0
480
- a_moment = 0.2 # seconds
481
- start_load_time = Time.now
482
-
483
- begin
484
- while @ie.busy # XXX need to add time out
485
- sleep a_moment
486
- end
487
- until @ie.readyState == READYSTATE_COMPLETE do
488
- sleep a_moment
489
- end
490
- sleep a_moment
491
- until @ie.document do
492
- sleep a_moment
493
- end
494
-
495
- documents_to_wait_for = [@ie.document]
496
-
497
- rescue WIN32OLERuntimeError # IE window must have been closed
498
- @down_load_time = Time.now - start_load_time
499
- sleep @pause_after_wait unless no_sleep
500
- return @down_load_time
501
- end
502
-
503
- while doc = documents_to_wait_for.shift
504
- begin
505
- until doc.readyState == "complete" do
506
- sleep a_moment
507
- end
508
- @url_list << doc.location.href unless @url_list.include?(doc.location.href)
509
- doc.frames.length.times do |n|
510
- begin
511
- documents_to_wait_for << doc.frames[n.to_s].document
512
- rescue WIN32OLERuntimeError, NoMethodError
513
- end
514
- end
515
- rescue WIN32OLERuntimeError
516
- end
517
- end
518
-
519
- @down_load_time = Time.now - start_load_time
520
- run_error_checks
521
- sleep @pause_after_wait unless no_sleep
522
- @down_load_time
523
- end
524
-
525
- # Error checkers
526
-
527
- # this method runs the predefined error checks
528
- def run_error_checks
529
- @error_checkers.each { |e| e.call(self) }
530
- end
531
-
532
- # this method is used to add an error checker that gets executed on every page load
533
- # * checker Proc Object, that contains the code to be run
534
- def add_checker(checker)
535
- @error_checkers << checker
536
- end
537
-
538
- # this allows a checker to be disabled
539
- # * checker Proc Object, the checker that is to be disabled
540
- def disable_checker(checker)
541
- @error_checkers.delete(checker)
542
- end
543
-
544
- #
545
- # Show me state
546
- #
547
-
548
- # Show all forms displays all the forms that are on a web page.
549
- def show_forms
550
- if allForms = document.forms
551
- count = allForms.length
552
- puts "There are #{count} forms"
553
- for i in 0..count-1 do
554
- wrapped = FormWrapper.new(allForms.item(i))
555
- puts "Form name: #{wrapped.name}"
556
- puts " id: #{wrapped.id}"
557
- puts " method: #{wrapped.method}"
558
- puts " action: #{wrapped.action}"
559
- end
560
- else
561
- puts "No forms"
562
- end
563
- end
564
-
565
- # this method shows all the images availble in the document
566
- def show_images
567
- doc = document
568
- index = 1
569
- doc.images.each do |l|
570
- puts "image: name: #{l.name}"
571
- puts " id: #{l.invoke("id")}"
572
- puts " src: #{l.src}"
573
- puts " index: #{index}"
574
- index += 1
575
- end
576
- end
577
-
578
- # this method shows all the links availble in the document
579
- def show_links
580
- props = ["name", "id", "href"]
581
- print_sizes = [12, 12, 60]
582
- doc = document
583
- index = 0
584
- text_size = 60
585
- # draw the table header
586
- s = "index".ljust(6)
587
- props.each_with_index do |p, i|
588
- s += p.ljust(print_sizes[i])
589
- end
590
- s += "text/src".ljust(text_size)
591
- s += "\n"
592
-
593
- # now get the details of the links
594
- doc.links.each do |n|
595
- index += 1
596
- s = s + index.to_s.ljust(6)
597
- props.each_with_index do |prop, i|
598
- printsize = print_sizes[i]
599
- begin
600
- p = n.invoke(prop)
601
- temp_var = "#{p}".to_s.ljust(printsize)
602
- rescue
603
- # this object probably doesnt have this property
604
- temp_var = "".to_s.ljust(printsize)
605
- end
606
- s += temp_var
607
- end
608
- s += n.innerText
609
- if n.getElementsByTagName("IMG").length > 0
610
- s += " / " + n.getElementsByTagName("IMG").item(0).src
611
- end
612
- s += "\n"
613
- end
614
- puts s
615
- end
616
-
617
- # this method shows the name, id etc of the object that is currently active - ie the element that has focus
618
- # its mostly used in irb when creating a script
619
- def show_active
620
- s = ""
621
-
622
- current = document.activeElement
623
- begin
624
- s += current.invoke("type").to_s.ljust(16)
625
- rescue
626
- end
627
- props = ["name", "id", "value", "alt", "src", "innerText", "href"]
628
- props.each do |prop|
629
- begin
630
- p = current.invoke(prop)
631
- s += " " + "#{prop}=#{p}".to_s.ljust(18)
632
- rescue
633
- #this object probably doesnt have this property
634
- end
635
- end
636
- s += "\n"
637
- end
638
-
639
- # this method shows all the divs availble in the document
640
- def show_divs
641
- divs = document.getElementsByTagName("DIV")
642
- puts "Found #{divs.length} div tags"
643
- index = 1
644
- divs.each do |d|
645
- puts "#{index} id=#{d.invoke('id')} class=#{d.invoke("className")}"
646
- index += 1
647
- end
648
- end
649
-
650
- # this method is used to show all the tables that are available
651
- def show_tables
652
- tables = document.getElementsByTagName("TABLE")
653
- puts "Found #{tables.length} tables"
654
- index = 1
655
- tables.each do |d|
656
- puts "#{index} id=#{d.invoke('id')} rows=#{d.rows.length} columns=#{begin d.rows["0"].cells.length; rescue; end}"
657
- index += 1
658
- end
659
- end
660
-
661
- def show_pres
662
- pres = document.getElementsByTagName("PRE")
663
- puts "Found #{ pres.length } pre tags"
664
- index = 1
665
- pres.each do |d|
666
- puts "#{index} id=#{d.invoke('id')} class=#{d.invoke("className")}"
667
- index+=1
668
- end
669
- end
670
-
671
- # this method shows all the spans availble in the document
672
- def show_spans
673
- spans = document.getElementsByTagName("SPAN")
674
- puts "Found #{spans.length} span tags"
675
- index = 1
676
- spans.each do |d|
677
- puts "#{index} id=#{d.invoke('id')} class=#{d.invoke("className")}"
678
- index += 1
679
- end
680
- end
681
-
682
- def show_labels
683
- labels = document.getElementsByTagName("LABEL")
684
- puts "Found #{labels.length} label tags"
685
- index = 1
686
- labels.each do |d|
687
- puts "#{index} text=#{d.invoke('innerText')} class=#{d.invoke("className")} for=#{d.invoke("htmlFor")}"
688
- index += 1
689
- end
690
- end
691
-
692
- # Gives focus to the frame
693
- def focus
694
- document.activeElement.blur
695
- document.focus
696
- end
697
-
698
-
699
- # Functions written for using xpath for getting the elements.
700
- def xmlparser_document_object
701
- if @xml_parser_doc == nil
702
- create_xml_parser_doc
703
- end
704
- return @xml_parser_doc
705
- end
706
-
707
- # Create the Nokogiri object if it is nil. This method is private so can be called only
708
- # from xmlparser_document_object method.
709
- def create_xml_parser_doc
710
- require 'nokogiri'
711
- if @xml_parser_doc == nil
712
- htmlSource ="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<HTML>\n"
713
- htmlSource = html_source(document.body,htmlSource," ")
714
- htmlSource += "\n</HTML>\n"
715
- # Angrez: Resolving Jira issue WTR-114
716
- htmlSource = htmlSource.gsub(/&nbsp;/, '&#160;')
717
- begin
718
- #@xml_parser_doc = Nokogiri::HTML::Document.new(htmlSource)
719
- @xml_parser_doc = Nokogiri.parse(htmlSource)
720
- rescue => e
721
- output_xml_parser_doc("error.xml", htmlSource)
722
- raise e
723
- end
724
- end
725
- end
726
- private :create_xml_parser_doc
727
-
728
- def output_xml_parser_doc(name, text)
729
- file = File.open(name,"w")
730
- file.print(text)
731
- file.close
732
- end
733
- private :output_xml_parser_doc
734
-
735
- #Function Tokenizes the tag line and returns array of tokens.
736
- #Token could be either tagName or "=" or attribute name or attribute value
737
- #Attribute value could be either quoted string or single word
738
- def tokenize_tagline(outerHtml)
739
- outerHtml = outerHtml.gsub(/\n|\r/," ")
740
- #removing "< symbol", opening of current tag
741
- outerHtml =~ /^\s*<(.*)$/
742
- outerHtml = $1
743
- tokens = Array.new
744
- i = startOffset = 0
745
- length = outerHtml.length
746
- #puts outerHtml
747
- parsingValue = false
748
- while i < length do
749
- i +=1 while (i < length && outerHtml[i,1] =~ /\s/)
750
- next if i == length
751
- currentToken = outerHtml[i,1]
752
-
753
- #Either current tag has been closed or user has not closed the tag >
754
- # and we have received the opening of next element
755
- break if currentToken =~ /<|>/
756
-
757
- #parse quoted value
758
- if(currentToken == "\"" || currentToken == "'")
759
- parsingValue = false
760
- quote = currentToken
761
- startOffset = i
762
- i += 1
763
- i += 1 while (i < length && (outerHtml[i,1] != quote || outerHtml[i-1,1] == "\\"))
764
- if i == length
765
- tokens.push quote + outerHtml[startOffset..i-1]
766
- else
767
- tokens.push outerHtml[startOffset..i]
768
- end
769
- elsif currentToken == "="
770
- tokens.push "="
771
- parsingValue = true
772
- else
773
- startOffset = i
774
- i += 1 while (i < length && !(outerHtml[i,1] =~ /\s|=|<|>/)) if !parsingValue
775
- i += 1 while (i < length && !(outerHtml[i,1] =~ /\s|<|>/)) if parsingValue
776
- parsingValue = false
777
- i -= 1
778
- tokens.push outerHtml[startOffset..i]
779
- end
780
- i += 1
781
- end
782
- return tokens
783
- end
784
- private :tokenize_tagline
785
-
786
- # This function get and clean all the attributes of the tag.
787
- def all_tag_attributes(outerHtml)
788
- tokens = tokenize_tagline(outerHtml)
789
- #puts tokens
790
- tagLine = ""
791
- count = 1
792
- tokensLength = tokens.length
793
- expectedEqualityOP= false
794
- while count < tokensLength do
795
- if expectedEqualityOP == false
796
- #print Attribute Name
797
- # If attribute name is valid. Refer: http://www.w3.org/TR/REC-xml/#NT-Name
798
- if tokens[count] =~ /^(\w|_|:)(.*)$/
799
- tagLine += " #{tokens[count]}"
800
- expectedEqualityOP = true
801
- end
802
- elsif tokens[count] == "="
803
- count += 1
804
- if count == tokensLength
805
- tagLine += "=\"\""
806
- elsif(tokens[count][0,1] == "\"" || tokens[count][0,1] == "'")
807
- tagLine += "=#{tokens[count]}"
808
- else
809
- tagLine += "=\"#{tokens[count]}\""
810
- end
811
- expectedEqualityOP = false
812
- else
813
- #Opps! equality was expected but its not there.
814
- #Set value same as the attribute name e.g. selected="selected"
815
- tagLine += "=\"#{tokens[count-1]}\""
816
- expectedEqualityOP = false
817
- next
818
- end
819
- count += 1
820
- end
821
- tagLine += "=\"#{tokens[count-1]}\" " if expectedEqualityOP == true
822
- #puts tagLine
823
- return tagLine
824
- end
825
- private :all_tag_attributes
826
-
827
- # This function is used to escape the characters that are not valid XML data.
828
- def xml_escape(str)
829
- str = str.gsub(/&/,'&amp;')
830
- str = str.gsub(/</,'&lt;')
831
- str = str.gsub(/>/,'&gt;')
832
- str = str.gsub(/"/, '&quot;')
833
- str
834
- end
835
- private :xml_escape
836
-
837
- # Returns HTML Source
838
- # Traverse the DOM tree rooted at body element
839
- # and generate the HTML source.
840
- # element: Represent Current element
841
- # htmlString:HTML Source
842
- # spaces:(Used for debugging). Helps in indentation
843
- def html_source(element, htmlString, spaceString)
844
- begin
845
- tagLine = ""
846
- outerHtml = ""
847
- tagName = ""
848
- begin
849
- tagName = element.tagName.downcase
850
- tagName = EMPTY_TAG_NAME if tagName == ""
851
- # If tag is a mismatched tag.
852
- if !(tagName =~ /^(\w|_|:)(.*)$/)
853
- return htmlString
854
- end
855
- rescue
856
- #handling text nodes
857
- htmlString += xml_escape(element.toString)
858
- return htmlString
859
- end
860
- #puts tagName
861
- #Skip comment and script tag
862
- if tagName =~ /^!/ || tagName== "script" || tagName =="style"
863
- return htmlString
864
- end
865
- #tagLine += spaceString
866
- outerHtml = all_tag_attributes(element.outerHtml) if tagName != EMPTY_TAG_NAME
867
- tagLine += "<#{tagName} #{outerHtml}"
868
-
869
- canHaveChildren = element.canHaveChildren
870
- if canHaveChildren
871
- tagLine += ">"
872
- else
873
- tagLine += "/>" #self closing tag
874
- end
875
- #spaceString += spaceString
876
- htmlString += tagLine
877
- childElements = element.childnodes
878
- childElements.each do |child|
879
- htmlString = html_source(child,htmlString,spaceString)
880
- end
881
- if canHaveChildren
882
- #tagLine += spaceString
883
- tagLine ="</" + tagName + ">"
884
- htmlString += tagLine
885
- end
886
- return htmlString
887
- rescue => e
888
- puts e.to_s
889
- end
890
- return htmlString
891
- end
892
- private :html_source
893
-
894
- # return the first element that matches the xpath
895
- def element_by_xpath(xpath)
896
- temp = elements_by_xpath(xpath)
897
- temp = temp[0] if temp
898
- return temp
899
- end
900
-
901
- # execute xpath and return an array of elements
902
- def elements_by_xpath(xpath)
903
- doc = xmlparser_document_object
904
- modifiedXpath = ""
905
- selectedElements = Array.new
906
-
907
- # strip any trailing slash from the xpath expression (as used in watir unit tests)
908
- xpath.chop! unless (/\/$/ =~ xpath).nil?
909
-
910
- doc.search(xpath).each do |element|
911
- modifiedXpath = element.path
912
- temp = element_by_absolute_xpath(modifiedXpath) # temp = a DOM/COM element
913
- selectedElements << temp if temp != nil
914
- end
915
- #puts selectedElements.length
916
- if selectedElements.length == 0
917
- return nil
918
- else
919
- return selectedElements
920
- end
921
- end
922
-
923
- # Method that iterates over IE DOM object and get the elements for the given
924
- # xpath.
925
- def element_by_absolute_xpath(xpath)
926
- curElem = nil
927
-
928
- #puts "Hello; Given xpath is : #{xpath}"
929
- doc = document
930
- curElem = doc.getElementsByTagName("body").item(0)
931
- xpath =~ /^.*\/body\[?\d*\]?\/(.*)/
932
- xpath = $1
933
-
934
- if xpath == nil
935
- puts "Function Requires absolute XPath."
936
- return
937
- end
938
-
939
- arr = xpath.split(/\//)
940
- return nil if arr.length == 0
941
-
942
- lastTagName = arr[arr.length-1].to_s.upcase
943
-
944
- # lastTagName is like tagName[number] or just tagName. For the first case we need to
945
- # separate tagName and number.
946
- lastTagName =~ /(\w*)\[?\d*\]?/
947
- lastTagName = $1
948
- #puts lastTagName
949
-
950
- for element in arr do
951
- element =~ /(\w*)\[?(\d*)\]?/
952
- tagname = $1
953
- tagname = tagname.upcase
954
-
955
- if $2 != nil && $2 != ""
956
- index = $2
957
- index = "#{index}".to_i - 1
958
- else
959
- index = 0
960
- end
961
-
962
- #puts "#{element} #{tagname} #{index}"
963
- allElemns = curElem.childnodes
964
- if allElemns == nil || allElemns.length == 0
965
- puts "#{element} is null"
966
- next # Go to next element
967
- end
968
-
969
- #puts "Current element is : #{curElem.tagName}"
970
- allElemns.each do |child|
971
- gotIt = false
972
- begin
973
- curTag = child.tagName
974
- curTag = EMPTY_TAG_NAME if curTag == ""
975
- rescue
976
- next
977
- end
978
- #puts child.tagName
979
- if curTag == tagname
980
- index-=1
981
- if index < 0
982
- curElem = child
983
- break
984
- end
985
- end
986
- end
987
-
988
- #puts "Node selected at index #{index.to_s} : #{curElem.tagName}"
989
- end
990
- begin
991
- if curElem.tagName == lastTagName
992
- #puts curElem.tagName
993
- return curElem
994
- else
995
- return nil
996
- end
997
- rescue
998
- return nil
999
- end
1000
- end
1001
- private :element_by_absolute_xpath
1002
-
1003
- def attach_command
1004
- "Watir::IE.attach(:hwnd, #{hwnd})"
1005
- end
1006
-
1007
-
1008
- end # class IE
1009
- end
1
+ module Watir
2
+ class IE
3
+ include Watir::Exception
4
+ include Container
5
+ include PageContainer
6
+
7
+ # Maximum number of seconds to wait when attaching to a window
8
+ @@attach_timeout = 2.0 # default value
9
+ def self.attach_timeout
10
+ @@attach_timeout
11
+ end
12
+ def self.attach_timeout=(timeout)
13
+ @@attach_timeout = timeout
14
+ end
15
+
16
+ # Return the options used when creating new instances of IE.
17
+ # BUG: this interface invites misunderstanding/misuse such as IE.options[:speed] = :zippy]
18
+ def self.options
19
+ {:speed => self.speed, :visible => self.visible, :attach_timeout => self.attach_timeout}
20
+ end
21
+ # set values for options used when creating new instances of IE.
22
+ def self.set_options options
23
+ options.each do |name, value|
24
+ send "#{name}=", value
25
+ end
26
+ end
27
+ # The globals $FAST_SPEED and $HIDE_IE are checked both at initialization
28
+ # and later, because they
29
+ # might be set after initialization. Setting them beforehand (e.g. from
30
+ # the command line) will affect the class, otherwise it is only a temporary
31
+ # effect
32
+ @@speed = $FAST_SPEED ? :fast : :slow
33
+ def self.speed
34
+ return :fast if $FAST_SPEED
35
+ @@speed
36
+ end
37
+ def self.speed= x
38
+ $FAST_SPEED = nil
39
+ @@speed = x
40
+ end
41
+ @@visible = $HIDE_IE ? false : true
42
+ def self.visible
43
+ return false if $HIDE_IE
44
+ @@visible
45
+ end
46
+ def self.visible= x
47
+ $HIDE_IE = nil
48
+ @@visible = x
49
+ end
50
+
51
+ # Used internally to determine when IE has finished loading a page
52
+ READYSTATE_INTERACTIVE = 3
53
+ READYSTATE_COMPLETE = 4
54
+
55
+ # The default color for highlighting objects as they are accessed.
56
+ HIGHLIGHT_COLOR = 'yellow'
57
+
58
+ # IE inserts some element whose tagName is empty and just acts as block level element
59
+ # Probably some IE method of cleaning things
60
+ # To pass the same to the xml parser we need to give some name to empty tagName
61
+ EMPTY_TAG_NAME = "DUMMY"
62
+
63
+ # The time, in seconds, it took for the new page to load after executing the
64
+ # the last command
65
+ attr_reader :down_load_time
66
+
67
+ # the OLE Internet Explorer object
68
+ attr_accessor :ie
69
+
70
+ # access to the logger object
71
+ attr_accessor :logger
72
+
73
+ # this contains the list of unique urls that have been visited
74
+ attr_reader :url_list
75
+
76
+ # Create a new IE window. Works just like IE.new in Watir 1.4.
77
+ def self.new_window
78
+ ie = new true
79
+ ie._new_window_init
80
+ ie
81
+ end
82
+
83
+ # Create an IE browser.
84
+ def initialize suppress_new_window=nil
85
+ _new_window_init unless suppress_new_window
86
+ end
87
+
88
+ def _new_window_init
89
+ create_browser_window
90
+ initialize_options
91
+ goto 'about:blank' # this avoids numerous problems caused by lack of a document
92
+ end
93
+
94
+ # Create a new IE Window, starting at the specified url.
95
+ # If no url is given, start empty.
96
+ def self.start url=nil
97
+ start_window url
98
+ end
99
+
100
+ # Create a new IE window, starting at the specified url.
101
+ # If no url is given, start empty. Works like IE.start in Watir 1.4.
102
+ def self.start_window url=nil
103
+ ie = new_window
104
+ ie.goto url if url
105
+ ie
106
+ end
107
+
108
+ # Create a new IE window in a new process.
109
+ # This method will not work when
110
+ # Watir/Ruby is run under a service (instead of a user).
111
+ def self.new_process
112
+ ie = new true
113
+ ie._new_process_init
114
+ ie
115
+ end
116
+
117
+ def _new_process_init
118
+ iep = Process.start
119
+ @ie = iep.window
120
+ @process_id = iep.process_id
121
+ initialize_options
122
+ goto 'about:blank'
123
+ end
124
+
125
+ # Create a new IE window in a new process, starting at the specified URL.
126
+ # Same as IE.start.
127
+ def self.start_process url=nil
128
+ ie = new_process
129
+ ie.goto url if url
130
+ ie
131
+ end
132
+
133
+ # Return a Watir::IE object for an existing IE window. Window can be
134
+ # referenced by url, title, or window handle.
135
+ # Second argument can be either a string or a regular expression in the
136
+ # case of of :url or :title.
137
+ # IE.attach(:url, 'http://www.google.com')
138
+ # IE.attach(:title, 'Google')
139
+ # IE.attach(:hwnd, 528140)
140
+ # This method will not work when
141
+ # Watir/Ruby is run under a service (instead of a user).
142
+ def self.attach how, what
143
+ ie = new true # don't create window
144
+ ie._attach_init(how, what)
145
+ ie
146
+ end
147
+
148
+ # this method is used internally to attach to an existing window
149
+ def _attach_init how, what
150
+ attach_browser_window how, what
151
+ initialize_options
152
+ wait
153
+ end
154
+
155
+ # Return an IE object that wraps the given window, typically obtained from
156
+ # Shell.Application.windows.
157
+ def self.bind window
158
+ ie = new true
159
+ ie.ie = window
160
+ ie.initialize_options
161
+ ie
162
+ end
163
+
164
+ def create_browser_window
165
+ @ie = WIN32OLE.new('InternetExplorer.Application')
166
+ end
167
+ private :create_browser_window
168
+
169
+ def initialize_options
170
+ self.visible = IE.visible
171
+ self.speed = IE.speed
172
+
173
+ @ole_object = nil
174
+ @page_container = self
175
+ @error_checkers = []
176
+ @activeObjectHighLightColor = HIGHLIGHT_COLOR
177
+
178
+
179
+ @logger = DefaultLogger.new
180
+ @url_list = []
181
+ end
182
+
183
+ # Specifies the speed that commands will be executed at. Choices are:
184
+ # * :slow (default)
185
+ # * :fast
186
+ # * :zippy
187
+ # With IE#speed= :zippy, text fields will be entered at once, instead of
188
+ # character by character (default).
189
+ def speed= how_fast
190
+ case how_fast
191
+ when :zippy then
192
+ @typingspeed = 0
193
+ @pause_after_wait = 0.01
194
+ @type_keys = false
195
+ @speed = :fast
196
+ when :fast then
197
+ @typingspeed = 0
198
+ @pause_after_wait = 0.01
199
+ @type_keys = true
200
+ @speed = :fast
201
+ when :slow then
202
+ @typingspeed = 0.08
203
+ @pause_after_wait = 0.1
204
+ @type_keys = true
205
+ @speed = :slow
206
+ else
207
+ raise ArgumentError, "Invalid speed: #{how_fast}"
208
+ end
209
+ end
210
+
211
+ def speed
212
+ return @speed if @speed == :slow
213
+ return @type_keys ? :fast : :zippy
214
+ end
215
+
216
+ # deprecated: use speed = :fast instead
217
+ def set_fast_speed
218
+ self.speed = :fast
219
+ end
220
+
221
+ # deprecated: use speed = :slow instead
222
+ def set_slow_speed
223
+ self.speed = :slow
224
+ end
225
+
226
+ def visible
227
+ @ie.visible
228
+ end
229
+ def visible=(boolean)
230
+ @ie.visible = boolean if boolean != @ie.visible
231
+ end
232
+
233
+ # Yields successively to each IE window on the current desktop. Takes a block.
234
+ # This method will not work when
235
+ # Watir/Ruby is run under a service (instead of a user).
236
+ # Yields to the window and its hwnd.
237
+ def self.each
238
+ shell = WIN32OLE.new('Shell.Application')
239
+ shell.Windows.each do |window|
240
+ next unless (window.path =~ /Internet Explorer/ rescue false)
241
+ next unless (hwnd = window.hwnd rescue false)
242
+ ie = IE.bind(window)
243
+ ie.hwnd = hwnd
244
+ yield ie
245
+ end
246
+ end
247
+
248
+ # return internet explorer instance as specified. if none is found,
249
+ # return nil.
250
+ # arguments:
251
+ # :url, url -- the URL of the IE browser window
252
+ # :title, title -- the title of the browser page
253
+ # :hwnd, hwnd -- the window handle of the browser window.
254
+ # This method will not work when
255
+ # Watir/Ruby is run under a service (instead of a user).
256
+ def self.find(how, what)
257
+ ie_ole = IE._find(how, what)
258
+ IE.bind ie_ole if ie_ole
259
+ end
260
+
261
+ def self._find(how, what)
262
+ ieTemp = nil
263
+ IE.each do |ie|
264
+ window = ie.ie
265
+
266
+ case how
267
+ when :url
268
+ ieTemp = window if (what.matches(window.locationURL))
269
+ when :title
270
+ # normal windows explorer shells do not have document
271
+ # note window.document will fail for "new" browsers
272
+ begin
273
+ title = window.locationname
274
+ title = window.document.title
275
+ rescue WIN32OLERuntimeError
276
+ end
277
+ ieTemp = window if what.matches(title)
278
+ when :hwnd
279
+ begin
280
+ ieTemp = window if what == window.HWND
281
+ rescue WIN32OLERuntimeError
282
+ end
283
+ else
284
+ raise ArgumentError
285
+ end
286
+ end
287
+ return ieTemp
288
+ end
289
+
290
+ def attach_browser_window how, what
291
+ log "Seeking Window with #{how}: #{what}"
292
+ ieTemp = nil
293
+ begin
294
+ Watir::until_with_timeout do
295
+ ieTemp = IE._find how, what
296
+ end
297
+ rescue TimeOutException
298
+ raise NoMatchingWindowFoundException,
299
+ "Unable to locate a window with #{how} of #{what}"
300
+ end
301
+ @ie = ieTemp
302
+ end
303
+ private :attach_browser_window
304
+
305
+ # Return the current window handle
306
+ def hwnd
307
+ raise "Not attached to a browser" if @ie.nil?
308
+ @hwnd ||= @ie.hwnd
309
+ end
310
+ attr_writer :hwnd
311
+
312
+ # Are we attached to an open browser?
313
+ def exists?
314
+ return false if @closing
315
+ begin
316
+ @ie.name =~ /Internet Explorer/
317
+ rescue WIN32OLERuntimeError
318
+ false
319
+ end
320
+ end
321
+ alias :exist? :exists?
322
+
323
+ # deprecated: use logger= instead
324
+ def set_logger(logger)
325
+ @logger = logger
326
+ end
327
+
328
+ def log(what)
329
+ @logger.debug(what) if @logger
330
+ end
331
+
332
+ #
333
+ # Accessing data outside the document
334
+ #
335
+
336
+ # Return the title of the document
337
+ def title
338
+ @ie.document.title
339
+ end
340
+
341
+ # Return the status of the window, typically from the status bar at the bottom.
342
+ def status
343
+ return @ie.statusText
344
+ end
345
+
346
+ #
347
+ # Navigation
348
+ #
349
+
350
+ # Navigate to the specified URL.
351
+ # * url - string - the URL to navigate to
352
+ def goto(url)
353
+ @ie.navigate(url)
354
+ wait
355
+ return @down_load_time
356
+ end
357
+
358
+ # Go to the previous page - the same as clicking the browsers back button
359
+ # an WIN32OLERuntimeError exception is raised if the browser cant go back
360
+ def back
361
+ @ie.GoBack
362
+ wait
363
+ end
364
+
365
+ # Go to the next page - the same as clicking the browsers forward button
366
+ # an WIN32OLERuntimeError exception is raised if the browser cant go forward
367
+ def forward
368
+ @ie.GoForward
369
+ wait
370
+ end
371
+
372
+ # Refresh the current page - the same as clicking the browsers refresh button
373
+ # an WIN32OLERuntimeError exception is raised if the browser cant refresh
374
+ def refresh
375
+ @ie.refresh2(3)
376
+ wait
377
+ end
378
+
379
+ def inspect
380
+ '#<%s:0x%x url=%s title=%s>' % [self.class, hash*2, url.inspect, title.inspect]
381
+ end
382
+
383
+ # Execute the given JavaScript string
384
+ def execute_script(source)
385
+ document.parentWindow.eval(source.to_s)
386
+ rescue WIN32OLERuntimeError
387
+ document.parentWindow.execScript(source.to_s)
388
+ end
389
+
390
+ # clear the list of urls that we have visited
391
+ def clear_url_list
392
+ @url_list.clear
393
+ end
394
+
395
+ # Closes the Browser
396
+ def close
397
+ return unless exists?
398
+ @closing = true
399
+ @ie.stop
400
+ wait rescue nil
401
+ chwnd = @ie.hwnd.to_i
402
+ @ie.quit
403
+ while Win32API.new("user32","IsWindow", 'L', 'L').Call(chwnd) == 1
404
+ sleep 0.3
405
+ end
406
+ end
407
+
408
+ # Maximize the window (expands to fill the screen)
409
+ def maximize
410
+ set_window_state :SW_MAXIMIZE
411
+ end
412
+
413
+ # Minimize the window (appears as icon on taskbar)
414
+ def minimize
415
+ set_window_state :SW_MINIMIZE
416
+ end
417
+
418
+ # Restore the window (after minimizing or maximizing)
419
+ def restore
420
+ set_window_state :SW_RESTORE
421
+ end
422
+
423
+ # Make the window come to the front
424
+ def bring_to_front
425
+ autoit.WinActivate title, ''
426
+ end
427
+
428
+ def front?
429
+ 1 == autoit.WinActive(title, '')
430
+ end
431
+
432
+ private
433
+ def set_window_state(state)
434
+ autoit.WinSetState title, '', autoit.send(state)
435
+ end
436
+ def autoit
437
+ Watir::autoit
438
+ end
439
+ public
440
+
441
+ # Send key events to IE window.
442
+ # See http://www.autoitscript.com/autoit3/docs/appendix/SendKeys.htm
443
+ # for complete documentation on keys supported and syntax.
444
+ def send_keys(key_string)
445
+ autoit.WinActivate title
446
+ autoit.Send key_string
447
+ end
448
+
449
+ def dir
450
+ return File.expand_path(File.dirname(__FILE__))
451
+ end
452
+
453
+ #
454
+ # Document and Document Data
455
+ #
456
+
457
+ # Return the current document
458
+ def document
459
+ return @ie.document
460
+ end
461
+
462
+ # returns the current url, as displayed in the address bar of the browser
463
+ def url
464
+ return @ie.LocationURL
465
+ end
466
+
467
+ #
468
+ # Synchronization
469
+ #
470
+
471
+ # Block execution until the page has loaded.
472
+ #
473
+ # Will raise Timeout::Error if page hasn't been loaded within 5 minutes.
474
+ # =nodoc
475
+ # Note: This code needs to be prepared for the ie object to be closed at
476
+ # any moment!
477
+ def wait(no_sleep=false)
478
+ @xml_parser_doc = nil
479
+ @down_load_time = 0.0
480
+ interval = 0.05
481
+ start_load_time = Time.now
482
+
483
+ Timeout::timeout(5*60) do
484
+ begin
485
+ until [READYSTATE_INTERACTIVE, READYSTATE_COMPLETE].include?(@ie.readyState)
486
+ sleep interval
487
+ end
488
+
489
+ until @ie.document
490
+ sleep interval
491
+ end
492
+
493
+ documents_to_wait_for = [@ie.document]
494
+ rescue WIN32OLERuntimeError # IE window must have been closed
495
+ @down_load_time = Time.now - start_load_time
496
+ return @down_load_time
497
+ end
498
+
499
+ while doc = documents_to_wait_for.shift
500
+ begin
501
+ until ["interactive", "complete"].include?(doc.readyState)
502
+ sleep interval
503
+ end
504
+ @url_list << doc.location.href unless @url_list.include?(doc.location.href)
505
+ doc.frames.length.times do |n|
506
+ begin
507
+ documents_to_wait_for << doc.frames[n.to_s].document
508
+ rescue WIN32OLERuntimeError, NoMethodError
509
+ end
510
+ end
511
+ rescue WIN32OLERuntimeError
512
+ end
513
+ end
514
+ end
515
+
516
+ @down_load_time = Time.now - start_load_time
517
+ run_error_checks
518
+ sleep @pause_after_wait unless no_sleep
519
+ @down_load_time
520
+ end
521
+
522
+ # Error checkers
523
+
524
+ # this method runs the predefined error checks
525
+ def run_error_checks
526
+ @error_checkers.each { |e| e.call(self) }
527
+ end
528
+
529
+ # this method is used to add an error checker that gets executed on every page load
530
+ # * checker Proc Object, that contains the code to be run
531
+ def add_checker(checker)
532
+ @error_checkers << checker
533
+ end
534
+
535
+ # this allows a checker to be disabled
536
+ # * checker Proc Object, the checker that is to be disabled
537
+ def disable_checker(checker)
538
+ @error_checkers.delete(checker)
539
+ end
540
+
541
+ #
542
+ # Show me state
543
+ #
544
+
545
+ # Show all forms displays all the forms that are on a web page.
546
+ def show_forms
547
+ if allForms = document.forms
548
+ count = allForms.length
549
+ puts "There are #{count} forms"
550
+ for i in 0..count-1 do
551
+ wrapped = FormWrapper.new(allForms.item(i))
552
+ puts "Form name: #{wrapped.name}"
553
+ puts " id: #{wrapped.id}"
554
+ puts " method: #{wrapped.method}"
555
+ puts " action: #{wrapped.action}"
556
+ end
557
+ else
558
+ puts "No forms"
559
+ end
560
+ end
561
+
562
+ # this method shows all the images availble in the document
563
+ def show_images
564
+ doc = document
565
+ index = 1
566
+ doc.images.each do |l|
567
+ puts "image: name: #{l.name}"
568
+ puts " id: #{l.invoke("id")}"
569
+ puts " src: #{l.src}"
570
+ puts " index: #{index}"
571
+ index += 1
572
+ end
573
+ end
574
+
575
+ # this method shows all the links availble in the document
576
+ def show_links
577
+ props = ["name", "id", "href"]
578
+ print_sizes = [12, 12, 60]
579
+ doc = document
580
+ index = 0
581
+ text_size = 60
582
+ # draw the table header
583
+ s = "index".ljust(6)
584
+ props.each_with_index do |p, i|
585
+ s += p.ljust(print_sizes[i])
586
+ end
587
+ s += "text/src".ljust(text_size)
588
+ s += "\n"
589
+
590
+ # now get the details of the links
591
+ doc.links.each do |n|
592
+ index += 1
593
+ s = s + index.to_s.ljust(6)
594
+ props.each_with_index do |prop, i|
595
+ printsize = print_sizes[i]
596
+ begin
597
+ p = n.invoke(prop)
598
+ temp_var = "#{p}".to_s.ljust(printsize)
599
+ rescue
600
+ # this object probably doesnt have this property
601
+ temp_var = "".to_s.ljust(printsize)
602
+ end
603
+ s += temp_var
604
+ end
605
+ s += n.innerText
606
+ if n.getElementsByTagName("IMG").length > 0
607
+ s += " / " + n.getElementsByTagName("IMG").item(0).src
608
+ end
609
+ s += "\n"
610
+ end
611
+ puts s
612
+ end
613
+
614
+ # this method shows the name, id etc of the object that is currently active - ie the element that has focus
615
+ # its mostly used in irb when creating a script
616
+ def show_active
617
+ s = ""
618
+
619
+ current = document.activeElement
620
+ begin
621
+ s += current.invoke("type").to_s.ljust(16)
622
+ rescue
623
+ end
624
+ props = ["name", "id", "value", "alt", "src", "innerText", "href"]
625
+ props.each do |prop|
626
+ begin
627
+ p = current.invoke(prop)
628
+ s += " " + "#{prop}=#{p}".to_s.ljust(18)
629
+ rescue
630
+ #this object probably doesnt have this property
631
+ end
632
+ end
633
+ s += "\n"
634
+ end
635
+
636
+ # this method shows all the divs availble in the document
637
+ def show_divs
638
+ divs = document.getElementsByTagName("DIV")
639
+ puts "Found #{divs.length} div tags"
640
+ index = 1
641
+ divs.each do |d|
642
+ puts "#{index} id=#{d.invoke('id')} class=#{d.invoke("className")}"
643
+ index += 1
644
+ end
645
+ end
646
+
647
+ # this method is used to show all the tables that are available
648
+ def show_tables
649
+ tables = document.getElementsByTagName("TABLE")
650
+ puts "Found #{tables.length} tables"
651
+ index = 1
652
+ tables.each do |d|
653
+ puts "#{index} id=#{d.invoke('id')} rows=#{d.rows.length} columns=#{begin d.rows["0"].cells.length; rescue; end}"
654
+ index += 1
655
+ end
656
+ end
657
+
658
+ def show_pres
659
+ pres = document.getElementsByTagName("PRE")
660
+ puts "Found #{ pres.length } pre tags"
661
+ index = 1
662
+ pres.each do |d|
663
+ puts "#{index} id=#{d.invoke('id')} class=#{d.invoke("className")}"
664
+ index+=1
665
+ end
666
+ end
667
+
668
+ # this method shows all the spans availble in the document
669
+ def show_spans
670
+ spans = document.getElementsByTagName("SPAN")
671
+ puts "Found #{spans.length} span tags"
672
+ index = 1
673
+ spans.each do |d|
674
+ puts "#{index} id=#{d.invoke('id')} class=#{d.invoke("className")}"
675
+ index += 1
676
+ end
677
+ end
678
+
679
+ def show_labels
680
+ labels = document.getElementsByTagName("LABEL")
681
+ puts "Found #{labels.length} label tags"
682
+ index = 1
683
+ labels.each do |d|
684
+ puts "#{index} text=#{d.invoke('innerText')} class=#{d.invoke("className")} for=#{d.invoke("htmlFor")}"
685
+ index += 1
686
+ end
687
+ end
688
+
689
+ # Gives focus to the frame
690
+ def focus
691
+ document.activeElement.blur
692
+ document.focus
693
+ end
694
+
695
+
696
+ # Functions written for using xpath for getting the elements.
697
+ def xmlparser_document_object
698
+ if @xml_parser_doc == nil
699
+ create_xml_parser_doc
700
+ end
701
+ return @xml_parser_doc
702
+ end
703
+
704
+ # Create the Nokogiri object if it is nil. This method is private so can be called only
705
+ # from xmlparser_document_object method.
706
+ def create_xml_parser_doc
707
+ require 'nokogiri'
708
+ if @xml_parser_doc == nil
709
+ htmlSource ="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<HTML>\n"
710
+ htmlSource = html_source(document.body,htmlSource," ")
711
+ htmlSource += "\n</HTML>\n"
712
+ # Angrez: Resolving Jira issue WTR-114
713
+ htmlSource = htmlSource.gsub(/&nbsp;/, '&#160;')
714
+ begin
715
+ #@xml_parser_doc = Nokogiri::HTML::Document.new(htmlSource)
716
+ @xml_parser_doc = Nokogiri.parse(htmlSource)
717
+ rescue => e
718
+ output_xml_parser_doc("error.xml", htmlSource)
719
+ raise e
720
+ end
721
+ end
722
+ end
723
+ private :create_xml_parser_doc
724
+
725
+ def output_xml_parser_doc(name, text)
726
+ file = File.open(name,"w")
727
+ file.print(text)
728
+ file.close
729
+ end
730
+ private :output_xml_parser_doc
731
+
732
+ #Function Tokenizes the tag line and returns array of tokens.
733
+ #Token could be either tagName or "=" or attribute name or attribute value
734
+ #Attribute value could be either quoted string or single word
735
+ def tokenize_tagline(outerHtml)
736
+ outerHtml = outerHtml.gsub(/\n|\r/," ")
737
+ #removing "< symbol", opening of current tag
738
+ outerHtml =~ /^\s*<(.*)$/
739
+ outerHtml = $1
740
+ tokens = Array.new
741
+ i = startOffset = 0
742
+ length = outerHtml.length
743
+ #puts outerHtml
744
+ parsingValue = false
745
+ while i < length do
746
+ i +=1 while (i < length && outerHtml[i,1] =~ /\s/)
747
+ next if i == length
748
+ currentToken = outerHtml[i,1]
749
+
750
+ #Either current tag has been closed or user has not closed the tag >
751
+ # and we have received the opening of next element
752
+ break if currentToken =~ /<|>/
753
+
754
+ #parse quoted value
755
+ if(currentToken == "\"" || currentToken == "'")
756
+ parsingValue = false
757
+ quote = currentToken
758
+ startOffset = i
759
+ i += 1
760
+ i += 1 while (i < length && (outerHtml[i,1] != quote || outerHtml[i-1,1] == "\\"))
761
+ if i == length
762
+ tokens.push quote + outerHtml[startOffset..i-1]
763
+ else
764
+ tokens.push outerHtml[startOffset..i]
765
+ end
766
+ elsif currentToken == "="
767
+ tokens.push "="
768
+ parsingValue = true
769
+ else
770
+ startOffset = i
771
+ i += 1 while (i < length && !(outerHtml[i,1] =~ /\s|=|<|>/)) if !parsingValue
772
+ i += 1 while (i < length && !(outerHtml[i,1] =~ /\s|<|>/)) if parsingValue
773
+ parsingValue = false
774
+ i -= 1
775
+ tokens.push outerHtml[startOffset..i]
776
+ end
777
+ i += 1
778
+ end
779
+ return tokens
780
+ end
781
+ private :tokenize_tagline
782
+
783
+ # This function get and clean all the attributes of the tag.
784
+ def all_tag_attributes(outerHtml)
785
+ tokens = tokenize_tagline(outerHtml)
786
+ #puts tokens
787
+ tagLine = ""
788
+ count = 1
789
+ tokensLength = tokens.length
790
+ expectedEqualityOP= false
791
+ while count < tokensLength do
792
+ if expectedEqualityOP == false
793
+ #print Attribute Name
794
+ # If attribute name is valid. Refer: http://www.w3.org/TR/REC-xml/#NT-Name
795
+ if tokens[count] =~ /^(\w|_|:)(.*)$/
796
+ tagLine += " #{tokens[count]}"
797
+ expectedEqualityOP = true
798
+ end
799
+ elsif tokens[count] == "="
800
+ count += 1
801
+ if count == tokensLength
802
+ tagLine += "=\"\""
803
+ elsif(tokens[count][0,1] == "\"" || tokens[count][0,1] == "'")
804
+ tagLine += "=#{tokens[count]}"
805
+ else
806
+ tagLine += "=\"#{tokens[count]}\""
807
+ end
808
+ expectedEqualityOP = false
809
+ else
810
+ #Opps! equality was expected but its not there.
811
+ #Set value same as the attribute name e.g. selected="selected"
812
+ tagLine += "=\"#{tokens[count-1]}\""
813
+ expectedEqualityOP = false
814
+ next
815
+ end
816
+ count += 1
817
+ end
818
+ tagLine += "=\"#{tokens[count-1]}\" " if expectedEqualityOP == true
819
+ #puts tagLine
820
+ return tagLine
821
+ end
822
+ private :all_tag_attributes
823
+
824
+ # This function is used to escape the characters that are not valid XML data.
825
+ def xml_escape(str)
826
+ str = str.gsub(/&/,'&amp;')
827
+ str = str.gsub(/</,'&lt;')
828
+ str = str.gsub(/>/,'&gt;')
829
+ str = str.gsub(/"/, '&quot;')
830
+ str
831
+ end
832
+ private :xml_escape
833
+
834
+ # Returns HTML Source
835
+ # Traverse the DOM tree rooted at body element
836
+ # and generate the HTML source.
837
+ # element: Represent Current element
838
+ # htmlString:HTML Source
839
+ # spaces:(Used for debugging). Helps in indentation
840
+ def html_source(element, htmlString, spaceString)
841
+ begin
842
+ tagLine = ""
843
+ outerHtml = ""
844
+ tagName = ""
845
+ begin
846
+ tagName = element.tagName.downcase
847
+ tagName = EMPTY_TAG_NAME if tagName == ""
848
+ # If tag is a mismatched tag.
849
+ if !(tagName =~ /^(\w|_|:)(.*)$/)
850
+ return htmlString
851
+ end
852
+ rescue
853
+ #handling text nodes
854
+ htmlString += xml_escape(element.toString)
855
+ return htmlString
856
+ end
857
+ #puts tagName
858
+ #Skip comment and script tag
859
+ if tagName =~ /^!/ || tagName== "script" || tagName =="style"
860
+ return htmlString
861
+ end
862
+ #tagLine += spaceString
863
+ outerHtml = all_tag_attributes(element.outerHtml) if tagName != EMPTY_TAG_NAME
864
+ tagLine += "<#{tagName} #{outerHtml}"
865
+
866
+ canHaveChildren = element.canHaveChildren
867
+ if canHaveChildren
868
+ tagLine += ">"
869
+ else
870
+ tagLine += "/>" #self closing tag
871
+ end
872
+ #spaceString += spaceString
873
+ htmlString += tagLine
874
+ childElements = element.childnodes
875
+ childElements.each do |child|
876
+ htmlString = html_source(child,htmlString,spaceString)
877
+ end
878
+ if canHaveChildren
879
+ #tagLine += spaceString
880
+ tagLine ="</" + tagName + ">"
881
+ htmlString += tagLine
882
+ end
883
+ return htmlString
884
+ rescue => e
885
+ puts e.to_s
886
+ end
887
+ return htmlString
888
+ end
889
+ private :html_source
890
+
891
+ # return the first element that matches the xpath
892
+ def element_by_xpath(xpath)
893
+ temp = elements_by_xpath(xpath)
894
+ temp = temp[0] if temp
895
+ return temp
896
+ end
897
+
898
+ # execute xpath and return an array of elements
899
+ def elements_by_xpath(xpath)
900
+ doc = xmlparser_document_object
901
+ modifiedXpath = ""
902
+ selectedElements = Array.new
903
+
904
+ # strip any trailing slash from the xpath expression (as used in watir unit tests)
905
+ xpath.chop! unless (/\/$/ =~ xpath).nil?
906
+
907
+ doc.xpath(xpath).each do |element|
908
+ modifiedXpath = element.path
909
+ temp = element_by_absolute_xpath(modifiedXpath) # temp = a DOM/COM element
910
+ selectedElements << temp if temp != nil
911
+ end
912
+ #puts selectedElements.length
913
+ if selectedElements.length == 0
914
+ return nil
915
+ else
916
+ return selectedElements
917
+ end
918
+ end
919
+
920
+ # Method that iterates over IE DOM object and get the elements for the given
921
+ # xpath.
922
+ def element_by_absolute_xpath(xpath)
923
+ curElem = nil
924
+
925
+ #puts "Hello; Given xpath is : #{xpath}"
926
+ doc = document
927
+ curElem = doc.getElementsByTagName("body").item(0)
928
+ xpath =~ /^.*\/body\[?\d*\]?\/(.*)/
929
+ xpath = $1
930
+
931
+ if xpath == nil
932
+ puts "Function Requires absolute XPath."
933
+ return
934
+ end
935
+
936
+ arr = xpath.split(/\//)
937
+ return nil if arr.length == 0
938
+
939
+ lastTagName = arr[arr.length-1].to_s.upcase
940
+
941
+ # lastTagName is like tagName[number] or just tagName. For the first case we need to
942
+ # separate tagName and number.
943
+ lastTagName =~ /(\w*)\[?\d*\]?/
944
+ lastTagName = $1
945
+ #puts lastTagName
946
+
947
+ for element in arr do
948
+ element =~ /(\w*)\[?(\d*)\]?/
949
+ tagname = $1
950
+ tagname = tagname.upcase
951
+
952
+ if $2 != nil && $2 != ""
953
+ index = $2
954
+ index = "#{index}".to_i - 1
955
+ else
956
+ index = 0
957
+ end
958
+
959
+ #puts "#{element} #{tagname} #{index}"
960
+ allElemns = curElem.childnodes
961
+ if allElemns == nil || allElemns.length == 0
962
+ puts "#{element} is null"
963
+ next # Go to next element
964
+ end
965
+
966
+ #puts "Current element is : #{curElem.tagName}"
967
+ allElemns.each do |child|
968
+ gotIt = false
969
+ begin
970
+ curTag = child.tagName
971
+ curTag = EMPTY_TAG_NAME if curTag == ""
972
+ rescue
973
+ next
974
+ end
975
+ #puts child.tagName
976
+ if curTag == tagname
977
+ index-=1
978
+ if index < 0
979
+ curElem = child
980
+ break
981
+ end
982
+ end
983
+ end
984
+
985
+ #puts "Node selected at index #{index.to_s} : #{curElem.tagName}"
986
+ end
987
+ begin
988
+ if curElem.tagName == lastTagName
989
+ #puts curElem.tagName
990
+ return curElem
991
+ else
992
+ return nil
993
+ end
994
+ rescue
995
+ return nil
996
+ end
997
+ end
998
+ private :element_by_absolute_xpath
999
+
1000
+ def attach_command
1001
+ "Watir::IE.attach(:hwnd, #{hwnd})"
1002
+ end
1003
+
1004
+
1005
+ end # class IE
1006
+ end