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.
- data/README.rdoc +9 -1
- data/Rakefile +2 -1
- data/VERSION +1 -1
- data/lib/watir-webdriver.rb +6 -7
- data/lib/watir-webdriver/attribute_helper.rb +17 -10
- data/lib/watir-webdriver/browser.rb +1 -1
- data/lib/watir-webdriver/cell_container.rb +19 -0
- data/lib/watir-webdriver/container.rb +8 -0
- data/lib/watir-webdriver/element_collection.rb +2 -2
- data/lib/watir-webdriver/elements/button.rb +3 -2
- data/lib/watir-webdriver/elements/element.rb +41 -1
- data/lib/watir-webdriver/elements/generated.rb +3 -3
- data/lib/watir-webdriver/elements/input.rb +0 -52
- data/lib/watir-webdriver/elements/select.rb +0 -1
- data/lib/watir-webdriver/elements/table.rb +26 -4
- data/lib/watir-webdriver/elements/table_cell.rb +36 -0
- data/lib/watir-webdriver/elements/table_row.rb +23 -14
- data/lib/watir-webdriver/elements/table_section.rb +9 -0
- data/lib/watir-webdriver/extensions/alerts.rb +69 -0
- data/lib/watir-webdriver/extensions/performance.rb +54 -0
- data/lib/watir-webdriver/locators/button_locator.rb +3 -5
- data/lib/watir-webdriver/locators/{table_row_locator.rb → child_cell_locator.rb} +11 -6
- data/lib/watir-webdriver/locators/child_row_locator.rb +37 -0
- data/lib/watir-webdriver/locators/element_locator.rb +24 -14
- data/lib/watir-webdriver/row_container.rb +19 -0
- data/lib/watir-webdriver/window_switching.rb +37 -10
- data/spec/alert_spec.rb +49 -0
- data/spec/element_locator_spec.rb +15 -16
- data/spec/element_spec.rb +0 -32
- data/spec/html/alerts.html +11 -0
- data/spec/input_spec.rb +8 -46
- data/spec/locator_spec_helper.rb +19 -5
- data/spec/spec_helper.rb +3 -0
- data/spec/watirspec/areas_spec.rb +8 -0
- data/spec/watirspec/browser_spec.rb +4 -4
- data/spec/watirspec/button_spec.rb +3 -4
- data/spec/watirspec/buttons_spec.rb +8 -0
- data/spec/watirspec/checkboxes_spec.rb +8 -0
- data/spec/watirspec/dds_spec.rb +8 -0
- data/spec/watirspec/dels_spec.rb +8 -0
- data/spec/watirspec/divs_spec.rb +8 -0
- data/spec/watirspec/dls_spec.rb +8 -0
- data/spec/watirspec/dts_spec.rb +8 -0
- data/spec/watirspec/element_spec.rb +71 -2
- data/spec/watirspec/ems_spec.rb +8 -0
- data/spec/watirspec/filefield_spec.rb +16 -11
- data/spec/watirspec/filefields_spec.rb +8 -0
- data/spec/watirspec/font_spec.rb +21 -19
- data/spec/watirspec/form_spec.rb +5 -3
- data/spec/watirspec/forms_spec.rb +11 -5
- data/spec/watirspec/frames_spec.rb +8 -0
- data/spec/watirspec/hiddens_spec.rb +8 -0
- data/spec/watirspec/hns_spec.rb +8 -0
- data/spec/watirspec/images_spec.rb +8 -0
- data/spec/watirspec/inses_spec.rb +8 -0
- data/spec/watirspec/label_spec.rb +2 -0
- data/spec/watirspec/labels_spec.rb +8 -0
- data/spec/watirspec/lib/server.rb +19 -1
- data/spec/watirspec/lib/spec_helper.rb +1 -1
- data/spec/watirspec/links_spec.rb +8 -0
- data/spec/watirspec/lis_spec.rb +8 -0
- data/spec/watirspec/maps_spec.rb +8 -0
- data/spec/watirspec/metas_spec.rb +8 -0
- data/spec/watirspec/ols_spec.rb +8 -0
- data/spec/watirspec/pres_spec.rb +8 -0
- data/spec/watirspec/ps_spec.rb +8 -0
- data/spec/watirspec/radios_spec.rb +8 -0
- data/spec/watirspec/select_list_spec.rb +6 -6
- data/spec/watirspec/select_lists_spec.rb +8 -0
- data/spec/watirspec/spans_spec.rb +8 -0
- data/spec/watirspec/strongs_spec.rb +8 -0
- data/spec/watirspec/table_nesting_spec.rb +50 -0
- data/spec/watirspec/table_spec.rb +62 -102
- data/spec/watirspec/tables_spec.rb +8 -0
- data/spec/watirspec/{table_body_spec.rb → tbody_spec.rb} +21 -31
- data/spec/watirspec/{table_bodies_spec.rb → tbodys_spec.rb} +8 -0
- data/spec/watirspec/td_spec.rb +72 -0
- data/spec/watirspec/{table_cells_spec.rb → tds_spec.rb} +18 -25
- data/spec/watirspec/text_fields_spec.rb +8 -0
- data/spec/watirspec/{table_footer_spec.rb → tfoot_spec.rb} +21 -28
- data/spec/watirspec/{table_footers_spec.rb → tfoots_spec.rb} +8 -0
- data/spec/watirspec/{table_header_spec.rb → thead_spec.rb} +21 -29
- data/spec/watirspec/{table_headers_spec.rb → theads_spec.rb} +8 -0
- data/spec/watirspec/tr_spec.rb +88 -0
- data/spec/watirspec/trs_spec.rb +68 -0
- data/spec/watirspec/uls_spec.rb +8 -0
- data/spec/watirspec/window_switching_spec.rb +165 -0
- data/support/html5.html +884 -422
- data/watir-webdriver.gemspec +91 -85
- metadata +159 -161
- data/Gemfile.lock +0 -48
- data/spec/html/closeable.html +0 -13
- data/spec/html/data_attributes.html +0 -9
- data/spec/html/window_switching.html +0 -12
- data/spec/watirspec/table_cell_spec.rb +0 -74
- data/spec/watirspec/table_row_spec.rb +0 -99
- data/spec/watirspec/table_rows_spec.rb +0 -60
- 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
|
9
|
+
# Get the n'th cell (<th> or <td>) of this row
|
6
10
|
#
|
7
|
-
# @return Watir::
|
11
|
+
# @return Watir::TableCell
|
8
12
|
#
|
9
13
|
|
10
14
|
def [](idx)
|
11
|
-
|
15
|
+
cell(:index, idx)
|
12
16
|
end
|
13
17
|
|
14
18
|
private
|
15
19
|
|
16
|
-
def
|
17
|
-
|
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
|
-
|
27
|
+
attr_writer :locator_class
|
30
28
|
|
31
|
-
def
|
32
|
-
|
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,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
|
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
|
-
|
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 = "
|
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 #
|
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
|
-
|
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
|
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
|
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 :
|
203
|
-
|
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 :
|
207
|
-
|
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
|
-
|
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
|
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
|
@@ -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
|
-
|
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
|
-
|
11
|
+
all
|
11
12
|
else
|
12
|
-
filter_windows(args,
|
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,
|
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
|
-
|
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
|