vapir-ie 1.7.2 → 1.8.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.
data/lib/vapir-ie.rb CHANGED
@@ -6,23 +6,8 @@ module Vapir
6
6
  IE= Class.new(Vapir::Browser)
7
7
  end
8
8
 
9
- # these switches need to be deleted from ARGV to enable the Test::Unit
10
- # functionality that grabs
11
- # the remaining ARGV as a filter on what tests to run.
12
- # Note: this means that watir must be require'd BEFORE test/unit.
13
- # (Alternatively, you could require test/unit first and then put the Vapir::IE
14
- # arguments after the '--'.)
15
-
16
- # Make Internet Explorer invisible. -b stands for background
17
- $HIDE_IE ||= ARGV.delete('-b')
18
-
19
- # Run fast
20
- $FAST_SPEED = ARGV.delete('-f')
21
-
22
- # Eat the -s command line switch (deprecated)
23
- ARGV.delete('-s')
24
-
25
- require 'vapir-ie/ie-class'
9
+ require 'vapir-ie/config'
10
+ require 'vapir-ie/browser'
26
11
  require 'vapir-ie/elements'
27
12
  require 'vapir-ie/version'
28
13
 
@@ -31,14 +16,5 @@ require 'vapir-common/waiter'
31
16
  module Vapir
32
17
  include Vapir::Exception
33
18
 
34
- # Directory containing the watir.rb file
35
- @@dir = File.expand_path(File.dirname(__FILE__))
36
19
 
37
- ATTACHER = Waiter.new
38
- # Like regular Ruby "until", except that a TimeOutException is raised
39
- # if the timeout is exceeded. Timeout is IE.attach_timeout.
40
- def self.until_with_timeout # block
41
- ATTACHER.timeout = IE.attach_timeout
42
- ATTACHER.wait_until { yield }
43
- end
44
20
  end
@@ -11,50 +11,6 @@ module Vapir
11
11
  include Vapir::Exception
12
12
  include IE::PageContainer
13
13
 
14
- # Maximum number of seconds to wait when attaching to a window
15
- @@attach_timeout = 2.0 # default value
16
- def self.attach_timeout
17
- @@attach_timeout
18
- end
19
- def self.attach_timeout=(timeout)
20
- @@attach_timeout = timeout
21
- end
22
-
23
- # Return the options used when creating new instances of IE.
24
- # BUG: this interface invites misunderstanding/misuse such as IE.options[:speed] = :zippy]
25
- def self.options
26
- {:speed => self.speed, :visible => self.visible, :attach_timeout => self.attach_timeout}
27
- end
28
- # set values for options used when creating new instances of IE.
29
- def self.set_options options
30
- options.each do |name, value|
31
- send "#{name}=", value
32
- end
33
- end
34
- # The globals $FAST_SPEED and $HIDE_IE are checked both at initialization
35
- # and later, because they
36
- # might be set after initialization. Setting them beforehand (e.g. from
37
- # the command line) will affect the class, otherwise it is only a temporary
38
- # effect
39
- @@speed = $FAST_SPEED ? :fast : :slow
40
- def self.speed
41
- return :fast if $FAST_SPEED
42
- @@speed
43
- end
44
- def self.speed= x
45
- $FAST_SPEED = nil
46
- @@speed = x
47
- end
48
- @@visible = $HIDE_IE ? false : true
49
- def self.visible
50
- return false if $HIDE_IE
51
- @@visible
52
- end
53
- def self.visible= x
54
- $HIDE_IE = nil
55
- @@visible = x
56
- end
57
-
58
14
  # IE inserts some element whose tagName is empty and just acts as block level element
59
15
  # Probably some IE method of cleaning things
60
16
  # To pass the same to the xml parser we need to give some name to empty tagName
@@ -64,257 +20,179 @@ module Vapir
64
20
  # the last command
65
21
  attr_reader :down_load_time
66
22
 
67
- # the OLE Internet Explorer object
68
- attr_accessor :ie
69
-
70
23
  # access to the logger object
71
24
  attr_accessor :logger
72
25
 
73
26
  # this contains the list of unique urls that have been visited
