watir 5.0.0 → 6.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/.document +5 -0
  3. data/.gitignore +21 -0
  4. data/.gitmodules +3 -0
  5. data/.travis.yml +35 -0
  6. data/CHANGES.md +1756 -0
  7. data/Gemfile +12 -0
  8. data/LICENSE +23 -0
  9. data/README.md +92 -0
  10. data/Rakefile +161 -32
  11. data/lib/watir.rb +127 -1
  12. data/lib/watir/after_hooks.rb +132 -0
  13. data/lib/watir/alert.rb +104 -0
  14. data/lib/watir/aliases.rb +6 -0
  15. data/lib/watir/atoms.rb +24 -0
  16. data/lib/watir/atoms/README +3 -0
  17. data/lib/watir/atoms/fireEvent.js +29 -0
  18. data/lib/watir/atoms/getAttribute.js +18 -0
  19. data/lib/watir/atoms/getInnerHtml.js +18 -0
  20. data/lib/watir/atoms/getOuterHtml.js +18 -0
  21. data/lib/watir/atoms/getParentElement.js +17 -0
  22. data/lib/watir/atoms/selectText.js +61 -0
  23. data/lib/watir/attribute_helper.rb +98 -0
  24. data/lib/watir/browser.rb +346 -0
  25. data/lib/watir/cell_container.rb +25 -0
  26. data/lib/watir/container.rb +51 -0
  27. data/lib/watir/cookies.rb +132 -0
  28. data/lib/watir/element_collection.rb +126 -0
  29. data/lib/watir/elements/area.rb +12 -0
  30. data/lib/watir/elements/button.rb +37 -0
  31. data/lib/watir/elements/cell.rb +17 -0
  32. data/lib/watir/elements/checkbox.rb +54 -0
  33. data/lib/watir/elements/dlist.rb +12 -0
  34. data/lib/watir/elements/element.rb +646 -0
  35. data/lib/watir/elements/file_field.rb +41 -0
  36. data/lib/watir/elements/font.rb +11 -0
  37. data/lib/watir/elements/form.rb +17 -0
  38. data/lib/watir/elements/hidden.rb +20 -0
  39. data/lib/watir/elements/html_elements.rb +2063 -0
  40. data/lib/watir/elements/iframe.rb +163 -0
  41. data/lib/watir/elements/image.rb +62 -0
  42. data/lib/watir/elements/input.rb +7 -0
  43. data/lib/watir/elements/link.rb +18 -0
  44. data/lib/watir/elements/option.rb +74 -0
  45. data/lib/watir/elements/radio.rb +42 -0
  46. data/lib/watir/elements/row.rb +17 -0
  47. data/lib/watir/elements/select.rb +238 -0
  48. data/lib/watir/elements/svg_elements.rb +667 -0
  49. data/lib/watir/elements/table.rb +42 -0
  50. data/lib/watir/elements/table_cell.rb +6 -0
  51. data/lib/watir/elements/table_row.rb +15 -0
  52. data/lib/watir/elements/table_section.rb +15 -0
  53. data/lib/watir/elements/text_area.rb +5 -0
  54. data/lib/watir/elements/text_field.rb +37 -0
  55. data/lib/watir/exception.rb +17 -0
  56. data/lib/watir/extensions/nokogiri.rb +14 -0
  57. data/lib/watir/extensions/select_text.rb +10 -0
  58. data/lib/watir/generator.rb +3 -0
  59. data/lib/watir/generator/base.rb +11 -0
  60. data/lib/watir/generator/base/generator.rb +115 -0
  61. data/lib/watir/generator/base/idl_sorter.rb +47 -0
  62. data/lib/watir/generator/base/spec_extractor.rb +138 -0
  63. data/lib/watir/generator/base/util.rb +21 -0
  64. data/lib/watir/generator/base/visitor.rb +157 -0
  65. data/lib/watir/generator/html.rb +15 -0
  66. data/lib/watir/generator/html/generator.rb +36 -0
  67. data/lib/watir/generator/html/spec_extractor.rb +50 -0
  68. data/lib/watir/generator/html/visitor.rb +21 -0
  69. data/lib/watir/generator/svg.rb +7 -0
  70. data/lib/watir/generator/svg/generator.rb +38 -0
  71. data/lib/watir/generator/svg/spec_extractor.rb +46 -0
  72. data/lib/watir/generator/svg/visitor.rb +21 -0
  73. data/lib/watir/has_window.rb +53 -0
  74. data/lib/watir/locators.rb +22 -0
  75. data/lib/watir/locators/button/locator.rb +38 -0
  76. data/lib/watir/locators/button/selector_builder.rb +27 -0
  77. data/lib/watir/locators/button/selector_builder/xpath.rb +29 -0
  78. data/lib/watir/locators/button/validator.rb +15 -0
  79. data/lib/watir/locators/cell/locator.rb +17 -0
  80. data/lib/watir/locators/cell/selector_builder.rb +24 -0
  81. data/lib/watir/locators/element/locator.rb +249 -0
  82. data/lib/watir/locators/element/selector_builder.rb +147 -0
  83. data/lib/watir/locators/element/selector_builder/css.rb +65 -0
  84. data/lib/watir/locators/element/selector_builder/xpath.rb +72 -0
  85. data/lib/watir/locators/element/validator.rb +23 -0
  86. data/lib/watir/locators/row/locator.rb +17 -0
  87. data/lib/watir/locators/row/selector_builder.rb +29 -0
  88. data/lib/watir/locators/text_area/locator.rb +13 -0
  89. data/lib/watir/locators/text_area/selector_builder.rb +22 -0
  90. data/lib/watir/locators/text_field/locator.rb +44 -0
  91. data/lib/watir/locators/text_field/selector_builder.rb +34 -0
  92. data/lib/watir/locators/text_field/selector_builder/xpath.rb +19 -0
  93. data/lib/watir/locators/text_field/validator.rb +20 -0
  94. data/lib/watir/row_container.rb +36 -0
  95. data/lib/watir/screenshot.rb +50 -0
  96. data/lib/watir/user_editable.rb +38 -0
  97. data/lib/watir/version.rb +3 -3
  98. data/lib/watir/wait.rb +250 -0
  99. data/lib/watir/wait/timer.rb +19 -0
  100. data/lib/watir/window.rb +244 -0
  101. data/lib/watir/xpath_support.rb +20 -0
  102. data/spec/always_locate_spec.rb +43 -0
  103. data/spec/browser_spec.rb +130 -0
  104. data/spec/click_spec.rb +19 -0
  105. data/spec/container_spec.rb +34 -0
  106. data/spec/element_locator_spec.rb +532 -0
  107. data/spec/element_spec.rb +136 -0
  108. data/spec/implementation.rb +216 -0
  109. data/spec/input_spec.rb +14 -0
  110. data/spec/locator_spec_helper.rb +57 -0
  111. data/spec/spec_helper.rb +35 -0
  112. data/spec/special_chars_spec.rb +13 -0
  113. data/support/doctest_helper.rb +78 -0
  114. data/support/travis.sh +44 -0
  115. data/support/version_differ.rb +59 -0
  116. data/watir.gemspec +37 -25
  117. metadata +288 -23
  118. data/lib/watir/loader.rb +0 -64
