watir 1.5.2 → 1.5.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|