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 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