watir-classic 3.7.0 → 4.0.0
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/CHANGES +6 -0
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/lib/watir-classic.rb +36 -3
- data/lib/watir-classic/browser.rb +613 -115
- data/lib/watir-classic/{ie-process.rb → browser_process.rb} +4 -4
- data/lib/watir-classic/cookies.rb +1 -1
- data/lib/watir-classic/element.rb +2 -2
- data/lib/watir-classic/frame.rb +1 -1
- data/lib/watir-classic/ie_deprecated.rb +5 -0
- data/lib/watir-classic/modal_dialog.rb +1 -1
- data/lib/watir-classic/process.rb +1 -1
- data/lib/watir-classic/screenshot.rb +1 -1
- data/lib/watir-classic/window.rb +3 -3
- data/lib/watir-classic/xpath_locator.rb +2 -2
- data/spec/implementation.rb +1 -1
- data/watir-classic.gemspec +1 -1
- metadata +19 -24
- data/Gemfile.lock +0 -79
- data/lib/watir-classic/browsers.rb +0 -7
- data/lib/watir-classic/core.rb +0 -40
- data/lib/watir-classic/ie-class.rb +0 -664
- data/lib/watir-classic/ie.rb +0 -5
- data/lib/watir-classic/options.rb +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b48648a4afcf9526da12f6baf012a4f0fec8411
|
4
|
+
data.tar.gz: 70def43f23d469fbb1de955b8112c6ce7d4e7a11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7980313c5a552ed151618b593bc1742d26c7918241a2fac62871fd8ef0b7f0ce593e5bd02d3953feeb0a68411155ea85bd4059fdefd94363e2dca8a4bbdc69dc
|
7
|
+
data.tar.gz: d89a17e83ebf2e1ae901e89808c1b6ceb9f4551089663a263a45e7a38da368af0ad0a4bcf027879ddf6eccb8e423b8e6bec8eddf72f8e25dd8c8861363e6eb09
|
data/CHANGES
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
== 4.0.0 - 2013/10/05
|
2
|
+
|
3
|
+
* Browser#add_checker also accepts block instead of a proc object.
|
4
|
+
* Browser#initialize suppresses window only when actual "true" value is given as an argument.
|
5
|
+
* Rename Watir::IE to Watir::Browser. Closes #47 and #53.
|
6
|
+
|
1
7
|
== 3.7.0 - 2013/05/10
|
2
8
|
|
3
9
|
* Add #required? method for input elements.
|
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
4.0.0
|
data/lib/watir-classic.rb
CHANGED
@@ -1,8 +1,41 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'multi_json'
|
3
|
+
require 'rautomation'
|
4
|
+
|
1
5
|
require 'watir-classic/version'
|
2
|
-
require 'watir-classic/
|
3
|
-
require 'watir-classic/wait_helper'
|
4
|
-
require 'watir-classic/element_extensions'
|
6
|
+
require 'watir-classic/win32ole'
|
5
7
|
require 'watir-classic/util'
|
6
8
|
require 'watir-classic/exceptions'
|
7
9
|
require 'watir-classic/matches'
|
10
|
+
require 'watir-classic/wait'
|
11
|
+
require 'watir-classic/wait_helper'
|
12
|
+
require 'watir-classic/element_extensions'
|
13
|
+
require 'watir-classic/container'
|
14
|
+
require 'watir-classic/xpath_locator'
|
15
|
+
require 'watir-classic/locator'
|
16
|
+
require 'watir-classic/page-container'
|
17
|
+
require 'watir-classic/browser_process'
|
18
|
+
require 'watir-classic/screenshot'
|
8
19
|
require 'watir-classic/browser'
|
20
|
+
require 'watir-classic/drag_and_drop_helper'
|
21
|
+
require 'watir-classic/element'
|
22
|
+
require 'watir-classic/element_collection'
|
23
|
+
require 'watir-classic/form'
|
24
|
+
require 'watir-classic/frame'
|
25
|
+
require 'watir-classic/input_elements'
|
26
|
+
require 'watir-classic/non_control_elements'
|
27
|
+
require 'watir-classic/table'
|
28
|
+
require 'watir-classic/image'
|
29
|
+
require 'watir-classic/link'
|
30
|
+
require 'watir-classic/window'
|
31
|
+
require 'watir-classic/cookies'
|
32
|
+
require 'watir-classic/win32'
|
33
|
+
require 'watir-classic/modal_dialog'
|
34
|
+
require 'watir-classic/module'
|
35
|
+
require 'watir-classic/dialogs/file_field'
|
36
|
+
require 'watir-classic/dialogs/alert'
|
37
|
+
require 'watir-classic/supported_elements'
|
38
|
+
|
39
|
+
module Watir
|
40
|
+
autoload :IE, File.expand_path("watir-classic/ie_deprecated", File.dirname(__FILE__))
|
41
|
+
end
|
@@ -1,60 +1,83 @@
|
|
1
|
-
require 'watir-classic/options'
|
2
1
|
module Watir
|
3
|
-
|
4
|
-
|
2
|
+
# Main browser class.
|
3
|
+
class Browser
|
4
|
+
include WaitHelper
|
5
|
+
include Exception
|
6
|
+
include Container
|
7
|
+
include PageContainer
|
5
8
|
|
6
|
-
|
7
|
-
|
9
|
+
class << self
|
10
|
+
# Maximum number of seconds to wait when attaching to a window
|
11
|
+
attr_writer :attach_timeout
|
8
12
|
|
9
|
-
|
10
|
-
|
11
|
-
|
13
|
+
def attach_timeout
|
14
|
+
@attach_timeout ||= 2
|
15
|
+
end
|
12
16
|
|
13
|
-
|
17
|
+
# Return the options used when creating new instances of {Browser}.
|
18
|
+
# BUG: this interface invites misunderstanding/misuse such as Browser.options[:speed] = :zippy]
|
19
|
+
def options
|
20
|
+
{:speed => self.speed, :visible => self.visible, :attach_timeout => self.attach_timeout}
|
21
|
+
end
|
14
22
|
|
15
|
-
|
23
|
+
# set values for options used when creating new instances of {Browser}.
|
24
|
+
def set_options options
|
25
|
+
options.each do |name, value|
|
26
|
+
send "#{name}=", value
|
27
|
+
end
|
28
|
+
end
|
16
29
|
|
17
|
-
|
30
|
+
# The speed in which browser will type keys etc. Possible values are
|
31
|
+
# :slow (default), :fast and :zippy.
|
32
|
+
attr_writer :speed
|
18
33
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
browser.text_field(:name => 'q').set 'pickaxe'
|
23
|
-
browser.button(:name => 'btnG').click
|
24
|
-
if browser.text.include? 'Programming Ruby'
|
25
|
-
puts 'Text was found'
|
26
|
-
else
|
27
|
-
puts 'Text was not found'
|
28
|
-
end
|
34
|
+
def speed
|
35
|
+
@speed ||= :slow
|
36
|
+
end
|
29
37
|
|
30
|
-
|
31
|
-
|
32
|
-
class Browser
|
33
|
-
# @private
|
34
|
-
@@browser_classes = {}
|
38
|
+
# Set browser window to visible or hidden. Defaults to true.
|
39
|
+
attr_writer :visible
|
35
40
|
|
36
|
-
|
37
|
-
|
41
|
+
def visible
|
42
|
+
@visible ||= true
|
43
|
+
end
|
38
44
|
|
39
|
-
|
40
|
-
|
45
|
+
# Create a new IE window.
|
46
|
+
def new_window
|
47
|
+
ie = new true
|
48
|
+
ie._new_window_init
|
49
|
+
ie
|
50
|
+
end
|
41
51
|
|
42
|
-
|
52
|
+
# Create a new IE, starting at the specified url.
|
53
|
+
# @param [String] url url to navigate to.
|
54
|
+
def start(url=nil)
|
55
|
+
start_window url
|
56
|
+
end
|
57
|
+
|
58
|
+
# Create a new IE window, starting at the specified url.
|
59
|
+
# @param [String] url url to navigate to.
|
60
|
+
def start_window(url=nil)
|
61
|
+
ie = new_window
|
62
|
+
ie.goto url if url
|
63
|
+
ie
|
64
|
+
end
|
43
65
|
|
44
|
-
# Create a new
|
45
|
-
# @
|
46
|
-
#
|
47
|
-
def
|
48
|
-
|
49
|
-
|
66
|
+
# Create a new IE window in a new process.
|
67
|
+
# @note This method will not work when
|
68
|
+
# Watir/Ruby is run under a service (instead of a user).
|
69
|
+
def new_process
|
70
|
+
ie = new true
|
71
|
+
ie._new_process_init
|
72
|
+
ie
|
50
73
|
end
|
51
74
|
|
52
|
-
# Create a new
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
75
|
+
# Create a new IE window in a new process, starting at the specified URL.
|
76
|
+
# @param [String] url url to navigate to.
|
77
|
+
def start_process(url=nil)
|
78
|
+
ie = new_process
|
79
|
+
ie.goto url if url
|
80
|
+
ie
|
58
81
|
end
|
59
82
|
|
60
83
|
# Attach to an existing IE {Browser}.
|
@@ -74,99 +97,574 @@ Project Homepage: http://watir.com
|
|
74
97
|
# @param [Symbol] how type of the locator. Can be :title, :url or :hwnd.
|
75
98
|
# @param [Symbol] what value of the locator. Can be {String}, {Regexp} or {Fixnum}
|
76
99
|
# depending of the type parameter.
|
100
|
+
#
|
101
|
+
# @note This method will not work when
|
102
|
+
# Watir/Ruby is run under a service (instead of a user).
|
77
103
|
def attach(how, what)
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
# Set options for the {Browser}.
|
83
|
-
def set_options(options)
|
84
|
-
return unless klass.respond_to?(:set_options)
|
85
|
-
klass.set_options options
|
104
|
+
ie = new true # don't create window
|
105
|
+
ie._attach_init(how, what)
|
106
|
+
ie
|
86
107
|
end
|
87
108
|
|
88
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
|
109
|
+
# Yields successively to each IE window on the current desktop. Takes a block.
|
110
|
+
# @note This method will not work when
|
111
|
+
# Watir/Ruby is run under a service (instead of a user).
|
112
|
+
# @yieldparam [Browser] ie instances of IE found.
|
113
|
+
def each
|
114
|
+
shell = WIN32OLE.new('Shell.Application')
|
115
|
+
ie_browsers = []
|
116
|
+
shell.Windows.each do |window|
|
117
|
+
next unless (window.path =~ /Internet Explorer/ rescue false)
|
118
|
+
next unless (hwnd = window.hwnd rescue false)
|
119
|
+
ie = bind(window)
|
120
|
+
ie.hwnd = hwnd
|
121
|
+
ie_browsers << ie
|
122
|
+
end
|
123
|
+
ie_browsers.each do |ie|
|
124
|
+
yield ie
|
125
|
+
end
|
92
126
|
end
|
93
127
|
|
94
|
-
|
95
|
-
|
96
|
-
|
128
|
+
# @return [String] the IE browser version number as a string.
|
129
|
+
def version
|
130
|
+
@ie_version ||= begin
|
131
|
+
require 'win32/registry'
|
132
|
+
::Win32::Registry::HKEY_LOCAL_MACHINE.open("SOFTWARE\\Microsoft\\Internet Explorer") do |ie_key|
|
133
|
+
begin
|
134
|
+
ie_key['svcVersion']
|
135
|
+
rescue ::Win32::Registry::Error
|
136
|
+
ie_key['Version']
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
97
140
|
end
|
98
|
-
private :klass
|
99
|
-
|
100
|
-
# Add support for the browser option, using the specified class,
|
101
|
-
# provided as a string. Optionally, additional options supported by
|
102
|
-
# the class can be specified as an array of symbols. Options specified
|
103
|
-
# by the user and included in this list will be passed (as a hash) to
|
104
|
-
# the set_options class method (if defined) before creating an instance.
|
105
|
-
# @todo remove this and autoloading since now only IE is supported.
|
106
|
-
# @private
|
107
|
-
def support hash_args
|
108
|
-
option = hash_args[:name]
|
109
|
-
class_string = hash_args[:class]
|
110
|
-
additional_options = hash_args[:options]
|
111
|
-
library = hash_args[:library]
|
112
|
-
gem = hash_args[:gem] || library
|
113
141
|
|
114
|
-
|
115
|
-
|
142
|
+
# @return [Array<String>] the IE browser version numbers split by "." in an Array.
|
143
|
+
def version_parts
|
144
|
+
version.split('.')
|
145
|
+
end
|
116
146
|
|
117
|
-
|
118
|
-
|
147
|
+
# Find existing IE window with locators.
|
148
|
+
# @see .attach
|
149
|
+
def find(how, what)
|
150
|
+
ie_ole = _find(how, what)
|
151
|
+
bind ie_ole if ie_ole
|
119
152
|
end
|
120
|
-
|
153
|
+
|
154
|
+
# Return an Browser object that wraps the given window, typically obtained from
|
155
|
+
# Shell.Application.windows.
|
121
156
|
# @private
|
122
|
-
def
|
123
|
-
|
157
|
+
def bind(window)
|
158
|
+
ie = new true
|
159
|
+
ie.ie = window
|
160
|
+
ie.initialize_options
|
161
|
+
ie
|
124
162
|
end
|
125
163
|
|
126
|
-
# Specifies a default browser. Must be specified before options are parsed.
|
127
|
-
# @todo remove this since only IE is supported.
|
128
164
|
# @private
|
129
|
-
def
|
130
|
-
|
165
|
+
def _find(how, what)
|
166
|
+
_find_all(how, what).first
|
131
167
|
end
|
132
168
|
|
133
|
-
# Returns the names of the browsers that are supported by this module.
|
134
|
-
# These are the options for 'watir_browser' (env var) or 'browser:' (yaml).
|
135
|
-
# @todo remove this since only IE is supported.
|
136
169
|
# @private
|
137
|
-
def
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
170
|
+
def _find_all(how, what)
|
171
|
+
ies = []
|
172
|
+
count = -1
|
173
|
+
each do |ie|
|
174
|
+
window = ie.ie
|
175
|
+
|
176
|
+
case how
|
177
|
+
when :url
|
178
|
+
ies << window if (what.matches(window.locationURL))
|
179
|
+
when :title
|
180
|
+
# normal windows explorer shells do not have document
|
181
|
+
# note window.document will fail for "new" browsers
|
182
|
+
begin
|
183
|
+
title = window.locationname
|
184
|
+
title = window.document.title
|
185
|
+
rescue WIN32OLERuntimeError
|
186
|
+
end
|
187
|
+
ies << window if what.matches(title)
|
188
|
+
when :hwnd
|
189
|
+
begin
|
190
|
+
ies << window if what == window.HWND
|
191
|
+
rescue WIN32OLERuntimeError
|
192
|
+
end
|
193
|
+
when :index
|
194
|
+
count += 1
|
195
|
+
if count == what
|
196
|
+
ies << window
|
197
|
+
break
|
198
|
+
end
|
199
|
+
when nil
|
200
|
+
ies << window
|
201
|
+
else
|
202
|
+
raise ArgumentError
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
ies
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
# Used internally to determine when IE has finished loading a page.
|
212
|
+
# @private
|
213
|
+
READYSTATES = {:complete => 4}
|
214
|
+
|
215
|
+
# The default color for highlighting objects as they are accessed.
|
216
|
+
# @private
|
217
|
+
HIGHLIGHT_COLOR = 'yellow'
|
218
|
+
|
219
|
+
# The time, in seconds, it took for the new page to load after executing
|
220
|
+
# the last command.
|
221
|
+
attr_reader :down_load_time
|
222
|
+
|
223
|
+
# The OLE Internet Explorer object.
|
224
|
+
attr_accessor :ie
|
225
|
+
|
226
|
+
# The list of unique urls that have been visited.
|
227
|
+
attr_reader :url_list
|
228
|
+
|
229
|
+
# @private
|
230
|
+
attr_writer :hwnd
|
231
|
+
|
232
|
+
# Create an IE browser instance.
|
233
|
+
# @param [Boolean] suppress_new_window set to true for not creating a IE
|
234
|
+
# window.
|
235
|
+
def initialize(suppress_new_window=nil)
|
236
|
+
_new_window_init unless suppress_new_window == true
|
237
|
+
end
|
238
|
+
|
239
|
+
# Specifies the speed that commands will be executed at.
|
240
|
+
# Possible choices are:
|
241
|
+
# * :slow (default)
|
242
|
+
# * :fast
|
243
|
+
# * :zippy
|
244
|
+
#
|
245
|
+
# With :zippy, text fields will be entered at once, instead of
|
246
|
+
# character by character.
|
247
|
+
#
|
248
|
+
# @note :zippy speed does not trigger JavaScript events like onChange etc.
|
249
|
+
#
|
250
|
+
# @param [Symbol] how_fast possible choices are :slow (default), :fast and
|
251
|
+
# :zippy
|
252
|
+
# @raise [ArgumentError] when invalid speed is specified.
|
253
|
+
def speed=(how_fast)
|
254
|
+
case how_fast
|
255
|
+
when :zippy
|
256
|
+
@typingspeed = 0
|
257
|
+
@pause_after_wait = 0.01
|
258
|
+
@type_keys = false
|
259
|
+
@speed = :fast
|
260
|
+
when :fast
|
261
|
+
@typingspeed = 0
|
262
|
+
@pause_after_wait = 0.01
|
263
|
+
@type_keys = true
|
264
|
+
@speed = :fast
|
265
|
+
when :slow
|
266
|
+
@typingspeed = 0.08
|
267
|
+
@pause_after_wait = 0.1
|
268
|
+
@type_keys = true
|
269
|
+
@speed = :slow
|
270
|
+
else
|
271
|
+
raise ArgumentError, "Invalid speed: #{how_fast}. Possible choices are :slow, :fast and :zippy."
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
# @return [Symbol] current speed setting. May be :slow, :fast or :zippy.
|
276
|
+
def speed
|
277
|
+
return @speed if @speed == :slow
|
278
|
+
return @type_keys ? :fast : :zippy
|
279
|
+
end
|
280
|
+
|
281
|
+
# @deprecated Use {#speed=} with :fast argument instead.
|
282
|
+
def set_fast_speed
|
283
|
+
Kernel.warn "Deprecated(Browser.set_fast_speed) - use Browser#speed = :fast instead."
|
284
|
+
self.speed = :fast
|
285
|
+
end
|
286
|
+
|
287
|
+
# @deprecated Use {#speed=} with :slow argument instead.
|
288
|
+
def set_slow_speed
|
289
|
+
Kernel.warn "Deprecated(Browser.set_slow_speed) - use Browser#speed = :slow instead."
|
290
|
+
self.speed = :slow
|
291
|
+
end
|
292
|
+
|
293
|
+
# @return [Boolean] true when window is visible, false otherwise.
|
294
|
+
def visible
|
295
|
+
@ie.visible
|
296
|
+
end
|
297
|
+
|
298
|
+
# Set the visibility of IE window.
|
299
|
+
# @param [Boolean] boolean set to true if IE window should be visible, false
|
300
|
+
# otherwise.
|
301
|
+
def visible=(boolean)
|
302
|
+
@ie.visible = boolean if boolean != @ie.visible
|
303
|
+
end
|
304
|
+
|
305
|
+
# @return [Fixnum] current IE window handle.
|
306
|
+
# @raise [RuntimeError] when not attached to a browser.
|
307
|
+
def hwnd
|
308
|
+
raise "Not attached to a browser" if @ie.nil?
|
309
|
+
@hwnd ||= @ie.hwnd
|
310
|
+
end
|
311
|
+
|
312
|
+
# @return [Symbol] the name of the browser. Is always :internet_explorer.
|
313
|
+
def name
|
314
|
+
:internet_explorer
|
315
|
+
end
|
316
|
+
|
317
|
+
# @return [Boolean] true when IE window exists, false otherwise.
|
318
|
+
def exists?
|
319
|
+
!!(@ie.name =~ /Internet Explorer/)
|
320
|
+
rescue WIN32OLERuntimeError, NoMethodError
|
321
|
+
false
|
322
|
+
end
|
323
|
+
|
324
|
+
alias :exist? :exists?
|
325
|
+
|
326
|
+
# @return [String] the title of the document.
|
327
|
+
def title
|
328
|
+
@ie.document.title
|
329
|
+
end
|
330
|
+
|
331
|
+
# @return [String] the status text of the window, typically from the status bar at the bottom.
|
332
|
+
# Will be empty if there's no status or when there are problems accessing status text.
|
333
|
+
def status
|
334
|
+
@ie.statusText
|
335
|
+
rescue WIN32OLERuntimeError
|
336
|
+
""
|
337
|
+
end
|
338
|
+
|
339
|
+
#
|
340
|
+
# Navigation
|
341
|
+
#
|
342
|
+
|
343
|
+
# Navigate to the specified URL.
|
344
|
+
# @param [String] url url to navigate to.
|
345
|
+
# @return [Fixnum] time in seconds the page took to load.
|
346
|
+
def goto(url)
|
347
|
+
url = "http://" + url unless url =~ %r{://} || url == "about:blank"
|
348
|
+
@ie.navigate(url)
|
349
|
+
wait
|
350
|
+
return @down_load_time
|
351
|
+
end
|
352
|
+
|
353
|
+
# Go to the previous page - the same as clicking the browsers back button.
|
354
|
+
# @raise [WIN32OLERuntimeError] when the browser can't go back.
|
355
|
+
def back
|
356
|
+
@ie.GoBack
|
357
|
+
wait
|
358
|
+
end
|
359
|
+
|
360
|
+
# Go to the next page - the same as clicking the browsers forward button.
|
361
|
+
# @raise [WIN32OLERuntimeError] when the browser can't go forward.
|
362
|
+
def forward
|
363
|
+
@ie.GoForward
|
364
|
+
wait
|
365
|
+
end
|
366
|
+
|
367
|
+
# Refresh the current page - the same as clicking the browsers refresh button.
|
368
|
+
# @raise [WIN32OLERuntimeError] when the browser can't refresh.
|
369
|
+
def refresh
|
370
|
+
@ie.refresh2(3)
|
371
|
+
wait
|
372
|
+
end
|
373
|
+
|
374
|
+
def inspect
|
375
|
+
'#<%s:0x%x url=%s title=%s>' % [self.class, hash*2, url.inspect, title.inspect]
|
376
|
+
end
|
377
|
+
|
378
|
+
# Clear the list of urls that have been visited.
|
379
|
+
def clear_url_list
|
380
|
+
@url_list.clear
|
381
|
+
end
|
382
|
+
|
383
|
+
# Close the {Browser}.
|
384
|
+
def close
|
385
|
+
return unless exists?
|
386
|
+
@ie.stop
|
387
|
+
wait rescue nil
|
388
|
+
chwnd = @ie.hwnd.to_i
|
389
|
+
@ie.quit
|
390
|
+
t = ::Time.now
|
391
|
+
while exists?
|
392
|
+
# just in case to avoid possible endless loop if failing to close some
|
393
|
+
# window or tab
|
394
|
+
break if ::Time.now - t > 10
|
395
|
+
sleep 0.3
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
# Maximize the window (expands to fill the screen).
|
400
|
+
def maximize
|
401
|
+
rautomation.maximize
|
402
|
+
end
|
403
|
+
|
404
|
+
# Minimize the window (appears as icon on taskbar).
|
405
|
+
def minimize
|
406
|
+
rautomation.minimize
|
407
|
+
end
|
408
|
+
|
409
|
+
# @return [Boolean] true when window is minimized, false otherwise.
|
410
|
+
def minimized?
|
411
|
+
rautomation.minimized?
|
412
|
+
end
|
413
|
+
|
414
|
+
# Restore the window (after minimizing or maximizing).
|
415
|
+
def restore
|
416
|
+
rautomation.restore
|
417
|
+
end
|
418
|
+
|
419
|
+
# Make the window come to the front.
|
420
|
+
def activate
|
421
|
+
rautomation.activate
|
422
|
+
end
|
423
|
+
|
424
|
+
alias :bring_to_front :activate
|
425
|
+
|
426
|
+
# @return [Boolean] true when window is in front e.g. in focus, false otherwise.
|
427
|
+
def active?
|
428
|
+
rautomation.active?
|
429
|
+
end
|
430
|
+
|
431
|
+
alias :front? :active?
|
432
|
+
|
433
|
+
# @return [RAutomation::Window] the RAutomation instance for this IE window.
|
434
|
+
# @see https://github.com/jarmo/rautomation
|
435
|
+
def rautomation
|
436
|
+
@rautomation ||= ::RAutomation::Window.new(:hwnd => hwnd)
|
437
|
+
end
|
438
|
+
|
439
|
+
# @deprecated use {#rautomation} instead.
|
440
|
+
def autoit
|
441
|
+
Kernel.warn "Deprecated(Browser#autoit) - use Browser#rautomation instead. Refer to https://github.com/jarmo/RAutomation for updating your scripts."
|
442
|
+
@autoit ||= ::RAutomation::Window.new(:hwnd => hwnd, :adapter => :autoit)
|
443
|
+
end
|
444
|
+
|
445
|
+
# Activates the window and sends keys to it.
|
446
|
+
#
|
447
|
+
# @example
|
448
|
+
# browser.send_keys("Hello World", :enter)
|
449
|
+
#
|
450
|
+
# @see https://github.com/jarmo/RAutomation/blob/master/lib/rautomation/adapter/win_32/window.rb RAutomation::Window#send_keys documentation.
|
451
|
+
def send_keys(*keys)
|
452
|
+
rautomation.send_keys *keys
|
453
|
+
end
|
454
|
+
|
455
|
+
#
|
456
|
+
# Document and Document Data
|
457
|
+
#
|
458
|
+
|
459
|
+
# @return [WIN32OLE] current IE document.
|
460
|
+
def document
|
461
|
+
@ie.document
|
462
|
+
end
|
463
|
+
|
464
|
+
# @return [String] current url, as displayed in the address bar of the browser.
|
465
|
+
def url
|
466
|
+
@ie.LocationURL
|
467
|
+
end
|
468
|
+
|
469
|
+
# Create a {Screenshot} instance.
|
470
|
+
def screenshot
|
471
|
+
Screenshot.new(hwnd)
|
472
|
+
end
|
473
|
+
|
474
|
+
# Retrieve a {Window} instance.
|
475
|
+
#
|
476
|
+
# @example Retrieve a different window without block.
|
477
|
+
# browser.window(:title => /other window title/).use
|
478
|
+
# browser.title # => "other window title"
|
479
|
+
#
|
480
|
+
# @example Use different window with block.
|
481
|
+
# browser.window(:title => /other window title/) do
|
482
|
+
# browser.title # => "other window title"
|
483
|
+
# end
|
484
|
+
# browser.title # => "current window title"
|
485
|
+
#
|
486
|
+
# @param [Hash] specifiers options for finding window.
|
487
|
+
# @option specifiers [String,Regexp] :title Title of the window.
|
488
|
+
# @option specifiers [String,Regexp] :url Url of the window.
|
489
|
+
# @option specifiers [Fixnum] :index The index of the window.
|
490
|
+
# @yield yield optionally to the found window.
|
491
|
+
# @return [Window] found window instance.
|
492
|
+
def window(specifiers={}, &blk)
|
493
|
+
win = Window.new(self, specifiers, &blk)
|
494
|
+
win.use &blk if blk
|
495
|
+
win
|
496
|
+
end
|
497
|
+
|
498
|
+
# @see #window
|
499
|
+
# @return [Array<Window>] array of found windows.
|
500
|
+
def windows(specifiers={})
|
501
|
+
self.class._find_all(specifiers.keys.first, specifiers.values.first).map {|ie| Window.new(self, specifiers, self.class.bind(ie))}
|
502
|
+
end
|
503
|
+
|
504
|
+
# Retrieve {Cookies} instance.
|
505
|
+
def cookies
|
506
|
+
Cookies.new(self)
|
507
|
+
end
|
508
|
+
|
509
|
+
# Add an error checker that gets executed after every page load, click etc.
|
510
|
+
#
|
511
|
+
# @example
|
512
|
+
# browser.add_checker lambda { |browser| raise "Error!" if browser.text.include? "Error" }
|
513
|
+
#
|
514
|
+
# @param [Proc] checker Proc object which gets yielded with {Browser} instance.
|
515
|
+
def add_checker(checker = nil, &block)
|
516
|
+
if block_given?
|
517
|
+
@error_checkers << block
|
518
|
+
elsif checker.respond_to? :call
|
519
|
+
@error_checkers << checker
|
520
|
+
else
|
521
|
+
raise ArgumentError, "expected block or object responding to #call"
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
# Disable an error checker added via {#add_checker}.
|
526
|
+
#
|
527
|
+
# @param [Proc] checker Proc object to be removed from error checkers.
|
528
|
+
def disable_checker(checker)
|
529
|
+
@error_checkers.delete(checker)
|
530
|
+
end
|
531
|
+
|
532
|
+
# Gives focus to the window frame.
|
533
|
+
def focus
|
534
|
+
active_element = document.activeElement
|
535
|
+
active_element.blur if active_element && active_element.tagName != "BODY"
|
536
|
+
document.focus
|
537
|
+
end
|
538
|
+
|
539
|
+
# @private
|
540
|
+
def attach_command
|
541
|
+
"Watir::Browser.attach(:hwnd, #{hwnd})"
|
542
|
+
end
|
543
|
+
|
544
|
+
# @private
|
545
|
+
def _new_window_init
|
546
|
+
create_browser_window
|
547
|
+
initialize_options
|
548
|
+
goto 'about:blank' # this avoids numerous problems caused by lack of a document
|
549
|
+
end
|
550
|
+
|
551
|
+
# @private
|
552
|
+
def _new_process_init
|
553
|
+
iep = Process.start
|
554
|
+
@ie = iep.window
|
555
|
+
@process_id = iep.process_id
|
556
|
+
initialize_options
|
557
|
+
goto 'about:blank'
|
558
|
+
end
|
559
|
+
|
560
|
+
# this method is used internally to attach to an existing window
|
561
|
+
# @private
|
562
|
+
def _attach_init how, what
|
563
|
+
attach_browser_window how, what
|
564
|
+
initialize_options
|
565
|
+
wait
|
566
|
+
end
|
567
|
+
|
568
|
+
# @private
|
569
|
+
def initialize_options
|
570
|
+
self.visible = self.class.visible
|
571
|
+
self.speed = self.class.speed
|
572
|
+
|
573
|
+
@ole_object = nil
|
574
|
+
@page_container = self
|
575
|
+
@error_checkers = []
|
576
|
+
@active_object_highlight_color = HIGHLIGHT_COLOR
|
577
|
+
@url_list = []
|
578
|
+
end
|
579
|
+
|
580
|
+
#
|
581
|
+
# Synchronization
|
582
|
+
#
|
583
|
+
|
584
|
+
# Block execution until the page has loaded.
|
585
|
+
#
|
586
|
+
# Will raise Timeout::Error if page hasn't been loaded within 5 minutes.
|
587
|
+
# Note: This code needs to be prepared for the ie object to be closed at
|
588
|
+
# any moment!
|
589
|
+
#
|
590
|
+
# @private
|
591
|
+
def wait(no_sleep=false)
|
592
|
+
@xml_parser_doc = nil
|
593
|
+
@down_load_time = 0.0
|
594
|
+
interval = 0.05
|
595
|
+
start_load_time = ::Time.now
|
596
|
+
|
597
|
+
Timeout::timeout(5*60) do
|
153
598
|
begin
|
154
|
-
|
155
|
-
|
156
|
-
|
599
|
+
while @ie.busy
|
600
|
+
sleep interval
|
601
|
+
end
|
602
|
+
|
603
|
+
until READYSTATES.has_value?(@ie.readyState)
|
604
|
+
sleep interval
|
605
|
+
end
|
606
|
+
|
607
|
+
until @ie.document
|
608
|
+
sleep interval
|
609
|
+
end
|
610
|
+
|
611
|
+
documents_to_wait_for = [@ie.document]
|
612
|
+
rescue WIN32OLERuntimeError # IE window must have been closed
|
613
|
+
@down_load_time = ::Time.now - start_load_time
|
614
|
+
return @down_load_time
|
615
|
+
end
|
616
|
+
|
617
|
+
while doc = documents_to_wait_for.shift
|
618
|
+
begin
|
619
|
+
until READYSTATES.has_key?(doc.readyState.to_sym)
|
620
|
+
sleep interval
|
621
|
+
end
|
622
|
+
@url_list << doc.location.href unless @url_list.include?(doc.location.href)
|
623
|
+
doc.frames.length.times do |n|
|
624
|
+
begin
|
625
|
+
documents_to_wait_for << doc.frames[n.to_s].document
|
626
|
+
rescue WIN32OLERuntimeError, NoMethodError
|
627
|
+
end
|
628
|
+
end
|
629
|
+
rescue WIN32OLERuntimeError
|
630
|
+
end
|
157
631
|
end
|
158
632
|
end
|
159
633
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
634
|
+
@down_load_time = ::Time.now - start_load_time
|
635
|
+
run_error_checks
|
636
|
+
sleep @pause_after_wait unless no_sleep
|
637
|
+
@down_load_time
|
638
|
+
end
|
639
|
+
|
640
|
+
# Error checkers
|
641
|
+
|
642
|
+
# Run the predefined error checks.
|
643
|
+
#
|
644
|
+
# @private
|
645
|
+
def run_error_checks
|
646
|
+
@error_checkers.each { |e| e.call(self) }
|
647
|
+
end
|
648
|
+
|
649
|
+
private
|
650
|
+
|
651
|
+
def create_browser_window
|
652
|
+
@ie = WIN32OLE.new('InternetExplorer.Application')
|
653
|
+
end
|
654
|
+
|
655
|
+
def attach_browser_window how, what
|
656
|
+
ieTemp = nil
|
657
|
+
begin
|
658
|
+
Wait.until(self.class.attach_timeout) do
|
659
|
+
ieTemp = self.class._find how, what
|
660
|
+
end
|
661
|
+
rescue Wait::TimeoutError
|
662
|
+
raise NoMatchingWindowFoundException,
|
663
|
+
"Unable to locate a window with #{how} of #{what}"
|
166
664
|
end
|
665
|
+
@ie = ieTemp
|
167
666
|
end
|
168
|
-
end
|
169
667
|
|
170
|
-
end
|
171
668
|
|
172
|
-
|
669
|
+
end
|
670
|
+
end
|