watir-webdriver 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/README.rdoc +9 -1
  2. data/Rakefile +2 -1
  3. data/VERSION +1 -1
  4. data/lib/watir-webdriver.rb +6 -7
  5. data/lib/watir-webdriver/attribute_helper.rb +17 -10
  6. data/lib/watir-webdriver/browser.rb +1 -1
  7. data/lib/watir-webdriver/cell_container.rb +19 -0
  8. data/lib/watir-webdriver/container.rb +8 -0
  9. data/lib/watir-webdriver/element_collection.rb +2 -2
  10. data/lib/watir-webdriver/elements/button.rb +3 -2
  11. data/lib/watir-webdriver/elements/element.rb +41 -1
  12. data/lib/watir-webdriver/elements/generated.rb +3 -3
  13. data/lib/watir-webdriver/elements/input.rb +0 -52
  14. data/lib/watir-webdriver/elements/select.rb +0 -1
  15. data/lib/watir-webdriver/elements/table.rb +26 -4
  16. data/lib/watir-webdriver/elements/table_cell.rb +36 -0
  17. data/lib/watir-webdriver/elements/table_row.rb +23 -14
  18. data/lib/watir-webdriver/elements/table_section.rb +9 -0
  19. data/lib/watir-webdriver/extensions/alerts.rb +69 -0
  20. data/lib/watir-webdriver/extensions/performance.rb +54 -0
  21. data/lib/watir-webdriver/locators/button_locator.rb +3 -5
  22. data/lib/watir-webdriver/locators/{table_row_locator.rb → child_cell_locator.rb} +11 -6
  23. data/lib/watir-webdriver/locators/child_row_locator.rb +37 -0
  24. data/lib/watir-webdriver/locators/element_locator.rb +24 -14
  25. data/lib/watir-webdriver/row_container.rb +19 -0
  26. data/lib/watir-webdriver/window_switching.rb +37 -10
  27. data/spec/alert_spec.rb +49 -0
  28. data/spec/element_locator_spec.rb +15 -16
  29. data/spec/element_spec.rb +0 -32
  30. data/spec/html/alerts.html +11 -0
  31. data/spec/input_spec.rb +8 -46
  32. data/spec/locator_spec_helper.rb +19 -5
  33. data/spec/spec_helper.rb +3 -0
  34. data/spec/watirspec/areas_spec.rb +8 -0
  35. data/spec/watirspec/browser_spec.rb +4 -4
  36. data/spec/watirspec/button_spec.rb +3 -4
  37. data/spec/watirspec/buttons_spec.rb +8 -0
  38. data/spec/watirspec/checkboxes_spec.rb +8 -0
  39. data/spec/watirspec/dds_spec.rb +8 -0
  40. data/spec/watirspec/dels_spec.rb +8 -0
  41. data/spec/watirspec/divs_spec.rb +8 -0
  42. data/spec/watirspec/dls_spec.rb +8 -0
  43. data/spec/watirspec/dts_spec.rb +8 -0
  44. data/spec/watirspec/element_spec.rb +71 -2
  45. data/spec/watirspec/ems_spec.rb +8 -0
  46. data/spec/watirspec/filefield_spec.rb +16 -11
  47. data/spec/watirspec/filefields_spec.rb +8 -0
  48. data/spec/watirspec/font_spec.rb +21 -19
  49. data/spec/watirspec/form_spec.rb +5 -3
  50. data/spec/watirspec/forms_spec.rb +11 -5
  51. data/spec/watirspec/frames_spec.rb +8 -0
  52. data/spec/watirspec/hiddens_spec.rb +8 -0
  53. data/spec/watirspec/hns_spec.rb +8 -0
  54. data/spec/watirspec/images_spec.rb +8 -0
  55. data/spec/watirspec/inses_spec.rb +8 -0
  56. data/spec/watirspec/label_spec.rb +2 -0
  57. data/spec/watirspec/labels_spec.rb +8 -0
  58. data/spec/watirspec/lib/server.rb +19 -1
  59. data/spec/watirspec/lib/spec_helper.rb +1 -1
  60. data/spec/watirspec/links_spec.rb +8 -0
  61. data/spec/watirspec/lis_spec.rb +8 -0
  62. data/spec/watirspec/maps_spec.rb +8 -0
  63. data/spec/watirspec/metas_spec.rb +8 -0
  64. data/spec/watirspec/ols_spec.rb +8 -0
  65. data/spec/watirspec/pres_spec.rb +8 -0
  66. data/spec/watirspec/ps_spec.rb +8 -0
  67. data/spec/watirspec/radios_spec.rb +8 -0
  68. data/spec/watirspec/select_list_spec.rb +6 -6
  69. data/spec/watirspec/select_lists_spec.rb +8 -0
  70. data/spec/watirspec/spans_spec.rb +8 -0
  71. data/spec/watirspec/strongs_spec.rb +8 -0
  72. data/spec/watirspec/table_nesting_spec.rb +50 -0
  73. data/spec/watirspec/table_spec.rb +62 -102
  74. data/spec/watirspec/tables_spec.rb +8 -0
  75. data/spec/watirspec/{table_body_spec.rb → tbody_spec.rb} +21 -31
  76. data/spec/watirspec/{table_bodies_spec.rb → tbodys_spec.rb} +8 -0
  77. data/spec/watirspec/td_spec.rb +72 -0
  78. data/spec/watirspec/{table_cells_spec.rb → tds_spec.rb} +18 -25
  79. data/spec/watirspec/text_fields_spec.rb +8 -0
  80. data/spec/watirspec/{table_footer_spec.rb → tfoot_spec.rb} +21 -28
  81. data/spec/watirspec/{table_footers_spec.rb → tfoots_spec.rb} +8 -0
  82. data/spec/watirspec/{table_header_spec.rb → thead_spec.rb} +21 -29
  83. data/spec/watirspec/{table_headers_spec.rb → theads_spec.rb} +8 -0
  84. data/spec/watirspec/tr_spec.rb +88 -0
  85. data/spec/watirspec/trs_spec.rb +68 -0
  86. data/spec/watirspec/uls_spec.rb +8 -0
  87. data/spec/watirspec/window_switching_spec.rb +165 -0
  88. data/support/html5.html +884 -422
  89. data/watir-webdriver.gemspec +91 -85
  90. metadata +159 -161
  91. data/Gemfile.lock +0 -48
  92. data/spec/html/closeable.html +0 -13
  93. data/spec/html/data_attributes.html +0 -9
  94. data/spec/html/window_switching.html +0 -12
  95. data/spec/watirspec/table_cell_spec.rb +0 -74
  96. data/spec/watirspec/table_row_spec.rb +0 -99
  97. data/spec/watirspec/table_rows_spec.rb +0 -60
  98. data/spec/window_switching_spec.rb +0 -116
