watir 1.5.2 → 1.5.3
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/readme.rb +20 -12
- data/unittests/html/table1.html +41 -1
- data/unittests/links_test.rb +2 -2
- data/unittests/navigate_test.rb +2 -2
- data/unittests/parent_child_test.rb +0 -15
- data/unittests/table_test.rb +5 -2
- data/unittests/textarea_test.rb +55 -39
- data/unittests/windows/iedialog_test.rb +2 -2
- data/watir.rb +20 -4386
- data/watir/{elements.rb → bonus-elements.rb} +0 -0
- data/watir/collections.rb +317 -0
- data/watir/container.rb +883 -0
- data/watir/element.rb +306 -0
- data/watir/element_collections.rb +82 -0
- data/watir/form.rb +151 -0
- data/watir/frame.rb +60 -0
- data/watir/ie.rb +973 -0
- data/watir/image.rb +131 -0
- data/watir/input_elements.rb +518 -0
- data/watir/link.rb +65 -0
- data/watir/locator.rb +79 -0
- data/watir/logger.rb +19 -0
- data/watir/modal_dialog.rb +123 -0
- data/watir/non_control_elements.rb +91 -0
- data/watir/page-container.rb +106 -0
- data/watir/popup.rb +30 -0
- data/watir/table.rb +356 -0
- data/watir/win32.rb +29 -0
- metadata +21 -3
data/watir/link.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
module Watir
|
2
|
+
|
3
|
+
# This class is the means of accessing a link on a page
|
4
|
+
# Normally a user would not need to create this object as it is returned by the Watir::Container#link method
|
5
|
+
# many of the methods available to this object are inherited from the Element class
|
6
|
+
#
|
7
|
+
class Link < Element
|
8
|
+
# Returns an initialized instance of a link object
|
9
|
+
# * container - an instance of a container
|
10
|
+
# * how - symbol - how we access the link
|
11
|
+
# * what - what we use to access the link, text, url, index etc
|
12
|
+
def initialize(container, how, what)
|
13
|
+
set_container container
|
14
|
+
@how = how
|
15
|
+
@what = what
|
16
|
+
super(nil)
|
17
|
+
end
|
18
|
+
|
19
|
+
def locate
|
20
|
+
if @how == :xpath
|
21
|
+
@o = @container.element_by_xpath(@what)
|
22
|
+
else
|
23
|
+
begin
|
24
|
+
@o = @container.locate_tagged_element('A', @how, @what)
|
25
|
+
rescue UnknownObjectException
|
26
|
+
@o = nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# if an image is used as part of the link, this will return true
|
32
|
+
def link_has_image
|
33
|
+
assert_exists
|
34
|
+
return true if @o.getElementsByTagName("IMG").length > 0
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
|
38
|
+
# this method returns the src of an image, if an image is used as part of the link
|
39
|
+
def src # BUG?
|
40
|
+
assert_exists
|
41
|
+
if @o.getElementsByTagName("IMG").length > 0
|
42
|
+
return @o.getElementsByTagName("IMG")[0.to_s].src
|
43
|
+
else
|
44
|
+
return ""
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def link_string_creator
|
49
|
+
n = []
|
50
|
+
n << "href:".ljust(TO_S_SIZE) + self.href
|
51
|
+
n << "inner text:".ljust(TO_S_SIZE) + self.text
|
52
|
+
n << "img src:".ljust(TO_S_SIZE) + self.src if self.link_has_image
|
53
|
+
return n
|
54
|
+
end
|
55
|
+
|
56
|
+
# returns a textual description of the link
|
57
|
+
def to_s
|
58
|
+
assert_exists
|
59
|
+
r = string_creator
|
60
|
+
r = r + link_string_creator
|
61
|
+
return r.join("\n")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
data/watir/locator.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
module Watir
|
2
|
+
class TaggedElementLocator
|
3
|
+
include Watir
|
4
|
+
include Watir::Exception
|
5
|
+
|
6
|
+
def initialize(container, tag)
|
7
|
+
@container = container
|
8
|
+
@tag = tag
|
9
|
+
end
|
10
|
+
|
11
|
+
def set_specifier(how, what)
|
12
|
+
if how.class == Hash and what.nil?
|
13
|
+
specifiers = how
|
14
|
+
else
|
15
|
+
specifiers = {how => what}
|
16
|
+
end
|
17
|
+
|
18
|
+
@specifiers = {:index => 1} # default if not specified
|
19
|
+
|
20
|
+
specifiers.each do |how, what|
|
21
|
+
what = what.to_i if how == :index
|
22
|
+
how = :href if how == :url
|
23
|
+
how = :class_name if how == :class
|
24
|
+
|
25
|
+
@specifiers[how] = what
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
def each_element tag
|
31
|
+
@container.document.getElementsByTagName(tag).each do |ole_element|
|
32
|
+
yield Element.new(ole_element)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def locate
|
37
|
+
index_target = @specifiers[:index]
|
38
|
+
|
39
|
+
count = 0
|
40
|
+
each_element(@tag) do |element|
|
41
|
+
|
42
|
+
catch :next_element do
|
43
|
+
@specifiers.each do |how, what|
|
44
|
+
next if how == :index
|
45
|
+
unless match? element, how, what
|
46
|
+
throw :next_element
|
47
|
+
end
|
48
|
+
end
|
49
|
+
count += 1
|
50
|
+
unless index_target == count
|
51
|
+
throw :next_element
|
52
|
+
end
|
53
|
+
return element.ole_object
|
54
|
+
end
|
55
|
+
|
56
|
+
end # elements
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def match?(element, how, what)
|
61
|
+
begin
|
62
|
+
method = element.method(how)
|
63
|
+
rescue NameError
|
64
|
+
raise MissingWayOfFindingObjectException,
|
65
|
+
"#{how} is an unknown way of finding a <#{@tag}> element (#{what})"
|
66
|
+
end
|
67
|
+
case method.arity
|
68
|
+
when 0
|
69
|
+
what.matches method.call
|
70
|
+
when 1
|
71
|
+
method.call(what)
|
72
|
+
else
|
73
|
+
raise MissingWayOfFindingObjectException,
|
74
|
+
"#{how} is an unknown way of finding a <#{@tag}> element (#{what})"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
data/watir/logger.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Watir
|
2
|
+
class WatirLogger < Logger
|
3
|
+
def initialize(filName, logsToKeep, maxLogSize)
|
4
|
+
super(filName, logsToKeep, maxLogSize)
|
5
|
+
self.level = Logger::DEBUG
|
6
|
+
self.datetime_format = "%d-%b-%Y %H:%M:%S"
|
7
|
+
self.debug("Watir starting")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class DefaultLogger < Logger
|
12
|
+
def initialize
|
13
|
+
super(STDERR)
|
14
|
+
self.level = Logger::WARN
|
15
|
+
self.datetime_format = "%d-%b-%Y %H:%M:%S"
|
16
|
+
self.info "Log started"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module Watir
|
2
|
+
class ModalDialog
|
3
|
+
include Container
|
4
|
+
include PageContainer
|
5
|
+
include Win32
|
6
|
+
|
7
|
+
# Return the current window handle
|
8
|
+
attr_reader :hwnd
|
9
|
+
|
10
|
+
def find_modal_from_window
|
11
|
+
# Use handle of our parent window to see if we have any currently
|
12
|
+
# enabled popup.
|
13
|
+
hwnd = @container.hwnd
|
14
|
+
hwnd_modal = 0
|
15
|
+
begin
|
16
|
+
Watir::until_with_timeout do
|
17
|
+
hwnd_modal, arr = GetWindow.call(hwnd, GW_ENABLEDPOPUP) # GW_ENABLEDPOPUP = 6
|
18
|
+
hwnd_modal > 0
|
19
|
+
end
|
20
|
+
rescue TimeOutException
|
21
|
+
return nil
|
22
|
+
end
|
23
|
+
if hwnd_modal == hwnd || hwnd_modal == 0
|
24
|
+
hwnd_modal = nil
|
25
|
+
end
|
26
|
+
@hwnd = hwnd_modal
|
27
|
+
end
|
28
|
+
private :find_modal_from_window
|
29
|
+
|
30
|
+
def locate
|
31
|
+
how = @how
|
32
|
+
what = @what
|
33
|
+
|
34
|
+
case how
|
35
|
+
when nil
|
36
|
+
unless find_modal_from_window
|
37
|
+
raise NoMatchingWindowFoundException,
|
38
|
+
"Modal Dialog not found. Timeout = #{Watir::IE.attach_timeout}"
|
39
|
+
end
|
40
|
+
when :title
|
41
|
+
case what.class.to_s
|
42
|
+
# TODO: re-write like WET's so we can select on regular expressions too.
|
43
|
+
when "String"
|
44
|
+
begin
|
45
|
+
Watir::until_with_timeout do
|
46
|
+
title = "#{what} -- Web Page Dialog"
|
47
|
+
@hwnd, arr = FindWindowEx.call(0, 0, nil, title)
|
48
|
+
@hwnd > 0
|
49
|
+
end
|
50
|
+
rescue TimeOutException
|
51
|
+
raise NoMatchingWindowFoundException,
|
52
|
+
"Modal Dialog with title #{what} not found. Timeout = #{Watir::IE.attach_timeout}"
|
53
|
+
end
|
54
|
+
else
|
55
|
+
raise ArgumentError, "Title value must be String"
|
56
|
+
end
|
57
|
+
else
|
58
|
+
raise ArgumentError, "Only null and :title methods are supported"
|
59
|
+
end
|
60
|
+
|
61
|
+
intUnknown = 0
|
62
|
+
begin
|
63
|
+
Watir::until_with_timeout do
|
64
|
+
intPointer = " " * 4 # will contain the int value of the IUnknown*
|
65
|
+
GetUnknown.call(@hwnd, intPointer)
|
66
|
+
intArray = intPointer.unpack('L')
|
67
|
+
intUnknown = intArray.first
|
68
|
+
intUnknown > 0
|
69
|
+
end
|
70
|
+
rescue TimeOutException => e
|
71
|
+
raise NoMatchingWindowFoundException,
|
72
|
+
"Unable to attach to Modal Window #{what.inspect} after #{e.duration} seconds."
|
73
|
+
end
|
74
|
+
|
75
|
+
copy_test_config @parent_container
|
76
|
+
@document = WIN32OLE.connect_unknown(intUnknown)
|
77
|
+
end
|
78
|
+
|
79
|
+
def initialize(container, how, what=nil)
|
80
|
+
set_container container
|
81
|
+
@how = how
|
82
|
+
@what = what
|
83
|
+
@parent_container = container
|
84
|
+
# locate our modal dialog's Document object and save it
|
85
|
+
begin
|
86
|
+
locate
|
87
|
+
rescue NoMethodError => e
|
88
|
+
message =
|
89
|
+
"IE#modal_dialog not supported with the current version of Ruby (#{RUBY_VERSION}).\n" +
|
90
|
+
"See http://jira.openqa.org/browse/WTR-2 for details.\n" +
|
91
|
+
e.message
|
92
|
+
raise NoMethodError.new(message)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def document
|
97
|
+
@document
|
98
|
+
end
|
99
|
+
|
100
|
+
# Return the title of the document
|
101
|
+
def title
|
102
|
+
document.title
|
103
|
+
end
|
104
|
+
|
105
|
+
def close
|
106
|
+
document.parentWindow.close
|
107
|
+
end
|
108
|
+
|
109
|
+
def attach_command
|
110
|
+
"Watir::IE.find(:hwnd, #{@container.hwnd}).modal_dialog"
|
111
|
+
end
|
112
|
+
|
113
|
+
def wait(no_sleep=false)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Return true if the modal exists. Mostly this is useful for testing whether
|
117
|
+
# a modal has closed.
|
118
|
+
def exists?
|
119
|
+
Watir::Win32::window_exists? @hwnd
|
120
|
+
end
|
121
|
+
alias :exist? :exists?
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Watir
|
2
|
+
|
3
|
+
# this class contains items that are common between the span, div, and pre objects
|
4
|
+
# it would not normally be used directly
|
5
|
+
#
|
6
|
+
# many of the methods available to this object are inherited from the Element class
|
7
|
+
#
|
8
|
+
class NonControlElement < Element
|
9
|
+
include Watir::Exception
|
10
|
+
|
11
|
+
def locate
|
12
|
+
if @how == :xpath
|
13
|
+
@o = @container.element_by_xpath(@what)
|
14
|
+
else
|
15
|
+
@o = @container.locate_tagged_element(self.class::TAG, @how, @what)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(container, how, what)
|
20
|
+
set_container container
|
21
|
+
@how = how
|
22
|
+
@what = what
|
23
|
+
super nil
|
24
|
+
end
|
25
|
+
|
26
|
+
# this method is used to populate the properties in the to_s method
|
27
|
+
def span_div_string_creator
|
28
|
+
n = []
|
29
|
+
n << "class:".ljust(TO_S_SIZE) + self.class_name
|
30
|
+
n << "text:".ljust(TO_S_SIZE) + self.text
|
31
|
+
return n
|
32
|
+
end
|
33
|
+
private :span_div_string_creator
|
34
|
+
|
35
|
+
# returns the properties of the object in a string
|
36
|
+
# raises an ObjectNotFound exception if the object cannot be found
|
37
|
+
def to_s
|
38
|
+
assert_exists
|
39
|
+
r = string_creator
|
40
|
+
r += span_div_string_creator
|
41
|
+
return r.join("\n")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Pre < NonControlElement
|
46
|
+
TAG = 'PRE'
|
47
|
+
end
|
48
|
+
|
49
|
+
class P < NonControlElement
|
50
|
+
TAG = 'P'
|
51
|
+
end
|
52
|
+
|
53
|
+
# this class is used to deal with Div tags in the html page. http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/div.asp?frame=true
|
54
|
+
# It would not normally be created by users
|
55
|
+
class Div < NonControlElement
|
56
|
+
TAG = 'DIV'
|
57
|
+
end
|
58
|
+
|
59
|
+
# this class is used to deal with Span tags in the html page. It would not normally be created by users
|
60
|
+
class Span < NonControlElement
|
61
|
+
TAG = 'SPAN'
|
62
|
+
end
|
63
|
+
|
64
|
+
# Accesses Label element on the html page - http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/label.asp?frame=true
|
65
|
+
class Label < NonControlElement
|
66
|
+
TAG = 'LABEL'
|
67
|
+
|
68
|
+
# this method is used to populate the properties in the to_s method
|
69
|
+
def label_string_creator
|
70
|
+
n = []
|
71
|
+
n << "for:".ljust(TO_S_SIZE) + self.for
|
72
|
+
n << "text:".ljust(TO_S_SIZE) + self.text
|
73
|
+
return n
|
74
|
+
end
|
75
|
+
private :label_string_creator
|
76
|
+
|
77
|
+
# returns the properties of the object in a string
|
78
|
+
# raises an ObjectNotFound exception if the object cannot be found
|
79
|
+
def to_s
|
80
|
+
assert_exists
|
81
|
+
r = string_creator
|
82
|
+
r += label_string_creator
|
83
|
+
return r.join("\n")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class Li < NonControlElement
|
88
|
+
TAG = 'LI'
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Watir
|
2
|
+
# A PageContainer contains an HTML Document. In other words, it is a
|
3
|
+
# what JavaScript calls a Window.
|
4
|
+
module PageContainer
|
5
|
+
include Watir::Exception
|
6
|
+
|
7
|
+
# This method checks the currently displayed page for http errors, 404, 500 etc
|
8
|
+
# It gets called internally by the wait method, so a user does not need to call it explicitly
|
9
|
+
|
10
|
+
def check_for_http_error
|
11
|
+
# check for IE7
|
12
|
+
n = self.document.invoke('parentWindow').navigator.appVersion
|
13
|
+
m=/MSIE\s(.*?);/.match( n )
|
14
|
+
if m and m[1] =='7.0'
|
15
|
+
if m=/HTTP (\d\d\d.*)/.match( self.title )
|
16
|
+
raise NavigationException, m[1]
|
17
|
+
end
|
18
|
+
else
|
19
|
+
# assume its IE6
|
20
|
+
url = self.document.url
|
21
|
+
if /shdoclc.dll/.match(url)
|
22
|
+
m = /id=IEText.*?>(.*?)</i.match(self.html)
|
23
|
+
raise NavigationException, m[1] if m
|
24
|
+
end
|
25
|
+
end
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
# The HTML Page
|
30
|
+
def page
|
31
|
+
document.documentelement
|
32
|
+
end
|
33
|
+
private :page
|
34
|
+
|
35
|
+
# The HTML of the current page
|
36
|
+
def html
|
37
|
+
page.outerhtml
|
38
|
+
end
|
39
|
+
|
40
|
+
# The url of the page object.
|
41
|
+
def url
|
42
|
+
page.document.location.href
|
43
|
+
end
|
44
|
+
|
45
|
+
# The text of the current page
|
46
|
+
def text
|
47
|
+
page.innertext.strip
|
48
|
+
end
|
49
|
+
|
50
|
+
def eval_in_spawned_process(command)
|
51
|
+
command.strip!
|
52
|
+
load_path_code = _code_that_copies_readonly_array($LOAD_PATH, '$LOAD_PATH')
|
53
|
+
ruby_code = "require 'watir'; "
|
54
|
+
# ruby_code = "$HIDE_IE = #{$HIDE_IE};" # This prevents attaching to a window from setting it visible. However modal dialogs cannot be attached to when not visible.
|
55
|
+
ruby_code << "pc = #{attach_command}; " # pc = page container
|
56
|
+
# IDEA: consider changing this to not use instance_eval (it makes the code hard to understand)
|
57
|
+
ruby_code << "pc.instance_eval(#{command.inspect})"
|
58
|
+
exec_string = "start rubyw -e #{(load_path_code + '; ' + ruby_code).inspect}"
|
59
|
+
system(exec_string)
|
60
|
+
end
|
61
|
+
|
62
|
+
def set_container container
|
63
|
+
@container = container
|
64
|
+
@page_container = self
|
65
|
+
end
|
66
|
+
|
67
|
+
# This method is used to display the available html frames that Internet Explorer currently has loaded.
|
68
|
+
# This method is usually only used for debugging test scripts.
|
69
|
+
def show_frames
|
70
|
+
if allFrames = document.frames
|
71
|
+
count = allFrames.length
|
72
|
+
puts "there are #{count} frames"
|
73
|
+
for i in 0..count-1 do
|
74
|
+
begin
|
75
|
+
fname = allFrames[i.to_s].name.to_s
|
76
|
+
puts "frame index: #{i + 1} name: #{fname}"
|
77
|
+
rescue => e
|
78
|
+
puts "frame index: #{i + 1} Access Denied, see http://wiki.openqa.org/display/WTR/FAQ#access-denied" if e.to_s.match(/Access is denied/)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
else
|
82
|
+
puts "no frames"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Search the current page for specified text or regexp.
|
87
|
+
# Returns the index if the specified text was found.
|
88
|
+
# Returns matchdata object if the specified regexp was found.
|
89
|
+
#
|
90
|
+
# *Deprecated*
|
91
|
+
# Instead use
|
92
|
+
# IE#text.include? target
|
93
|
+
# or
|
94
|
+
# IE#text.match target
|
95
|
+
def contains_text(target)
|
96
|
+
if target.kind_of? Regexp
|
97
|
+
self.text.match(target)
|
98
|
+
elsif target.kind_of? String
|
99
|
+
self.text.index(target)
|
100
|
+
else
|
101
|
+
raise ArgumentError, "Argument #{target} should be a string or regexp."
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end # module
|
106
|
+
end
|