watir 6.11.0.beta1 → 6.11.0.beta2
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 +5 -0
- data/lib/watir/element_collection.rb +3 -8
- data/lib/watir/elements/element.rb +3 -12
- data/lib/watir/locators.rb +8 -0
- data/lib/watir/locators/element/locator.rb +81 -76
- data/spec/element_locator_spec.rb +0 -2
- data/spec/spec_helper.rb +1 -1
- data/spec/watirspec/relaxed_locate_spec.rb +32 -0
- data/watir.gemspec +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 37e5bd05d8b6ed813503264d89bcaf6aceb4b67d5ad2217569c4aef4b7762ca5
|
|
4
|
+
data.tar.gz: 49c34f4a6e37dec3788fdc5c91ae3d06368b6b0d34c5365387e46d2ee07fe922
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b654a96f43a8d9dc84645cc595c018a6263f180f3bd2e8dc20f03ed8ff2d43c135a267d0cf65f7c87c5cfe1ac9d3524cd438a77d13830ebfb179c9cbb4802693
|
|
7
|
+
data.tar.gz: d358cfee80f3afae74f39f8aa1d91ba9e98ed6d231735ab19d535ccb3932a0ef273e29e5749dc3ca51778c6220a58e84e5774a26e44403ab0c1592db5fc1ade3
|
data/CHANGES.md
CHANGED
|
@@ -45,7 +45,7 @@ module Watir
|
|
|
45
45
|
#
|
|
46
46
|
|
|
47
47
|
def [](idx)
|
|
48
|
-
|
|
48
|
+
element_class.new(@query_scope, @selector.merge(index: idx))
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
#
|
|
@@ -121,13 +121,8 @@ module Watir
|
|
|
121
121
|
private
|
|
122
122
|
|
|
123
123
|
def elements
|
|
124
|
-
@
|
|
125
|
-
|
|
126
|
-
element_validator = element_validator_class.new
|
|
127
|
-
selector_builder = selector_builder_class.new(@query_scope, @selector, element_class.attribute_list)
|
|
128
|
-
locator = locator_class.new(@query_scope, @selector, selector_builder, element_validator)
|
|
129
|
-
|
|
130
|
-
@elements ||= locator.locate_all
|
|
124
|
+
@locator ||= build_locator
|
|
125
|
+
@elements ||= @locator.locate_all
|
|
131
126
|
end
|
|
132
127
|
|
|
133
128
|
def element_class
|
|
@@ -389,8 +389,8 @@ module Watir
|
|
|
389
389
|
#
|
|
390
390
|
|
|
391
391
|
def wd
|
|
392
|
-
return driver if @element.is_a? FramedDriver
|
|
393
392
|
assert_exists if @element.nil?
|
|
393
|
+
return driver if @element.is_a? FramedDriver
|
|
394
394
|
@element
|
|
395
395
|
end
|
|
396
396
|
|
|
@@ -577,21 +577,12 @@ module Watir
|
|
|
577
577
|
# Ensure that the element exists, making sure that it is not stale and located if necessary
|
|
578
578
|
def assert_exists
|
|
579
579
|
locate unless @element
|
|
580
|
-
assert_element_found
|
|
581
|
-
end
|
|
582
|
-
|
|
583
|
-
def assert_element_found
|
|
584
580
|
return if @element
|
|
585
581
|
raise unknown_exception, "unable to locate element: #{inspect}"
|
|
586
582
|
end
|
|
587
583
|
|
|
588
584
|
def locate
|
|
589
|
-
@
|
|
590
|
-
|
|
591
|
-
element_validator = element_validator_class.new
|
|
592
|
-
selector_builder = selector_builder_class.new(@query_scope, @selector.dup, self.class.attribute_list)
|
|
593
|
-
@locator = locator_class.new(@query_scope, @selector.dup, selector_builder, element_validator)
|
|
594
|
-
|
|
585
|
+
@locator = build_locator
|
|
595
586
|
@element = @locator.locate
|
|
596
587
|
end
|
|
597
588
|
|
|
@@ -662,7 +653,7 @@ module Watir
|
|
|
662
653
|
end
|
|
663
654
|
msg = ex.message
|
|
664
655
|
msg += "; Maybe look in an iframe?" if @query_scope.ensure_context && @query_scope.iframes.count > 0
|
|
665
|
-
custom_attributes = @locator.selector_builder.custom_attributes
|
|
656
|
+
custom_attributes = @locator.nil? ? [] : @locator.selector_builder.custom_attributes
|
|
666
657
|
msg += "; Watir treated #{custom_attributes} as a non-HTML compliant attribute, ensure that was intended" unless custom_attributes.empty?
|
|
667
658
|
raise unknown_exception, msg
|
|
668
659
|
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
data/lib/watir/locators.rb
CHANGED
|
@@ -55,6 +55,14 @@ module Watir
|
|
|
55
55
|
def element_class_name
|
|
56
56
|
element_class.to_s.split('::').last
|
|
57
57
|
end
|
|
58
|
+
|
|
59
|
+
def build_locator
|
|
60
|
+
@query_scope.send :ensure_context
|
|
61
|
+
|
|
62
|
+
element_validator = element_validator_class.new
|
|
63
|
+
selector_builder = selector_builder_class.new(@query_scope, @selector.dup, element_class.attribute_list)
|
|
64
|
+
locator_class.new(@query_scope, @selector.dup, selector_builder, element_validator)
|
|
65
|
+
end
|
|
58
66
|
end
|
|
59
67
|
end
|
|
60
68
|
end
|
|
@@ -5,14 +5,10 @@ module Watir
|
|
|
5
5
|
attr_reader :selector_builder
|
|
6
6
|
attr_reader :element_validator
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
:class,
|
|
10
|
-
:class_name,
|
|
8
|
+
W3C_FINDERS = [
|
|
11
9
|
:css,
|
|
12
|
-
:id,
|
|
13
10
|
:link,
|
|
14
11
|
:link_text,
|
|
15
|
-
:name,
|
|
16
12
|
:partial_link_text,
|
|
17
13
|
:tag_name,
|
|
18
14
|
:xpath
|
|
@@ -49,53 +45,34 @@ module Watir
|
|
|
49
45
|
private
|
|
50
46
|
|
|
51
47
|
def using_selenium(filter = :first)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
selector.delete(:tag_name) if selector.size > 1
|
|
55
|
-
|
|
56
|
-
WD_FINDERS.each do |sel|
|
|
57
|
-
next unless (value = selector.delete(sel))
|
|
58
|
-
return unless selector.empty? && wd_supported?(sel, value)
|
|
59
|
-
if filter == :all
|
|
60
|
-
found = locate_elements(sel, value)
|
|
61
|
-
return found if sel == :tag_name
|
|
62
|
-
filter_selector = tag_name ? {tag_name: tag_name} : {}
|
|
63
|
-
return filter_elements(found, filter_selector, filter: filter).compact
|
|
64
|
-
else
|
|
65
|
-
found = locate_element(sel, value)
|
|
66
|
-
return sel != :tag_name && tag_name && !validate([found], tag_name) ? nil : found
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
nil
|
|
70
|
-
end
|
|
48
|
+
tag = @selector[:tag_name].is_a?(::Symbol) ? @selector.delete(:tag_name).to_s : @selector.delete(:tag_name)
|
|
49
|
+
return if @selector.size > 1
|
|
71
50
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
selector = selector_builder.normalized_selector
|
|
51
|
+
how = @selector.keys.first || :tag_name
|
|
52
|
+
what = @selector.values.first || tag
|
|
75
53
|
|
|
76
|
-
|
|
77
|
-
query_scope = convert_label_to_scope_or_selector(query_scope, selector)
|
|
78
|
-
return unless query_scope # stop, label not found
|
|
79
|
-
end
|
|
54
|
+
return unless wd_supported?(how, what, tag)
|
|
80
55
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
56
|
+
filter == :all ? locate_elements(how, what) : locate_element(how, what)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def using_watir(filter = :first)
|
|
60
|
+
create_normalized_selector(filter)
|
|
61
|
+
return unless @normalized_selector
|
|
84
62
|
|
|
85
|
-
|
|
63
|
+
create_filter_selector
|
|
86
64
|
|
|
87
|
-
how, what = selector_builder.build(
|
|
65
|
+
how, what = selector_builder.build(@normalized_selector.dup)
|
|
88
66
|
unless how
|
|
89
|
-
raise Error, "internal error: unable to build Selenium selector from #{
|
|
67
|
+
raise Error, "internal error: unable to build Selenium selector from #{@normalized_selector.inspect}"
|
|
90
68
|
end
|
|
91
|
-
what = add_regexp_predicates(what
|
|
69
|
+
what = add_regexp_predicates(what) if how == :xpath
|
|
92
70
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
elements
|
|
96
|
-
filter_elements(elements, filter_selector, filter: filter)
|
|
71
|
+
if filter == :all || !@filter_selector.empty?
|
|
72
|
+
elements = locate_elements(how, what, @driver_scope) || []
|
|
73
|
+
filter_elements(elements, filter: filter)
|
|
97
74
|
else
|
|
98
|
-
locate_element(how, what,
|
|
75
|
+
locate_element(how, what, @driver_scope)
|
|
99
76
|
end
|
|
100
77
|
end
|
|
101
78
|
|
|
@@ -125,7 +102,8 @@ module Watir
|
|
|
125
102
|
end
|
|
126
103
|
end
|
|
127
104
|
|
|
128
|
-
def filter_elements(elements,
|
|
105
|
+
def filter_elements(elements, filter: :first)
|
|
106
|
+
selector = @filter_selector.dup
|
|
129
107
|
if filter == :first
|
|
130
108
|
idx = selector.delete(:index) || 0
|
|
131
109
|
if idx < 0
|
|
@@ -141,57 +119,79 @@ module Watir
|
|
|
141
119
|
end
|
|
142
120
|
end
|
|
143
121
|
|
|
144
|
-
def
|
|
145
|
-
|
|
122
|
+
def create_normalized_selector(filter)
|
|
123
|
+
return @normalized_selector if @normalized_selector
|
|
124
|
+
@driver_scope = ensure_scope_context
|
|
125
|
+
|
|
126
|
+
@normalized_selector = selector_builder.normalized_selector
|
|
127
|
+
|
|
128
|
+
if @normalized_selector[:label]
|
|
129
|
+
process_label
|
|
130
|
+
return if @normalized_selector.nil?
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
if @normalized_selector.key?(:index) && filter == :all
|
|
134
|
+
raise ArgumentError, "can't locate all elements by :index"
|
|
135
|
+
end
|
|
136
|
+
@normalized_selector
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def create_filter_selector
|
|
140
|
+
return @filter_selector if @filter_selector
|
|
141
|
+
@filter_selector = {}
|
|
146
142
|
|
|
147
143
|
# Remove selectors that can never be used in XPath builder
|
|
148
144
|
[:visible, :visible_text].each do |how|
|
|
149
|
-
next unless
|
|
150
|
-
filter_selector[how] =
|
|
145
|
+
next unless @normalized_selector.key?(how)
|
|
146
|
+
@filter_selector[how] = @normalized_selector.delete(how)
|
|
151
147
|
end
|
|
152
148
|
|
|
153
|
-
if tag_validation_required?(
|
|
154
|
-
tag_name =
|
|
155
|
-
filter_selector[:tag_name] = tag_name
|
|
149
|
+
if tag_validation_required?(@normalized_selector)
|
|
150
|
+
tag_name = @normalized_selector[:tag_name].is_a?(::Symbol) ? @normalized_selector[:tag_name].to_s : @normalized_selector[:tag_name]
|
|
151
|
+
@filter_selector[:tag_name] = tag_name
|
|
156
152
|
end
|
|
157
153
|
|
|
158
154
|
# Regexp locators currently need to be validated even if they are included in the XPath builder
|
|
159
155
|
# TODO: Identify Regexp that can have an exact equivalent using XPath contains (ie would not require
|
|
160
156
|
# filtering) vs approximations (ie would still requiring filtering)
|
|
161
|
-
|
|
157
|
+
@normalized_selector.each do |how, what|
|
|
162
158
|
next unless what.is_a?(Regexp)
|
|
163
|
-
filter_selector[how] =
|
|
159
|
+
@filter_selector[how] = @normalized_selector.delete(how)
|
|
164
160
|
end
|
|
165
161
|
|
|
166
|
-
if
|
|
167
|
-
idx =
|
|
162
|
+
if @normalized_selector[:index] && !@normalized_selector[:adjacent]
|
|
163
|
+
idx = @normalized_selector.delete(:index)
|
|
168
164
|
|
|
169
165
|
# Do not add {index: 0} filter if the only filter. This will allow using #find_element instead of #find_elements.
|
|
170
|
-
implicit_idx_filter = filter_selector.empty? && idx == 0
|
|
171
|
-
filter_selector[:index] = idx unless implicit_idx_filter
|
|
166
|
+
implicit_idx_filter = @filter_selector.empty? && idx == 0
|
|
167
|
+
@filter_selector[:index] = idx unless implicit_idx_filter
|
|
172
168
|
end
|
|
173
169
|
|
|
174
|
-
filter_selector
|
|
170
|
+
@filter_selector
|
|
175
171
|
end
|
|
176
172
|
|
|
177
|
-
def
|
|
178
|
-
return
|
|
173
|
+
def process_label
|
|
174
|
+
return unless @normalized_selector[:label].kind_of?(Regexp) && selector_builder.should_use_label_element?
|
|
179
175
|
|
|
180
|
-
label = label_from_text
|
|
181
|
-
|
|
176
|
+
label = label_from_text
|
|
177
|
+
unless label # label not found, stop looking for element
|
|
178
|
+
@normalized_selector = nil
|
|
179
|
+
return
|
|
180
|
+
end
|
|
182
181
|
|
|
183
182
|
if (id = label.attribute('for'))
|
|
184
|
-
|
|
185
|
-
query_scope
|
|
183
|
+
@normalized_selector[:id] = id
|
|
186
184
|
else
|
|
187
|
-
label
|
|
185
|
+
@driver_scope = label
|
|
188
186
|
end
|
|
189
187
|
end
|
|
190
188
|
|
|
191
|
-
def label_from_text
|
|
192
|
-
# TODO: this won't work correctly if @wd is a sub-element
|
|
193
|
-
|
|
194
|
-
|
|
189
|
+
def label_from_text
|
|
190
|
+
# TODO: this won't work correctly if @wd is a sub-element, write spec
|
|
191
|
+
# TODO: Figure out how to do this with find_element
|
|
192
|
+
label_text = @normalized_selector.delete(:label)
|
|
193
|
+
locate_elements(:tag_name, 'label', @driver_scope).find do |el|
|
|
194
|
+
matches_selector?(el, text: label_text)
|
|
195
195
|
end
|
|
196
196
|
end
|
|
197
197
|
|
|
@@ -209,10 +209,10 @@ module Watir
|
|
|
209
209
|
true
|
|
210
210
|
end
|
|
211
211
|
|
|
212
|
-
def add_regexp_predicates(what
|
|
212
|
+
def add_regexp_predicates(what)
|
|
213
213
|
return what unless can_convert_regexp_to_contains?
|
|
214
214
|
|
|
215
|
-
filter_selector.each do |key, value|
|
|
215
|
+
@filter_selector.each do |key, value|
|
|
216
216
|
next if [:tag_name, :text, :visible_text, :visible, :index].include?(key)
|
|
217
217
|
|
|
218
218
|
predicates = regexp_selector_to_predicates(key, value)
|
|
@@ -251,12 +251,17 @@ module Watir
|
|
|
251
251
|
scope.find_elements(how, what)
|
|
252
252
|
end
|
|
253
253
|
|
|
254
|
-
def wd_supported?(how, what)
|
|
254
|
+
def wd_supported?(how, what, tag)
|
|
255
|
+
return false unless W3C_FINDERS.include? how
|
|
255
256
|
return false unless what.kind_of?(String)
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
if %i[partial_link_text link_text link].include?(how)
|
|
258
|
+
Watir.logger.deprecate(":#{how} locator", ':visible_text')
|
|
259
|
+
return true if [:a, :link, nil].include?(tag)
|
|
260
|
+
raise StandardError, "Can not use #{how} locator to find a #{what} element"
|
|
261
|
+
elsif how == :tag_name
|
|
262
|
+
return true
|
|
263
|
+
else
|
|
264
|
+
return false unless tag.nil?
|
|
260
265
|
end
|
|
261
266
|
true
|
|
262
267
|
end
|
|
@@ -88,7 +88,6 @@ describe Watir::Locators::Element::Locator do
|
|
|
88
88
|
element(tag_name: "div", attributes: { class: "foo" })
|
|
89
89
|
]
|
|
90
90
|
|
|
91
|
-
expect_one(:xpath, './/*[@class="foo"]').and_return(elements.first)
|
|
92
91
|
expect_all(:xpath, './/*[@class="foo"]').and_return(elements)
|
|
93
92
|
|
|
94
93
|
selector = {
|
|
@@ -337,7 +336,6 @@ describe Watir::Locators::Element::Locator do
|
|
|
337
336
|
end
|
|
338
337
|
|
|
339
338
|
it "returns nil if found element didn't match the selector tag_name" do
|
|
340
|
-
expect_one(:xpath, "//div").and_return(element(tag_name: "div"))
|
|
341
339
|
expect_all(:xpath, "//div").and_return([element(tag_name: "div")])
|
|
342
340
|
|
|
343
341
|
selector = {
|
data/spec/spec_helper.rb
CHANGED
|
@@ -9,7 +9,7 @@ require 'webdrivers'
|
|
|
9
9
|
require 'locator_spec_helper'
|
|
10
10
|
require 'rspec'
|
|
11
11
|
|
|
12
|
-
SELENIUM_SELECTORS = %i(
|
|
12
|
+
SELENIUM_SELECTORS = %i(css tag_name xpath link_text partial_link_text link)
|
|
13
13
|
|
|
14
14
|
if ENV['RELAXED_LOCATE'] == "false"
|
|
15
15
|
Watir.relaxed_locate = false
|
|
@@ -23,6 +23,38 @@ describe 'Watir#relaxed_locate?' do
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
context 'when acting on an element whose parent is never present' do
|
|
27
|
+
it 'raises exception after timing out' do
|
|
28
|
+
begin
|
|
29
|
+
time_out = 2
|
|
30
|
+
Watir.default_timeout = time_out
|
|
31
|
+
element = browser.link(id: 'not_there')
|
|
32
|
+
start_time = ::Time.now
|
|
33
|
+
allow($stderr).to receive(:write).twice
|
|
34
|
+
expect { element.element.click }.to raise_exception(Watir::Exception::UnknownObjectException)
|
|
35
|
+
expect(::Time.now - start_time).to be > time_out
|
|
36
|
+
ensure
|
|
37
|
+
Watir.default_timeout = 30
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
context 'when acting on an element from a collection whose parent is never present' do
|
|
43
|
+
it 'raises exception after timing out' do
|
|
44
|
+
begin
|
|
45
|
+
time_out = 2
|
|
46
|
+
Watir.default_timeout = time_out
|
|
47
|
+
element = browser.link(id: 'not_there')
|
|
48
|
+
start_time = ::Time.now
|
|
49
|
+
allow($stderr).to receive(:write).twice
|
|
50
|
+
expect { element.elements[2].click }.to raise_exception(Watir::Exception::UnknownObjectException)
|
|
51
|
+
expect(::Time.now - start_time).to be > time_out
|
|
52
|
+
ensure
|
|
53
|
+
Watir.default_timeout = 30
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
26
58
|
context 'when acting on an element that is already present' do
|
|
27
59
|
it 'does not wait' do
|
|
28
60
|
begin
|
data/watir.gemspec
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: watir
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 6.11.0.
|
|
4
|
+
version: 6.11.0.beta2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex Rodionov
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2018-05-
|
|
12
|
+
date: 2018-05-10 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: selenium-webdriver
|