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.
@@ -4,7 +4,7 @@ module Watir
4
4
  class ElementCollections
5
5
  include Enumerable
6
6
 
7
- # Super class for all the iteractor classes
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.tagged_element_locator(element_tag, @how, @what, element_class).each {|element| yield element}
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 {|e| return e if count == i; count += 1}
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 element_tag
76
- element_class.const_defined?(:TAG) ? element_class::TAG : element_class.name.split("::").last
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
@@ -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.invoke('submit')
44
+ @o.submit if dispatch_event "onSubmit"
43
45
  @container.wait
44
46
  end
45
47
 
@@ -1,13 +1,13 @@
1
1
  module Watir
2
2
  class Frame < Element
3
3
  include PageContainer
4
- TAG = ['FRAME', 'IFRAME']
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
@@ -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
- ieTemp = nil
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
- ieTemp = window if (what.matches(window.locationURL))
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
- ieTemp = window if what.matches(title)
307
+ ies << window if what.matches(title)
309
308
  when :hwnd
310
309
  begin
311
- ieTemp = window if what == window.HWND
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
- def attach_browser_window how, what
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
- escaped_src = source.to_s.gsub(/[\r\n']/) {|m| "\\#{m}"}
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
- if @xml_parser_doc == nil
761
- create_xml_parser_doc
762
- end
763
- return @xml_parser_doc
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
- # Angrez: Resolving Jira issue WTR-114
775
- htmlSource = htmlSource.gsub(/&nbsp;/, '&#160;')
798
+ # Angrez: Resolving Jira issue WTR-114
799
+ htmlSource = htmlSource.gsub(/&nbsp;/, '&#160;')
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(/"/, '&quot;')
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
- #puts "Hello; Given xpath is : #{xpath}"
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
- lastTagName = arr[arr.length-1].to_s.upcase
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 =~ /(\w*)\[?\d*\]?/
1024
- lastTagName = $1
1025
- #puts lastTagName
990
+ lastTagName = lastTagName.scan(/(\w*)\[?\d*\]?/).flatten.first
1026
991
 
1027
- for element in arr do
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
- #puts "#{element} #{tagname} #{index}"
1040
- allElemns = curElem.childnodes
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
- #puts child.tagName
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
- def attach_command
1081
- "Watir::IE.attach(:hwnd, #{hwnd})"
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