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
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'win32/process'
|
2
2
|
|
3
3
|
module Watir
|
4
|
-
class
|
4
|
+
class Browser
|
5
5
|
class Process
|
6
6
|
def self.start
|
7
7
|
program_files = ENV['ProgramFiles'] || "c:\\Program Files"
|
8
8
|
startup_command = "#{program_files}\\Internet Explorer\\iexplore.exe"
|
9
|
-
startup_command << " -nomerge" if
|
10
|
-
startup_command << " -noframemerging" if
|
9
|
+
startup_command << " -nomerge" if Browser.version_parts.first.to_i == 8
|
10
|
+
startup_command << " -noframemerging" if Browser.version_parts.first.to_i >= 9
|
11
11
|
process_info = ::Process.create('app_name' => "#{startup_command} about:blank")
|
12
12
|
process_id = process_info.process_id
|
13
13
|
new process_id
|
@@ -22,7 +22,7 @@ module Watir
|
|
22
22
|
def window
|
23
23
|
Wait.until do
|
24
24
|
found_window = nil
|
25
|
-
|
25
|
+
Browser.each do | ie |
|
26
26
|
window = ie.ie
|
27
27
|
hwnd = ie.hwnd
|
28
28
|
process_id = Process.process_id_from_hwnd hwnd
|
@@ -361,7 +361,7 @@ module Watir
|
|
361
361
|
|
362
362
|
# @private
|
363
363
|
def dispatch_event(event)
|
364
|
-
if
|
364
|
+
if Browser.version_parts.first.to_i >= 9 && container.page_container.document.documentMode.to_i >= 9
|
365
365
|
ole_object.dispatchEvent(create_event(event))
|
366
366
|
else
|
367
367
|
ole_object.fireEvent(event)
|
@@ -454,7 +454,7 @@ module Watir
|
|
454
454
|
element = "#{self.class}.new(#{@page_container.attach_command}, :tag_name => Array.new << '#{tag_name}', :unique_number => #{unique_number})"
|
455
455
|
method = build_method(method_name, *args)
|
456
456
|
ruby_code = "$:.unshift(#{$LOAD_PATH.map {|p| "'#{p}'" }.join(").unshift(")});" <<
|
457
|
-
"require '#{File.expand_path(File.dirname(__FILE__))}
|
457
|
+
"require '#{File.expand_path(File.dirname(__FILE__))}/../watir-classic';#{element}.#{method};"
|
458
458
|
ruby_code
|
459
459
|
end
|
460
460
|
|
data/lib/watir-classic/frame.rb
CHANGED
@@ -22,7 +22,7 @@ module Watir
|
|
22
22
|
if @document
|
23
23
|
@document
|
24
24
|
else
|
25
|
-
raise FrameAccessDeniedException, "IE will not allow access to this frame for security reasons. You can work around this with
|
25
|
+
raise FrameAccessDeniedException, "IE will not allow access to this frame for security reasons. You can work around this with browser.goto(frame.src)"
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
data/lib/watir-classic/window.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Watir
|
2
|
-
# Returned by {
|
2
|
+
# Returned by {Browser#window}.
|
3
3
|
class Window
|
4
4
|
include ElementExtensions
|
5
5
|
|
@@ -43,7 +43,7 @@ module Watir
|
|
43
43
|
# @return [Browser] browser of the window.
|
44
44
|
def browser
|
45
45
|
@browser ||= begin
|
46
|
-
|
46
|
+
Browser.find(@locators.keys.first, @locators.values.first)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -68,7 +68,7 @@ module Watir
|
|
68
68
|
ensure
|
69
69
|
@main_browser.ie = self.class.__main_ie
|
70
70
|
# try to find some existing IE when needed
|
71
|
-
@main_browser.ie =
|
71
|
+
@main_browser.ie = Browser._find(:index, 0) unless @main_browser.exists?
|
72
72
|
end
|
73
73
|
end
|
74
74
|
self
|
@@ -29,7 +29,7 @@ module Watir
|
|
29
29
|
# execute xpath selector and return an array of elements
|
30
30
|
def elements_by_xpath(xpath)
|
31
31
|
doc = xmlparser_document_object
|
32
|
-
current_tag = @container.is_a?(
|
32
|
+
current_tag = @container.is_a?(Browser) ? "body" : @container.tag_name
|
33
33
|
|
34
34
|
doc.xpath(xpath).reduce([]) do |elements, element|
|
35
35
|
absolute_xpath_parts = element.path.split("/")
|
@@ -45,7 +45,7 @@ module Watir
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def direct_children container, elements
|
48
|
-
return elements if container.is_a?(
|
48
|
+
return elements if container.is_a?(Browser)
|
49
49
|
elements.select {|el| el.parent == container}
|
50
50
|
end
|
51
51
|
|
data/spec/implementation.rb
CHANGED
@@ -5,7 +5,7 @@ WatirSpec.implementation do |imp|
|
|
5
5
|
imp.name = :watir_classic
|
6
6
|
|
7
7
|
WatirSpec.persistent_browser = true
|
8
|
-
imp.browser_class = Watir::
|
8
|
+
imp.browser_class = Watir::Browser
|
9
9
|
browser = :internet_explorer
|
10
10
|
browser_version = "#{browser}#{imp.browser_class.version.to_i}".to_sym
|
11
11
|
|
data/watir-classic.gemspec
CHANGED
@@ -28,7 +28,6 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.add_dependency 'nokogiri', ">= 1.5.7.rc3"
|
29
29
|
s.add_dependency 'ffi', '~>1.0'
|
30
30
|
s.add_dependency 'rautomation', '~>0.7'
|
31
|
-
s.add_dependency 'user-choices'
|
32
31
|
s.add_dependency 'multi_json'
|
33
32
|
s.add_dependency 'win32screenshot'
|
34
33
|
|
@@ -37,4 +36,5 @@ Gem::Specification.new do |s|
|
|
37
36
|
s.add_development_dependency("yard")
|
38
37
|
s.add_development_dependency("sinatra")
|
39
38
|
s.add_development_dependency("childprocess")
|
39
|
+
s.add_development_dependency('rake')
|
40
40
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: watir-classic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bret Pettichord
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-05
|
11
|
+
date: 2013-10-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: win32-process
|
@@ -80,20 +80,6 @@ dependencies:
|
|
80
80
|
- - ~>
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0.7'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: user-choices
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - '>='
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :runtime
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - '>='
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
84
|
name: multi_json
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,6 +178,20 @@ dependencies:
|
|
192
178
|
- - '>='
|
193
179
|
- !ruby/object:Gem::Version
|
194
180
|
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: rake
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - '>='
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - '>='
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
195
|
description: |2
|
196
196
|
WATIR is "Web Application Testing in Ruby". Watir (pronounced water) is a free,
|
197
197
|
open-source functional testing tool for automating browser-based tests of web applications.
|
@@ -214,7 +214,6 @@ files:
|
|
214
214
|
- CHANGES
|
215
215
|
- CONTRIBUTORS.txt
|
216
216
|
- Gemfile
|
217
|
-
- Gemfile.lock
|
218
217
|
- LICENSE
|
219
218
|
- README.rdoc
|
220
219
|
- Rakefile
|
@@ -228,10 +227,9 @@ files:
|
|
228
227
|
- lib/watir-classic/IEDialog/stdafx.cpp
|
229
228
|
- lib/watir-classic/IEDialog/stdafx.h
|
230
229
|
- lib/watir-classic/browser.rb
|
231
|
-
- lib/watir-classic/
|
230
|
+
- lib/watir-classic/browser_process.rb
|
232
231
|
- lib/watir-classic/container.rb
|
233
232
|
- lib/watir-classic/cookies.rb
|
234
|
-
- lib/watir-classic/core.rb
|
235
233
|
- lib/watir-classic/dialogs/alert.rb
|
236
234
|
- lib/watir-classic/dialogs/file_field.rb
|
237
235
|
- lib/watir-classic/drag_and_drop_helper.rb
|
@@ -242,9 +240,7 @@ files:
|
|
242
240
|
- lib/watir-classic/ext/json2.js
|
243
241
|
- lib/watir-classic/form.rb
|
244
242
|
- lib/watir-classic/frame.rb
|
245
|
-
- lib/watir-classic/
|
246
|
-
- lib/watir-classic/ie-process.rb
|
247
|
-
- lib/watir-classic/ie.rb
|
243
|
+
- lib/watir-classic/ie_deprecated.rb
|
248
244
|
- lib/watir-classic/image.rb
|
249
245
|
- lib/watir-classic/input_elements.rb
|
250
246
|
- lib/watir-classic/link.rb
|
@@ -253,7 +249,6 @@ files:
|
|
253
249
|
- lib/watir-classic/modal_dialog.rb
|
254
250
|
- lib/watir-classic/module.rb
|
255
251
|
- lib/watir-classic/non_control_elements.rb
|
256
|
-
- lib/watir-classic/options.rb
|
257
252
|
- lib/watir-classic/page-container.rb
|
258
253
|
- lib/watir-classic/process.rb
|
259
254
|
- lib/watir-classic/screenshot.rb
|
@@ -304,7 +299,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
304
299
|
requirements:
|
305
300
|
- Microsoft Windows running Internet Explorer 5.5 or later.
|
306
301
|
rubyforge_project:
|
307
|
-
rubygems_version: 2.0.
|
302
|
+
rubygems_version: 2.0.7
|
308
303
|
signing_key:
|
309
304
|
specification_version: 4
|
310
305
|
summary: Automated testing tool for web applications.
|
data/Gemfile.lock
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
watir-classic (3.7.0)
|
5
|
-
ffi (~> 1.0)
|
6
|
-
multi_json
|
7
|
-
nokogiri (>= 1.5.7.rc3)
|
8
|
-
rautomation (~> 0.7)
|
9
|
-
user-choices
|
10
|
-
win32-process (>= 0.5.5)
|
11
|
-
win32screenshot
|
12
|
-
windows-pr (>= 0.6.6)
|
13
|
-
|
14
|
-
GEM
|
15
|
-
remote: https://rubygems.org/
|
16
|
-
specs:
|
17
|
-
builder (3.2.0)
|
18
|
-
childprocess (0.3.9)
|
19
|
-
ffi (~> 1.0, >= 1.0.11)
|
20
|
-
diff-lcs (1.2.1)
|
21
|
-
ffi (1.8.1-x86-mingw32)
|
22
|
-
hoe (3.5.1)
|
23
|
-
rake (>= 0.8, < 11.0)
|
24
|
-
mini_magick (3.5.0)
|
25
|
-
subexec (~> 0.2.1)
|
26
|
-
multi_json (1.7.2)
|
27
|
-
nokogiri (1.5.7.rc3-x86-mingw32)
|
28
|
-
rack (1.5.2)
|
29
|
-
rack-protection (1.4.0)
|
30
|
-
rack
|
31
|
-
rake (10.0.4)
|
32
|
-
rautomation (0.8.0)
|
33
|
-
ffi
|
34
|
-
rspec (2.13.0)
|
35
|
-
rspec-core (~> 2.13.0)
|
36
|
-
rspec-expectations (~> 2.13.0)
|
37
|
-
rspec-mocks (~> 2.13.0)
|
38
|
-
rspec-core (2.13.0)
|
39
|
-
rspec-expectations (2.13.0)
|
40
|
-
diff-lcs (>= 1.1.3, < 2.0)
|
41
|
-
rspec-mocks (2.13.0)
|
42
|
-
s4t-utils (1.0.4)
|
43
|
-
hoe (>= 1.3.0)
|
44
|
-
sinatra (1.3.5)
|
45
|
-
rack (~> 1.4)
|
46
|
-
rack-protection (~> 1.3)
|
47
|
-
tilt (~> 1.3, >= 1.3.3)
|
48
|
-
subexec (0.2.2)
|
49
|
-
syntax (1.0.0)
|
50
|
-
tilt (1.3.4)
|
51
|
-
user-choices (1.1.6.1)
|
52
|
-
builder (>= 2.1.2)
|
53
|
-
s4t-utils (>= 1.0.3)
|
54
|
-
xml-simple (>= 1.0.11)
|
55
|
-
win32-api (1.4.8-x86-mingw32)
|
56
|
-
win32-process (0.7.1)
|
57
|
-
ffi (>= 1.0.0)
|
58
|
-
win32screenshot (1.0.8)
|
59
|
-
ffi (~> 1.0)
|
60
|
-
mini_magick (~> 3.2)
|
61
|
-
rautomation (~> 0.7)
|
62
|
-
windows-api (0.4.2)
|
63
|
-
win32-api (>= 1.4.5)
|
64
|
-
windows-pr (1.2.2)
|
65
|
-
win32-api (>= 1.4.5)
|
66
|
-
windows-api (>= 0.3.0)
|
67
|
-
xml-simple (1.1.2)
|
68
|
-
yard (0.8.5.2)
|
69
|
-
|
70
|
-
PLATFORMS
|
71
|
-
x86-mingw32
|
72
|
-
|
73
|
-
DEPENDENCIES
|
74
|
-
childprocess
|
75
|
-
rspec (~> 2.3)
|
76
|
-
sinatra
|
77
|
-
syntax
|
78
|
-
watir-classic!
|
79
|
-
yard
|
data/lib/watir-classic/core.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
# these require statements are needed for Watir
|
2
|
-
# to work with minimum functionality
|
3
|
-
require 'timeout'
|
4
|
-
require 'watir-classic/win32ole'
|
5
|
-
|
6
|
-
require 'watir-classic/util'
|
7
|
-
require 'watir-classic/exceptions'
|
8
|
-
require 'watir-classic/matches'
|
9
|
-
require 'watir-classic/wait'
|
10
|
-
require 'watir-classic/wait_helper'
|
11
|
-
require 'watir-classic/element_extensions'
|
12
|
-
|
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/ie-class'
|
18
|
-
require 'watir-classic/drag_and_drop_helper'
|
19
|
-
require 'watir-classic/element'
|
20
|
-
require 'watir-classic/element_collection'
|
21
|
-
require 'watir-classic/form'
|
22
|
-
require 'watir-classic/frame'
|
23
|
-
require 'watir-classic/input_elements'
|
24
|
-
require 'watir-classic/non_control_elements'
|
25
|
-
require 'watir-classic/table'
|
26
|
-
require 'watir-classic/image'
|
27
|
-
require 'watir-classic/link'
|
28
|
-
require 'watir-classic/window'
|
29
|
-
require 'watir-classic/cookies'
|
30
|
-
|
31
|
-
require 'watir-classic/win32'
|
32
|
-
require 'watir-classic/modal_dialog'
|
33
|
-
|
34
|
-
require 'watir-classic/module'
|
35
|
-
|
36
|
-
require 'rautomation'
|
37
|
-
require 'watir-classic/dialogs/file_field'
|
38
|
-
require 'watir-classic/dialogs/alert'
|
39
|
-
|
40
|
-
require 'watir-classic/supported_elements'
|
@@ -1,664 +0,0 @@
|
|
1
|
-
module Watir
|
2
|
-
# Main browser class.
|
3
|
-
class IE
|
4
|
-
include WaitHelper
|
5
|
-
include Exception
|
6
|
-
include Container
|
7
|
-
include PageContainer
|
8
|
-
|
9
|
-
class << self
|
10
|
-
# Maximum number of seconds to wait when attaching to a window
|
11
|
-
attr_writer :attach_timeout
|
12
|
-
|
13
|
-
def attach_timeout
|
14
|
-
@attach_timeout ||= 2
|
15
|
-
end
|
16
|
-
|
17
|
-
# Return the options used when creating new instances of IE.
|
18
|
-
# BUG: this interface invites misunderstanding/misuse such as IE.options[:speed] = :zippy]
|
19
|
-
def options
|
20
|
-
{:speed => self.speed, :visible => self.visible, :attach_timeout => self.attach_timeout}
|
21
|
-
end
|
22
|
-
|
23
|
-
# set values for options used when creating new instances of IE.
|
24
|
-
def set_options options
|
25
|
-
options.each do |name, value|
|
26
|
-
send "#{name}=", value
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# The speed in which browser will type keys etc. Possible values are
|
31
|
-
# :slow (default), :fast and :zippy.
|
32
|
-
attr_writer :speed
|
33
|
-
|
34
|
-
def speed
|
35
|
-
@speed ||= :slow
|
36
|
-
end
|
37
|
-
|
38
|
-
# Set browser window to visible or hidden. Defaults to true.
|
39
|
-
attr_writer :visible
|
40
|
-
|
41
|
-
def visible
|
42
|
-
@visible ||= true
|
43
|
-
end
|
44
|
-
|
45
|
-
# Create a new IE window.
|
46
|
-
def new_window
|
47
|
-
ie = new true
|
48
|
-
ie._new_window_init
|
49
|
-
ie
|
50
|
-
end
|
51
|
-
|
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
|
65
|
-
|
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
|
73
|
-
end
|
74
|
-
|
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
|
81
|
-
end
|
82
|
-
|
83
|
-
# Attach to an existing IE {Browser}.
|
84
|
-
#
|
85
|
-
# @example Attach with full title:
|
86
|
-
# Watir::Browser.attach(:title, "Full title of IE")
|
87
|
-
#
|
88
|
-
# @example Attach with part of the title using {Regexp}:
|
89
|
-
# Watir::Browser.attach(:title, /part of the title of IE/)
|
90
|
-
#
|
91
|
-
# @example Attach with part of the url:
|
92
|
-
# Watir::Browser.attach(:url, /google/)
|
93
|
-
#
|
94
|
-
# @example Attach with window handle:
|
95
|
-
# Watir::Browser.attach(:hwnd, 123456)
|
96
|
-
#
|
97
|
-
# @param [Symbol] how type of the locator. Can be :title, :url or :hwnd.
|
98
|
-
# @param [Symbol] what value of the locator. Can be {String}, {Regexp} or {Fixnum}
|
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).
|
103
|
-
def attach(how, what)
|
104
|
-
ie = new true # don't create window
|
105
|
-
ie._attach_init(how, what)
|
106
|
-
ie
|
107
|
-
end
|
108
|
-
|
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 [IE] 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
|
126
|
-
end
|
127
|
-
|
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
|
140
|
-
end
|
141
|
-
|
142
|
-
# @return [Array<String>] the IE browser version numbers split by "." in an Array.
|
143
|
-
def version_parts
|
144
|
-
version.split('.')
|
145
|
-
end
|
146
|
-
|
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
|
152
|
-
end
|
153
|
-
|
154
|
-
# Return an IE object that wraps the given window, typically obtained from
|
155
|
-
# Shell.Application.windows.
|
156
|
-
# @private
|
157
|
-
def bind(window)
|
158
|
-
ie = new true
|
159
|
-
ie.ie = window
|
160
|
-
ie.initialize_options
|
161
|
-
ie
|
162
|
-
end
|
163
|
-
|
164
|
-
# @private
|
165
|
-
def _find(how, what)
|
166
|
-
_find_all(how, what).first
|
167
|
-
end
|
168
|
-
|
169
|
-
# @private
|
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
|
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(IE.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(IE.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 is 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(IE#autoit) - use IE#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, IE.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 {IE} instance.
|
515
|
-
def add_checker(checker)
|
516
|
-
@error_checkers << checker
|
517
|
-
end
|
518
|
-
|
519
|
-
# Disable an error checker added via {#add_checker}.
|
520
|
-
#
|
521
|
-
# @param [Proc] checker Proc object to be removed from error checkers.
|
522
|
-
def disable_checker(checker)
|
523
|
-
@error_checkers.delete(checker)
|
524
|
-
end
|
525
|
-
|
526
|
-
# Gives focus to the window frame.
|
527
|
-
def focus
|
528
|
-
active_element = document.activeElement
|
529
|
-
active_element.blur if active_element && active_element.tagName != "BODY"
|
530
|
-
document.focus
|
531
|
-
end
|
532
|
-
|
533
|
-
# @private
|
534
|
-
def attach_command
|
535
|
-
"Watir::IE.attach(:hwnd, #{hwnd})"
|
536
|
-
end
|
537
|
-
|
538
|
-
# @private
|
539
|
-
def _new_window_init
|
540
|
-
create_browser_window
|
541
|
-
initialize_options
|
542
|
-
goto 'about:blank' # this avoids numerous problems caused by lack of a document
|
543
|
-
end
|
544
|
-
|
545
|
-
# @private
|
546
|
-
def _new_process_init
|
547
|
-
iep = Process.start
|
548
|
-
@ie = iep.window
|
549
|
-
@process_id = iep.process_id
|
550
|
-
initialize_options
|
551
|
-
goto 'about:blank'
|
552
|
-
end
|
553
|
-
|
554
|
-
# this method is used internally to attach to an existing window
|
555
|
-
# @private
|
556
|
-
def _attach_init how, what
|
557
|
-
attach_browser_window how, what
|
558
|
-
initialize_options
|
559
|
-
wait
|
560
|
-
end
|
561
|
-
|
562
|
-
# @private
|
563
|
-
def initialize_options
|
564
|
-
self.visible = IE.visible
|
565
|
-
self.speed = IE.speed
|
566
|
-
|
567
|
-
@ole_object = nil
|
568
|
-
@page_container = self
|
569
|
-
@error_checkers = []
|
570
|
-
@active_object_highlight_color = HIGHLIGHT_COLOR
|
571
|
-
@url_list = []
|
572
|
-
end
|
573
|
-
|
574
|
-
#
|
575
|
-
# Synchronization
|
576
|
-
#
|
577
|
-
|
578
|
-
# Block execution until the page has loaded.
|
579
|
-
#
|
580
|
-
# Will raise Timeout::Error if page hasn't been loaded within 5 minutes.
|
581
|
-
# Note: This code needs to be prepared for the ie object to be closed at
|
582
|
-
# any moment!
|
583
|
-
#
|
584
|
-
# @private
|
585
|
-
def wait(no_sleep=false)
|
586
|
-
@xml_parser_doc = nil
|
587
|
-
@down_load_time = 0.0
|
588
|
-
interval = 0.05
|
589
|
-
start_load_time = ::Time.now
|
590
|
-
|
591
|
-
Timeout::timeout(5*60) do
|
592
|
-
begin
|
593
|
-
while @ie.busy
|
594
|
-
sleep interval
|
595
|
-
end
|
596
|
-
|
597
|
-
until READYSTATES.has_value?(@ie.readyState)
|
598
|
-
sleep interval
|
599
|
-
end
|
600
|
-
|
601
|
-
until @ie.document
|
602
|
-
sleep interval
|
603
|
-
end
|
604
|
-
|
605
|
-
documents_to_wait_for = [@ie.document]
|
606
|
-
rescue WIN32OLERuntimeError # IE window must have been closed
|
607
|
-
@down_load_time = ::Time.now - start_load_time
|
608
|
-
return @down_load_time
|
609
|
-
end
|
610
|
-
|
611
|
-
while doc = documents_to_wait_for.shift
|
612
|
-
begin
|
613
|
-
until READYSTATES.has_key?(doc.readyState.to_sym)
|
614
|
-
sleep interval
|
615
|
-
end
|
616
|
-
@url_list << doc.location.href unless @url_list.include?(doc.location.href)
|
617
|
-
doc.frames.length.times do |n|
|
618
|
-
begin
|
619
|
-
documents_to_wait_for << doc.frames[n.to_s].document
|
620
|
-
rescue WIN32OLERuntimeError, NoMethodError
|
621
|
-
end
|
622
|
-
end
|
623
|
-
rescue WIN32OLERuntimeError
|
624
|
-
end
|
625
|
-
end
|
626
|
-
end
|
627
|
-
|
628
|
-
@down_load_time = ::Time.now - start_load_time
|
629
|
-
run_error_checks
|
630
|
-
sleep @pause_after_wait unless no_sleep
|
631
|
-
@down_load_time
|
632
|
-
end
|
633
|
-
|
634
|
-
# Error checkers
|
635
|
-
|
636
|
-
# Run the predefined error checks.
|
637
|
-
#
|
638
|
-
# @private
|
639
|
-
def run_error_checks
|
640
|
-
@error_checkers.each { |e| e.call(self) }
|
641
|
-
end
|
642
|
-
|
643
|
-
private
|
644
|
-
|
645
|
-
def create_browser_window
|
646
|
-
@ie = WIN32OLE.new('InternetExplorer.Application')
|
647
|
-
end
|
648
|
-
|
649
|
-
def attach_browser_window how, what
|
650
|
-
ieTemp = nil
|
651
|
-
begin
|
652
|
-
Wait.until(IE.attach_timeout) do
|
653
|
-
ieTemp = IE._find how, what
|
654
|
-
end
|
655
|
-
rescue Wait::TimeoutError
|
656
|
-
raise NoMatchingWindowFoundException,
|
657
|
-
"Unable to locate a window with #{how} of #{what}"
|
658
|
-
end
|
659
|
-
@ie = ieTemp
|
660
|
-
end
|
661
|
-
|
662
|
-
|
663
|
-
end # class IE
|
664
|
-
end
|