@@ -1,36 +1,45 @@
1
1
  module Watir
2
2
  class TableRow < HTMLElement
3
+ include CellContainer
4
+
5
+ # @private
6
+ attr_writer :locator_class
3
7
 
4
8
  #
5
- # Get the n'th <td> of this element
9
+ # Get the n'th cell (<th> or <td>) of this row
6
10
  #
7
- # @return Watir::TableDataCell
11
+ # @return Watir::TableCell
8
12
  #
9
13
 
10
14
  def [](idx)
11
- td(:index, idx)
15
+ cell(:index, idx)
12
16
  end
13
17
 
14
18
  private
15
19
 
16
- def locate
17
- if @parent.kind_of?(Watir::Table)
18
- @parent.assert_exists
19
- TableRowLocator.new(@parent.wd, @selector, self.class.attribute_list).locate
20
- else
21
- super
22
- end
20
+ def locator_class
21
+ @locator_class || super
23
22
  end
24
-
25
23
  end # TableRow
26
24
 
27
25
 
28
26
  class TableRowCollection < ElementCollection
29
- private
27
+ attr_writer :locator_class
30
28
 
31
- def locator_class
32
- @parent.kind_of?(Watir::Table) ? TableRowLocator : super
29
+ def elements
30
+ # we do this craziness since the xpath used will find direct child rows
31
+ # before any rows inside thead/tbody/tfoot...
32
+ elements = super
33
+
34
+ if locator_class == ChildRowLocator and @parent.kind_of? Table
35
+ elements = elements.sort_by { |row| row.attribute(:rowIndex).to_i }
36
+ end
37
+
38
+ elements
33
39
  end
34
40
 
41
+ def locator_class
42
+ @locator_class || super
43
+ end
35
44
  end # TableRowCollection
36
45
  end # Watir