74
27
  attr_reader :url_list
75
28
 
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
29
+ class << self
30
+ # Create a new IE window in a new process.
31
+ # This method will not work when
32
+ # Vapir/Ruby is run under a service (instead of a user).
33
+ def new_process(options={})
34
+ new(options.merge(:new_process => true))
35
+ end
36
+
37
+ # Create a new IE window in a new process, starting at the specified URL.
38
+ # Same as IE.start.
39
+ def start_process(url='about:blank', options={})
40
+ new(options.merge(:new_process => true, :goto => url))
41
+ end
42
+
43
+ # Yields successively to each IE window on the current desktop. Takes a block.
44
+ # This method will not work when
45
+ # Vapir/Ruby is run under a service (instead of a user).
46
+ # Yields to the window and its hwnd.
47
+ def each_browser
48
+ each_browser_object do |browser_object|
49
+ yield attach(:browser_object, browser_object)
50
+ end
51
+ end
52
+ alias each each_browser
53
+ def browsers
54
+ Enumerator.new(self, :each_browser)
55
+ end
56
+
57
+ # yields a WIN32OLE of each IE browser object that is available.
58
+ def each_browser_object
59
+ shell = WIN32OLE.new('Shell.Application')
60
+ shell.Windows.each do |window|
61
+ if (window.path =~ /Internet Explorer/ rescue false) && (window.hwnd rescue false)
62
+ yield window
63
+ end
64
+ end
65
+ end
66
+ def browser_objects
67
+ Enumerator.new(self, :each_browser_object)
68
+ end
69
+
81
70
  end
82
71
 
83
72
  # 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
- # Vapir/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 Vapir::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
- # Vapir/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
73
+ #
74
+ # Takes a hash of options:
75
+ # - :timeout - the number of seconds to wait for a window to appear when
76
+ # attaching or launching.
77
+ # - :goto - a url to which the IE browser will navigate. by default this
78
+ # is 'about:blank' for newly-launched IE instances, and the default is
79
+ # not to navigate anywhere for attached instances.
80
+ # - :new_process - true or false, default is false. whether to launch this
81
+ # IE instance as its own process (this has no effect if :attach is
82
+ # specified)
83
+ # - :attach - a two-element Array of [how, what] where how is one of:
84
+ # - :title - a string or regexp matching the title of the browser that
85
+ # should be attached to.
86
+ # - :URL - a string or regexp matching the URL of the browser that
87
+ # should be attached to.
88
+ # - :HWND - specifies the HWND of the browser that should be attached to.
89
+ # - :name - the name of the window (as specified in the second argument to a
90
+ # window.open() javascript call)
91
+ # - :browser_object - this is generally just used internally. 'what'
92
+ # is a WIN32OLE object representing the browser.
93
+ # - :wait - true or false, default is true. whether to wait for the browser
94
+ # to be ready before continuing.
95
+ def initialize(method_options = {})
96
+ if method_options==true || method_options==false
97
+ raise NotImplementedError, "#{self.class.name}.new takes an options hash - passing a boolean for 'suppress_new_window' is no longer supported. Please see the documentation for #{self.class}.new"
98
+ end
99
+ options = options_from_config(method_options, {:timeout => :attach_timeout, :new_process => :ie_launch_new_process, :wait => :wait, :visible => :browser_visible}, [:attach, :goto])
172
100
 
173
- @element_object = nil
174
- @page_container = self
175
101
  @error_checkers = []
176
102
 
177
103
  @logger = DefaultLogger.new
178
104
  @url_list = []
179
- end
180
105
 
