ayanko-watir-webdriver 0.1.1.1

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.
Files changed (74) hide show
  1. data/.document +5 -0
  2. data/.gitignore +5 -0
  3. data/.gitmodules +3 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +20 -0
  6. data/README.rdoc +55 -0
  7. data/Rakefile +139 -0
  8. data/VERSION +1 -0
  9. data/lib/watir-webdriver.rb +71 -0
  10. data/lib/watir-webdriver/attribute_helper.rb +128 -0
  11. data/lib/watir-webdriver/browser.rb +164 -0
  12. data/lib/watir-webdriver/browserbot.js +49 -0
  13. data/lib/watir-webdriver/cell_container.rb +19 -0
  14. data/lib/watir-webdriver/container.rb +40 -0
  15. data/lib/watir-webdriver/core_ext/string.rb +22 -0
  16. data/lib/watir-webdriver/element_collection.rb +96 -0
  17. data/lib/watir-webdriver/elements/button.rb +75 -0
  18. data/lib/watir-webdriver/elements/checkbox.rb +73 -0
  19. data/lib/watir-webdriver/elements/element.rb +265 -0
  20. data/lib/watir-webdriver/elements/file_field.rb +69 -0
  21. data/lib/watir-webdriver/elements/font.rb +11 -0
  22. data/lib/watir-webdriver/elements/form.rb +17 -0
  23. data/lib/watir-webdriver/elements/frame.rb +110 -0
  24. data/lib/watir-webdriver/elements/generated.rb +2541 -0
  25. data/lib/watir-webdriver/elements/hidden.rb +24 -0
  26. data/lib/watir-webdriver/elements/image.rb +51 -0
  27. data/lib/watir-webdriver/elements/input.rb +42 -0
  28. data/lib/watir-webdriver/elements/link.rb +7 -0
  29. data/lib/watir-webdriver/elements/option.rb +55 -0
  30. data/lib/watir-webdriver/elements/radio.rb +49 -0
  31. data/lib/watir-webdriver/elements/select.rb +216 -0
  32. data/lib/watir-webdriver/elements/table.rb +37 -0
  33. data/lib/watir-webdriver/elements/table_cell.rb +36 -0
  34. data/lib/watir-webdriver/elements/table_row.rb +45 -0
  35. data/lib/watir-webdriver/elements/table_section.rb +9 -0
  36. data/lib/watir-webdriver/elements/text_field.rb +97 -0
  37. data/lib/watir-webdriver/exception.rb +21 -0
  38. data/lib/watir-webdriver/extensions/alerts.rb +69 -0
  39. data/lib/watir-webdriver/extensions/cookies.rb +39 -0
  40. data/lib/watir-webdriver/extensions/firefox/webdriver.xpi +0 -0
  41. data/lib/watir-webdriver/extensions/nokogiri.rb +14 -0
  42. data/lib/watir-webdriver/extensions/performance.rb +54 -0
  43. data/lib/watir-webdriver/extensions/wait.rb +141 -0
  44. data/lib/watir-webdriver/html.rb +19 -0
  45. data/lib/watir-webdriver/html/generator.rb +112 -0
  46. data/lib/watir-webdriver/html/idl_sorter.rb +49 -0
  47. data/lib/watir-webdriver/html/spec_extractor.rb +111 -0
  48. data/lib/watir-webdriver/html/util.rb +22 -0
  49. data/lib/watir-webdriver/html/visitor.rb +174 -0
  50. data/lib/watir-webdriver/locators/button_locator.rb +74 -0
  51. data/lib/watir-webdriver/locators/child_cell_locator.rb +32 -0
  52. data/lib/watir-webdriver/locators/child_row_locator.rb +37 -0
  53. data/lib/watir-webdriver/locators/element_locator.rb +352 -0
  54. data/lib/watir-webdriver/locators/text_field_locator.rb +65 -0
  55. data/lib/watir-webdriver/row_container.rb +34 -0
  56. data/lib/watir-webdriver/window_switching.rb +105 -0
  57. data/lib/watir-webdriver/xpath_support.rb +28 -0
  58. data/lib/yard/handlers/watir.rb +57 -0
  59. data/spec/alert_spec.rb +49 -0
  60. data/spec/browser_spec.rb +42 -0
  61. data/spec/container_spec.rb +42 -0
  62. data/spec/element_locator_spec.rb +304 -0
  63. data/spec/element_spec.rb +13 -0
  64. data/spec/html/alerts.html +11 -0
  65. data/spec/html/keylogger.html +15 -0
  66. data/spec/html/wait.html +27 -0
  67. data/spec/implementation.rb +17 -0
  68. data/spec/input_spec.rb +39 -0
  69. data/spec/locator_spec_helper.rb +51 -0
  70. data/spec/spec_helper.rb +14 -0
  71. data/spec/wait_spec.rb +98 -0
  72. data/support/html5.html +90243 -0
  73. data/watir-webdriver.gemspec +59 -0
  74. metadata +238 -0