@@ -0,0 +1,9 @@
1
+ module Watir
2
+ class TableSection < HTMLElement
3
+ include RowContainer
4
+
5
+ def [](idx)
6
+ row(:index => idx)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,69 @@
1
+ module Watir
2
+
3
+ #
4
+ # Module provided by optional require:
5
+ #
6
+ # require "watir-webdriver/extensions/alerts"
7
+ #
8
+
9
+ module AlertHelper
10
+
11
+ #
12
+ # Overwrite window.alert()
13
+ #
14
+ # This method is provided by an optional require - API is subject to change.
15
+ #
16
+ # @example
17
+ # browser.alert do
18
+ # browser.button(:value => "Alert").click
19
+ # end #=> "the alert message"
20
+ #
21
+
22
+ def alert(&blk)
23
+ execute_script "window.alert = function(msg) { window.__lastWatirAlert = msg; }"
24
+ yield
25
+ execute_script "return window.__lastWatirAlert"
26
+ end
27
+
28
+ #
29
+ # Overwrite window.confirm()
30
+ #
31
+ # This method is provided by an optional require - API is subject to change.
32
+ #
33
+ # @example
34
+ # browser.confirm(true) do
35
+ # browser.button(:value => "Confirm").click
36
+ # end #=> "the confirm message"
37
+
38
+ def confirm(bool, &blk)
39
+ execute_script "window.confirm = function(msg) { window.__lastWatirConfirm = msg; return #{!!bool} }"
40
+ yield
41
+ execute_script "return window.__lastWatirConfirm"
42
+ end
43
+
44
+ #
45
+ # Overwrite window.prompt()
46
+ #
47
+ # This method is provided by an optional require - API is subject to change.
48
+ #
49
+ # @example
50
+ # browser.prompt("hello") do
51
+ # browser.button(:value => "Prompt").click
52
+ # end #=> { :message => "foo", :default => "bar" }
53
+ #
54
+
55
+ def prompt(answer, &blk)
56
+ execute_script "window.prompt = function(text, value) { window.__lastWatirPrompt = { message: text, default: value }; return #{answer.to_json}; }"
57
+ yield
58
+ result = execute_script "return window.__lastWatirPrompt"
59
+
60
+ result && result.dup.each_key { |k| result[k.to_sym] = result.delete(k)}
61
+ result
62
+ end
63
+ end
64
+
65
+ class Browser
66
+ include AlertHelper
67
+ end
68
+
69
+ end
@@ -0,0 +1,54 @@
1
+ require "ostruct"
2
+
3
+ module Watir
4
+
5
+ # Adds helper for window.performance to Watir::Browser.
6
+ #
7
+ # This module is provided by an optional require:
8
+ #
9
+ # require "watir-webdriver/extensions/performance"
10
+ #
11
+ # @see http://dev.w3.org/2006/webapi/WebTiming/
12
+ #
13
+
14
+ module PerformanceHelper
15
+
16
+ def performance
17
+ data = driver.execute_script("return window.performance || window.webkitPerformance || window.mozPerformance || window.msPerformance;")
18
+ data && Performance.new(data)
19
+ end
20
+
21
+ class Performance
22
+ attr_reader :timing, :navigation, :memory
23
+
24
+ def initialize(data)
25
+ @timing = rubify data['timing'] || {}
26
+ @navigation = rubify data['navigation'] || {}
27
+ @memory = rubify data['memory'] || {}
28
+ end
29
+
30
+ private
31
+
32
+ def rubify(hash)
33
+ result = {}
34
+
35
+ hash.each do |k, v|
36
+ if k =~ /^[A-Z_]+$/
37
+ k = k.downcase
38
+ elsif k =~ /(start|end)$/i && Fixnum === v
39
+ v = ::Time.at(v / 1000)
40
+ end
41
+
42
+ result[k.snake_case] = v
43
+ end
44
+
45
+ OpenStruct.new(result)
46
+ end
47
+
48
+ end # Performance
49
+ end # PerformanceHelper
50
+
51
+ class Browser
52
+ include PerformanceHelper
53
+ end
54
+ end # Watir
@@ -1,8 +1,6 @@
1
1
  module Watir
2
2
  class ButtonLocator < ElementLocator
3
3
 
4
- VALID_TYPES = %w[button reset submit image]
5
-
6
4
  def locate_all