@@ -0,0 +1,21 @@
1
+ module Watir
2
+ module Generator
3
+ module Util
4
+
5
+ module_function
6
+
7
+ def classify(regexp, str)
8
+ if str =~ regexp
9
+ $1
10
+ else
11
+ str
12
+ end
13
+ end
14
+
15
+ def paramify(regexp, str)
16
+ classify(regexp, str).snake_case
17
+ end
18
+
19
+ end # Util
20
+ end # Generator
21
+ end # Watir
@@ -0,0 +1,157 @@
1
+ module Watir
2
+ module Generator
3
+ class Base::Visitor < WebIDL::RubySexpVisitor
4
+
5
+ def initialize
6
+ super
7
+
8
+ # When an interface has multiple IDL definitions in the spec, the inheritance is sometimes
9
+ # not repeated. So we'll keep track ourselves.
10
+ @inheritance_map = {}
11
+
12
+ @already_defined = []
13
+ end
14
+
15
+ #
16
+ # WebIDL visitor interface
17
+ #
18
+
19
+ def visit_interface(interface)
20
+ name = interface.name
21
+ parent = interface.inherits.first
22
+
23
+ $stderr.puts name
24
+ return if name !~ interface_regexp || name =~ /(Collection|Document)$/
25
+
26
+ if force_inheritance.keys.include?(name)
27
+ parent = force_inheritance[name]
28
+ elsif parent
29
+ @inheritance_map[name] ||= parent.name
30
+ parent = parent.name
31
+ else
32
+ parent = @inheritance_map[name] || return
33
+ end
34
+
35
+ [ :scope,
36
+ [:block,
37
+ element_class(interface.name, extract_attributes(interface), parent),
38
+ collection_class(interface.name)
39
+ ]
40
+ ]
41
+ end
42
+
43
+ def visit_module(mod)
44
+ # ignored
45
+ end
46
+
47
+ def visit_implements_statement(stmt)
48
+ # ignored
49
+ end
50
+
51
+ # TODO: do everything in the visitor somehow?
52
+ # problem is we lack the tag name info while walking the interface AST
53
+ # #
54
+ # # Watir generator visitor interface
55
+ # #
56
+ #
57
+ # def visit_tag(tag_name, interface_name)
58
+ # tag_string = tag.inspect
59
+ # singular = Util.paramify(classify_regexp, tag)
60
+ # plural = singular.pluralize
61
+ # element_class = Util.classify(classify_regexp, interfaces.first.name)
62
+ # collection_class = "#{element_class}Collection"
63
+ #
64
+ # [:defn,
65
+ # :a,
66
+ # [:args, :"*args"],
67
+ # [:scope,
68
+ # [:block,
69
+ # [:call,
70
+ # [:const, :Anchor],
71
+ # :new,
72
+ # [:arglist,
73
+ # [:self],
74
+ # [:call,
75
+ # [:call, nil, :extract_selector, [:arglist, [:lvar, :args]]],
76
+ # :merge,
77
+ # [:arglist, [:hash, [:lit, :tag_name], [:str, "a"]]]]]]]]]
78
+ # end
79
+
80
+ private
81
+
82
+ def element_class(name, attributes, parent)
83
+ [:class, Util.classify(classify_regexp, name), [:const, Util.classify(classify_regexp, parent)],
84
+ *attribute_calls(attributes)
85
+ ]
86
+ end
87
+
88
+ def extract_attributes(interface)
89
+ members = interface.members
90
+ members += interface.implements.flat_map(&:members)
91
+
92
+ members.select { |e| e.kind_of?(WebIDL::Ast::Attribute) }
93
+ end
94
+
95
+ def collection_class(name)
96
+ return if @already_defined.include?(name)
97
+ @already_defined << name
98
+ name = Util.classify(classify_regexp, name)
99
+
100
+ [:class, "#{name}Collection", [:const, :ElementCollection]]
101
+ end
102
+
103
+ def attribute_calls(attributes)
104
+ attributes.map do |attribute|
105
+ call(:attribute, [
106
+ [:lit, ruby_type_for(attribute.type)],
107
+ [:lit, ruby_method_name_for(attribute)],
108
+ [:lit, attribute.name.to_sym]
109
+ ])
110
+ end
111
+ end
112
+
113
+ def call(name, args)
114
+ [:call, nil, name.to_sym, [:arglist] + args]
115
+ end
116
+
117
+ def ruby_method_name_for(attribute)
118
+ str = attribute.name.snake_case
119
+
120
+ if attribute.type.name == :Boolean
121
+ str = $1 if str =~ /^is_(.+)/
122
+ str << '?'
123
+ end
124
+
125
+ str = 'for' if str == 'html_for'
126
+
127
+ str.to_sym
128
+ end
129
+
130
+ def ruby_type_for(type)
131
+ case type.name.to_s
132
+ when 'DOMString', 'any'
133
+ String
134
+ when 'UnsignedLong', 'Long', 'Integer', 'Short', 'UnsignedShort',
135
+ 'SVGAnimatedLength'
136
+ Fixnum
137
+ when 'Float', /.*Double$/
138
+ Float
139
+ when 'Boolean'
140
+ 'Boolean'
141
+ when 'WindowProxy', 'ValidityState', 'TimeRanges', 'Location',
142
+ 'Any', 'TimedTrackArray', 'TimedTrack', 'TextTrackArray', 'TextTrack',
143
+ /Media.+/, 'TextTrackKind', 'Function', /.*EventHandler$/,
144
+ 'Document', 'DocumentFragment', 'DOMTokenList', 'DOMSettableTokenList',
145
+ 'DOMStringMap', 'HTMLPropertiesCollection', /HTML.*Element/, /HTML.*Collection/,
146
+ 'CSSStyleDeclaration', /.+List$/, 'Date', 'Element', /DOM.+ReadOnly/,
147
+ /SVGAnimated.+/, /SVG.*Element/, /SVG.*Collection/, 'SVGViewSpec'
148
+ # probably completely wrong.
149
+ String
150
+ else
151
+ raise "unknown type: #{type.name}"
152
+ end
153
+ end
154
+
155
+ end # Visitor
156
+ end # Generator
157
+ end # Watir
@@ -0,0 +1,15 @@
1
+ ActiveSupport::Inflector.inflections do |inflect|
2
+ inflect.plural 'body', 'bodys'
3
+ inflect.plural 'tbody', 'tbodys'
4
+ inflect.plural 'canvas', 'canvases'
5
+ inflect.plural 'ins', 'inses'
6
+ inflect.plural /^s$/, 'ss'
7
+ inflect.plural 'meta', 'metas'
8
+ inflect.plural 'details', 'detailses'
9
+ inflect.plural 'data', 'datas'
10
+ inflect.plural 'datalist', 'datalists'
11
+ end
12
+
13
+ require "watir/generator/html/generator"
14
+ require "watir/generator/html/spec_extractor"
15
+ require "watir/generator/html/visitor"
@@ -0,0 +1,36 @@
1
+ module Watir
2
+ module Generator
3
+ class HTML < Base
4
+
5
+ private
6
+
7
+ def ignored_tags
8
+ # ignore the link element for now
9
+ %w(link)
10
+ end
11
+
12
+ def ignored_interfaces
13
+ ignored = ignored_tags.map { |tag| "HTML#{tag.capitalize}Element" }
14
+ # frame is implemented manually, see https://github.com/watir/watir/issues/204
15
+ ignored << 'HTMLFrameElement'
16
+ end
17
+
18
+ def ignored_attributes
19
+ %w(cells elements hash rows span text)
20
+ end
21
+
22
+ def generator_implementation
23
+ 'HTML'
24
+ end
25
+
26
+ def visitor_class
27
+ HTML::Visitor
28
+ end
29
+
30
+ def extractor_class
31
+ HTML::SpecExtractor
32
+ end
33
+
34
+ end # Generator
35
+ end # HTML
36
+ end # Watir
@@ -0,0 +1,50 @@
1
+ module Watir
2
+ module Generator
3
+ class HTML::SpecExtractor < Base::SpecExtractor
4
+
5
+ private
6
+
7
+ def extract_interface_map
8
+ # http://www.whatwg.org/specs/web-apps/current-work/#elements-1
9
+ table = @doc.search("//h3[@id='elements-3']/following-sibling::table[1]").first
10
+ table or raise "could not find elements-3 table"
11
+
12
+ @interface_map = {}
13
+
14
+ parse_table(table).each do |row|
15
+ row['Element'].split(", ").each { |tag| @interface_map[tag] = row['Interface'] }
16
+ end
17
+ end
18
+
19
+ def build_result
20
+ {}.tap do |result|
21
+ @interface_map.each do |tag, interface|
22
+ result[tag] = fetch_interface(interface)
23
+ end
24
+
25
+ # missing from the elements-1 table
26
+ result['frameset'] = fetch_interface('HTMLFrameSetElement')
27
+ end
28
+ end
29
+
30
+ def parse_table(table)
31
+ headers = table.css("thead th").map { |e| e.inner_text.strip }
32
+
33
+ table.css("tbody tr").map do |row|
34
+ result = {}
35
+
36
+ row.css("th, td").each_with_index do |node, idx|
37
+ result[headers[idx]] = node.inner_text.strip
38
+ end
39
+
40
+ result
41
+ end
42
+ end
43
+
44
+ def issued_interfaces
45
+ []
46
+ end
47
+
48
+ end # HTML:;SpecExtractor
49
+ end # Generator
50
+ end # Watir
@@ -0,0 +1,21 @@
1
+ module Watir
2
+ module Generator
3
+ class HTML::Visitor < Base::Visitor
4
+
5
+ def classify_regexp
6
+ /^HTML(.+)Element$/
7
+ end
8
+
9
+ private
10
+
11
+ def interface_regexp
12
+ /^HTML/
13
+ end
14
+
15
+ def force_inheritance
16
+ { 'HTMLElement' => 'Element' }
17
+ end
18
+
19
+ end # HTML::Visitor
20
+ end # Generator
21
+ end # Watir
@@ -0,0 +1,7 @@
1
+ ActiveSupport::Inflector.inflections do |inflect|
2
+ inflect.plural 'defs', 'defss'
3
+ end
4
+
5
+ require "watir/generator/svg/generator"
6
+ require "watir/generator/svg/spec_extractor"
7
+ require "watir/generator/svg/visitor"
@@ -0,0 +1,38 @@
1
+ module Watir
2
+ module Generator
3
+ class SVG < Base
4
+
5
+ private
6
+
7
+ # fix collisions with HTML
8
+ #
9
+ # TODO: change generator so instead these classes
10
+ # are inherited from HTML ones
11
+
12
+ def ignored_tags
13
+ %w(a audio canvas iframe image script source style text title track video)
14
+ end
15
+
16
+ def ignored_interfaces
17
+ ignored_tags.map { |tag| "SVG#{tag.capitalize}Element" }
18
+ end
19
+
20
+ def ignored_attributes
21
+ []
22
+ end
23
+
24
+ def generator_implementation
25
+ 'SVG'
26
+ end
27
+
28
+ def visitor_class
29
+ SVG::Visitor
30
+ end
31
+
32
+ def extractor_class
33
+ SVG::SpecExtractor
34
+ end
35
+
36
+ end # SVG
37
+ end # Generator
38
+ end # Watir
@@ -0,0 +1,46 @@
1
+ module Watir
2
+ module Generator
3
+ class SVG::SpecExtractor < Base::SpecExtractor
4
+
5
+ private
6
+
7
+ def extract_interface_map
8
+ list = @doc.search("//div[@id='chapter-eltindex']//ul/li")
9
+ list.any? or raise 'could not find elements list'
10
+
11
+ @interface_map = parse_list(list)
12
+ end
13
+
14
+ def build_result
15
+ {}.tap do |result|
16
+ @interface_map.each do |tag, interface|
17
+ result[tag] = fetch_interface(interface)
18
+ end
19
+ end
20
+ end
21
+
22
+ def parse_list(list)
23
+ {}.tap do |result|
24
+ list.each do |node|
25
+ tag_name = node.css('a span').inner_text.strip
26
+ id = node.css('a').attr('href').to_s
27
+
28
+ # Some interfaces are actually defined in different specs
29
+ # (for example, clipPath), so we ignore them for now
30
+ if id =~ /^#.+/
31
+ interface_css = 'div.element-summary a.idlinterface'
32
+ interface_name = @doc.css("#{id} #{interface_css}, #{id} ~ #{interface_css}").first.inner_text.strip
33
+
34
+ result[tag_name] = interface_name
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def issued_interfaces
41
+ %w(SVGHatchElement SVGHatchPathElement SVGSolidColorElement)
42
+ end
43
+
44
+ end # SVG::SpecExtractor
45
+ end # Generator
46
+ end # Watir
@@ -0,0 +1,21 @@
1
+ module Watir
2
+ module Generator
3
+ class SVG::Visitor < Base::Visitor
4
+
5
+ def classify_regexp
6
+ /^SVG(.+)Element$/
7
+ end
8
+
9
+ private
10
+
11
+ def interface_regexp
12
+ /^SVG.*Element$/
13
+ end
14
+
15
+ def force_inheritance
16
+ { 'SVGElement' => 'HTMLElement' }
17
+ end
18
+
19
+ end # SVG::Visitor
20
+ end # Generator
21
+ end # Watir
@@ -0,0 +1,53 @@
1
+ module Watir
2
+ module HasWindow
3
+
4
+ #
5
+ # Returns browser windows array.
6
+ #
7
+ # @example
8
+ # browser.windows(title: 'closeable window')
9
+ #
10
+ # @return [Array<Window>]
11
+ #
12
+
13
+ def windows(*args)
14
+ all = @driver.window_handles.map { |handle| Window.new(@driver, handle: handle) }
15
+
16
+ if args.empty?
17
+ all
18
+ else
19
+ filter_windows extract_selector(args), all
20
+ end
21
+ end
22
+
23
+ #
24
+ # Returns browser window.
25
+ #
26
+ # @example
27
+ # browser.window(title: 'closeable window')
28
+ #
29
+ # @return [Window]
30
+ #
31
+
32
+ def window(*args, &blk)
33
+ win = Window.new @driver, extract_selector(args)
34
+
35
+ win.use(&blk) if block_given?
36
+
37
+ win
38
+ end
39
+
40
+ private
41
+
42
+ def filter_windows(selector, windows)
43
+ unless selector.keys.all? { |k| [:title, :url].include? k }
44
+ raise ArgumentError, "invalid window selector: #{selector.inspect}"
45
+ end
46
+
47
+ windows.select do |win|
48
+ selector.all? { |key, value| value === win.send(key) }
49
+ end
50
+ end
51
+
52
+ end # HasWindow
53
+ end # Watir