@@ -0,0 +1,19 @@
1
+ require "nokogiri"
2
+ require "open-uri"
3
+ require "pp"
4
+ require "webidl"
5
+ require "active_support/inflector"
6
+
7
+ ActiveSupport::Inflector.inflections do |inflect|
8
+ inflect.plural 'body', 'bodys'
9
+ inflect.plural 'tbody', 'tbodys'
10
+ inflect.plural 'canvas', 'canvases'
11
+ inflect.plural 'ins', 'inses'
12
+ inflect.plural /^s$/, 'ss'
13
+ end
14
+
15
+ require "watir-webdriver/html/util"
16
+ require "watir-webdriver/html/visitor"
17
+ require "watir-webdriver/html/idl_sorter"
18
+ require "watir-webdriver/html/spec_extractor"
19
+ require "watir-webdriver/html/generator"
@@ -0,0 +1,112 @@
1
+ # encoding: utf-8
2
+
3
+ module Watir
4
+ module HTML
5
+ class Generator
6
+
7
+ def generate(spec_url, io = StringIO.new)
8
+ @spec_url, @io = spec_url, io
9
+
10
+ extract_spec
11
+ cleanup_spec
12
+
13
+ write_header
14
+ write_class_defs
15
+ write_container_methods
16
+ write_footer
17
+
18
+ io
19
+ end
20
+
21
+ private
22
+
23
+ def generator
24
+ @generator ||= WebIDL::Generator.new(visitor)
25
+ end
26
+
27
+ def visitor
28
+ @visitor ||= Visitor.new
29
+ end
30
+
31
+ def extractor
32
+ @extractor ||= SpecExtractor.new(@spec_url)
33
+ end
34
+
35
+ def extract_spec
36
+ @tag2interfaces = extractor.process
37
+ @sorted_interfaces = extractor.sorted_interfaces
38
+
39
+ if extractor.errors.any?
40
+ raise "error extracting spec: #{extractor.errors.join("\n")}"
41
+ end
42
+ end
43
+
44
+ def cleanup_spec
45
+ # ignore the link element for now
46
+ @tag2interfaces.delete("link")
47
+ @sorted_interfaces.reject! { |intf| intf.name == "HTMLLinkElement" }
48
+ end
49
+
50
+ def write_header
51
+ @io.puts "# Autogenerated from the HTML5 specification. Edits may be lost."
52
+ @io.puts "module Watir"
53
+ end
54
+
55
+ def write_class_defs
56
+ @sorted_interfaces.each do |interface|
57
+ @io.puts indent(generator.generate(interface))
58
+ end
59
+ end
60
+
61
+
62
+ def write_container_methods
63
+ @io.puts indent("module Container")
64
+
65
+ @tag2interfaces.sort.each do |tag, interfaces|
66
+ raise "multiple interfaces for tag #{tag.inspect}" unless interfaces.map { |e| e.name }.uniq.size == 1
67
+
68
+ tag_string = tag.inspect
69
+ singular = Util.paramify(tag)
70
+ plural = singular.pluralize
71
+ element_class = Util.classify(interfaces.first.name)
72
+ collection_class = "#{element_class}Collection"
73
+
74
+ # visitor.visit_tag(tag, interfaces.first.name) !?
75
+ @io.puts indent(<<-CODE, 3)
76
+ #
77
+ # @return [#{element_class}]
78
+ #
79
+
80
+ def #{singular}(*args)
81
+ #{element_class}.new(self, extract_selector(args).merge(:tag_name => #{tag_string}))
82
+ end
83
+
84
+ #
85
+ # @return [#{collection_class}]
86
+ #
87
+
88
+ def #{plural}(*args)
89
+ #{collection_class}.new(self, extract_selector(args).merge(:tag_name => #{tag_string}))
90
+ end
91
+
92
+ Watir.tag_to_class[#{tag.to_sym.inspect}] = #{element_class}
93
+
94
+ CODE
95
+ end
96
+
97
+ @io.puts indent("end # Container")
98
+ end
99
+
100
+ def write_footer
101
+ @io.puts "end # Watir"
102
+ end
103
+
104
+
105
+ def indent(code, indent = 1)
106
+ indent_string = " "*indent
107
+ code.split("\n").map { |line| line.empty? ? line : indent_string + line }.join("\n")
108
+ end
109
+
110
+ end # Generator
111
+ end # HTML5
112
+ end # Watir
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'tsort'
4
+
5
+ module Watir
6
+ module HTML
7
+ class IDLSorter
8
+ include TSort
9
+
10
+ def initialize(interfaces)
11
+ @interfaces = {}
12
+
13
+ interfaces.each do |interface|
14
+ @interfaces[interface.name] ||= []
15
+ interface.inherits.each do |inherit|
16
+ (@interfaces[inherit.name] ||= []) << interface.name
17
+ end
18
+ end
19
+ end
20
+
21
+ def print
22
+ @visited = []
23
+ sort.each { |node| print_node(node) }
24
+ end
25
+
26
+ def sort
27
+ tsort.reverse
28
+ end
29
+
30
+ def tsort_each_node(&blk)
31
+ @interfaces.each_key(&blk)
32
+ end
33
+
34
+ def tsort_each_child(node, &blk)
35
+ @interfaces[node].each(&blk)
36
+ end
37
+
38
+ private
39
+
40
+ def print_node(node, indent = 0)
41
+ return if @visited.include?(node)
42
+ @visited << node
43
+ puts " "*indent + node
44
+ tsort_each_child(node) { |child| print_node(child, indent + 2)}
45
+ end
46
+
47
+ end # IDLSorter
48
+ end # HTML
49
+ end # Watir
@@ -0,0 +1,111 @@
1
+ # encoding: utf-8
2
+
3
+ module Watir
4
+ module HTML
5
+ class SpecExtractor
6
+ def initialize(uri)
7
+ @uri = uri
8
+ end
9
+
10
+ def process
11
+ download_and_parse
12
+ extract_idl_parts
13
+ extract_interface_map
14
+ build_result
15
+ end
16
+
17
+ def errors
18
+ @errors ||= []
19
+ end
20
+
21
+ #
22
+ # returns a topoligically sorted array of WebIDL::Ast::Interface objects
23
+ #
24
+
25
+ def sorted_interfaces
26
+ process if @interfaces.nil?
27
+
28
+ sorter.sort.map { |name|
29
+ @interfaces_by_name[name] or puts "ignoring interface: #{name}"
30
+ }.flatten.compact
31
+ end
32
+
33
+ def print_hierarchy
34
+ process if @interfaces.nil?
35
+ sorter.print
36
+ end
37
+
38
+ private
39
+
40
+ def download_and_parse
41
+ open(@uri) { |io| @doc = Nokogiri.HTML(io) }
42
+ end
43
+
44
+ def extract_idl_parts
45
+ parsed = @doc.search("//pre[@class='idl']").map { |e| parse_idl(e.inner_text) }.compact
46
+
47
+ @interfaces = parsed.map { |elements|
48
+ elements.select { |e| e.kind_of? WebIDL::Ast::Interface }
49
+ }.flatten
50
+
51
+ @interfaces_by_name = @interfaces.group_by { |i| i.name }
52
+ end
53
+
54
+ def extract_interface_map
55
+ table = @doc.search("//h3[@id='elements-1']/following-sibling::table[1]").first
56
+ table or raise "could not find elements-1 table"
57
+
58
+ @interface_map = {}
59
+
60
+ parse_table(table).each do |row|
61
+ row['Element'].split(", ").each { |tag| @interface_map[tag] = row['Interface'] }
62
+ end
63
+ end
64
+
65
+ def build_result
66
+ # tag name => Interface instance(s)
67
+ result = {}
68
+
69
+ @interface_map.each do |tag, interface|
70
+ result[tag] = @interfaces_by_name[interface] or raise "#{interface} not found in IDL"
71
+ end
72
+
73
+ result
74
+ end
75
+
76
+ def parse_table(table)
77
+ headers = table.css("thead th").map { |e| e.inner_text.strip }
78
+
79
+ table.css("tbody tr").map do |row|
80
+ result = {}
81
+
82
+ row.css("th, td").each_with_index do |node, idx|
83
+ result[headers[idx]] = node.inner_text.strip
84
+ end
85
+
86
+ result
87
+ end
88
+ end
89
+
90
+ def parse_idl(str)
91
+ result = idl_parser.parse(str)
92
+
93
+ if result
94
+ result.build
95
+ else
96
+ errors << idl_parser.failure_reason
97
+ nil
98
+ end
99
+ end
100
+
101
+ def idl_parser
102
+ @idl_parser ||= WebIDL::Parser::IDLParser.new
103
+ end
104
+
105
+ def sorter
106
+ @idl_sroter ||= IDLSorter.new(@interfaces)
107
+ end
108
+
109
+ end # SpecExtractor
110
+ end # HTML
111
+ end # Watir
@@ -0,0 +1,22 @@
1
+ module Watir
2
+ module HTML
3
+ module Util
4
+
5
+ module_function
6
+
7
+ def classify(name)
8
+ if name =~ /^HTML(.+)Element$/
9
+ $1
10
+ else
11
+ name
12
+ end
13
+ end
14
+
15
+ def paramify(str)
16
+ classify(str).snake_case
17
+ end
18
+
19
+ end # Util
20
+ end # HTML
21
+ end # Watir
22
+
@@ -0,0 +1,174 @@
1
+ # encoding: utf-8
2
+
3
+ module Watir
4
+ module HTML
5
+ class Visitor < WebIDL::RubySexpVisitor
6
+
7
+ def initialize
8
+ super
9
+
10
+ # When an interface has multiple IDL definitions in the spec, the inheritance is sometimes
11
+ # not repeated. So we'll keep track ourselves.
12
+ @inheritance_map = {}
13
+
14
+ @already_defined = []
15
+ end
16
+
17
+ #
18
+ # WebIDL visitor interface
19
+ #
20
+
21
+ def visit_interface(interface)
22
+ name = interface.name
23
+ parent = interface.inherits.first
24
+
25
+ $stderr.puts name
26
+ return unless name =~ /^HTML/ && name !~ /(Collection|Document)$/
27
+
28
+ if name == "HTMLElement"
29
+ parent = 'Element'
30
+ elsif parent
31
+ @inheritance_map[name] ||= parent.name
32
+ parent = parent.name
33
+ else
34
+ parent = @inheritance_map[name] || return
35
+ end
36
+
37
+ [ :scope,
38
+ [:block,
39
+ element_class(interface.name, interface.members.select { |e| e.kind_of?(WebIDL::Ast::Attribute) }, parent),
40
+ collection_class(interface.name)
41
+ ]
42
+ ]
43
+ end
44
+
45
+ def visit_module(mod)
46
+ # ignored
47
+ end
48
+
49
+ def visit_implements_statement(stmt)
50
+ # ignored
51
+ end
52
+
53
+ # TODO: do everything in the visitor somehow?
54
+ # problem is we lack the tag name info while walking the interface AST
55
+ # #
56
+ # # Watir generator visitor interface
57
+ # #
58
+ #
59
+ # def visit_tag(tag_name, interface_name)
60
+ # tag_string = tag.inspect
61
+ # singular = Util.paramify(tag)
62
+ # plural = singular.pluralize
63
+ # element_class = Util.classify(interfaces.first.name)
64
+ # collection_class = "#{element_class}Collection"
65
+ #
66
+ # [:defn,
67
+ # :a,
68
+ # [:args, :"*args"],
69
+ # [:scope,
70
+ # [:block,
71
+ # [:call,
72
+ # [:const, :Anchor],
73
+ # :new,
74
+ # [:arglist,
75
+ # [:self],
76
+ # [:call,
77
+ # [:call, nil, :extract_selector, [:arglist, [:lvar, :args]]],
78
+ # :merge,
79
+ # [:arglist, [:hash, [:lit, :tag_name], [:str, "a"]]]]]]]]]
80
+ # end
81
+
82
+ private
83
+
84
+ def element_class(name, attributes, parent)
85
+ [:class, Util.classify(name), [:const, Util.classify(parent)],
86
+ [:scope,
87
+ [:block, attributes_call(attributes)]
88
+ ]
89
+ ]
90
+ end
91
+
92
+ def collection_class(name)
93
+ return if @already_defined.include?(name)
94
+ @already_defined << name
95
+ name = Util.classify(name)
96
+
97
+ [:class, "#{name}Collection", [:const, :ElementCollection],
98
+ [:scope,
99
+ [:defn, :element_class,
100
+ [:args],
101
+ [:scope,
102
+ [:block, [:const, name]]
103
+ ]
104
+ ]
105
+ ]
106
+ ]
107
+ end
108
+
109
+ def attributes_call(attributes)
110
+ return if attributes.empty?
111
+
112
+ attrs = Hash.new { |hash, key| hash[key] = [] }
113
+ attributes.each do |a|
114
+ attrs[ruby_type_for(a.type)] << a.name.snake_case.to_sym
115
+ end
116
+
117
+ call :attributes, [literal_hash(attrs)]
118
+ end
119
+
120
+ def literal_hash(hash)
121
+ [:hash] + hash.map { |k, v| [[:lit, k.to_sym], [:lit, v]] }.flatten(1)
122
+ end
123
+
124
+ def literal_array(arr)
125
+ [:array] + arr.map { |e| [:lit, e.to_sym] }
126
+ end
127
+
128
+ def call(name, args)
129
+ [:call, nil, name.to_sym, [:arglist] + args]
130
+ end
131
+
132
+ def ruby_type_for(type)
133
+ case type.name.to_s
134
+ when 'DOMString', 'any'
135
+ :string
136
+ when 'UnsignedLong', 'Long', 'Integer', 'Short', 'UnsignedShort'
137
+ :int
138
+ when 'Float', 'Double'
139
+ :float
140
+ when 'Function'
141
+ :function
142
+ when 'Boolean'
143
+ :bool
144
+ when 'Document'
145
+ :document
146
+ when 'DOMTokenList', 'DOMSettableTokenList'
147
+ :token_list
148
+ when 'DOMStringMap'
149
+ :string_map
150
+ when 'HTMLPropertiesCollection'
151
+ :properties_collection
152
+ when /HTML(.*)Element/
153
+ :html_element
154
+ when /HTML(.*)Collection/
155
+ :html_collection
156
+ when 'CSSStyleDeclaration'
157
+ :style
158
+ when /.+List$/
159
+ :list
160
+ when 'Date'
161
+ :date
162
+ when 'Element'
163
+ :element
164
+ when 'WindowProxy', 'ValidityState', 'MediaError', 'TimeRanges', 'Location', 'Any', 'TimedTrackArray', 'TimedTrack'
165
+ # probably completely wrong.
166
+ :string
167
+ else
168
+ raise "unknown type: #{type.name}"
169
+ end
170
+ end
171
+
172
+ end # Visitor
173
+ end # Support
174
+ end # Watir