7
5
  find_all_by_multiple
8
6
  end
@@ -12,7 +10,7 @@ module Watir
12
10
  def wd_find_first_by(how, what)
13
11
  if how == :tag_name
14
12
  how = :xpath
15
- what = ".//button | .//input[#{attribute_expression :type => VALID_TYPES}]"
13
+ what = ".//button | .//input[#{attribute_expression :type => Button::VALID_TYPES}]"
16
14
  end
17
15
 
18
16
  super
@@ -27,7 +25,7 @@ module Watir
27
25
  button_attr_exp = attribute_expression(selectors)
28
26
 
29
27
  @building = :input
30
- selectors[:type] = VALID_TYPES
28
+ selectors[:type] = Button::VALID_TYPES
31
29
  input_attr_exp = attribute_expression(selectors)
32
30
 
33
31
  xpath = ".//button"
@@ -68,7 +66,7 @@ module Watir
68
66
  end
69
67
 
70
68
  def validate_element(element)
71
- return if element.tag_name == "input" && !VALID_TYPES.include?(element.attribute(:type))
69
+ return if element.tag_name == "input" && !Button::VALID_TYPES.include?(element.attribute(:type))
72
70
  super
73
71
  end
74
72
 
@@ -1,5 +1,5 @@
1
1
  module Watir
2
- class TableRowLocator < ElementLocator
2
+ class ChildCellLocator < ElementLocator
3
3
 
4
4
  def locate_all
5
5
  find_all_by_multiple
@@ -7,21 +7,26 @@ module Watir
7
7
 
8
8
  private
9
9
 
10
+ def by_id
11
+ nil
12
+ end
13
+
10
14
  def build_xpath(selectors)
11
15
  return if selectors.values.any? { |e| e.kind_of? Regexp }
12
16
 
13
- selectors.delete(:tag_name) || raise("internal error: no tag_name?!")
14
-
17
+ expressions = %w[./th ./td]
15
18
  attr_expr = attribute_expression(selectors)
16
19
 
20
+ unless attr_expr.empty?
21
+ expressions.map! { |e| "#{e}[#{attr_expr}]" }
22
+ end
17
23
 
18
- xpath = "./*/child::tr"
19
- xpath << "[#{attr_expr}]" unless attr_expr.empty?
24
+ xpath = expressions.join(" | ")
20
25
 
21
26
  p :build_xpath => xpath if $DEBUG
22
27
 
23
28
  xpath
24
29
  end
25
30
 
26
- end # TableRowLocator
31
+ end # ChildCellLocator
27
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
@@ -24,10 +24,8 @@ module Watir
24
24
  end
25
25
 
26
26
  def locate
27
- # short-circuit if :id is given
28
- if e = by_id
29
- return e
30
- end
27
+ e = by_id and return e # short-circuit if :id is given
28
+
31
29
 
32
30
  if @selector.size == 1
33
31
  element = find_first_by_one
@@ -78,7 +76,7 @@ module Watir
78
76
  selector = normalized_selector
79
77
 
80
78
  idx = selector.delete(:index)
81
- xpath = selector[:xpath] || build_xpath(selector)
79
+ xpath = given_xpath(selector) || build_xpath(selector)
82
80
 
83
81
  if xpath
84
82
  # could build xpath for selector
@@ -104,7 +102,7 @@ module Watir
104
102
  raise ArgumentError, "can't locate all elements by :index"
105
103
  end
106
104
 
107
- xpath = selector[:xpath] || build_xpath(selector)
105
+ xpath = given_xpath(selector) || build_xpath(selector)
108
106
  if xpath
109
107
  @wd.find_elements(:xpath, xpath)
110
108
  else
@@ -199,13 +197,14 @@ module Watir
199
197
 
200
198
  def normalize_selector(how, what)
201
199
  case how
202
- when :caption
203
- [:text, what]
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
204
  when :class_name
205
205
  [:class, what]
206
- when :tag_name, :text, :xpath, :index, :class
207
- # include class since the valid attribute is 'class_name'
208
- [how, what]
206
+ when :caption
207
+ [:text, what]
209
208
  else
210
209
  assert_valid_as_attribute how
211
210
  [how, what]
@@ -231,14 +230,15 @@ module Watir
231
230
  end
232
231
 
233
232
  def by_id
