watir-webdriver 0.6.4 → 0.6.5
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.
- 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
|