watir 2.0.4 → 3.0.0.rc1
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 +41 -0
- data/VERSION +1 -1
- data/lib/watir/collections.rb +9 -17
- data/lib/watir/container.rb +2 -14
- data/lib/watir/core.rb +1 -0
- data/lib/watir/dialogs/file_field.rb +4 -2
- data/lib/watir/element.rb +146 -90
- data/lib/watir/element_collections.rb +13 -11
- data/lib/watir/form.rb +4 -2
- data/lib/watir/frame.rb +15 -3
- data/lib/watir/ie-class.rb +100 -128
- data/lib/watir/image.rb +10 -13
- data/lib/watir/input_elements.rb +92 -156
- data/lib/watir/locator.rb +61 -66
- data/lib/watir/non_control_elements.rb +8 -1
- data/lib/watir/table.rb +89 -242
- data/lib/watir/window.rb +68 -0
- metadata +21 -14
@@ -4,7 +4,7 @@ module Watir
|
|
4
4
|
class ElementCollections
|
5
5
|
include Enumerable
|
6
6
|
|
7
|
-
# Super class for all the
|
7
|
+
# Super class for all the iterator classes
|
8
8
|
# * container - an instance of an IE object
|
9
9
|
def initialize(container, how, what)
|
10
10
|
if how == :index || (how.is_a?(Hash) && how[:index])
|
@@ -30,19 +30,14 @@ module Watir
|
|
30
30
|
|
31
31
|
# iterate through each of the elements in the collection in turn
|
32
32
|
def each
|
33
|
-
@container.
|
33
|
+
@container.locator_for(TaggedElementLocator, element_tags, @how, @what, element_class).each {|element| yield element}
|
34
34
|
end
|
35
35
|
|
36
36
|
# allows access to a specific item in the collection
|
37
37
|
def [](n)
|
38
38
|
number = n - Watir::IE.base_index
|
39
39
|
offset = Watir::IE.zero_based_indexing ? (length - 1) : length
|
40
|
-
|
41
|
-
unless number.between?(0, offset)
|
42
|
-
raise Exception::MissingWayOfFindingObjectException,
|
43
|
-
"Can't find #{element_tag.downcase} with :index #{n} from #{self.class} with size of #{length}"
|
44
|
-
end
|
45
|
-
return iterator_object(number)
|
40
|
+
iterator_object(number) || element_class.new(@container, :index, n)
|
46
41
|
end
|
47
42
|
|
48
43
|
def first
|
@@ -65,15 +60,22 @@ module Watir
|
|
65
60
|
|
66
61
|
def iterator_object(i)
|
67
62
|
count = 0
|
68
|
-
each
|
63
|
+
each do |e|
|
64
|
+
return e if (i >= 0 && count == i) || (i < 0 && count == length + i)
|
65
|
+
count += 1
|
66
|
+
end
|
69
67
|
end
|
70
68
|
|
71
69
|
def element_class
|
72
70
|
Watir.const_get self.class.name.split("::").last.chop
|
73
71
|
end
|
74
72
|
|
75
|
-
def
|
76
|
-
|
73
|
+
def element_tags
|
74
|
+
tags = @how.is_a?(Hash) && @how[:tag_name] ? [@how[:tag_name].upcase] :
|
75
|
+
element_class.const_defined?(:TAG) ? [element_class::TAG] :
|
76
|
+
element_class.const_defined?(:TAGS) ? element_class::TAGS :
|
77
|
+
[element_class.name.split("::").last.upcase]
|
78
|
+
tags
|
77
79
|
end
|
78
80
|
end
|
79
81
|
end
|
data/lib/watir/form.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module Watir
|
2
2
|
|
3
3
|
class Form < Element
|
4
|
+
TAG = 'FORM'
|
5
|
+
|
4
6
|
# * container - the containing object, normally an instance of IE
|
5
7
|
# * how - symbol - how we access the form (:name, :id, :index, :action, :method)
|
6
8
|
# * what - what we use to access the form
|
@@ -33,13 +35,13 @@ module Watir
|
|
33
35
|
end
|
34
36
|
|
35
37
|
def locate
|
36
|
-
@o = @container.locator_for(FormLocator, @how, @what).locate
|
38
|
+
@o = @container.locator_for(FormLocator, [self.class::TAG], @how, @what, self.class).locate
|
37
39
|
end
|
38
40
|
|
39
41
|
# Submit the data -- equivalent to pressing Enter or Return to submit a form.
|
40
42
|
def submit
|
41
43
|
assert_exists
|
42
|
-
@o.
|
44
|
+
@o.submit if dispatch_event "onSubmit"
|
43
45
|
@container.wait
|
44
46
|
end
|
45
47
|
|
data/lib/watir/frame.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
module Watir
|
2
2
|
class Frame < Element
|
3
3
|
include PageContainer
|
4
|
-
|
4
|
+
TAGS = ['FRAME', 'IFRAME']
|
5
5
|
|
6
6
|
attr_accessor :document
|
7
7
|
|
8
8
|
# Find the frame denoted by how and what in the container and return its ole_object
|
9
9
|
def locate
|
10
|
-
frame, document = @container.locator_for(FrameLocator, @how, @what).locate
|
10
|
+
frame, document = @container.locator_for(FrameLocator, self.class::TAGS, @how, @what, self.class).locate
|
11
11
|
if frame && document
|
12
12
|
@o = frame
|
13
13
|
begin
|
@@ -47,6 +47,18 @@ module Watir
|
|
47
47
|
def attach_command
|
48
48
|
@container.page_container.attach_command + ".frame(#{@how.inspect}, #{@what.inspect})".gsub('"','\'')
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
|
+
def execute_script(source)
|
52
|
+
document.parentWindow.eval(source.to_s)
|
53
|
+
rescue WIN32OLERuntimeError, NoMethodError #if eval fails we need to use execScript(source.to_s) which does not return a value, hence the workaround
|
54
|
+
escaped_src = source.to_s.gsub(/[\r\n']/) {|m| "\\#{m}"}
|
55
|
+
wrapper = "_watir_helper_div_#{Time.now.to_i}"
|
56
|
+
cmd = "var e = document.createElement('DIV'); e.style.display = 'none'; e.id='#{wrapper}'; e.innerHTML = eval('#{escaped_src}'); document.body.appendChild(e);"
|
57
|
+
document.parentWindow.execScript(cmd)
|
58
|
+
wrapper_obj = document.getElementById(wrapper)
|
59
|
+
result_value = wrapper_obj.innerHTML
|
60
|
+
result_value
|
61
|
+
end
|
62
|
+
|
51
63
|
end
|
52
64
|
end
|
data/lib/watir/ie-class.rb
CHANGED
@@ -79,7 +79,6 @@ module Watir
|
|
79
79
|
|
80
80
|
# the OLE Internet Explorer object
|
81
81
|
attr_accessor :ie
|
82
|
-
|
83
82
|
# access to the logger object
|
84
83
|
attr_accessor :logger
|
85
84
|
|
@@ -174,11 +173,6 @@ module Watir
|
|
174
173
|
ie
|
175
174
|
end
|
176
175
|
|
177
|
-
def create_browser_window
|
178
|
-
@ie = WIN32OLE.new('InternetExplorer.Application')
|
179
|
-
end
|
180
|
-
private :create_browser_window
|
181
|
-
|
182
176
|
def initialize_options
|
183
177
|
self.visible = IE.visible
|
184
178
|
self.speed = IE.speed
|
@@ -290,13 +284,18 @@ module Watir
|
|
290
284
|
end
|
291
285
|
|
292
286
|
def self._find(how, what)
|
293
|
-
|
287
|
+
self._find_all(how, what).first
|
288
|
+
end
|
289
|
+
|
290
|
+
def self._find_all(how, what)
|
291
|
+
ies = []
|
292
|
+
count = -1
|
294
293
|
IE.each do |ie|
|
295
294
|
window = ie.ie
|
296
295
|
|
297
296
|
case how
|
298
297
|
when :url
|
299
|
-
|
298
|
+
ies << window if (what.matches(window.locationURL))
|
300
299
|
when :title
|
301
300
|
# normal windows explorer shells do not have document
|
302
301
|
# note window.document will fail for "new" browsers
|
@@ -305,33 +304,27 @@ module Watir
|
|
305
304
|
title = window.document.title
|
306
305
|
rescue WIN32OLERuntimeError
|
307
306
|
end
|
308
|
-
|
307
|
+
ies << window if what.matches(title)
|
309
308
|
when :hwnd
|
310
309
|
begin
|
311
|
-
|
310
|
+
ies << window if what == window.HWND
|
312
311
|
rescue WIN32OLERuntimeError
|
313
312
|
end
|
313
|
+
when :index
|
314
|
+
count += 1
|
315
|
+
if count == what
|
316
|
+
ies << window
|
317
|
+
break
|
318
|
+
end
|
319
|
+
when nil
|
320
|
+
ies << window
|
314
321
|
else
|
315
322
|
raise ArgumentError
|
316
323
|
end
|
317
|
-
end
|
318
|
-
return ieTemp
|
319
|
-
end
|
324
|
+
end
|
320
325
|
|
321
|
-
|
322
|
-
log "Seeking Window with #{how}: #{what}"
|
323
|
-
ieTemp = nil
|
324
|
-
begin
|
325
|
-
Watir::until_with_timeout do
|
326
|
-
ieTemp = IE._find how, what
|
327
|
-
end
|
328
|
-
rescue Watir::Wait::TimeoutError
|
329
|
-
raise NoMatchingWindowFoundException,
|
330
|
-
"Unable to locate a window with #{how} of #{what}"
|
331
|
-
end
|
332
|
-
@ie = ieTemp
|
326
|
+
ies
|
333
327
|
end
|
334
|
-
private :attach_browser_window
|
335
328
|
|
336
329
|
# Return the current window handle
|
337
330
|
def hwnd
|
@@ -387,6 +380,7 @@ module Watir
|
|
387
380
|
# Navigate to the specified URL.
|
388
381
|
# * url - string - the URL to navigate to
|
389
382
|
def goto(url)
|
383
|
+
url = "http://" + url unless url =~ %r{://} || url == "about:blank"
|
390
384
|
@ie.navigate(url)
|
391
385
|
wait
|
392
386
|
return @down_load_time
|
@@ -419,9 +413,9 @@ module Watir
|
|
419
413
|
|
420
414
|
# Execute the given JavaScript string
|
421
415
|
def execute_script(source)
|
422
|
-
|
423
|
-
document.parentWindow.eval(escaped_src)
|
416
|
+
document.parentWindow.eval(source.to_s)
|
424
417
|
rescue WIN32OLERuntimeError, NoMethodError #if eval fails we need to use execScript(source.to_s) which does not return a value, hence the workaround
|
418
|
+
escaped_src = source.to_s.gsub(/[\r\n']/) {|m| "\\#{m}"}
|
425
419
|
wrapper = "_watir_helper_div_#{rand(100000)}"
|
426
420
|
cmd = "var e = document.createElement('DIV'); e.id='#{wrapper}'; e.innerHTML = eval('#{escaped_src}'); document.body.appendChild(e);"
|
427
421
|
document.parentWindow.execScript(cmd)
|
@@ -523,6 +517,16 @@ module Watir
|
|
523
517
|
return @ie.LocationURL
|
524
518
|
end
|
525
519
|
|
520
|
+
def window(how={}, &blk)
|
521
|
+
win = Window.new(self, how, &blk)
|
522
|
+
win.use &blk if blk
|
523
|
+
win
|
524
|
+
end
|
525
|
+
|
526
|
+
def windows(how={}, &blk)
|
527
|
+
self.class._find_all(how.keys.first, how.values.first).map {|ie| Window.new(self, how, IE.bind(ie), &blk)}
|
528
|
+
end
|
529
|
+
|
526
530
|
#
|
527
531
|
# Synchronization
|
528
532
|
#
|
@@ -754,13 +758,33 @@ module Watir
|
|
754
758
|
document.focus
|
755
759
|
end
|
756
760
|
|
757
|
-
|
758
761
|
# Functions written for using xpath for getting the elements.
|
759
762
|
def xmlparser_document_object
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
763
|
+
@xml_parser_doc ||= create_xml_parser_doc
|
764
|
+
end
|
765
|
+
|
766
|
+
def attach_command
|
767
|
+
"Watir::IE.attach(:hwnd, #{hwnd})"
|
768
|
+
end
|
769
|
+
|
770
|
+
private
|
771
|
+
|
772
|
+
def create_browser_window
|
773
|
+
@ie = WIN32OLE.new('InternetExplorer.Application')
|
774
|
+
end
|
775
|
+
|
776
|
+
def attach_browser_window how, what
|
777
|
+
log "Seeking Window with #{how}: #{what}"
|
778
|
+
ieTemp = nil
|
779
|
+
begin
|
780
|
+
Watir::until_with_timeout do
|
781
|
+
ieTemp = IE._find how, what
|
782
|
+
end
|
783
|
+
rescue Watir::Wait::TimeoutError
|
784
|
+
raise NoMatchingWindowFoundException,
|
785
|
+
"Unable to locate a window with #{how} of #{what}"
|
786
|
+
end
|
787
|
+
@ie = ieTemp
|
764
788
|
end
|
765
789
|
|
766
790
|
# Create the Nokogiri object if it is nil. This method is private so can be called only
|
@@ -771,10 +795,9 @@ module Watir
|
|
771
795
|
htmlSource ="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<HTML>\n"
|
772
796
|
htmlSource = html_source(document.body,htmlSource," ")
|
773
797
|
htmlSource += "\n</HTML>\n"
|
774
|
-
|
775
|
-
|
798
|
+
# Angrez: Resolving Jira issue WTR-114
|
799
|
+
htmlSource = htmlSource.gsub(/ /, ' ')
|
776
800
|
begin
|
777
|
-
#@xml_parser_doc = Nokogiri::HTML::Document.new(htmlSource)
|
778
801
|
@xml_parser_doc = Nokogiri.parse(htmlSource)
|
779
802
|
rescue => e
|
780
803
|
output_xml_parser_doc("error.xml", htmlSource)
|
@@ -782,14 +805,12 @@ module Watir
|
|
782
805
|
end
|
783
806
|
end
|
784
807
|
end
|
785
|
-
private :create_xml_parser_doc
|
786
808
|
|
787
809
|
def output_xml_parser_doc(name, text)
|
788
810
|
file = File.open(name,"w")
|
789
811
|
file.print(text)
|
790
812
|
file.close
|
791
813
|
end
|
792
|
-
private :output_xml_parser_doc
|
793
814
|
|
794
815
|
#Function Tokenizes the tag line and returns array of tokens.
|
795
816
|
#Token could be either tagName or "=" or attribute name or attribute value
|
@@ -840,7 +861,6 @@ module Watir
|
|
840
861
|
end
|
841
862
|
return tokens
|
842
863
|
end
|
843
|
-
private :tokenize_tagline
|
844
864
|
|
845
865
|
# This function get and clean all the attributes of the tag.
|
846
866
|
def all_tag_attributes(outerHtml)
|
@@ -881,7 +901,6 @@ module Watir
|
|
881
901
|
#puts tagLine
|
882
902
|
return tagLine
|
883
903
|
end
|
884
|
-
private :all_tag_attributes
|
885
904
|
|
886
905
|
# This function is used to escape the characters that are not valid XML data.
|
887
906
|
def xml_escape(str)
|
@@ -891,7 +910,6 @@ module Watir
|
|
891
910
|
str = str.gsub(/"/, '"')
|
892
911
|
str
|
893
912
|
end
|
894
|
-
private :xml_escape
|
895
913
|
|
896
914
|
# Returns HTML Source
|
897
915
|
# Traverse the DOM tree rooted at body element
|
@@ -921,7 +939,6 @@ module Watir
|
|
921
939
|
htmlString += xml_escape(element_text)
|
922
940
|
return htmlString
|
923
941
|
end
|
924
|
-
#puts tagName
|
925
942
|
#Skip comment and script tag
|
926
943
|
if tagName =~ /^!/ || tagName== "script" || tagName =="style"
|
927
944
|
return htmlString
|
@@ -953,78 +970,26 @@ module Watir
|
|
953
970
|
end
|
954
971
|
return htmlString
|
955
972
|
end
|
956
|
-
private :html_source
|
957
|
-
|
958
|
-
# execute css selector and return an array of (ole object) elements
|
959
|
-
def elements_by_css(selector)
|
960
|
-
xmlparser_document_object # Needed to ensure Nokogiri has been loaded
|
961
|
-
xpath = Nokogiri::CSS.xpath_for(selector)[0]
|
962
|
-
elements_by_xpath(xpath)
|
963
|
-
end
|
964
|
-
|
965
|
-
# return the first (ole object) element that matches the css selector
|
966
|
-
def element_by_css(selector)
|
967
|
-
temp = elements_by_css(selector)
|
968
|
-
return temp[0] if temp
|
969
|
-
end
|
970
|
-
|
971
|
-
# return the first element that matches the xpath
|
972
|
-
def element_by_xpath(xpath)
|
973
|
-
temp = elements_by_xpath(xpath)
|
974
|
-
temp = temp[0] if temp
|
975
|
-
return temp
|
976
|
-
end
|
977
|
-
|
978
|
-
# execute xpath and return an array of elements
|
979
|
-
def elements_by_xpath(xpath)
|
980
|
-
doc = xmlparser_document_object
|
981
|
-
modifiedXpath = ""
|
982
|
-
selectedElements = Array.new
|
983
|
-
|
984
|
-
# strip any trailing slash from the xpath expression (as used in watir unit tests)
|
985
|
-
xpath.chop! unless (/\/$/ =~ xpath).nil?
|
986
|
-
|
987
|
-
doc.xpath(xpath).each do |element|
|
988
|
-
modifiedXpath = element.path
|
989
|
-
temp = element_by_absolute_xpath(modifiedXpath) # temp = a DOM/COM element
|
990
|
-
selectedElements << temp if temp != nil
|
991
|
-
end
|
992
|
-
#puts selectedElements.length
|
993
|
-
if selectedElements.length == 0
|
994
|
-
return nil
|
995
|
-
else
|
996
|
-
return selectedElements
|
997
|
-
end
|
998
|
-
end
|
999
973
|
|
1000
974
|
# Method that iterates over IE DOM object and get the elements for the given
|
1001
975
|
# xpath.
|
1002
976
|
def element_by_absolute_xpath(xpath)
|
1003
977
|
curElem = nil
|
978
|
+
xpath = xpath.scan(/^.*\/body\[?\d*\]?\/(.*)/).flatten.first
|
979
|
+
return unless xpath
|
1004
980
|
|
1005
|
-
|
1006
|
-
doc = document
|
1007
|
-
curElem = doc.getElementsByTagName("body").item(0)
|
1008
|
-
xpath =~ /^.*\/body\[?\d*\]?\/(.*)/
|
1009
|
-
xpath = $1
|
1010
|
-
|
1011
|
-
if xpath == nil
|
1012
|
-
puts "Function Requires absolute XPath."
|
1013
|
-
return
|
1014
|
-
end
|
1015
|
-
|
1016
|
-
arr = xpath.split(/\//)
|
981
|
+
arr = xpath.split("/")
|
1017
982
|
return nil if arr.length == 0
|
1018
983
|
|
1019
|
-
|
984
|
+
doc = document
|
985
|
+
curElem = doc.getElementsByTagName("body").item(0)
|
986
|
+
lastTagName = arr.last.to_s.upcase
|
1020
987
|
|
1021
988
|
# lastTagName is like tagName[number] or just tagName. For the first case we need to
|
1022
989
|
# separate tagName and number.
|
1023
|
-
lastTagName
|
1024
|
-
lastTagName = $1
|
1025
|
-
#puts lastTagName
|
990
|
+
lastTagName = lastTagName.scan(/(\w*)\[?\d*\]?/).flatten.first
|
1026
991
|
|
1027
|
-
|
992
|
+
arr.each do |element|
|
1028
993
|
element =~ /(\w*)\[?(\d*)\]?/
|
1029
994
|
tagname = $1
|
1030
995
|
tagname = tagname.upcase
|
@@ -1036,51 +1001,58 @@ module Watir
|
|
1036
1001
|
index = 0
|
1037
1002
|
end
|
1038
1003
|
|
1039
|
-
|
1040
|
-
allElemns
|
1041
|
-
if allElemns == nil || allElemns.length == 0
|
1042
|
-
puts "#{element} is null"
|
1043
|
-
next # Go to next element
|
1044
|
-
end
|
1004
|
+
allElemns = tagname == "FRAME" ? [curElem] : curElem.childnodes
|
1005
|
+
next if allElemns == nil || allElemns.length == 0
|
1045
1006
|
|
1046
|
-
#puts "Current element is : #{curElem.tagName}"
|
1047
1007
|
allElemns.each do |child|
|
1048
|
-
gotIt = false
|
1049
1008
|
begin
|
1050
1009
|
curTag = child.tagName
|
1051
|
-
curTag = EMPTY_TAG_NAME if curTag
|
1010
|
+
curTag = EMPTY_TAG_NAME if curTag.empty?
|
1052
1011
|
rescue
|
1053
1012
|
next
|
1054
1013
|
end
|
1055
|
-
|
1014
|
+
|
1056
1015
|
if curTag == tagname
|
1057
|
-
index-=1
|
1016
|
+
index -= 1
|
1058
1017
|
if index < 0
|
1059
1018
|
curElem = child
|
1060
1019
|
break
|
1061
1020
|
end
|
1062
1021
|
end
|
1063
1022
|
end
|
1064
|
-
|
1065
|
-
#puts "Node selected at index #{index.to_s} : #{curElem.tagName}"
|
1066
|
-
end
|
1067
|
-
begin
|
1068
|
-
if curElem.tagName == lastTagName
|
1069
|
-
#puts curElem.tagName
|
1070
|
-
return curElem
|
1071
|
-
else
|
1072
|
-
return nil
|
1073
|
-
end
|
1074
|
-
rescue
|
1075
|
-
return nil
|
1076
1023
|
end
|
1024
|
+
|
1025
|
+
curElem.tagName == lastTagName ? curElem : nil rescue nil
|
1077
1026
|
end
|
1078
|
-
private :element_by_absolute_xpath
|
1079
1027
|
|
1080
|
-
|
1081
|
-
|
1028
|
+
# execute css selector and return an array of (ole object) elements
|
1029
|
+
def elements_by_css(selector)
|
1030
|
+
xmlparser_document_object # Needed to ensure Nokogiri has been loaded
|
1031
|
+
xpath = Nokogiri::CSS.xpath_for(selector)[0]
|
1032
|
+
elements_by_xpath(xpath)
|
1082
1033
|
end
|
1083
1034
|
|
1035
|
+
# return the first (ole object) element that matches the css selector
|
1036
|
+
def element_by_css(selector)
|
1037
|
+
elements_by_css(selector)[0]
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
# return the first element that matches the xpath
|
1041
|
+
def element_by_xpath(xpath)
|
1042
|
+
elements_by_xpath(xpath)[0]
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
# execute xpath and return an array of elements
|
1046
|
+
def elements_by_xpath(xpath)
|
1047
|
+
doc = xmlparser_document_object
|
1048
|
+
|
1049
|
+
# strip any trailing slash from the xpath expression (as used in watir unit tests)
|
1050
|
+
xpath.chop! if xpath =~ /\/$/
|
1051
|
+
|
1052
|
+
doc.xpath(xpath).reduce([]) do |memo, element|
|
1053
|
+
memo << element_by_absolute_xpath(element.path)
|
1054
|
+
end.compact
|
1055
|
+
end
|
1084
1056
|
|
1085
1057
|
end # class IE
|
1086
1058
|
end
|