233
+ return unless id = @selector[:id] and id.kind_of? String
234
+
234
235
  selector = @selector.dup
235
- id = selector.delete(:id)
236
- return unless id && id.kind_of?(String)
236
+ selector.delete(:id)
237
237
 
238
238
  tag_name = selector.delete(:tag_name)
239
239
  return unless selector.empty? # multiple attributes
240
240
 
241
- element = @wd.find_element(:id, id)
241
+ element = @wd.find_element(:id, id)
242
242
  return if tag_name && !tag_name_matches?(element, tag_name)
243
243
 
244
244
  element
@@ -326,5 +326,15 @@ module Watir
326
326
  element
327
327
  end
328
328
 
329
+ def given_xpath(selector)
330
+ return unless xpath = selector.delete(:xpath)
331
+
332
+ unless selector.empty? || selector.keys == [:tag_name] || (selector[:tag_name] == "input" && selector.keys == [:tag_name, :type])
333
+ raise ArgumentError, ":xpath cannot be combined with other selectors (#{selector.inspect})"
334
+ end
335
+
336
+ xpath
337
+ end
338
+
329
339
  end # ElementLocator
330
340
  end # Watir
@@ -0,0 +1,19 @@
1
+ module Watir
2
+ module RowContainer
3
+
4
+ def row(*args)
5
+ row = tr(*args)
6
+ row.locator_class = ChildRowLocator
7
+
8
+ row
9
+ end
10
+
11
+ def rows(*args)
12
+ rows = trs(*args)
13
+ rows.locator_class = ChildRowLocator
14
+
15
+ rows
16
+ end
17
+
18
+ end
19
+ end
@@ -1,15 +1,16 @@
1
1
  module Watir
2
2
  module WindowSwitching
3
3
 
4
+ class NoMatchingWindowFoundException < StandardError
5
+ end
6
+
4
7
  def windows(*args)
5
- wins = @driver.window_handles.map do |id|
6
- Window.new(@driver, id)
7
- end
8
+ all = @driver.window_handles.map { |id| Window.new(@driver, id) }
8
9
 
9
10
  if args.empty?
10
- wins
11
+ all
11
12
  else
12
- filter_windows(args, wins, :select)
13
+ filter_windows(args, all, :select)
13
14
  end
14
15
  end
15
16
 
@@ -20,19 +21,23 @@ module Watir
20
21
  win.use(&blk)
21
22
  end
22
23
 
23
- win
24
+ win or raise NoMatchingWindowFoundException, args.inspect
24
25
  end
25
26
 
26
27
  private
27
28
 
28
- def filter_windows(args, wins, method)
29
+ def filter_windows(args, all, method)
29
30
  sel = extract_selector(args)
30
31
 
32
+ if sel.empty?
33
+ all.find { |w| w.current? }
34
+ end
35
+
31
36
  unless sel.keys.all? { |k| [:title, :url].include? k }
32
- raise ArgumentError, "invalid window selector: #{sel}"
37
+ raise ArgumentError, "invalid window selector: #{sel.inspect}"
33
38
  end
34
39
 
35
- wins.send(method) do |win|
40
+ all.send(method) do |win|
36
41
  sel.all? { |key, value| value === win.send(key) }
37
42
  end
38
43
  end
@@ -43,11 +48,21 @@ module Watir
43
48
  @driver, @id = driver, id
44
49
  end
45
50
 
46
-
47
51
  def inspect
48
52
  '#<%s:0x%x id=%s>' % [self.class, hash*2, @id.to_s]
49
53
  end
50
54
 
55
+ def ==(other)
56
+ return false unless other.kind_of?(self.class)
57
+
58
+ @id == other.id
59
+ end
60
+ alias_method :eql?, :==
61
+
62
+ def hash
63
+ @id.hash ^ self.class.hash
64
+ end
65
+
51
66
  def current?
52
67
  @driver.window_handle == @id
53
68
  end
@@ -71,8 +86,20 @@ module Watir
71
86
  end
72
87
 
73
88
  def use(&blk)
89
+ if current?
90
+ yield if block_given?
91
+ return self
92
+ end
93
+
74
94
  @driver.switch_to.window(@id, &blk)
75
95
  self
76
96
  end
97
+
98
+ protected
99
+
100
+ def id
101
+ @id
102
+ end
103
+
77
104
  end # Window
78
105
  end # Watir