181
- # Specifies the speed that commands will be executed at. Choices are:
182
- # * :slow (default)
183
- # * :fast
184
- # * :zippy
185
- # With IE#speed= :zippy, text fields will be entered at once, instead of
186
- # character by character (default).
187
- def speed= how_fast
188
- case how_fast
189
- when :zippy then
190
- @typingspeed = 0
191
- @pause_after_wait = 0.01
192
- @type_keys = false
193
- @speed = :fast
194
- when :fast then
195
- @typingspeed = 0
196
- @pause_after_wait = 0.01
197
- @type_keys = true
198
- @speed = :fast
199
- when :slow then
200
- @typingspeed = 0.08
201
- @pause_after_wait = 0.1
202
- @type_keys = true
203
- @speed = :slow
106
+ if options[:attach]
107
+ how, what = *options[:attach]
108
+ if how== :browser_object
109
+ @browser_object = what
110
+ else
111
+ orig_how=how
112
+ hows={
113
+ :title => proc{|bo| bo.document.title },
114
+ :URL => proc{|bo| bo.locationURL },
115
+ :name => proc{|bo| bo.document.parentWindow.name },
116
+ :HWND => proc{|bo| Vapir::IE.fix_win32ole_hwnd(bo.HWND) },
117
+ }
118
+ how=hows.keys.detect{|h| h.to_s.downcase==orig_how.to_s.downcase}
119
+ raise ArgumentError, "how should be one of: #{hows.keys.inspect} (was #{orig_how.inspect})" unless how
120
+ @browser_object = ::Waiter.try_for(options[:timeout], :exception => NoMatchingWindowFoundException.new("Unable to locate a window with #{how} of #{what}")) do
121
+ self.class.browser_objects.detect do |browser_object|
122
+ begin
123
+ Vapir::fuzzy_match(hows[how].call(browser_object), what)
124
+ rescue WIN32OLERuntimeError, NoMethodError
125
+ false
126
+ end
127
+ end
128
+ end
129
+ end
130
+ if method_options.key?(:visible)
131
+ # only set visibility if it's explicitly in the options given to the method - don't set from config when using attach
132
+ self.visible= method_options[:visible]
133
+ end
204
134
  else
205
- raise ArgumentError, "Invalid speed: #{how_fast}"
135
+ if options[:new_process]
136
+ iep = Process.start
137
+ @browser_object = iep.browser_object(:timeout => options[:timeout])
138
+ @process_id = iep.process_id
139
+ else
140
+ @browser_object = WIN32OLE.new('InternetExplorer.Application')
141
+ end
142
+ self.visible= options[:visible]
143
+ goto('about:blank')
206
144
  end
207
- end
208
-
209
- def speed
210
- return @speed if @speed == :slow
211
- return @type_keys ? :fast : :zippy
212
- end
213
-
214
- # deprecated: use speed = :fast instead
215
- def set_fast_speed
216
- self.speed = :fast
145
+ goto(options[:goto]) if options[:goto]
146
+ wait if options[:wait]
147
+ self
217
148
  end
218
149
 
219
- # deprecated: use speed = :slow instead
220
- def set_slow_speed
221
- self.speed = :slow
222
- end
223
-
224
150
  def visible
225
151
  assert_exists
226
- @ie.visible
152
+ @browser_object.visible
227
153
  end
228
- def visible=(boolean)
154
+ def visible=(visibility)
229
155
  assert_exists
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
- # Vapir/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
- # Vapir/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 Vapir::fuzzy_match(window.locationURL, what)
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, NoMethodError
276
- end
277
- ieTemp = window if Vapir::fuzzy_match(title, what)
278
- when :hwnd
279
- begin
280
- ieTemp = window if what == window.HWND
281
- rescue WIN32OLERuntimeError, NoMethodError
282
- end
283
- else
284
- raise ArgumentError
285
- end
286
- end
287
- return ieTemp
156
+ @browser_object.visible = visibility
288
157
  end
289
158
 
290
- def attach_browser_window how, what
291
- log "Seeking Window with #{how}: #{what}"
292
- ieTemp = nil
293
- begin
294
- Vapir::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
159
+ # the WIN32OLE Internet Explorer object
160
+ #
161
+ # See: http://msdn.microsoft.com/en-us/library/aa752085%28v=VS.85%29.aspx
162
+ # and http://msdn.microsoft.com/en-us/library/aa752084%28v=VS.85%29.aspx
163
+ attr_reader :browser_object
164
+ alias ie browser_object
304
165
 
305
- def browser_object
166
+ # Return the window handle of this browser
167
+ def hwnd
306
168
  assert_exists
