ayanko-watir-webdriver 0.1.1.1

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