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,74 @@
1
+ module Watir
2
+ class ButtonLocator < ElementLocator
3
+
4
+ def locate_all
5
+ find_all_by_multiple
6
+ end
7
+
8
+ private
9
+
10
+ def wd_find_first_by(how, what)
11
+ if how == :tag_name
12
+ how = :xpath
13
+ what = ".//button | .//input[#{attribute_expression :type => Button::VALID_TYPES}]"
14
+ end
15
+
16
+ super
17
+ end
18
+
19
+ def build_xpath(selectors)
20
+ return if selectors.values.any? { |e| e.kind_of? Regexp }
21
+
22
+ selectors.delete(:tag_name) || raise("internal error: no tag_name?!")
23
+
24
+ @building = :button
25
+ button_attr_exp = attribute_expression(selectors)
26
+
27
+ @building = :input
28
+ selectors[:type] = Button::VALID_TYPES
29
+ input_attr_exp = attribute_expression(selectors)
30
+
31
+ xpath = ".//button"
32
+ xpath << "[#{button_attr_exp}]" unless button_attr_exp.empty?
33
+ xpath << " | .//input"
34
+ xpath << "[#{input_attr_exp}]"
35
+
36
+ p :build_xpath => xpath if $DEBUG
37
+
38
+ xpath
39
+ end
40
+
41
+ def lhs_for(key)
42
+ if @building == :input && key == :text
43
+ "@value"
44
+ elsif @building == :button && key == :value
45
+ "text()"
46
+ else
47
+ super
48
+ end
49
+ end
50
+
51
+ def matches_selector?(element, rx_selector)
52
+ rx_selector = rx_selector.dup
53
+
54
+ [:value, :caption].each do |key|
55
+ if rx_selector.has_key?(key)
56
+ correct_key = element.tag_name == 'button' ? :text : :value
57
+ rx_selector[correct_key] = rx_selector.delete(key)
58
+ end
59
+ end
60
+
61
+ super
62
+ end
63
+
64
+ def tag_name_matches?(element, _)
65
+ !!(/^(input|button)$/ === element.tag_name)
66
+ end
67
+
68
+ def validate_element(element)
69
+ return if element.tag_name == "input" && !Button::VALID_TYPES.include?(element.attribute(:type))
70
+ super
71
+ end
72
+
73
+ end # ButtonLocator
74
+ end # Watir
@@ -0,0 +1,32 @@
1
+ module Watir
2
+ class ChildCellLocator < ElementLocator
3
+
4
+ def locate_all
5
+ find_all_by_multiple
6
+ end
7
+
8
+ private
9
+
10
+ def by_id
11
+ nil
12
+ end
13
+
14
+ def build_xpath(selectors)
15
+ return if selectors.values.any? { |e| e.kind_of? Regexp }
16
+
17
+ expressions = %w[./th ./td]
18
+ attr_expr = attribute_expression(selectors)
19
+
20
+ unless attr_expr.empty?
21
+ expressions.map! { |e| "#{e}[#{attr_expr}]" }
22
+ end
23
+
24
+ xpath = expressions.join(" | ")
25
+
26
+ p :build_xpath => xpath if $DEBUG
27
+
28
+ xpath
29
+ end
30
+
31
+ end # ChildCellLocator
32
+ end # Watir
@@ -0,0 +1,37 @@
1
+ module Watir
2
+ class ChildRowLocator < ElementLocator
3
+
4
+ def locate_all
5
+ find_all_by_multiple
6
+ end
7
+
8
+ private
9
+
10
+ def by_id
11
+ nil # avoid this
12
+ end
13
+
14
+ def build_xpath(selectors)
15
+ return if selectors.values.any? { |e| e.kind_of? Regexp }
16
+ selectors.delete(:tag_name) || raise("internal error: no tag_name?!")
17
+
18
+ expressions = %w[./tr]
19
+ unless %w[tbody tfoot thead].include?(@wd.tag_name)
20
+ expressions += %w[./tbody/tr ./thead/tr ./tfoot/tr]
21
+ end
22
+
23
+ attr_expr = attribute_expression(selectors)
24
+
25
+ unless attr_expr.empty?
26
+ expressions.map! { |e| "#{e}[#{attr_expr}]" }
27
+ end
28
+
29
+ xpath = expressions.join(" | ")
30
+
31
+ p :build_xpath => xpath if $DEBUG
32
+
33
+ xpath
34
+ end
35
+
36
+ end # ChildRowLocator
37
+ end # Watir
@@ -0,0 +1,352 @@
1
+ # encoding: utf-8
2
+ module Watir
3
+ class ElementLocator
4
+ include Watir::Exception
5
+ include Selenium
6
+
7
+ WD_FINDERS = [
8
+ :class,
9
+ :class_name,
10
+ :css,
11
+ :id,
12
+ :link,
13
+ :link_text,
14
+ :name,
15
+ :partial_link_text,
16
+ :tag_name,
17
+ :xpath
18
+ ]
19
+
20
+ def initialize(wd, selector, valid_attributes)
21
+ @wd = wd
22
+ @selector = selector.dup
23
+ @valid_attributes = valid_attributes
24
+ end
25
+
26
+ def locate
27
+ e = by_id and return e # short-circuit if :id is given
28
+
29
+
30
+ if @selector.size == 1
31
+ element = find_first_by_one
32
+ else
33
+ element = find_first_by_multiple
34
+ end
35
+
36
+ # this actually only applies when finding by xpath - browser.text_field(:xpath, "//input[@type='radio']")
37
+ # we don't need to validate the element if we built the xpath ourselves.
38
+ validate_element(element) if element
39
+ rescue WebDriver::Error::NoSuchElementError => wde
40
+ nil
41
+ end
42
+
43
+ def locate_all
44
+ if @selector.size == 1
45
+ find_all_by_one
46
+ else
47
+ find_all_by_multiple
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def find_first_by_one
54
+ how, what = @selector.to_a.first
55
+ check_type how, what
56
+
57
+ if WD_FINDERS.include?(how)
58
+ wd_find_first_by(how, what)
59
+ else
60
+ find_first_by_multiple
61
+ end
62
+ end
63
+
64
+ def find_all_by_one
65
+ how, what = @selector.to_a.first
66
+ check_type how, what
67
+
68
+ if WD_FINDERS.include?(how)
69
+ wd_find_all_by(how, what)
70
+ else
71
+ find_all_by_multiple
72
+ end
73
+ end
74
+
75
+ def find_first_by_multiple
76
+ selector = normalized_selector
77
+
78
+ idx = selector.delete(:index)
79
+ xpath = given_xpath(selector) || build_xpath(selector)
80
+
81
+ if xpath
82
+ # could build xpath for selector
83
+ if idx
84
+ @wd.find_elements(:xpath, xpath)[idx]
85
+ else
86
+ @wd.find_element(:xpath, xpath)
87
+ end
88
+ else
89
+ # can't use xpath, probably a regexp in there
90
+ if idx
91
+ wd_find_by_regexp_selector(selector, :select)[idx]
92
+ else
93
+ wd_find_by_regexp_selector(selector, :find)
94
+ end
95
+ end
96
+ end
97
+
98
+ def find_all_by_multiple
99
+ selector = normalized_selector
100
+
101
+ if selector.has_key? :index
102
+ raise ArgumentError, "can't locate all elements by :index"
103
+ end
104
+
105
+ xpath = given_xpath(selector) || build_xpath(selector)
106
+ if xpath
107
+ @wd.find_elements(:xpath, xpath)
108
+ else
109
+ wd_find_by_regexp_selector(selector, :select)
110
+ end
111
+ end
112
+
113
+ def wd_find_first_by(how, what)
114
+ if what.kind_of? String
115
+ @wd.find_element(how, what)
116
+ else
117
+ all_elements.find { |element| fetch_value(element, how) =~ what }
118
+ end
119
+ end
120
+
121
+ def wd_find_all_by(how, what)
122
+ if what.kind_of? String
123
+ @wd.find_elements(how, what)
124
+ else
125
+ all_elements.select { |element| fetch_value(element, how) =~ what }
126
+ end
127
+ end
128
+
129
+ def wd_find_by_regexp_selector(selector, method = :find)
130
+ rx_selector = delete_regexps_from(selector)
131
+
132
+ if rx_selector.has_key?(:label) && should_use_label_element?
133
+ selector[:id] = id_from_label(rx_selector.delete(:label)) || return
134
+ end
135
+
136
+ xpath = build_xpath(selector) || raise("internal error: unable to build xpath from #{selector.inspect}")
137
+
138
+ elements = @wd.find_elements(:xpath, xpath)
139
+ elements.__send__(method) { |el| matches_selector?(el, rx_selector) }
140
+ end
141
+
142
+ VALID_WHATS = [String, Regexp]
143
+
144
+ def check_type(how, what)
145
+ case how
146
+ when :index
147
+ unless what.kind_of?(Fixnum)
148
+ raise TypeError, "expected Fixnum, got #{what.inspect}:#{what.class}"
149
+ end
150
+ else
151
+ unless VALID_WHATS.any? { |t| what.kind_of? t }
152
+ raise TypeError, "expected one of #{VALID_WHATS.inspect}, got #{what.inspect}:#{what.class}"
153
+ end
154
+ end
155
+ end
156
+
157
+ def id_from_label(label_exp)
158
+ # TODO: this won't work correctly if @wd is a sub-element
159
+ label = @wd.find_elements(:tag_name, 'label').find do |el|
160
+ matches_selector?(el, :text => label_exp)
161
+ end
162
+
163
+ label.attribute(:for) if label
164
+ end
165
+
166
+ def fetch_value(element, how)
167
+ case how
168
+ when :text
169
+ element.text
170
+ when :tag_name
171
+ element.tag_name
172
+ when :href
173
+ (href = element.attribute(:href)) && href.strip
174
+ else
175
+ element.attribute(how)
176
+ end
177
+ end
178
+
179
+ def matches_selector?(element, selector)
180
+ selector.all? do |how, what|
181
+ what === fetch_value(element, how)
182
+ end
183
+ end
184
+
185
+ def normalized_selector
186
+ selector = {}
187
+
188
+ @selector.each do |how, what|
189
+ check_type(how, what)
190
+
191
+ how, what = normalize_selector(how, what)
192
+ selector[how] = what
193
+ end
194
+
195
+ selector
196
+ end
197
+
198
+ def normalize_selector(how, what)
199
+ case how
200
+ when :tag_name, :text, :xpath, :index, :class, :for
201
+ # include :class since the valid attribute is 'class_name'
202
+ # include :for since the valid attribute is 'html_for'
203
+ [how, what]
204
+ when :class_name
205
+ [:class, what]
206
+ when :caption
207
+ [:text, what]
208
+ else
209
+ assert_valid_as_attribute how
210
+ [how, what]
211
+ end
212
+ end
213
+
214
+ def delete_regexps_from(selector)
215
+ rx_selector = {}
216
+
217
+ selector.dup.each do |how, what|
218
+ next unless what.kind_of?(Regexp)
219
+ rx_selector[how] = what
220
+ selector.delete how
221
+ end
222
+
223
+ rx_selector
224
+ end
225
+
226
+ def assert_valid_as_attribute(attribute)
227
+ unless valid_attribute? attribute or attribute.to_s =~ /^data_.+$/
228
+ raise MissingWayOfFindingObjectException, "invalid attribute: #{attribute.inspect}"
229
+ end
230
+ end
231
+
232
+ def by_id
233
+ return unless id = @selector[:id] and id.kind_of? String
234
+
235
+ selector = @selector.dup
236
+ selector.delete(:id)
237
+
238
+ tag_name = selector.delete(:tag_name)
239
+ return unless selector.empty? # multiple attributes
240
+
241
+ element = @wd.find_element(:id, id)
242
+ return if tag_name && !tag_name_matches?(element, tag_name)
243
+
244
+ element
245
+ rescue WebDriver::Error::NoSuchElementError => wde
246
+ nil
247
+ end
248
+
249
+ def all_elements
250
+ @wd.find_elements(:xpath => ".//*")
251
+ end
252
+
253
+ def tag_name_matches?(element, tag_name)
254
+ tag_name === element.tag_name
255
+ end
256
+
257
+ def valid_attribute?(attribute)
258
+ @valid_attributes && @valid_attributes.include?(attribute)
259
+ end
260
+
261
+ def should_use_label_element?
262
+ @selector[:tag_name] != "option"
263
+ end
264
+
265
+ def build_xpath(selectors)
266
+ return if selectors.values.any? { |e| e.kind_of? Regexp }
267
+
268
+ xpath = ".//"
269
+ xpath << (selectors.delete(:tag_name) || '*').to_s
270
+
271
+ idx = selectors.delete(:index)
272
+
273
+ # the remaining entries should be attributes
274
+ unless selectors.empty?
275
+ xpath << "[" << attribute_expression(selectors) << "]"
276
+ end
277
+
278
+ if idx
279
+ xpath << "[#{idx + 1}]"
280
+ end
281
+
282
+ p :xpath => xpath, :selectors => selectors if $DEBUG
283
+
284
+ xpath
285
+ end
286
+
287
+ def attribute_expression(selectors)
288
+ selectors.map do |key, val|
289
+ if val.kind_of?(Array)
290
+ "(" + val.map { |v| equal_pair(key, v) }.join(" or ") + ")"
291
+ else
292
+ equal_pair(key, val)
293
+ end
294
+ end.join(" and ")
295
+ end
296
+
297
+ def equal_pair(key, value)
298
+ # we assume :label means a corresponding label element, not the attribute
299
+ if key == :label && should_use_label_element?
300
+ "@id=//label[normalize-space()='#{value}']/@for"
301
+ else
302
+ "#{lhs_for(key)}='#{value}'"
303
+ end
304
+ end
305
+
306
+ def lhs_for(key)
307
+ case key
308
+ when :text, 'text'
309
+ 'normalize-space()'
310
+ when :href
311
+ # TODO: change this behaviour?
312
+ 'normalize-space(@href)'
313
+ else
314
+ "@#{key.to_s.gsub("_", "-")}"
315
+ end
316
+ end
317
+
318
+ def validate_element(element)
319
+ tn = @selector[:tag_name]
320
+ return if tn && !tag_name_matches?(element, tn)
321
+
322
+ if element.tag_name == 'input'
323
+ return if @selector[:type] && @selector[:type] != element.attribute(:type)
324
+ end
325
+
326
+ element
327
+ end
328
+
329
+ def given_xpath(selector)
330
+ return unless xpath = selector.delete(:xpath)
331
+
332
+ unless selector.empty? || can_be_combined_with_xpath?(selector)
333
+ raise ArgumentError, ":xpath cannot be combined with other selectors (#{selector.inspect})"
334
+ end
335
+
336
+ xpath
337
+ end
338
+
339
+ def can_be_combined_with_xpath?(selector)
340
+ # ouch - is this worth it?
341
+ keys = selector.keys
342
+ return true if keys == [:tag_name]
343
+
344
+ if selector[:tag_name] == "input"
345
+ return keys == [:tag_name, :type] || keys == [:type, :tag_name]
346
+ end
347
+
348
+ false
349
+ end
350
+
351
+ end # ElementLocator
352
+ end # Watir