307
- @ie
169
+ @hwnd ||= Vapir::IE.fix_win32ole_hwnd(@browser_object.HWND)
308
170
  end
309
171
 
310
- # Return the current window handle
311
- def hwnd
312
- assert_exists
313
- @hwnd ||= @ie.hwnd
172
+ # win32ole's #HWND method casts to signed somewhere along its way, so returns
173
+ # a negative number. this is wrong, WinWindow will reject it (correctly), so we
174
+ # need to fix.
175
+ def self.fix_win32ole_hwnd(win32ole_hwnd)
176
+ win32ole_hwnd < 0 ? win32ole_hwnd % 2**32 : win32ole_hwnd
177
+ end
178
+
179
+ # returns the process id of this browser
180
+ def process_id
181
+ @process_id ||= win_window.process_id
182
+ end
183
+ # kills this process. NOTE that this process may be running
184
+ # multiple browsers; killing the process will kill them all.
185
+ # use #close to close a single browser.
186
+ def kill
187
+ # todo: drop win32api; use ffi
188
+ require 'Win32API'
189
+ right_to_terminate_process = 1
190
+ handle = Win32API.new('kernel32.dll', 'OpenProcess', 'lil', 'l').call(right_to_terminate_process, 0, process_id)
191
+ Win32API.new('kernel32.dll', 'TerminateProcess', 'll', 'l').call(handle, 0)
314
192
  end
315
- attr_writer :hwnd
316
193
 
317
194
  def win_window
195
+ Vapir.require_winwindow
318
196
  @win_window||= WinWindow.new(hwnd)
319
197
  end
320
198
 
@@ -343,8 +221,8 @@ module Vapir
343
221
 
344
222
  # Are we attached to an open browser?
345
223
  def exists?
