watir-classic 3.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.
- data/CHANGES +721 -0
- data/LICENSE +34 -0
- data/README.rdoc +78 -0
- data/VERSION +1 -0
- data/bin/watir-console +5 -0
- data/lib/watir-classic.rb +14 -0
- data/lib/watir-classic/IEDialog/Release/IEDialog.dll +0 -0
- data/lib/watir-classic/assertions.rb +44 -0
- data/lib/watir-classic/browser.rb +149 -0
- data/lib/watir-classic/browsers.rb +7 -0
- data/lib/watir-classic/close_all.rb +31 -0
- data/lib/watir-classic/container.rb +110 -0
- data/lib/watir-classic/contrib/enabled_popup.rb +21 -0
- data/lib/watir-classic/contrib/ie-new-process.rb +27 -0
- data/lib/watir-classic/contrib/page_checker.rb +29 -0
- data/lib/watir-classic/cookies.rb +80 -0
- data/lib/watir-classic/core.rb +43 -0
- data/lib/watir-classic/dialogs/file_field.rb +34 -0
- data/lib/watir-classic/dialogs/javascript.rb +43 -0
- data/lib/watir-classic/drag_and_drop_helper.rb +68 -0
- data/lib/watir-classic/element.rb +438 -0
- data/lib/watir-classic/element_collection.rb +109 -0
- data/lib/watir-classic/element_extensions.rb +69 -0
- data/lib/watir-classic/exceptions.rb +50 -0
- data/lib/watir-classic/form.rb +96 -0
- data/lib/watir-classic/frame.rb +47 -0
- data/lib/watir-classic/ie-class.rb +767 -0
- data/lib/watir-classic/ie-process.rb +47 -0
- data/lib/watir-classic/ie.rb +20 -0
- data/lib/watir-classic/image.rb +111 -0
- data/lib/watir-classic/input_elements.rb +480 -0
- data/lib/watir-classic/irb-history.rb +31 -0
- data/lib/watir-classic/link.rb +46 -0
- data/lib/watir-classic/locator.rb +243 -0
- data/lib/watir-classic/logger.rb +19 -0
- data/lib/watir-classic/matches.rb +23 -0
- data/lib/watir-classic/modal_dialog.rb +72 -0
- data/lib/watir-classic/module.rb +12 -0
- data/lib/watir-classic/non_control_elements.rb +114 -0
- data/lib/watir-classic/options.rb +56 -0
- data/lib/watir-classic/page-container.rb +114 -0
- data/lib/watir-classic/process.rb +20 -0
- data/lib/watir-classic/screen_capture.rb +115 -0
- data/lib/watir-classic/supported_elements.rb +172 -0
- data/lib/watir-classic/table.rb +224 -0
- data/lib/watir-classic/testcase.rb +97 -0
- data/lib/watir-classic/util.rb +35 -0
- data/lib/watir-classic/version.rb +4 -0
- data/lib/watir-classic/wait.rb +41 -0
- data/lib/watir-classic/wait_helper.rb +12 -0
- data/lib/watir-classic/waiter.rb +98 -0
- data/lib/watir-classic/win32.rb +40 -0
- data/lib/watir-classic/win32ole.rb +16 -0
- data/lib/watir-classic/win32ole/1.8.7/win32ole.so +0 -0
- data/lib/watir-classic/win32ole/1.9.3/win32ole.so +0 -0
- data/lib/watir-classic/window.rb +68 -0
- data/lib/watir-classic/xpath_locator.rb +52 -0
- data/rakefile.rb +54 -0
- data/unittests/all_tests.rb +10 -0
- data/unittests/buttons_xpath_test.rb +68 -0
- data/unittests/checkbox_test.rb +163 -0
- data/unittests/checkbox_xpath_test.rb +106 -0
- data/unittests/click_no_wait_test.rb +23 -0
- data/unittests/close_all_test.rb +17 -0
- data/unittests/core_tests.rb +17 -0
- data/unittests/css_selector_test.rb +44 -0
- data/unittests/css_test.rb +38 -0
- data/unittests/dialog_test.rb +64 -0
- data/unittests/div2_xpath_test.rb +21 -0
- data/unittests/div_test.rb +170 -0
- data/unittests/div_xpath_test.rb +95 -0
- data/unittests/document_standards.rb +63 -0
- data/unittests/element_collection_indexes_test.rb +57 -0
- data/unittests/element_collections_test.rb +100 -0
- data/unittests/element_test.rb +47 -0
- data/unittests/errorchecker_test.rb +31 -0
- data/unittests/filefield_test.rb +43 -0
- data/unittests/filefield_xpath_test.rb +35 -0
- data/unittests/form_test.rb +282 -0
- data/unittests/form_xpath_test.rb +254 -0
- data/unittests/frame_test.rb +165 -0
- data/unittests/google_form_test.rb +15 -0
- data/unittests/html/JavascriptClick.html +39 -0
- data/unittests/html/blankpage.html +11 -0
- data/unittests/html/buttons1.html +40 -0
- data/unittests/html/checkboxes1.html +89 -0
- data/unittests/html/click_no_wait.html +14 -0
- data/unittests/html/complex_table.html +35 -0
- data/unittests/html/cssTest.html +42 -0
- data/unittests/html/depot_store.html +59 -0
- data/unittests/html/div.html +92 -0
- data/unittests/html/div_xml.html +21 -0
- data/unittests/html/fileupload.html +44 -0
- data/unittests/html/formTest1.html +38 -0
- data/unittests/html/forms2.html +44 -0
- data/unittests/html/forms3.html +131 -0
- data/unittests/html/forms4.html +26 -0
- data/unittests/html/frame_buttons.html +4 -0
- data/unittests/html/frame_links.html +4 -0
- data/unittests/html/frame_multi.html +5 -0
- data/unittests/html/google_india.html +119 -0
- data/unittests/html/ie7_document_standards.html +9 -0
- data/unittests/html/ie8_document_standards.html +9 -0
- data/unittests/html/ie9_document_standards.html +9 -0
- data/unittests/html/iframe.html +3 -0
- data/unittests/html/iframeTest.html +17 -0
- data/unittests/html/iframeTest1.html +7 -0
- data/unittests/html/iframeTest2.html +5 -0
- data/unittests/html/images/1.gif +0 -0
- data/unittests/html/images/2.GIF +0 -0
- data/unittests/html/images/3.GIF +0 -0
- data/unittests/html/images/button.jpg +0 -0
- data/unittests/html/images/circle.jpg +0 -0
- data/unittests/html/images/map.GIF +0 -0
- data/unittests/html/images/map2.gif +0 -0
- data/unittests/html/images/minus.GIF +0 -0
- data/unittests/html/images/originaltriangle.jpg +0 -0
- data/unittests/html/images/plus.gif +0 -0
- data/unittests/html/images/square.jpg +0 -0
- data/unittests/html/images/triangle.jpg +0 -0
- data/unittests/html/images1.html +65 -0
- data/unittests/html/javascriptevents.html +33 -0
- data/unittests/html/link_pass.html +11 -0
- data/unittests/html/links1.html +37 -0
- data/unittests/html/links2.html +11 -0
- data/unittests/html/links_multi.html +12 -0
- data/unittests/html/list_matters.html +720 -0
- data/unittests/html/lists.html +18 -0
- data/unittests/html/map_test.html +30 -0
- data/unittests/html/modal_dialog.html +10 -0
- data/unittests/html/modal_dialog_launcher.html +12 -0
- data/unittests/html/multiple_specifiers.html +64 -0
- data/unittests/html/nestedFrames.html +6 -0
- data/unittests/html/new_browser.html +17 -0
- data/unittests/html/pass.html +13 -0
- data/unittests/html/popups1.html +59 -0
- data/unittests/html/pre.html +29 -0
- data/unittests/html/quirks_document_standards.html +8 -0
- data/unittests/html/radioButtons1.html +71 -0
- data/unittests/html/select_tealeaf.html +54 -0
- data/unittests/html/selectboxes1.html +52 -0
- data/unittests/html/simple_table.html +25 -0
- data/unittests/html/simple_table_buttons.html +104 -0
- data/unittests/html/simple_table_columns.html +75 -0
- data/unittests/html/table1.html +179 -0
- data/unittests/html/tableCell_using_xpath.html +19 -0
- data/unittests/html/table_and_tablerow_to_a.html +174 -0
- data/unittests/html/textarea.html +30 -0
- data/unittests/html/textfields1.html +100 -0
- data/unittests/html/textsearch.html +44 -0
- data/unittests/html/wallofcheckboxes.html +1003 -0
- data/unittests/html/xpath_nbsp.html +11 -0
- data/unittests/html/zeroindex.html +11 -0
- data/unittests/ie_exists_test.rb +16 -0
- data/unittests/ie_mock.rb +94 -0
- data/unittests/ie_test.rb +54 -0
- data/unittests/images_test.rb +156 -0
- data/unittests/images_xpath_test.rb +90 -0
- data/unittests/index_specifier_test.rb +31 -0
- data/unittests/js_events_test.rb +31 -0
- data/unittests/links_multi_test.rb +34 -0
- data/unittests/links_test.rb +131 -0
- data/unittests/links_xpath_test.rb +38 -0
- data/unittests/lists_test.rb +23 -0
- data/unittests/map_test.rb +98 -0
- data/unittests/minmax_test.rb +37 -0
- data/unittests/navigate_test.rb +38 -0
- data/unittests/nbsp_xpath_test.rb +16 -0
- data/unittests/no_wait_test.rb +28 -0
- data/unittests/non_core_tests.rb +12 -0
- data/unittests/other/all_tests_concurrent.rb +57 -0
- data/unittests/other/navigate_exception_test.rb +24 -0
- data/unittests/other/rexml_unit_test.rb +27 -0
- data/unittests/other/screen_capture_test.rb +53 -0
- data/unittests/other/testcase_method_order_test.rb +36 -0
- data/unittests/other/testcase_verify_test.rb +25 -0
- data/unittests/other/wait_until_test.rb +102 -0
- data/unittests/pagecontainstext_test.rb +69 -0
- data/unittests/parent_child_test.rb +27 -0
- data/unittests/perf_test.rb +20 -0
- data/unittests/pre_test.rb +49 -0
- data/unittests/radios_test.rb +181 -0
- data/unittests/radios_xpath_test.rb +100 -0
- data/unittests/security_setting_test.rb +24 -0
- data/unittests/selectbox_test.rb +144 -0
- data/unittests/selectbox_xpath_test.rb +102 -0
- data/unittests/setup.rb +69 -0
- data/unittests/speed_settings_test.rb +67 -0
- data/unittests/table_cell_using_xpath_test.rb +34 -0
- data/unittests/table_test.rb +296 -0
- data/unittests/table_xpath_test.rb +109 -0
- data/unittests/test_tests.rb +9 -0
- data/unittests/textarea_test.rb +92 -0
- data/unittests/textarea_xpath_test.rb +77 -0
- data/unittests/textfield_for_ch_char_test.rb +32 -0
- data/unittests/textfields_test.rb +184 -0
- data/unittests/textfields_xpath_test.rb +110 -0
- data/unittests/version_test.rb +15 -0
- data/unittests/win32ole_so_test.rb +35 -0
- data/unittests/window_tests.rb +10 -0
- data/unittests/windows/attach_to_existing_window_test.rb +52 -0
- data/unittests/windows/attach_to_new_window_test.rb +74 -0
- data/unittests/windows/close_window_test.rb +20 -0
- data/unittests/windows/frame_links_test.rb +23 -0
- data/unittests/windows/ie-each_test.rb +46 -0
- data/unittests/windows/modal_dialog_test.rb +95 -0
- data/unittests/windows/new_process_test.rb +24 -0
- data/unittests/windows/new_test.rb +58 -0
- data/unittests/windows/open_close_test.rb +19 -0
- data/unittests/windows/send_keys_test.rb +26 -0
- data/unittests/xpath_tests.rb +11 -0
- data/watir-rdoc.rb +7 -0
- metadata +370 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
module Watir
|
|
2
|
+
# this class is the super class for the iterator classes (buttons, links, spans etc
|
|
3
|
+
# it would normally only be accessed by the iterator methods (spans, links etc) of IE
|
|
4
|
+
class ElementCollection
|
|
5
|
+
include Enumerable
|
|
6
|
+
|
|
7
|
+
# Super class for all the iterator classes
|
|
8
|
+
# * container - an instance of an IE object
|
|
9
|
+
def initialize(container, specifiers)
|
|
10
|
+
if specifiers[:index]
|
|
11
|
+
raise Exception::MissingWayOfFindingObjectException,
|
|
12
|
+
"#{self.class} does not support attribute :index in #{specifiers.inspect}"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
@container = container
|
|
16
|
+
@specifiers = specifiers
|
|
17
|
+
@page_container = container.page_container
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def length
|
|
21
|
+
count = 0
|
|
22
|
+
each {|element| count += 1 }
|
|
23
|
+
count
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
alias_method :size, :length
|
|
27
|
+
|
|
28
|
+
# iterate through each of the elements in the collection in turn
|
|
29
|
+
def each
|
|
30
|
+
@container.locator_for(TaggedElementLocator, @specifiers, element_class).each {|element| yield element}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# allows access to a specific item in the collection
|
|
34
|
+
def [](n)
|
|
35
|
+
number = n - Watir::IE.base_index
|
|
36
|
+
offset = Watir::IE.zero_based_indexing ? (length - 1) : length
|
|
37
|
+
non_existing_element = element_class.new(@container, @specifiers.merge(:index => n))
|
|
38
|
+
def non_existing_element.locate; nil end
|
|
39
|
+
iterator_object(number) || non_existing_element
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def first
|
|
43
|
+
iterator_object(0)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def last
|
|
47
|
+
iterator_object(length - 1)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def to_s
|
|
51
|
+
map { |e| e.to_s }.join("\n")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def inspect
|
|
55
|
+
'#<%s:0x%x length=%s container=%s>' % [self.class, hash*2, length.inspect, @container.inspect]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def iterator_object(i)
|
|
61
|
+
count = 0
|
|
62
|
+
each do |e|
|
|
63
|
+
return e if (i >= 0 && count == i) || (i < 0 && count == length + i)
|
|
64
|
+
count += 1
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def element_class
|
|
69
|
+
Watir.const_get self.class.name.split("::").last.scan(/(.*)Collection/).flatten.first
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
class TableElementCollection < ElementCollection
|
|
75
|
+
def initialize(container, specifiers, ole_collection=nil)
|
|
76
|
+
super container, specifiers
|
|
77
|
+
@ole_collection = ole_collection
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def each
|
|
81
|
+
if @ole_collection
|
|
82
|
+
elements = []
|
|
83
|
+
@ole_collection.each {|element| elements << element_class.new(@container, :ole_object => element)}
|
|
84
|
+
super do |element|
|
|
85
|
+
yield element if elements.include?(element)
|
|
86
|
+
end
|
|
87
|
+
else
|
|
88
|
+
super
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
class TableRowCollection < TableElementCollection; end
|
|
94
|
+
|
|
95
|
+
class TableCellCollection < TableElementCollection; end
|
|
96
|
+
|
|
97
|
+
class InputElementCollection < ElementCollection
|
|
98
|
+
def each
|
|
99
|
+
@container.locator_for(InputElementLocator, @specifiers, element_class).each {|element| yield element}
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
class HTMLElementCollection < ElementCollection
|
|
104
|
+
def each
|
|
105
|
+
@container.locator_for(TaggedElementLocator, @specifiers, Element).each { |element| yield element }
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Watir
|
|
4
|
+
# This assumes that Element#visible? is defined
|
|
5
|
+
module ElementExtensions
|
|
6
|
+
|
|
7
|
+
#
|
|
8
|
+
# Wraps a {Celerity,Watir}::Element so that any subsequent method calls are
|
|
9
|
+
# put on hold until the element is present on the page.
|
|
10
|
+
#
|
|
11
|
+
|
|
12
|
+
class WhenPresentDecorator
|
|
13
|
+
def initialize(element, timeout)
|
|
14
|
+
@element = element
|
|
15
|
+
@timeout = timeout
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def method_missing(m, *args, &block)
|
|
19
|
+
Watir::Wait.until(@timeout) { @element.present? }
|
|
20
|
+
@element.send(m, *args, &block)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Returns element id
|
|
24
|
+
def id
|
|
25
|
+
Watir::Wait.until(@timeout) { @element.present? }
|
|
26
|
+
@element.id
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
#
|
|
32
|
+
# Returns true if the element exists and is visible on the page
|
|
33
|
+
#
|
|
34
|
+
|
|
35
|
+
def present?
|
|
36
|
+
exists? && visible? rescue false
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
#
|
|
40
|
+
# Waits until the element is present.
|
|
41
|
+
#
|
|
42
|
+
# Optional argument:
|
|
43
|
+
#
|
|
44
|
+
# timeout - seconds to wait before timing out (default: 60)
|
|
45
|
+
#
|
|
46
|
+
# browser.button(:id, 'foo').when_present.click
|
|
47
|
+
# browser.div(:id, 'bar').when_present { |div| ... }
|
|
48
|
+
# browser.p(:id, 'baz').when_present(60).text
|
|
49
|
+
#
|
|
50
|
+
|
|
51
|
+
def when_present(timeout = 60)
|
|
52
|
+
if block_given?
|
|
53
|
+
Watir::Wait.until(timeout) { self.present? }
|
|
54
|
+
yield self
|
|
55
|
+
else
|
|
56
|
+
return WhenPresentDecorator.new(self, timeout)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def wait_until_present(timeout = 60)
|
|
61
|
+
Watir::Wait.until(timeout) { self.present? }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def wait_while_present(timeout = 60)
|
|
65
|
+
Watir::Wait.while(timeout) { self.present? }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end # module ElementExtensions
|
|
69
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Watir
|
|
2
|
+
module Exception
|
|
3
|
+
|
|
4
|
+
# Root class for all Watir Exceptions
|
|
5
|
+
class WatirException < RuntimeError
|
|
6
|
+
def initialize(message="")
|
|
7
|
+
super(message)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# This exception is raised if an attempt is made to access an object that doesn't exist
|
|
12
|
+
class UnknownObjectException < WatirException; end
|
|
13
|
+
# This exception is raised if an attempt is made to access an object that is in a disabled state
|
|
14
|
+
class ObjectDisabledException < WatirException; end
|
|
15
|
+
# This exception is raised if an attempt is made to access a frame that cannot be found
|
|
16
|
+
class UnknownFrameException < WatirException; end
|
|
17
|
+
# This exception is raised if an attempt is made to access a frame that IE is denying access to
|
|
18
|
+
class FrameAccessDeniedException < WatirException; end
|
|
19
|
+
# This exception is raised if an attempt is made to access a form that cannot be found
|
|
20
|
+
class UnknownFormException< WatirException; end
|
|
21
|
+
# This exception is raised if an attempt is made to access an object that is in a read only state
|
|
22
|
+
class ObjectReadOnlyException < WatirException; end
|
|
23
|
+
# This exception is raised if an attempt is made to access an object when the specified value cannot be found
|
|
24
|
+
class NoValueFoundException < WatirException; end
|
|
25
|
+
# This exception gets raised if part of finding an object is missing
|
|
26
|
+
class MissingWayOfFindingObjectException < WatirException; end
|
|
27
|
+
# this exception is raised if an attempt is made to access a table cell that doesnt exist
|
|
28
|
+
class UnknownCellException < WatirException; end
|
|
29
|
+
# This exception is raised if the window cannot be found
|
|
30
|
+
class NoMatchingWindowFoundException < WatirException; end
|
|
31
|
+
# This exception is raised if an attemp is made to acces the status bar of the browser when it doesnt exist
|
|
32
|
+
class NoStatusBarException < WatirException; end
|
|
33
|
+
# This exception is raised if an http error, such as a 404, 500 etc is encountered while navigating
|
|
34
|
+
class NavigationException < WatirException; end
|
|
35
|
+
# This exception is raised when an event is fired that we don't know how to handle
|
|
36
|
+
class UnhandledEventException < WatirException; end
|
|
37
|
+
# This exception is raised if a timeout is exceeded
|
|
38
|
+
class TimeOutException < WatirException
|
|
39
|
+
def initialize(duration, timeout)
|
|
40
|
+
@duration, @timeout = duration, timeout
|
|
41
|
+
end
|
|
42
|
+
attr_reader :duration, :timeout
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Return an error message for when unable to locate the element
|
|
46
|
+
def self.message_for_unable_to_locate(specifiers)
|
|
47
|
+
"Unable to locate element, using #{specifiers.inspect}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
module Watir
|
|
2
|
+
|
|
3
|
+
class Form < Element
|
|
4
|
+
def initialize(container, specifiers)
|
|
5
|
+
super
|
|
6
|
+
copy_test_config container
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
attr_ole :action
|
|
10
|
+
|
|
11
|
+
def name
|
|
12
|
+
assert_exists
|
|
13
|
+
name = ole_object.getAttributeNode('name')
|
|
14
|
+
name ? name.value : ''
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def form_method
|
|
18
|
+
assert_exists
|
|
19
|
+
ole_object.invoke('method')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def method(arg = nil)
|
|
23
|
+
if arg.nil?
|
|
24
|
+
form_method
|
|
25
|
+
else
|
|
26
|
+
super
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def locate
|
|
31
|
+
@o = @container.locator_for(FormLocator, @specifiers, self.class).locate
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Submit the data -- equivalent to pressing Enter or Return to submit a form.
|
|
35
|
+
def submit
|
|
36
|
+
assert_exists
|
|
37
|
+
@o.submit(0) if dispatch_event "onSubmit"
|
|
38
|
+
@container.wait
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def __ole_inner_elements
|
|
42
|
+
assert_exists
|
|
43
|
+
@o.elements
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# This method is responsible for setting and clearing the colored highlighting on the specified form.
|
|
47
|
+
# use :set to set the highlight
|
|
48
|
+
# :clear to clear the highlight
|
|
49
|
+
def highlight(set_or_clear, element, count)
|
|
50
|
+
if set_or_clear == :set
|
|
51
|
+
begin
|
|
52
|
+
original_color = element.style.backgroundColor
|
|
53
|
+
original_color = "" if original_color==nil
|
|
54
|
+
element.style.backgroundColor = activeObjectHighLightColor
|
|
55
|
+
rescue => e
|
|
56
|
+
puts e
|
|
57
|
+
puts e.backtrace.join("\n")
|
|
58
|
+
original_color = ""
|
|
59
|
+
end
|
|
60
|
+
@original_styles[count] = original_color
|
|
61
|
+
else
|
|
62
|
+
begin
|
|
63
|
+
element.style.backgroundColor = @original_styles[ count]
|
|
64
|
+
rescue => e
|
|
65
|
+
puts e
|
|
66
|
+
# we could be here for a number of reasons...
|
|
67
|
+
ensure
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
private :highlight
|
|
72
|
+
|
|
73
|
+
# causes the object to flash. Normally used in IRB when creating scripts
|
|
74
|
+
# Default is 10
|
|
75
|
+
def flash number=10
|
|
76
|
+
assert_exists
|
|
77
|
+
@original_styles = {}
|
|
78
|
+
number.times do
|
|
79
|
+
count = 0
|
|
80
|
+
@o.elements.each do |element|
|
|
81
|
+
highlight(:set, element, count)
|
|
82
|
+
count += 1
|
|
83
|
+
end
|
|
84
|
+
sleep 0.05
|
|
85
|
+
count = 0
|
|
86
|
+
@o.elements.each do |element|
|
|
87
|
+
highlight(:clear, element, count)
|
|
88
|
+
count += 1
|
|
89
|
+
end
|
|
90
|
+
sleep 0.05
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end # class Form
|
|
95
|
+
|
|
96
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Watir
|
|
2
|
+
class Frame < Element
|
|
3
|
+
include PageContainer
|
|
4
|
+
attr_accessor :document
|
|
5
|
+
|
|
6
|
+
attr_ole :name
|
|
7
|
+
attr_ole :src
|
|
8
|
+
|
|
9
|
+
def initialize(container, specifiers)
|
|
10
|
+
super
|
|
11
|
+
copy_test_config container
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Find the frame denoted by specifiers in the container and return its ole_object
|
|
15
|
+
def locate
|
|
16
|
+
frame, document = @container.locator_for(FrameLocator, @specifiers, self.class).locate
|
|
17
|
+
if frame && document
|
|
18
|
+
@o = frame
|
|
19
|
+
begin
|
|
20
|
+
@document = document.document
|
|
21
|
+
rescue WIN32OLERuntimeError => e
|
|
22
|
+
# This frame's content is not directly accessible but let the
|
|
23
|
+
# user continue so they can access the frame properties
|
|
24
|
+
raise e unless e.message =~ /Access is denied/
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def __ole_inner_elements
|
|
30
|
+
document.body.all
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def document
|
|
34
|
+
assert_exists
|
|
35
|
+
if @document
|
|
36
|
+
@document
|
|
37
|
+
else
|
|
38
|
+
raise FrameAccessDeniedException, "IE will not allow access to this frame for security reasons. You can work around this with ie.goto(frame.src)"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def attach_command
|
|
43
|
+
@container.page_container.attach_command + ".frame(#{@specifiers.inspect})".gsub('"','\'')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,767 @@
|
|
|
1
|
+
module Watir
|
|
2
|
+
class IE
|
|
3
|
+
include WaitHelper
|
|
4
|
+
include Exception
|
|
5
|
+
include Container
|
|
6
|
+
include PageContainer
|
|
7
|
+
|
|
8
|
+
# Maximum number of seconds to wait when attaching to a window
|
|
9
|
+
@@attach_timeout = 2.0 # default value
|
|
10
|
+
def self.attach_timeout
|
|
11
|
+
@@attach_timeout
|
|
12
|
+
end
|
|
13
|
+
def self.attach_timeout=(timeout)
|
|
14
|
+
@@attach_timeout = timeout
|
|
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 self.options
|
|
20
|
+
{:speed => self.speed, :visible => self.visible, :attach_timeout => self.attach_timeout, :zero_based_indexing => self.zero_based_indexing}
|
|
21
|
+
end
|
|
22
|
+
# set values for options used when creating new instances of IE.
|
|
23
|
+
def self.set_options options
|
|
24
|
+
options.each do |name, value|
|
|
25
|
+
send "#{name}=", value
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
# The globals $FAST_SPEED and $HIDE_IE are checked both at initialization
|
|
29
|
+
# and later, because they
|
|
30
|
+
# might be set after initialization. Setting them beforehand (e.g. from
|
|
31
|
+
# the command line) will affect the class, otherwise it is only a temporary
|
|
32
|
+
# effect
|
|
33
|
+
@@speed = $FAST_SPEED ? :fast : :slow
|
|
34
|
+
def self.speed
|
|
35
|
+
return :fast if $FAST_SPEED
|
|
36
|
+
@@speed
|
|
37
|
+
end
|
|
38
|
+
def self.speed= x
|
|
39
|
+
$FAST_SPEED = nil
|
|
40
|
+
@@speed = x
|
|
41
|
+
end
|
|
42
|
+
@@visible = $HIDE_IE ? false : true
|
|
43
|
+
def self.visible
|
|
44
|
+
return false if $HIDE_IE
|
|
45
|
+
@@visible
|
|
46
|
+
end
|
|
47
|
+
def self.visible= x
|
|
48
|
+
$HIDE_IE = nil
|
|
49
|
+
@@visible = x
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
@@zero_based_indexing = true
|
|
53
|
+
def self.zero_based_indexing= enabled
|
|
54
|
+
@@zero_based_indexing = enabled
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.zero_based_indexing
|
|
58
|
+
@@zero_based_indexing
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def self.base_index
|
|
62
|
+
self.zero_based_indexing ? 0 : 1
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Used internally to determine when IE has finished loading a page
|
|
66
|
+
READYSTATES = {:complete => 4}
|
|
67
|
+
|
|
68
|
+
# The default color for highlighting objects as they are accessed.
|
|
69
|
+
HIGHLIGHT_COLOR = 'yellow'
|
|
70
|
+
|
|
71
|
+
# The time, in seconds, it took for the new page to load after executing the
|
|
72
|
+
# the last command
|
|
73
|
+
attr_reader :down_load_time
|
|
74
|
+
|
|
75
|
+
# the OLE Internet Explorer object
|
|
76
|
+
attr_accessor :ie
|
|
77
|
+
# access to the logger object
|
|
78
|
+
attr_accessor :logger
|
|
79
|
+
|
|
80
|
+
# this contains the list of unique urls that have been visited
|
|
81
|
+
attr_reader :url_list
|
|
82
|
+
|
|
83
|
+
# Create a new IE window. Works just like IE.new in Watir 1.4.
|
|
84
|
+
def self.new_window
|
|
85
|
+
ie = new true
|
|
86
|
+
ie._new_window_init
|
|
87
|
+
ie
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Create an IE browser.
|
|
91
|
+
def initialize suppress_new_window=nil
|
|
92
|
+
_new_window_init unless suppress_new_window
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def _new_window_init
|
|
96
|
+
create_browser_window
|
|
97
|
+
initialize_options
|
|
98
|
+
goto 'about:blank' # this avoids numerous problems caused by lack of a document
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Create a new IE Window, starting at the specified url.
|
|
102
|
+
# If no url is given, start empty.
|
|
103
|
+
def self.start url=nil
|
|
104
|
+
start_window url
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Create a new IE window, starting at the specified url.
|
|
108
|
+
# If no url is given, start empty. Works like IE.start in Watir 1.4.
|
|
109
|
+
def self.start_window url=nil
|
|
110
|
+
ie = new_window
|
|
111
|
+
ie.goto url if url
|
|
112
|
+
ie
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Create a new IE window in a new process.
|
|
116
|
+
# This method will not work when
|
|
117
|
+
# Watir/Ruby is run under a service (instead of a user).
|
|
118
|
+
def self.new_process
|
|
119
|
+
ie = new true
|
|
120
|
+
ie._new_process_init
|
|
121
|
+
ie
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def _new_process_init
|
|
125
|
+
iep = Process.start
|
|
126
|
+
@ie = iep.window
|
|
127
|
+
@process_id = iep.process_id
|
|
128
|
+
initialize_options
|
|
129
|
+
goto 'about:blank'
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Create a new IE window in a new process, starting at the specified URL.
|
|
133
|
+
# Same as IE.start.
|
|
134
|
+
def self.start_process url=nil
|
|
135
|
+
ie = new_process
|
|
136
|
+
ie.goto url if url
|
|
137
|
+
ie
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Return a Watir::IE object for an existing IE window. Window can be
|
|
141
|
+
# referenced by url, title, or window handle.
|
|
142
|
+
# Second argument can be either a string or a regular expression in the
|
|
143
|
+
# case of of :url or :title.
|
|
144
|
+
# IE.attach(:url, 'http://www.google.com')
|
|
145
|
+
# IE.attach(:title, 'Google')
|
|
146
|
+
# IE.attach(:hwnd, 528140)
|
|
147
|
+
# This method will not work when
|
|
148
|
+
# Watir/Ruby is run under a service (instead of a user).
|
|
149
|
+
def self.attach how, what
|
|
150
|
+
ie = new true # don't create window
|
|
151
|
+
ie._attach_init(how, what)
|
|
152
|
+
ie
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# this method is used internally to attach to an existing window
|
|
156
|
+
def _attach_init how, what
|
|
157
|
+
attach_browser_window how, what
|
|
158
|
+
initialize_options
|
|
159
|
+
wait
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Return an IE object that wraps the given window, typically obtained from
|
|
163
|
+
# Shell.Application.windows.
|
|
164
|
+
def self.bind window
|
|
165
|
+
ie = new true
|
|
166
|
+
ie.ie = window
|
|
167
|
+
ie.initialize_options
|
|
168
|
+
ie
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def initialize_options
|
|
172
|
+
self.visible = IE.visible
|
|
173
|
+
self.speed = IE.speed
|
|
174
|
+
|
|
175
|
+
@ole_object = nil
|
|
176
|
+
@page_container = self
|
|
177
|
+
@error_checkers = []
|
|
178
|
+
@activeObjectHighLightColor = HIGHLIGHT_COLOR
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@logger = DefaultLogger.new
|
|
182
|
+
@url_list = []
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Specifies the speed that commands will be executed at. Choices are:
|
|
186
|
+
# * :slow (default)
|
|
187
|
+
# * :fast
|
|
188
|
+
# * :zippy
|
|
189
|
+
# With IE#speed= :zippy, text fields will be entered at once, instead of
|
|
190
|
+
# character by character (default).
|
|
191
|
+
def speed= how_fast
|
|
192
|
+
case how_fast
|
|
193
|
+
when :zippy then
|
|
194
|
+
@typingspeed = 0
|
|
195
|
+
@pause_after_wait = 0.01
|
|
196
|
+
@type_keys = false
|
|
197
|
+
@speed = :fast
|
|
198
|
+
when :fast then
|
|
199
|
+
@typingspeed = 0
|
|
200
|
+
@pause_after_wait = 0.01
|
|
201
|
+
@type_keys = true
|
|
202
|
+
@speed = :fast
|
|
203
|
+
when :slow then
|
|
204
|
+
@typingspeed = 0.08
|
|
205
|
+
@pause_after_wait = 0.1
|
|
206
|
+
@type_keys = true
|
|
207
|
+
@speed = :slow
|
|
208
|
+
else
|
|
209
|
+
raise ArgumentError, "Invalid speed: #{how_fast}"
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def speed
|
|
214
|
+
return @speed if @speed == :slow
|
|
215
|
+
return @type_keys ? :fast : :zippy
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# deprecated: use speed = :fast instead
|
|
219
|
+
def set_fast_speed
|
|
220
|
+
self.speed = :fast
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# deprecated: use speed = :slow instead
|
|
224
|
+
def set_slow_speed
|
|
225
|
+
self.speed = :slow
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def visible
|
|
229
|
+
@ie.visible
|
|
230
|
+
end
|
|
231
|
+
def visible=(boolean)
|
|
232
|
+
@ie.visible = boolean if boolean != @ie.visible
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Yields successively to each IE window on the current desktop. Takes a block.
|
|
236
|
+
# This method will not work when
|
|
237
|
+
# Watir/Ruby is run under a service (instead of a user).
|
|
238
|
+
# Yields to the window and its hwnd.
|
|
239
|
+
def self.each
|
|
240
|
+
shell = WIN32OLE.new('Shell.Application')
|
|
241
|
+
ie_browsers = []
|
|
242
|
+
shell.Windows.each do |window|
|
|
243
|
+
next unless (window.path =~ /Internet Explorer/ rescue false)
|
|
244
|
+
next unless (hwnd = window.hwnd rescue false)
|
|
245
|
+
ie = IE.bind(window)
|
|
246
|
+
ie.hwnd = hwnd
|
|
247
|
+
ie_browsers << ie
|
|
248
|
+
end
|
|
249
|
+
ie_browsers.each do |ie|
|
|
250
|
+
yield ie
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def self.version
|
|
255
|
+
@ie_version ||= begin
|
|
256
|
+
require 'win32/registry'
|
|
257
|
+
::Win32::Registry::HKEY_LOCAL_MACHINE.open("SOFTWARE\\Microsoft\\Internet Explorer") do |ie_key|
|
|
258
|
+
ie_key.read('Version').last
|
|
259
|
+
end
|
|
260
|
+
# OR: ::WIN32OLE.new("WScript.Shell").RegRead("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Internet Explorer\\Version")
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def self.version_parts
|
|
265
|
+
version.split('.')
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# return internet explorer instance as specified. if none is found,
|
|
269
|
+
# return nil.
|
|
270
|
+
# arguments:
|
|
271
|
+
# :url, url -- the URL of the IE browser window
|
|
272
|
+
# :title, title -- the title of the browser page
|
|
273
|
+
# :hwnd, hwnd -- the window handle of the browser window.
|
|
274
|
+
# This method will not work when
|
|
275
|
+
# Watir/Ruby is run under a service (instead of a user).
|
|
276
|
+
def self.find(how, what)
|
|
277
|
+
ie_ole = IE._find(how, what)
|
|
278
|
+
IE.bind ie_ole if ie_ole
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def self._find(how, what)
|
|
282
|
+
self._find_all(how, what).first
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def self._find_all(how, what)
|
|
286
|
+
ies = []
|
|
287
|
+
count = -1
|
|
288
|
+
IE.each do |ie|
|
|
289
|
+
window = ie.ie
|
|
290
|
+
|
|
291
|
+
case how
|
|
292
|
+
when :url
|
|
293
|
+
ies << window if (what.matches(window.locationURL))
|
|
294
|
+
when :title
|
|
295
|
+
# normal windows explorer shells do not have document
|
|
296
|
+
# note window.document will fail for "new" browsers
|
|
297
|
+
begin
|
|
298
|
+
title = window.locationname
|
|
299
|
+
title = window.document.title
|
|
300
|
+
rescue WIN32OLERuntimeError
|
|
301
|
+
end
|
|
302
|
+
ies << window if what.matches(title)
|
|
303
|
+
when :hwnd
|
|
304
|
+
begin
|
|
305
|
+
ies << window if what == window.HWND
|
|
306
|
+
rescue WIN32OLERuntimeError
|
|
307
|
+
end
|
|
308
|
+
when :index
|
|
309
|
+
count += 1
|
|
310
|
+
if count == what
|
|
311
|
+
ies << window
|
|
312
|
+
break
|
|
313
|
+
end
|
|
314
|
+
when nil
|
|
315
|
+
ies << window
|
|
316
|
+
else
|
|
317
|
+
raise ArgumentError
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
ies
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# Return the current window handle
|
|
325
|
+
def hwnd
|
|
326
|
+
raise "Not attached to a browser" if @ie.nil?
|
|
327
|
+
@hwnd ||= @ie.hwnd
|
|
328
|
+
end
|
|
329
|
+
attr_writer :hwnd
|
|
330
|
+
|
|
331
|
+
# Are we attached to an open browser?
|
|
332
|
+
def exists?
|
|
333
|
+
begin
|
|
334
|
+
!!(@ie.name =~ /Internet Explorer/)
|
|
335
|
+
rescue WIN32OLERuntimeError, NoMethodError
|
|
336
|
+
false
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
alias :exist? :exists?
|
|
340
|
+
|
|
341
|
+
# deprecated: use logger= instead
|
|
342
|
+
def set_logger(logger)
|
|
343
|
+
@logger = logger
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def log(what)
|
|
347
|
+
@logger.debug(what) if @logger
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
#
|
|
351
|
+
# Accessing data outside the document
|
|
352
|
+
#
|
|
353
|
+
|
|
354
|
+
# Return the title of the document
|
|
355
|
+
def title
|
|
356
|
+
@ie.document.title
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
# Return the status of the window, typically from the status bar at the bottom.
|
|
360
|
+
def status
|
|
361
|
+
@ie.statusText
|
|
362
|
+
rescue WIN32OLERuntimeError
|
|
363
|
+
""
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
#
|
|
367
|
+
# Navigation
|
|
368
|
+
#
|
|
369
|
+
|
|
370
|
+
# Navigate to the specified URL.
|
|
371
|
+
# * url - string - the URL to navigate to
|
|
372
|
+
def goto(url)
|
|
373
|
+
url = "http://" + url unless url =~ %r{://} || url == "about:blank"
|
|
374
|
+
@ie.navigate(url)
|
|
375
|
+
wait
|
|
376
|
+
return @down_load_time
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
# Go to the previous page - the same as clicking the browsers back button
|
|
380
|
+
# an WIN32OLERuntimeError exception is raised if the browser cant go back
|
|
381
|
+
def back
|
|
382
|
+
@ie.GoBack
|
|
383
|
+
wait
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
# Go to the next page - the same as clicking the browsers forward button
|
|
387
|
+
# an WIN32OLERuntimeError exception is raised if the browser cant go forward
|
|
388
|
+
def forward
|
|
389
|
+
@ie.GoForward
|
|
390
|
+
wait
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
# Refresh the current page - the same as clicking the browsers refresh button
|
|
394
|
+
# an WIN32OLERuntimeError exception is raised if the browser cant refresh
|
|
395
|
+
def refresh
|
|
396
|
+
@ie.refresh2(3)
|
|
397
|
+
wait
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
def inspect
|
|
401
|
+
'#<%s:0x%x url=%s title=%s>' % [self.class, hash*2, url.inspect, title.inspect]
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
# clear the list of urls that we have visited
|
|
405
|
+
def clear_url_list
|
|
406
|
+
@url_list.clear
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
# Closes the Browser
|
|
410
|
+
def close
|
|
411
|
+
return unless exists?
|
|
412
|
+
@ie.stop
|
|
413
|
+
wait rescue nil
|
|
414
|
+
chwnd = @ie.hwnd.to_i
|
|
415
|
+
@ie.quit
|
|
416
|
+
t = ::Time.now
|
|
417
|
+
while exists?
|
|
418
|
+
# just in case to avoid possible endless loop if failing to close some
|
|
419
|
+
# window or tab
|
|
420
|
+
break if ::Time.now - t > 10
|
|
421
|
+
sleep 0.3
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
# Maximize the window (expands to fill the screen)
|
|
426
|
+
def maximize
|
|
427
|
+
rautomation.maximize
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
# Minimize the window (appears as icon on taskbar)
|
|
431
|
+
def minimize
|
|
432
|
+
rautomation.minimize
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def minimized?
|
|
436
|
+
rautomation.minimized?
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
# Restore the window (after minimizing or maximizing)
|
|
440
|
+
def restore
|
|
441
|
+
rautomation.restore
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
# Make the window come to the front
|
|
445
|
+
def activate
|
|
446
|
+
rautomation.activate
|
|
447
|
+
end
|
|
448
|
+
alias :bring_to_front :activate
|
|
449
|
+
|
|
450
|
+
def active?
|
|
451
|
+
rautomation.active?
|
|
452
|
+
end
|
|
453
|
+
alias :front? :active?
|
|
454
|
+
|
|
455
|
+
def rautomation
|
|
456
|
+
@rautomation ||= ::RAutomation::Window.new(:hwnd => hwnd)
|
|
457
|
+
@rautomation
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def autoit
|
|
461
|
+
Kernel.warn "Usage of Watir::IE#autoit method is DEPRECATED! Use Watir::IE#rautomation method instead. Refer to https://github.com/jarmo/RAutomation for updating your scripts."
|
|
462
|
+
@autoit ||= ::RAutomation::Window.new(:hwnd => hwnd, :adapter => :autoit)
|
|
463
|
+
@autoit
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
# Activates the window and sends keys to it.
|
|
467
|
+
#
|
|
468
|
+
# Example:
|
|
469
|
+
# browser.send_keys("Hello World{enter}")
|
|
470
|
+
#
|
|
471
|
+
# Refer to RAutomation::Adapter::WinFfi::KeystrokeConverter.convert_special_characters for
|
|
472
|
+
# special characters conversion.
|
|
473
|
+
# @see RAutomation::Window#send_keys
|
|
474
|
+
def send_keys(*keys)
|
|
475
|
+
rautomation.send_keys *keys
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
def dir
|
|
479
|
+
return File.expand_path(File.dirname(__FILE__))
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
#
|
|
483
|
+
# Document and Document Data
|
|
484
|
+
#
|
|
485
|
+
|
|
486
|
+
# Return the current document
|
|
487
|
+
def document
|
|
488
|
+
return @ie.document
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
# returns the current url, as displayed in the address bar of the browser
|
|
492
|
+
def url
|
|
493
|
+
return @ie.LocationURL
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
def window(specifiers={}, &blk)
|
|
497
|
+
win = Window.new(self, specifiers, &blk)
|
|
498
|
+
win.use &blk if blk
|
|
499
|
+
win
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
def windows(specifiers={}, &blk)
|
|
503
|
+
self.class._find_all(specifiers.keys.first, specifiers.values.first).map {|ie| Window.new(self, specifiers, IE.bind(ie), &blk)}
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
def cookies
|
|
507
|
+
Cookies.new(self)
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
#
|
|
511
|
+
# Synchronization
|
|
512
|
+
#
|
|
513
|
+
|
|
514
|
+
# Block execution until the page has loaded.
|
|
515
|
+
#
|
|
516
|
+
# Will raise Timeout::Error if page hasn't been loaded within 5 minutes.
|
|
517
|
+
# =nodoc
|
|
518
|
+
# Note: This code needs to be prepared for the ie object to be closed at
|
|
519
|
+
# any moment!
|
|
520
|
+
def wait(no_sleep=false)
|
|
521
|
+
@xml_parser_doc = nil
|
|
522
|
+
@down_load_time = 0.0
|
|
523
|
+
interval = 0.05
|
|
524
|
+
start_load_time = ::Time.now
|
|
525
|
+
|
|
526
|
+
Timeout::timeout(5*60) do
|
|
527
|
+
begin
|
|
528
|
+
while @ie.busy
|
|
529
|
+
sleep interval
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
until READYSTATES.has_value?(@ie.readyState)
|
|
533
|
+
sleep interval
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
until @ie.document
|
|
537
|
+
sleep interval
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
documents_to_wait_for = [@ie.document]
|
|
541
|
+
rescue WIN32OLERuntimeError # IE window must have been closed
|
|
542
|
+
@down_load_time = ::Time.now - start_load_time
|
|
543
|
+
return @down_load_time
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
while doc = documents_to_wait_for.shift
|
|
547
|
+
begin
|
|
548
|
+
until READYSTATES.has_key?(doc.readyState.to_sym)
|
|
549
|
+
sleep interval
|
|
550
|
+
end
|
|
551
|
+
@url_list << doc.location.href unless @url_list.include?(doc.location.href)
|
|
552
|
+
doc.frames.length.times do |n|
|
|
553
|
+
begin
|
|
554
|
+
documents_to_wait_for << doc.frames[n.to_s].document
|
|
555
|
+
rescue WIN32OLERuntimeError, NoMethodError
|
|
556
|
+
end
|
|
557
|
+
end
|
|
558
|
+
rescue WIN32OLERuntimeError
|
|
559
|
+
end
|
|
560
|
+
end
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
@down_load_time = ::Time.now - start_load_time
|
|
564
|
+
run_error_checks
|
|
565
|
+
sleep @pause_after_wait unless no_sleep
|
|
566
|
+
@down_load_time
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
# Error checkers
|
|
570
|
+
|
|
571
|
+
# this method runs the predefined error checks
|
|
572
|
+
def run_error_checks
|
|
573
|
+
@error_checkers.each { |e| e.call(self) }
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
# this method is used to add an error checker that gets executed on every page load
|
|
577
|
+
# * checker Proc Object, that contains the code to be run
|
|
578
|
+
def add_checker(checker)
|
|
579
|
+
@error_checkers << checker
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
# this allows a checker to be disabled
|
|
583
|
+
# * checker Proc Object, the checker that is to be disabled
|
|
584
|
+
def disable_checker(checker)
|
|
585
|
+
@error_checkers.delete(checker)
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
#
|
|
589
|
+
# Show me state
|
|
590
|
+
#
|
|
591
|
+
|
|
592
|
+
# Show all forms displays all the forms that are on a web page.
|
|
593
|
+
def show_forms
|
|
594
|
+
if all_forms = self.forms
|
|
595
|
+
count = all_forms.length
|
|
596
|
+
puts "There are #{count} forms"
|
|
597
|
+
all_forms.each do |form|
|
|
598
|
+
puts "Form name: #{form.name}"
|
|
599
|
+
puts " id: #{form.id}"
|
|
600
|
+
puts " method: #{form.method}"
|
|
601
|
+
puts " action: #{form.action}"
|
|
602
|
+
end
|
|
603
|
+
else
|
|
604
|
+
puts "No forms"
|
|
605
|
+
end
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
# this method shows all the images availble in the document
|
|
609
|
+
def show_images
|
|
610
|
+
doc = document
|
|
611
|
+
index = 1
|
|
612
|
+
doc.images.each do |l|
|
|
613
|
+
puts "image: name: #{l.name}"
|
|
614
|
+
puts " id: #{l.invoke("id")}"
|
|
615
|
+
puts " src: #{l.src}"
|
|
616
|
+
puts " index: #{index}"
|
|
617
|
+
index += 1
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
# this method shows all the links availble in the document
|
|
622
|
+
def show_links
|
|
623
|
+
props = ["name", "id", "href"]
|
|
624
|
+
print_sizes = [12, 12, 60]
|
|
625
|
+
doc = document
|
|
626
|
+
index = 0
|
|
627
|
+
text_size = 60
|
|
628
|
+
# draw the table header
|
|
629
|
+
s = "index".ljust(6)
|
|
630
|
+
props.each_with_index do |p, i|
|
|
631
|
+
s += p.ljust(print_sizes[i])
|
|
632
|
+
end
|
|
633
|
+
s += "text/src".ljust(text_size)
|
|
634
|
+
s += "\n"
|
|
635
|
+
|
|
636
|
+
# now get the details of the links
|
|
637
|
+
doc.links.each do |n|
|
|
638
|
+
index += 1
|
|
639
|
+
s = s + index.to_s.ljust(6)
|
|
640
|
+
props.each_with_index do |prop, i|
|
|
641
|
+
printsize = print_sizes[i]
|
|
642
|
+
begin
|
|
643
|
+
p = n.invoke(prop)
|
|
644
|
+
temp_var = "#{p}".to_s.ljust(printsize)
|
|
645
|
+
rescue
|
|
646
|
+
# this object probably doesnt have this property
|
|
647
|
+
temp_var = "".to_s.ljust(printsize)
|
|
648
|
+
end
|
|
649
|
+
s += temp_var
|
|
650
|
+
end
|
|
651
|
+
s += n.innerText
|
|
652
|
+
if n.getElementsByTagName("IMG").length > 0
|
|
653
|
+
s += " / " + n.getElementsByTagName("IMG").item(0).src
|
|
654
|
+
end
|
|
655
|
+
s += "\n"
|
|
656
|
+
end
|
|
657
|
+
puts s
|
|
658
|
+
end
|
|
659
|
+
|
|
660
|
+
# this method shows the name, id etc of the object that is currently active - ie the element that has focus
|
|
661
|
+
# its mostly used in irb when creating a script
|
|
662
|
+
def show_active
|
|
663
|
+
s = ""
|
|
664
|
+
|
|
665
|
+
current = document.activeElement
|
|
666
|
+
begin
|
|
667
|
+
s += current.invoke("type").to_s.ljust(16)
|
|
668
|
+
rescue
|
|
669
|
+
end
|
|
670
|
+
props = ["name", "id", "value", "alt", "src", "innerText", "href"]
|
|
671
|
+
props.each do |prop|
|
|
672
|
+
begin
|
|
673
|
+
p = current.invoke(prop)
|
|
674
|
+
s += " " + "#{prop}=#{p}".to_s.ljust(18)
|
|
675
|
+
rescue
|
|
676
|
+
#this object probably doesnt have this property
|
|
677
|
+
end
|
|
678
|
+
end
|
|
679
|
+
s += "\n"
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
# this method shows all the divs availble in the document
|
|
683
|
+
def show_divs
|
|
684
|
+
divs = document.getElementsByTagName("DIV")
|
|
685
|
+
puts "Found #{divs.length} div tags"
|
|
686
|
+
index = 1
|
|
687
|
+
divs.each do |d|
|
|
688
|
+
puts "#{index} id=#{d.invoke('id')} class=#{d.invoke("className")}"
|
|
689
|
+
index += 1
|
|
690
|
+
end
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
# this method is used to show all the tables that are available
|
|
694
|
+
def show_tables
|
|
695
|
+
tables = document.getElementsByTagName("TABLE")
|
|
696
|
+
puts "Found #{tables.length} tables"
|
|
697
|
+
index = 1
|
|
698
|
+
tables.each do |d|
|
|
699
|
+
puts "#{index} id=#{d.invoke('id')} rows=#{d.rows.length} columns=#{begin d.rows["0"].cells.length; rescue; end}"
|
|
700
|
+
index += 1
|
|
701
|
+
end
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
def show_pres
|
|
705
|
+
pres = document.getElementsByTagName("PRE")
|
|
706
|
+
puts "Found #{ pres.length } pre tags"
|
|
707
|
+
index = 1
|
|
708
|
+
pres.each do |d|
|
|
709
|
+
puts "#{index} id=#{d.invoke('id')} class=#{d.invoke("className")}"
|
|
710
|
+
index+=1
|
|
711
|
+
end
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
# this method shows all the spans availble in the document
|
|
715
|
+
def show_spans
|
|
716
|
+
spans = document.getElementsByTagName("SPAN")
|
|
717
|
+
puts "Found #{spans.length} span tags"
|
|
718
|
+
index = 1
|
|
719
|
+
spans.each do |d|
|
|
720
|
+
puts "#{index} id=#{d.invoke('id')} class=#{d.invoke("className")}"
|
|
721
|
+
index += 1
|
|
722
|
+
end
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
def show_labels
|
|
726
|
+
labels = document.getElementsByTagName("LABEL")
|
|
727
|
+
puts "Found #{labels.length} label tags"
|
|
728
|
+
index = 1
|
|
729
|
+
labels.each do |d|
|
|
730
|
+
puts "#{index} text=#{d.invoke('innerText')} class=#{d.invoke("className")} for=#{d.invoke("htmlFor")}"
|
|
731
|
+
index += 1
|
|
732
|
+
end
|
|
733
|
+
end
|
|
734
|
+
|
|
735
|
+
# Gives focus to the frame
|
|
736
|
+
def focus
|
|
737
|
+
active_element = document.activeElement
|
|
738
|
+
active_element.blur unless active_element.tagName == "BODY"
|
|
739
|
+
document.focus
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
def attach_command
|
|
743
|
+
"Watir::IE.attach(:hwnd, #{hwnd})"
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
private
|
|
747
|
+
|
|
748
|
+
def create_browser_window
|
|
749
|
+
@ie = WIN32OLE.new('InternetExplorer.Application')
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
def attach_browser_window how, what
|
|
753
|
+
log "Seeking Window with #{how}: #{what}"
|
|
754
|
+
ieTemp = nil
|
|
755
|
+
begin
|
|
756
|
+
Watir::until_with_timeout do
|
|
757
|
+
ieTemp = IE._find how, what
|
|
758
|
+
end
|
|
759
|
+
rescue Watir::Wait::TimeoutError
|
|
760
|
+
raise NoMatchingWindowFoundException,
|
|
761
|
+
"Unable to locate a window with #{how} of #{what}"
|
|
762
|
+
end
|
|
763
|
+
@ie = ieTemp
|
|
764
|
+
end
|
|
765
|
+
|
|
766
|
+
end # class IE
|
|
767
|
+
end
|