watir-webdriver 0.6.4 → 0.6.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +78 -126
- data/LICENSE +3 -1
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/lib/watir-webdriver.rb +15 -1
- data/lib/watir-webdriver/browser.rb +2 -1
- data/lib/watir-webdriver/cookies.rb +35 -7
- data/lib/watir-webdriver/elements/area.rb +13 -0
- data/lib/watir-webdriver/elements/element.rb +3 -3
- data/lib/watir-webdriver/elements/generated.rb +94 -55
- data/lib/watir-webdriver/elements/{frame.rb → iframe.rb} +41 -28
- data/lib/watir-webdriver/elements/input.rb +0 -16
- data/lib/watir-webdriver/elements/link.rb +13 -1
- data/lib/watir-webdriver/elements/text_area.rb +17 -0
- data/lib/watir-webdriver/html/generator.rb +2 -2
- data/lib/watir-webdriver/html/spec_extractor.rb +31 -4
- data/lib/watir-webdriver/html/visitor.rb +12 -4
- data/lib/watir-webdriver/locators/button_locator.rb +7 -13
- data/lib/watir-webdriver/locators/element_locator.rb +9 -5
- data/lib/watir-webdriver/locators/text_area_locator.rb +20 -0
- data/lib/watir-webdriver/locators/text_field_locator.rb +8 -0
- data/lib/watir-webdriver/version.rb +1 -1
- data/lib/watir-webdriver/wait.rb +23 -11
- data/spec/browser_spec.rb +18 -18
- data/spec/click_spec.rb +5 -5
- data/spec/container_spec.rb +5 -11
- data/spec/element_locator_spec.rb +32 -26
- data/spec/element_spec.rb +9 -9
- data/spec/implementation.rb +6 -2
- data/spec/input_spec.rb +11 -5
- data/spec/locator_spec_helper.rb +3 -3
- data/spec/special_chars_spec.rb +1 -1
- data/support/travis.sh +19 -5
- data/watir-webdriver.gemspec +1 -0
- metadata +37 -38
- data/spec/html/wait.html +0 -28
- data/spec/wait_spec.rb +0 -118
@@ -1,12 +1,13 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Watir
|
3
|
-
class
|
3
|
+
class IFrame < HTMLElement
|
4
4
|
|
5
5
|
def locate
|
6
6
|
@parent.assert_exists
|
7
7
|
|
8
|
-
|
9
|
-
element
|
8
|
+
locator = locator_class.new(@parent.wd, @selector.merge(:tag_name => tag_name), self.class.attribute_list)
|
9
|
+
element = locator.locate
|
10
|
+
element or raise UnknownFrameException, "unable to locate #{@selector[:tag_name]} using #{selector_string}"
|
10
11
|
|
11
12
|
@parent.reset!
|
12
13
|
|
@@ -44,46 +45,58 @@ module Watir
|
|
44
45
|
|
45
46
|
private
|
46
47
|
|
47
|
-
def
|
48
|
-
|
49
|
-
locator.locate
|
48
|
+
def tag_name
|
49
|
+
'iframe'
|
50
50
|
end
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
end # IFrame
|
53
|
+
|
54
|
+
|
55
|
+
class IFrameCollection < ElementCollection
|
56
|
+
|
57
|
+
def to_a
|
58
|
+
(0...elements.size).map { |idx| element_class.new @parent, :index => idx }
|
55
59
|
end
|
56
60
|
|
57
|
-
def
|
58
|
-
|
61
|
+
def element_class
|
62
|
+
IFrame
|
59
63
|
end
|
64
|
+
|
65
|
+
end # IFrameCollection
|
66
|
+
|
67
|
+
|
68
|
+
class Frame < IFrame
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def tag_name
|
73
|
+
'frame'
|
74
|
+
end
|
75
|
+
|
60
76
|
end # Frame
|
61
77
|
|
78
|
+
|
79
|
+
class FrameCollection < IFrameCollection
|
80
|
+
|
81
|
+
def element_class
|
82
|
+
Frame
|
83
|
+
end
|
84
|
+
|
85
|
+
end # FrameCollection
|
86
|
+
|
87
|
+
|
62
88
|
module Container
|
89
|
+
|
63
90
|
def frame(*args)
|
64
|
-
Frame.new(self, extract_selector(args))
|
91
|
+
Frame.new(self, extract_selector(args).merge(:tag_name => "frame"))
|
65
92
|
end
|
66
93
|
|
67
94
|
def frames(*args)
|
68
|
-
FrameCollection.new(self, extract_selector(args).merge(:tag_name =>
|
95
|
+
FrameCollection.new(self, extract_selector(args).merge(:tag_name => "frame"))
|
69
96
|
end
|
70
97
|
|
71
|
-
|
72
|
-
warn "Watir::Container#iframe is replaced by Watir::Container#frame"
|
73
|
-
frame(*args)
|
74
|
-
end
|
75
|
-
|
76
|
-
def iframes(*args)
|
77
|
-
warn "Watir::Container#iframes is replaced by Watir::Container#frames"
|
78
|
-
frame(*args)
|
79
|
-
end
|
80
|
-
end
|
98
|
+
end # Container
|
81
99
|
|
82
|
-
class FrameCollection < ElementCollection
|
83
|
-
def to_a
|
84
|
-
(0...elements.size).map { |idx| element_class.new @parent, :index => idx }
|
85
|
-
end
|
86
|
-
end
|
87
100
|
|
88
101
|
# @api private
|
89
102
|
#
|
@@ -14,21 +14,5 @@ module Watir
|
|
14
14
|
!disabled?
|
15
15
|
end
|
16
16
|
|
17
|
-
#
|
18
|
-
# Return the type attribute of the element, or 'text' if the attribute is invalid.
|
19
|
-
# TODO: discuss.
|
20
|
-
#
|
21
|
-
# @return [String]
|
22
|
-
#
|
23
|
-
|
24
|
-
def type
|
25
|
-
assert_exists
|
26
|
-
value = @element.attribute("type").to_s
|
27
|
-
|
28
|
-
# we return 'text' if the type is invalid
|
29
|
-
# not sure if we really should do this
|
30
|
-
TextFieldLocator::NON_TEXT_TYPES.include?(value) ? value : 'text'
|
31
|
-
end
|
32
|
-
|
33
17
|
end # Input
|
34
18
|
end # Watir
|
@@ -3,5 +3,17 @@ module Watir
|
|
3
3
|
module Container
|
4
4
|
alias_method :link, :a
|
5
5
|
alias_method :links, :as
|
6
|
-
end
|
6
|
+
end # Container
|
7
|
+
|
8
|
+
|
9
|
+
class Anchor < HTMLElement
|
10
|
+
|
11
|
+
#
|
12
|
+
# @todo temporarily add href attribute
|
13
|
+
#
|
14
|
+
# @see https://www.w3.org/Bugs/Public/show_bug.cgi?id=23192
|
15
|
+
#
|
16
|
+
attributes :string => [:href]
|
17
|
+
|
18
|
+
end # Anchor
|
7
19
|
end # Watir
|
@@ -1,5 +1,22 @@
|
|
1
1
|
module Watir
|
2
2
|
class TextArea < HTMLElement
|
3
3
|
include UserEditable
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def locator_class
|
8
|
+
TextAreaLocator
|
9
|
+
end
|
10
|
+
|
4
11
|
end # TextArea
|
12
|
+
|
13
|
+
class TextAreaCollection < ElementCollection
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def locator_class
|
18
|
+
TextAreaLocator
|
19
|
+
end
|
20
|
+
|
21
|
+
end # TextAreaCollection
|
5
22
|
end # Watir
|
@@ -45,6 +45,8 @@ module Watir
|
|
45
45
|
# ignore the link element for now
|
46
46
|
@tag2interfaces.delete("link")
|
47
47
|
@sorted_interfaces.reject! { |intf| intf.name == "HTMLLinkElement" }
|
48
|
+
# frame is implemented manually, see https://github.com/watir/watir-webdriver/issues/204
|
49
|
+
@sorted_interfaces.reject! { |intf| intf.name == "HTMLFrameElement" }
|
48
50
|
end
|
49
51
|
|
50
52
|
def write_header
|
@@ -58,7 +60,6 @@ module Watir
|
|
58
60
|
end
|
59
61
|
end
|
60
62
|
|
61
|
-
|
62
63
|
def write_container_methods
|
63
64
|
@io.puts indent("module Container")
|
64
65
|
|
@@ -101,7 +102,6 @@ CODE
|
|
101
102
|
@io.puts "end # Watir"
|
102
103
|
end
|
103
104
|
|
104
|
-
|
105
105
|
def indent(code, indent = 1)
|
106
106
|
indent_string = " "*indent
|
107
107
|
code.split("\n").map { |line| line.empty? ? line : indent_string + line }.join("\n")
|
@@ -3,6 +3,10 @@
|
|
3
3
|
module Watir
|
4
4
|
module HTML
|
5
5
|
class SpecExtractor
|
6
|
+
|
7
|
+
class InterfaceNotFound < StandardError
|
8
|
+
end
|
9
|
+
|
6
10
|
def initialize(uri)
|
7
11
|
@uri = uri
|
8
12
|
end
|
@@ -39,7 +43,7 @@ module Watir
|
|
39
43
|
end
|
40
44
|
|
41
45
|
def fetch_interface(interface)
|
42
|
-
@interfaces_by_name[interface] or raise "#{interface} not found in IDL"
|
46
|
+
@interfaces_by_name[interface] or raise InterfaceNotFound, "#{interface} not found in IDL"
|
43
47
|
end
|
44
48
|
|
45
49
|
private
|
@@ -51,11 +55,20 @@ module Watir
|
|
51
55
|
def extract_idl_parts
|
52
56
|
parsed = @doc.search("//pre[@class='idl']").map { |e| parse_idl(e.inner_text) }.compact
|
53
57
|
|
54
|
-
|
55
|
-
|
56
|
-
|
58
|
+
implements = []
|
59
|
+
@interfaces = []
|
60
|
+
|
61
|
+
parsed.flatten.each do |element|
|
62
|
+
case element
|
63
|
+
when WebIDL::Ast::Interface
|
64
|
+
@interfaces << element
|
65
|
+
when WebIDL::Ast::ImplementsStatement
|
66
|
+
implements << element
|
67
|
+
end
|
68
|
+
end
|
57
69
|
|
58
70
|
@interfaces_by_name = @interfaces.group_by { |i| i.name }
|
71
|
+
apply_implements(implements)
|
59
72
|
end
|
60
73
|
|
61
74
|
def extract_interface_map
|
@@ -109,6 +122,20 @@ module Watir
|
|
109
122
|
end
|
110
123
|
end
|
111
124
|
|
125
|
+
def apply_implements(implements)
|
126
|
+
implements.each do |is|
|
127
|
+
implementor_name = is.implementor.gsub(/^::/, '')
|
128
|
+
implementee_name = is.implementee.gsub(/^::/, '')
|
129
|
+
|
130
|
+
begin
|
131
|
+
intf = fetch_interface(implementor_name).first
|
132
|
+
intf.implements << fetch_interface(implementee_name).first
|
133
|
+
rescue InterfaceNotFound => ex
|
134
|
+
puts ex.message
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
112
139
|
def idl_parser
|
113
140
|
@idl_parser ||= WebIDL::Parser::IDLParser.new
|
114
141
|
end
|
@@ -36,7 +36,7 @@ module Watir
|
|
36
36
|
|
37
37
|
[ :scope,
|
38
38
|
[:block,
|
39
|
-
element_class(interface.name, interface
|
39
|
+
element_class(interface.name, extract_attributes(interface), parent),
|
40
40
|
collection_class(interface.name)
|
41
41
|
]
|
42
42
|
]
|
@@ -89,6 +89,13 @@ module Watir
|
|
89
89
|
]
|
90
90
|
end
|
91
91
|
|
92
|
+
def extract_attributes(interface)
|
93
|
+
members = interface.members
|
94
|
+
members += interface.implements.flat_map(&:members)
|
95
|
+
|
96
|
+
members.select { |e| e.kind_of?(WebIDL::Ast::Attribute) }
|
97
|
+
end
|
98
|
+
|
92
99
|
def collection_class(name)
|
93
100
|
return if @already_defined.include?(name)
|
94
101
|
@already_defined << name
|
@@ -114,7 +121,7 @@ module Watir
|
|
114
121
|
type = ruby_type_for(a.type)
|
115
122
|
attrs[type] << ruby_attribute_for(type, a.name)
|
116
123
|
end
|
117
|
-
|
124
|
+
|
118
125
|
call :attributes, [literal_hash(attrs)]
|
119
126
|
end
|
120
127
|
|
@@ -152,7 +159,7 @@ module Watir
|
|
152
159
|
:function
|
153
160
|
when 'Boolean'
|
154
161
|
:bool
|
155
|
-
when 'Document'
|
162
|
+
when 'Document', 'DocumentFragment'
|
156
163
|
:document
|
157
164
|
when 'DOMTokenList', 'DOMSettableTokenList'
|
158
165
|
:token_list
|
@@ -173,7 +180,8 @@ module Watir
|
|
173
180
|
when 'Element'
|
174
181
|
:element
|
175
182
|
when 'WindowProxy', 'ValidityState', 'MediaError', 'TimeRanges', 'Location',
|
176
|
-
'Any', 'TimedTrackArray', 'TimedTrack', 'TextTrackArray', 'TextTrack',
|
183
|
+
'Any', 'TimedTrackArray', 'TimedTrack', 'TextTrackArray', 'TextTrack',
|
184
|
+
'MediaController', 'TextTrackKind'
|
177
185
|
# probably completely wrong.
|
178
186
|
:string
|
179
187
|
else
|
@@ -41,25 +41,19 @@ module Watir
|
|
41
41
|
def lhs_for(key)
|
42
42
|
if @building == :input && key == :text
|
43
43
|
"@value"
|
44
|
-
elsif @building == :button && key == :value
|
45
|
-
"text()"
|
46
44
|
else
|
47
45
|
super
|
48
46
|
end
|
49
47
|
end
|
50
48
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
rx_selector[correct_key] = rx_selector.delete(key)
|
59
|
-
end
|
49
|
+
def equal_pair(key, value)
|
50
|
+
if @building == :button && key == :value
|
51
|
+
# :value should look for both node text and @value attribute
|
52
|
+
text = XpathSupport.escape(value)
|
53
|
+
"(text()=#{text} or @value=#{text})"
|
54
|
+
else
|
55
|
+
super
|
60
56
|
end
|
61
|
-
|
62
|
-
super
|
63
57
|
end
|
64
58
|
|
65
59
|
def tag_name_matches?(tag_name, _)
|
@@ -10,12 +10,14 @@ module Watir
|
|
10
10
|
:id,
|
11
11
|
:link,
|
12
12
|
:link_text,
|
13
|
-
|
13
|
+
:name,
|
14
14
|
:partial_link_text,
|
15
15
|
:tag_name,
|
16
16
|
:xpath
|
17
17
|
]
|
18
18
|
|
19
|
+
WILDCARD_ATTRIBUTE = /^(aria|data)_(.+)$/
|
20
|
+
|
19
21
|
def initialize(wd, selector, valid_attributes)
|
20
22
|
@wd = wd
|
21
23
|
@selector = selector.dup
|
@@ -32,8 +34,10 @@ module Watir
|
|
32
34
|
element = find_first_by_multiple
|
33
35
|
end
|
34
36
|
|
35
|
-
#
|
36
|
-
#
|
37
|
+
# This actually only applies when finding by xpath - browser.text_field(:xpath, "//input[@type='radio']")
|
38
|
+
# We don't need to validate the element if we built the xpath ourselves.
|
39
|
+
# It is also used to alter behavior of methods locating more than one type of element
|
40
|
+
# (e.g. text_field locates both input and textarea)
|
37
41
|
validate_element(element) if element
|
38
42
|
rescue Selenium::WebDriver::Error::NoSuchElementError
|
39
43
|
nil
|
@@ -234,7 +238,7 @@ module Watir
|
|
234
238
|
end
|
235
239
|
|
236
240
|
def assert_valid_as_attribute(attribute)
|
237
|
-
unless valid_attribute? attribute or attribute.to_s =~
|
241
|
+
unless valid_attribute? attribute or attribute.to_s =~ WILDCARD_ATTRIBUTE
|
238
242
|
raise MissingWayOfFindingObjectException, "invalid attribute: #{attribute.inspect}"
|
239
243
|
end
|
240
244
|
end
|
@@ -269,7 +273,7 @@ module Watir
|
|
269
273
|
end
|
270
274
|
|
271
275
|
def should_use_label_element?
|
272
|
-
|
276
|
+
!valid_attribute?(:label)
|
273
277
|
end
|
274
278
|
|
275
279
|
def build_wd_selector(selectors)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Watir
|
2
|
+
class TextAreaLocator < ElementLocator
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def normalize_selector(how, what)
|
7
|
+
# We need to iterate through located elements and fetch
|
8
|
+
# attribute value using WebDriver because XPath doesn't understand
|
9
|
+
# difference between IDL vs content attribute.
|
10
|
+
# Current ElementLocator design doesn't allow to do that in any
|
11
|
+
# obvious way except to use regular expression.
|
12
|
+
if how == :value && what.kind_of?(String)
|
13
|
+
[how, Regexp.new('^' + Regexp.escape(what) + '$')]
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end # TextAreaLocator
|
20
|
+
end # Watir
|
@@ -68,5 +68,13 @@ module Watir
|
|
68
68
|
el = super
|
69
69
|
el if el and not NON_TEXT_TYPES.include? el.attribute(:type)
|
70
70
|
end
|
71
|
+
|
72
|
+
def validate_element(element)
|
73
|
+
if element.tag_name.downcase == 'textarea'
|
74
|
+
warn "Locating textareas with '#text_field' is deprecated. Please, use '#textarea' method instead."
|
75
|
+
end
|
76
|
+
super
|
77
|
+
end
|
78
|
+
|
71
79
|
end # TextFieldLocator
|
72
80
|
end # Watir
|
data/lib/watir-webdriver/wait.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
require 'forwardable'
|
3
|
+
|
2
4
|
module Watir
|
3
5
|
module Wait
|
4
6
|
|
@@ -7,6 +9,7 @@ module Watir
|
|
7
9
|
INTERVAL = 0.1
|
8
10
|
|
9
11
|
class << self
|
12
|
+
|
10
13
|
#
|
11
14
|
# Waits until the block evaluates to true or times out.
|
12
15
|
#
|
@@ -18,10 +21,9 @@ module Watir
|
|
18
21
|
# @raise [TimeoutError] if timeout is exceeded
|
19
22
|
#
|
20
23
|
|
21
|
-
def until(timeout =
|
22
|
-
|
23
|
-
|
24
|
-
until ::Time.now > end_time
|
24
|
+
def until(timeout = nil, message = nil, &block)
|
25
|
+
timeout ||= Watir.default_timeout
|
26
|
+
wait(timeout) do
|
25
27
|
result = yield(self)
|
26
28
|
return result if result
|
27
29
|
sleep INTERVAL
|
@@ -41,10 +43,9 @@ module Watir
|
|
41
43
|
# @raise [TimeoutError] if timeout is exceeded
|
42
44
|
#
|
43
45
|
|
44
|
-
def while(timeout =
|
45
|
-
|
46
|
-
|
47
|
-
until ::Time.now > end_time
|
46
|
+
def while(timeout = nil, message = nil, &block)
|
47
|
+
timeout ||= Watir.default_timeout
|
48
|
+
wait(timeout) do
|
48
49
|
return unless yield(self)
|
49
50
|
sleep INTERVAL
|
50
51
|
end
|
@@ -61,6 +62,10 @@ module Watir
|
|
61
62
|
err
|
62
63
|
end
|
63
64
|
|
65
|
+
def wait(timeout, &block)
|
66
|
+
(timeout / INTERVAL).to_i.times &block
|
67
|
+
end
|
68
|
+
|
64
69
|
end # self
|
65
70
|
end # Wait
|
66
71
|
|
@@ -80,6 +85,10 @@ module Watir
|
|
80
85
|
#
|
81
86
|
|
82
87
|
class WhenPresentDecorator
|
88
|
+
extend Forwardable
|
89
|
+
|
90
|
+
def_delegator :@element, :present?
|
91
|
+
|
83
92
|
def initialize(element, timeout, message = nil)
|
84
93
|
@element = element
|
85
94
|
@timeout = timeout
|
@@ -122,7 +131,8 @@ module Watir
|
|
122
131
|
# @see Watir::Element#present?
|
123
132
|
#
|
124
133
|
|
125
|
-
def when_present(timeout =
|
134
|
+
def when_present(timeout = nil)
|
135
|
+
timeout ||= Watir.default_timeout
|
126
136
|
message = "waiting for #{selector_string} to become present"
|
127
137
|
|
128
138
|
if block_given?
|
@@ -145,7 +155,8 @@ module Watir
|
|
145
155
|
# @see Watir::Element#present?
|
146
156
|
#
|
147
157
|
|
148
|
-
def wait_until_present(timeout =
|
158
|
+
def wait_until_present(timeout = nil)
|
159
|
+
timeout ||= Watir.default_timeout
|
149
160
|
message = "waiting for #{selector_string} to become present"
|
150
161
|
Watir::Wait.until(timeout, message) { present? }
|
151
162
|
end
|
@@ -162,7 +173,8 @@ module Watir
|
|
162
173
|
# @see Watir::Element#present?
|
163
174
|
#
|
164
175
|
|
165
|
-
def wait_while_present(timeout =
|
176
|
+
def wait_while_present(timeout = nil)
|
177
|
+
timeout ||= Watir.default_timeout
|
166
178
|
message = "waiting for #{selector_string} to disappear"
|
167
179
|
Watir::Wait.while(timeout, message) { present? }
|
168
180
|
rescue Selenium::WebDriver::Error::ObsoleteElementError
|