watir 6.11.0.beta1 → 6.11.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 656aad05e0cbe7226f3576b88f5a65ed0959c3672b322a5252d73ac3856f0acd
4
- data.tar.gz: 8112b892320b500fdf4cb113ea2b420b8f24b90509edc00367fcb20c264ca2ef
3
+ metadata.gz: 37e5bd05d8b6ed813503264d89bcaf6aceb4b67d5ad2217569c4aef4b7762ca5
4
+ data.tar.gz: 49c34f4a6e37dec3788fdc5c91ae3d06368b6b0d34c5365387e46d2ee07fe922
5
5
  SHA512:
6
- metadata.gz: 79f71a31ac314000ed7d1633290a808824881c690c6e05bbb161dfa55e77ee38dc63b2a2ebaae5f2c0f6e68f951e3646450db998fa623f34f6ac7cf6ef525470
7
- data.tar.gz: dba7348f6003bd93ec9ccf83a3d158f6c289a86ee80e09dac7a1487183583f2052762b5ba009da4c0eeaf9995a9b4fe9ed7d2027dc3d35d46836edeac5bac68c
6
+ metadata.gz: b654a96f43a8d9dc84645cc595c018a6263f180f3bd2e8dc20f03ed8ff2d43c135a267d0cf65f7c87c5cfe1ac9d3524cd438a77d13830ebfb179c9cbb4802693
7
+ data.tar.gz: d358cfee80f3afae74f39f8aa1d91ba9e98ed6d231735ab19d535ccb3932a0ef273e29e5749dc3ca51778c6220a58e84e5774a26e44403ab0c1592db5fc1ade3
data/CHANGES.md CHANGED
@@ -1,3 +1,8 @@
1
+ ### 6.11.0.beta2 (2018-05-10)
2
+
3
+ * Additional performance updates
4
+ * Fix bug with error message of unlocated parent element (#706)
5
+
1
6
  ### 6.11.0.beta1 (2018-05-04)
2
7
 
3
8
  * Significant performance updates
@@ -45,7 +45,7 @@ module Watir
45
45
  #
46
46
 
47
47
  def [](idx)
48
- to_a[idx] || element_class.new(@query_scope, @selector.merge(index: idx))
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
- @query_scope.send :ensure_context
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
- @query_scope.ensure_context
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
@@ -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
- WD_FINDERS = [
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
- selector = @selector.dup
53
- tag_name = selector[:tag_name].is_a?(::Symbol) ? selector[:tag_name].to_s : selector[:tag_name]
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
- def using_watir(filter = :first)
73
- query_scope = ensure_scope_context
74
- selector = selector_builder.normalized_selector
51
+ how = @selector.keys.first || :tag_name
52
+ what = @selector.values.first || tag
75
53
 
76
- if selector[:label]
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
- if selector.key?(:index) && filter == :all
82
- raise ArgumentError, "can't locate all elements by :index"
83
- end
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
- filter_selector = delete_filters_from(selector)
63
+ create_filter_selector
86
64
 
87
- how, what = selector_builder.build(selector)
65
+ how, what = selector_builder.build(@normalized_selector.dup)
88
66
  unless how
89
- raise Error, "internal error: unable to build Selenium selector from #{selector.inspect}"
67
+ raise Error, "internal error: unable to build Selenium selector from #{@normalized_selector.inspect}"
90
68
  end
91
- what = add_regexp_predicates(what, filter_selector) if how == :xpath
69
+ what = add_regexp_predicates(what) if how == :xpath
92
70
 
93
- needs_filtering = filter == :all || !filter_selector.empty?
94
- if needs_filtering
95
- elements = locate_elements(how, what, query_scope) || []
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, query_scope)
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, selector, filter: :first)
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 delete_filters_from(selector)
145
- filter_selector = {}
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 selector.key?(how)
150
- filter_selector[how] = selector.delete(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?(selector)
154
- tag_name = selector[:tag_name].is_a?(::Symbol) ? selector[:tag_name].to_s : selector[: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
- selector.dup.each do |how, what|
157
+ @normalized_selector.each do |how, what|
162
158
  next unless what.is_a?(Regexp)
163
- filter_selector[how] = selector.delete(how)
159
+ @filter_selector[how] = @normalized_selector.delete(how)
164
160
  end
165
161
 
166
- if selector[:index] && !selector[:adjacent]
167
- idx = selector.delete(:index)
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 convert_label_to_scope_or_selector(query_scope, selector)
178
- return query_scope unless selector[:label].kind_of?(Regexp) && selector_builder.should_use_label_element?
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(selector.delete(:label))
181
- return unless label # label not found, stop looking for element
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
- selector[:id] = id
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(label_exp)
192
- # TODO: this won't work correctly if @wd is a sub-element
193
- locate_elements(:tag_name, 'label').find do |el|
194
- matches_selector?(el, text: label_exp)
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, filter_selector)
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
- return false if [:class, :class_name].include?(how) && what.include?(' ')
257
- %i[partial_link_text link_text link].each do |loc|
258
- next unless how == loc
259
- Watir.logger.deprecate(":#{loc} locator", ':visible_text')
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 = {
@@ -9,7 +9,7 @@ require 'webdrivers'
9
9
  require 'locator_spec_helper'
10
10
  require 'rspec'
11
11
 
12
- SELENIUM_SELECTORS = %i(class class_name css id tag_name xpath link_text partial_link_text link)
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
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'watir'
5
- s.version = '6.11.0.beta1'
5
+ s.version = '6.11.0.beta2'
6
6
  s.platform = Gem::Platform::RUBY
7
7
  s.authors = ['Alex Rodionov', 'Titus Fortner']
8
8
  s.email = ['p0deje@gmail.com', 'titusfortner@gmail.com']
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.beta1
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-04 00:00:00.000000000 Z
12
+ date: 2018-05-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: selenium-webdriver