346
- !!(@ie && begin
347
- @ie.name
224
+ !!(@browser_object && begin
225
+ @browser_object.name
348
226
  rescue WIN32OLERuntimeError, NoMethodError
349
227
  raise unless $!.message =~ ExistenceFailureCodesRE
350
228
  false
@@ -367,12 +245,12 @@ module Vapir
367
245
 
368
246
  # Return the title of the document
369
247
  def title
370
- @ie.document.title
248
+ @browser_object.document.title
371
249
  end
372
250
 
373
251
  # Return the status of the window, typically from the status bar at the bottom.
374
252
  def status
375
- return @ie.statusText
253
+ return @browser_object.statusText
376
254
  end
377
255
 
378
256
  #
@@ -383,7 +261,7 @@ module Vapir
383
261
  # * url - string - the URL to navigate to
384
262
  def goto(url)
385
263
  assert_exists do
386
- @ie.navigate(url)
264
+ @browser_object.navigate(url)
387
265
  wait
388
266
  return @down_load_time
389
267
  end
@@ -393,7 +271,7 @@ module Vapir
393
271
  # an WIN32OLERuntimeError exception is raised if the browser cant go back
394
272
  def back
395
273
  assert_exists do
396
- @ie.GoBack
274
+ @browser_object.GoBack
397
275
  wait
398
276
  end
399
277
  end
@@ -402,7 +280,7 @@ module Vapir
402
280
  # an WIN32OLERuntimeError exception is raised if the browser cant go forward
403
281
  def forward
404
282
  assert_exists do
405
- @ie.GoForward
283
+ @browser_object.GoForward
406
284
  wait
407
285
  end
408
286
  end
@@ -417,7 +295,7 @@ module Vapir
417
295
  # an WIN32OLERuntimeError exception is raised if the browser cant refresh
418
296
  def refresh
419
297
  assert_exists do
420
- @ie.refresh2(RefreshConstants::REFRESH_COMPLETELY)
298
+ @browser_object.refresh2(RefreshConstants::REFRESH_COMPLETELY)
421
299
  wait
422
300
  end
423
301
  end
@@ -430,13 +308,13 @@ module Vapir
430
308
  # Closes the Browser
431
309
  def close
432
310
  assert_exists
433
- @ie.stop
434
- @ie.quit
311
+ @browser_object.stop
312
+ @browser_object.quit
435
313
  # TODO/fix timeout; this shouldn't be a hard-coded magic number.
436
314
  ::Waiter.try_for(32, :exception => WindowFailedToCloseException.new("The browser window did not close"), :interval => 1) do
437
315
  begin
438
316
  if exists?
439
- @ie.quit
317
+ @browser_object.quit
440
318
  false
441
319
  else
442
320
  true
@@ -446,7 +324,7 @@ module Vapir
446
324
  true
447
325
  end
448
326
  end
449
- @ie=nil
327
+ @browser_object=nil
450
328
  end
451
329
 
452
330
  # Maximize the window (expands to fill the screen)
@@ -486,18 +364,22 @@ module Vapir
486
364
 
487
365
  # saves a screenshot of this browser window to the given filename.
488
366
  #
489
- # second argument, optional, specifies what area to take a screenshot of.
490
- # - :client takes a screenshot of the client area, which excludes the menu bar and other window trimmings.
491
- # - :window (default) takes a screenshot of the full browser window
492
- # - :desktop takes a screenshot of the full desktop
493
- def screen_capture(filename, dc=:window)
494
- if dc==:desktop
495
- screenshot_win=WinWindow.desktop_window
496
- dc=:window
497
- else
498
- screenshot_win=win_window
367
+ # the screenshot format is BMP (DIB), so you should name your files to end with .bmp
368
+ #
369
+ # the last argument is an optional options hash, taking options:
370
+ # - :dc => (default is :window). may be one of:
371
+ # - :client takes a screenshot of the client area, which excludes the menu bar and other window trimmings.
372
+ # - :window (default) takes a screenshot of the full browser window
373
+ # - :desktop takes a screenshot of the full desktop
374
+ def screen_capture(filename, options = {})
375
+ unless options.is_a?(Hash)
376
+ dc = options
377
+ options = {:dc => dc}
378
+ if config.warn_deprecated
379
+ Kernel.warn_with_caller("WARNING: The API for #screen_capture has changed and the last argument is now an options hash. Please change calls to this method to specify :dc => #{dc.inspect}")
380
+ end
499
381
  end
500
- screenshot_win.capture_to_bmp_file(filename, :dc => dc)
382
+ screen_capture_win_window(filename, options)
501
383
  end
502
384
 
503
385
  def dir
@@ -511,7 +393,7 @@ module Vapir
511
393
  # Return the current document
512
394
  def document
513
395
  assert_exists
514
- return @ie.document
396
+ return @browser_object.document
515
397
  end
516
398
  alias document_object document
517
399
 
@@ -522,7 +404,7 @@ module Vapir
522
404
  # returns the current url, as displayed in the address bar of the browser
523
405
  def url
524
406
  assert_exists
525
- return @ie.LocationURL
407
+ return @browser_object.LocationURL
526
408
  end
527
409
 
528
410
  # Error checkers
@@ -778,12 +660,7 @@ module Vapir
778
660
  temp = element_by_absolute_xpath(modifiedXpath) # temp = a DOM/COM element
779
661
  selectedElements << temp if temp != nil
780
662
  end
781
- #puts selectedElements.length
782
- if selectedElements.length == 0
783
- return nil
784
- else
785
- return selectedElements
786
- end
663
+ return selectedElements
787
664
  end
788
665
 
789
666
  # Method that iterates over IE DOM object and get the elements for the given
@@ -875,4 +752,21 @@ module Vapir
875
752
  end
876
753
 
877
754
  end # class IE
755
+ module WatirConfigCompatibility
756
+ module Visible
757
+ def visible
758
+ if config.warn_deprecated
759
+ Kernel.warn_with_caller "WARNING: #visible is deprecated; please use the new config framework with config.browser_visible"
760
+ end
761
+ config.browser_visible
762
+ end
763
+ def visible= visibility
764
+ if config.warn_deprecated
765
+ Kernel.warn_with_caller "WARNING: #visible= is deprecated; please use the new config framework with config.browser_visible="
766
+ end
767
+ config.browser_visible=visibility
768
+ end
769
+ end
770
+ Vapir::IE.send(:extend, Visible)
771
+ end
878
772
  end