watir 6.16.1 → 6.16.2

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
  SHA1:
3
- metadata.gz: d2b4db146f289ef46ceb5bf9b9faabdad94743ba
4
- data.tar.gz: 4b54ec483198de8c748bffdfda298770c4c9c40e
3
+ metadata.gz: d9b4ce5fc3a28e83b85751052967ecdaa6d87b4d
4
+ data.tar.gz: 82dc5e6c96e4f259c12865a198503b39674094b7
5
5
  SHA512:
6
- metadata.gz: f1c78b53e3d1243c9a6dc0aa94d6844f174460798da81b76488449e34b2ca695b61e18bc8739a8ee2095d430a6d904bd8cd0cb3b6f8464129d7b1c5f3670c068
7
- data.tar.gz: 26147c5fa67a6b6289488ad39eae1ec3ad2f82af18a886d6d13935658fdaf138a8a8278a8dda58a5a71b82f9467a3aa9bfc96e0e80aa5f0a321a4317c4202605
6
+ metadata.gz: f57ef0d029dd2c0bd703d416288a1f65cfd0a1aaab36e33bd79924b54ae5cb796774fa44e2a728e508d1af0cf8e11bb7b595851d0d59b3ee587c5feed42f808e
7
+ data.tar.gz: 18f052aaca388fef0191bf23c115cac21bff5aed3f692d6e5c1794ef13cf555f6745f2b8b569f7f3a760a843226844f6ef53dc43ef9c95efb532bf0e6a7e9d67
data/CHANGES.md CHANGED
@@ -1,3 +1,9 @@
1
+ ### 6.16.2 (2018-12-24)
2
+
3
+ * Fix bug merging scope when locating nested elements with css locator (#841)
4
+ * Fix bug with IFrame#to_subtype
5
+ * Improve performance for nested frames
6
+
1
7
  ### 6.16.1 (2018-12-23)
2
8
 
3
9
  * Improve collection performance with JavaScript (thanks Lucas Tierney)
@@ -65,9 +65,12 @@ module Watir
65
65
  #
66
66
 
67
67
  def run
68
- return unless @after_hooks.any? && @browser.window.present? && !@browser.alert.exists?
68
+ # We can't just rescue exception because Firefox automatically closes alert when exception raised
69
+ return unless @after_hooks.any? && !@browser.alert.exists?
69
70
 
70
71
  each { |after_hook| after_hook.call(@browser) }
72
+ rescue Selenium::WebDriver::Error::NoSuchWindowError => ex
73
+ Watir.logger.info "Could not execute After Hooks because browser window was closed #{ex}"
71
74
  end
72
75
 
73
76
  #
@@ -270,18 +270,6 @@ module Watir
270
270
  after_hooks.run
271
271
  end
272
272
 
273
- #
274
- # @api private
275
- #
276
- # Always relocate a Browser to ensure proper context switching
277
- #
278
- # @return [Boolean]
279
- #
280
-
281
- def relocate?
282
- true
283
- end
284
-
285
273
  def browser
286
274
  self
287
275
  end
@@ -182,7 +182,7 @@ module Watir
182
182
  end
183
183
 
184
184
  def ensure_context
185
- @query_scope.locate if @query_scope.relocate?
185
+ @query_scope.locate if @query_scope.is_a?(Browser) || @query_scope.located? && @query_scope.stale?
186
186
  @query_scope.switch_to! if @query_scope.is_a?(IFrame)
187
187
  end
188
188
 
@@ -643,19 +643,6 @@ module Watir
643
643
  @element = element
644
644
  end
645
645
 
646
- #
647
- # @api private
648
- #
649
- # This is a performance shortcut for ensuring context
650
- # Returns true if ensuring context requires relocating the element.
651
- #
652
- # @return [Boolean]
653
- #
654
-
655
- def relocate?
656
- located? && stale?
657
- end
658
-
659
646
  #
660
647
  # @api private
661
648
  #
@@ -733,7 +720,7 @@ module Watir
733
720
  end
734
721
 
735
722
  def ensure_context
736
- @query_scope.locate if @query_scope.relocate?
723
+ @query_scope.locate if @query_scope.is_a?(Browser) || @query_scope.located? && @query_scope.stale?
737
724
  @query_scope.switch_to! if @query_scope.is_a?(IFrame)
738
725
  end
739
726
 
@@ -65,15 +65,12 @@ module Watir
65
65
  end
66
66
 
67
67
  #
68
- # @api private
69
- #
70
- # Always relocate a FramedDriver to ensure proper context switching
71
- #
72
- # @return [Boolean]
68
+ # Cast this Element instance to a more specific subtype.
69
+ # Cached element needs to be the IFrame element, not the FramedDriver
73
70
  #
74
71
 
75
- def relocate?
76
- true
72
+ def to_subtype
73
+ super.tap { |el| el.cache = @element }
77
74
  end
78
75
 
79
76
  private
@@ -25,8 +25,8 @@ module Watir
25
25
  ids: [:value_button])
26
26
  end
27
27
 
28
- def validate_tag(element, _tag_name)
29
- tag_name = element.tag_name.downcase
28
+ def validate_tag(element, _expected)
29
+ tag_name = fetch_value(element, :tag_name)
30
30
  return unless %w[input button].include?(tag_name)
31
31
 
32
32
  # TODO: - Verify this is desired behavior based on https://bugzilla.mozilla.org/show_bug.cgi?id=1290963
@@ -2,7 +2,7 @@ module Watir
2
2
  module Locators
3
3
  class Cell
4
4
  class SelectorBuilder < Element::SelectorBuilder
5
- def use_scope?
5
+ def merge_scope?
6
6
  false
7
7
  end
8
8
  end
@@ -14,7 +14,7 @@ module Watir
14
14
 
15
15
  def locate(built)
16
16
  @built = built.dup
17
- @driver_scope = (@built.delete(:scope) || @query_scope.browser).wd
17
+ @driver_scope = locator_scope.wd
18
18
  matching_elements(@built, :first)
19
19
  rescue Selenium::WebDriver::Error::NoSuchElementError
20
20
  nil
@@ -22,7 +22,7 @@ module Watir
22
22
 
23
23
  def locate_all(built)
24
24
  @built = built.dup
25
- @driver_scope = (@built.delete(:scope) || @query_scope.browser).wd
25
+ @driver_scope = locator_scope.wd
26
26
  raise ArgumentError, "can't locate all elements by :index" if built.key?(:index)
27
27
 
28
28
  [matching_elements(@built, :all)].flatten
@@ -52,6 +52,10 @@ module Watir
52
52
  end
53
53
  end
54
54
 
55
+ def locator_scope
56
+ @built.delete(:scope) || @query_scope.browser
57
+ end
58
+
55
59
  def locate_element(how, what, scope = driver_scope)
56
60
  scope.find_element(how, what)
57
61
  end
@@ -82,6 +82,8 @@ module Watir
82
82
 
83
83
  def fetch_value(element, how)
84
84
  case how
85
+ when :tag_name
86
+ element.tag_name.downcase
85
87
  when :text
86
88
  element.text
87
89
  when :visible
@@ -106,8 +108,9 @@ module Watir
106
108
  idx.abs - 1
107
109
  end
108
110
 
109
- def validate_tag(element, tag_name)
110
- matches_values?(element.tag_name.downcase, tag_name)
111
+ def validate_tag(element, expected)
112
+ tag_name = fetch_value(element, :tag_name)
113
+ matches_values?(tag_name, expected)
111
114
  end
112
115
 
113
116
  def deprecate_text_regexp(element, selector)
@@ -31,7 +31,7 @@ module Watir
31
31
  inspected = selector.inspect
32
32
  scope = @query_scope unless @selector.key?(:scope) || @query_scope.is_a?(Watir::Browser)
33
33
 
34
- @built = wd_locator(@selector.keys).nil? ? build_wd_selector(@selector) : @selector
34
+ @built = wd_locators.empty? ? build_wd_selector(@selector) : @selector
35
35
  @built.delete(:index) if @built[:index]&.zero?
36
36
  @built[:scope] = scope if scope
37
37
 
@@ -39,17 +39,16 @@ module Watir
39
39
  @built
40
40
  end
41
41
 
42
- def wd_locator(keys)
43
- (Watir::Locators::W3C_FINDERS & keys).first
42
+ def wd_locators
43
+ Watir::Locators::W3C_FINDERS & @selector.keys
44
44
  end
45
45
 
46
46
  private
47
47
 
48
48
  def normalize_selector
49
- wd_locators = @selector.keys & Watir::Locators::W3C_FINDERS
50
49
  raise LocatorException, "Can not locate element with #{wd_locators}" if wd_locators.size > 1
51
50
 
52
- @selector[:scope] = @query_scope.selector_builder.built if use_scope?
51
+ @selector[:scope] = @query_scope.selector_builder.built if merge_scope?
53
52
 
54
53
  if @selector.key?(:class) || @selector.key?(:class_name)
55
54
  classes = ([@selector[:class]].flatten + [@selector.delete(:class_name)].flatten).compact
@@ -75,13 +74,13 @@ module Watir
75
74
  end
76
75
  end
77
76
 
78
- def use_scope?
79
- return false if @query_scope.is_a?(Browser)
77
+ def merge_scope?
78
+ return false unless (Watir::Locators::W3C_FINDERS + [:adjacent] & @selector.keys).empty?
80
79
 
81
- !@selector.key?(:adjacent) &&
82
- (Watir::Locators::W3C_FINDERS & @selector.keys).empty? &&
83
- !(@query_scope.is_a?(Watir::IFrame) || @query_scope.is_a?(Watir::Radio)) &&
84
- @query_scope.selector_builder.built&.size == 1
80
+ return false if [Watir::Browser, Watir::IFrame].any? { |k| @query_scope.is_a?(k) }
81
+
82
+ scope_invalid_locators = @query_scope.selector_builder.built.keys.reject { |key| key == wd_locator }
83
+ scope_invalid_locators.empty?
85
84
  end
86
85
 
87
86
  def deprecate_class_array(class_name)
@@ -142,9 +141,17 @@ module Watir
142
141
  @custom_attributes << attribute.to_s
143
142
  end
144
143
 
145
- # Implement this method when creating a different selector builder
144
+ # Extensions implement this method when creating a different selector builder
145
+ def implementation_class
146
+ Kernel.const_get("#{self.class.name}::XPath")
147
+ end
148
+
146
149
  def build_wd_selector(selector)
147
- Kernel.const_get("#{self.class.name}::XPath").new.build(selector)
150
+ implementation_class.new.build(selector)
151
+ end
152
+
153
+ def wd_locator
154
+ implementation_class::LOCATOR
148
155
  end
149
156
 
150
157
  def valid_attribute?(attribute)
@@ -8,6 +8,8 @@ module Watir
8
8
 
9
9
  CAN_NOT_BUILD = %i[visible visible_text visible_label_element].freeze
10
10
 
11
+ LOCATOR = :xpath
12
+
11
13
  def build(selector)
12
14
  @selector = selector
13
15
 
@@ -4,10 +4,10 @@ module Watir
4
4
  class SelectorBuilder < Element::SelectorBuilder
5
5
  def build_wd_selector(selector)
6
6
  scope_tag_name = @query_scope.selector[:tag_name] || @query_scope.tag_name
7
- Kernel.const_get("#{self.class.name}::XPath").new.build(selector, scope_tag_name)
7
+ implementation_class.new.build(selector, scope_tag_name)
8
8
  end
9
9
 
10
- def use_scope?
10
+ def merge_scope?
11
11
  false
12
12
  end
13
13
  end
@@ -29,8 +29,9 @@ module Watir
29
29
  # does not apply to text_field
30
30
  end
31
31
 
32
- def validate_tag(element, _tag_name)
33
- matches_values?(element.tag_name.downcase, 'input')
32
+ def validate_tag(element, _expected)
33
+ tag_name = fetch_value(element, :tag_name)
34
+ matches_values?(tag_name, 'input')
34
35
  end
35
36
  end
36
37
  end
@@ -1,3 +1,3 @@
1
1
  module Watir
2
- VERSION = '6.16.1'.freeze
2
+ VERSION = '6.16.2'.freeze
3
3
  end
@@ -44,7 +44,7 @@ describe Watir::Locators::Element::SelectorBuilder do
44
44
 
45
45
  it 'raises exception when using xpath & css' do
46
46
  selector = {xpath: './/*', css: 'div'}
47
- msg = 'Can not locate element with [:xpath, :css]'
47
+ msg = 'Can not locate element with [:css, :xpath]'
48
48
 
49
49
  expect { selector_builder.build(selector) }.to raise_exception Watir::Exception::LocatorException, msg
50
50
  end
@@ -668,9 +668,9 @@ describe Watir::Locators::Element::SelectorBuilder do
668
668
  end
669
669
  end
670
670
 
671
- context 'with element scope' do
671
+ context 'with generic element scope' do
672
672
  let(:query_scope) { instance_double Watir::HTMLElement }
673
- let(:scope_built) { @scope_built || {xpath: ".//*[local-name()='div'][@id='table-rows-test']"} }
673
+ let(:scope_built) { {xpath: ".//*[local-name()='div'][@id='table-rows-test']"} }
674
674
 
675
675
  before do
676
676
  allow(query_scope).to receive(:selector_builder).and_return(selector_builder)
@@ -709,11 +709,31 @@ describe Watir::Locators::Element::SelectorBuilder do
709
709
  expect(build_selector.delete(:scope)).to_not be_nil
710
710
  expect(build_selector).to eq built
711
711
  end
712
+ end
713
+
714
+ context 'with invalid query scopes' do
715
+ let(:query_scope) { instance_double Watir::HTMLElement }
712
716
 
713
717
  it 'does not use scope if query_scope built has multiple keys' do
718
+ scope_built = {xpath: ".//*[local-name()='div']", visible: true}
719
+ allow(selector_builder).to receive(:built).and_return(scope_built)
720
+ allow(query_scope).to receive(:selector_builder).and_return(selector_builder)
721
+
722
+ selector = {tag_name: 'div'}
723
+ built = {xpath: ".//*[local-name()='div']"}
724
+
725
+ build_selector = selector_builder.build(selector)
726
+ expect(build_selector.delete(:scope)).to_not be_nil
727
+ expect(build_selector).to eq built
728
+ end
729
+
730
+ it 'does not use scope if query_scope uses different Selenium Locator' do
731
+ scope_built = {css: '#foo'}
732
+ allow(selector_builder).to receive(:built).and_return(scope_built)
733
+ allow(query_scope).to receive(:selector_builder).and_return(selector_builder)
734
+
714
735
  selector = {tag_name: 'div'}
715
736
  built = {xpath: ".//*[local-name()='div']"}
716
- scope_built[:visible] = true
717
737
 
718
738
  build_selector = selector_builder.build(selector)
719
739
  expect(build_selector.delete(:scope)).to_not be_nil
@@ -721,7 +741,7 @@ describe Watir::Locators::Element::SelectorBuilder do
721
741
  end
722
742
  end
723
743
 
724
- context 'with specific scope' do
744
+ context 'with specific element scope' do
725
745
  let(:scope_built) { {xpath: ".//*[local-name()='iframe'][@id='one']"} }
726
746
 
727
747
  it 'does not use scope if query scope is an IFrame' do
@@ -160,64 +160,56 @@ describe 'Browser::AfterHooks' do
160
160
  end
161
161
 
162
162
  not_compliant_on :safari, :headless do
163
- bug 'chromedriver 2.43 https://bugs.chromium.org/p/chromedriver/issues/detail?id=2615', :chrome do
164
- it 'does not run error checks with alert present' do
165
- browser.goto WatirSpec.url_for('alerts.html')
163
+ it 'does not run error checks with alert present' do
164
+ browser.goto WatirSpec.url_for('alerts.html')
166
165
 
167
- @page_after_hook = proc { @yield = browser.title == 'Alerts' }
168
- browser.after_hooks.add @page_after_hook
166
+ @page_after_hook = proc { @yield = browser.title == 'Alerts' }
167
+ browser.after_hooks.add @page_after_hook
169
168
 
170
- browser.button(id: 'alert').click
171
- expect(@yield).to be_nil
169
+ browser.button(id: 'alert').click
170
+ expect(@yield).to be_nil
172
171
 
173
- browser.alert.ok
174
- expect(@yield).to eq true
175
- end
172
+ browser.alert.ok
173
+ expect(@yield).to eq true
176
174
  end
177
175
  end
178
176
 
179
177
  not_compliant_on :headless do
180
- bug 'chromedriver 2.43 https://bugs.chromium.org/p/chromedriver/issues/detail?id=2615', :chrome do
181
- it 'does not raise error when running error checks using #after_hooks#without with alert present' do
182
- url = WatirSpec.url_for('alerts.html')
183
- @page_after_hook = proc { browser.url }
184
- browser.after_hooks.add @page_after_hook
185
- browser.goto url
186
- expect { browser.after_hooks.without { browser.button(id: 'alert').click } }.to_not raise_error
187
- browser.alert.ok
188
- end
178
+ it 'does not raise error when running error checks using #after_hooks#without with alert present' do
179
+ url = WatirSpec.url_for('alerts.html')
180
+ @page_after_hook = proc { browser.url }
181
+ browser.after_hooks.add @page_after_hook
182
+ browser.goto url
183
+ expect { browser.after_hooks.without { browser.button(id: 'alert').click } }.to_not raise_error
184
+ browser.alert.ok
185
+ end
186
+ end
187
+
188
+ not_compliant_on :headless do
189
+ it 'does not raise error if no error checks are defined with alert present' do
190
+ url = WatirSpec.url_for('alerts.html')
191
+ @page_after_hook = proc { browser.url }
192
+ browser.after_hooks.add @page_after_hook
193
+ browser.goto url
194
+ browser.after_hooks.delete @page_after_hook
195
+ expect { browser.button(id: 'alert').click }.to_not raise_error
196
+ browser.alert.ok
189
197
  end
190
198
  end
191
199
 
192
- bug 'chromedriver 2.43 https://bugs.chromium.org/p/chromedriver/issues/detail?id=2615', :chrome do
200
+ bug 'https://bugzilla.mozilla.org/show_bug.cgi?id=1223277', :firefox do
193
201
  not_compliant_on :headless do
194
- it 'does not raise error if no error checks are defined with alert present' do
195
- url = WatirSpec.url_for('alerts.html')
202
+ it 'does not raise error when running error checks on closed window' do
203
+ url = WatirSpec.url_for('window_switching.html')
196
204
  @page_after_hook = proc { browser.url }
197
205
  browser.after_hooks.add @page_after_hook
198
206
  browser.goto url
199
- browser.after_hooks.delete @page_after_hook
200
- expect { browser.button(id: 'alert').click }.to_not raise_error
201
- browser.alert.ok
202
- end
203
- end
204
- end
207
+ browser.a(id: 'open').click
205
208
 
206
- bug 'chromedriver 2.43 https://bugs.chromium.org/p/chromedriver/issues/detail?id=2615', :chrome do
207
- bug 'https://bugzilla.mozilla.org/show_bug.cgi?id=1223277', :firefox do
208
- not_compliant_on :headless do
209
- it 'does not raise error when running error checks on closed window' do
210
- url = WatirSpec.url_for('window_switching.html')
211
- @page_after_hook = proc { browser.url }
212
- browser.after_hooks.add @page_after_hook
213
- browser.goto url
214
- browser.a(id: 'open').click
215
-
216
- window = browser.window(title: 'closeable window')
217
- window.use
218
- expect { browser.a(id: 'close').click }.to_not raise_error
219
- browser.original_window.use
220
- end
209
+ window = browser.window(title: 'closeable window')
210
+ window.use
211
+ expect { browser.a(id: 'close').click }.to_not raise_error
212
+ browser.original_window.use
221
213
  end
222
214
  end
223
215
  end
@@ -26,24 +26,26 @@ describe 'CheckBox' do
26
26
  expect(browser.checkbox(xpath: "//input[@id='new_user_interests_books']")).to exist
27
27
  end
28
28
 
29
- it 'handles text_regexp deprecations for label locators' do
30
- expect {
31
- expect(browser.checkbox(label: /some visible/)).to exist
32
- }.to_not have_deprecated_text_regexp
33
-
34
- expect {
35
- expect(browser.checkbox(label: /some (visible|Jeff)/)).to exist
36
- }.to_not have_deprecated_text_regexp
37
-
38
- expect {
39
- expect(browser.checkbox(label: /this will not match/)).to exist
40
- }.to_not have_deprecated_text_regexp
41
-
42
- expect(browser.checkbox(label: /some visible some hidden/)).to_not exist
43
-
44
- expect {
45
- expect(browser.checkbox(label: /some visible$/)).to exist
46
- }.to have_deprecated_text_regexp
29
+ not_compliant_on :watigiri do
30
+ it 'handles text_regexp deprecations for label locators' do
31
+ expect {
32
+ expect(browser.checkbox(label: /some visible/)).to exist
33
+ }.to_not have_deprecated_text_regexp
34
+
35
+ expect {
36
+ expect(browser.checkbox(label: /some (visible|Jeff)/)).to exist
37
+ }.to_not have_deprecated_text_regexp
38
+
39
+ expect {
40
+ expect(browser.checkbox(label: /this will not match/)).to exist
41
+ }.to_not have_deprecated_text_regexp
42
+
43
+ expect(browser.checkbox(label: /some visible some hidden/)).to_not exist
44
+
45
+ expect {
46
+ expect(browser.checkbox(label: /some visible$/)).to exist
47
+ }.to have_deprecated_text_regexp
48
+ end
47
49
  end
48
50
 
49
51
  it 'returns true if the checkbox button exists (search by name and value)' do
@@ -149,8 +149,10 @@ describe 'Div' do
149
149
  end
150
150
 
151
151
  # Note: This will work after:text_regexp deprecation removed
152
- it 'does not locate entire content with regular expressions' do
153
- expect(browser.div(text: /some visible some hidden/)).to_not exist
152
+ not_compliant_on :watigiri do
153
+ it 'does not locate entire content with regular expressions' do
154
+ expect(browser.div(text: /some visible some hidden/)).to_not exist
155
+ end
154
156
  end
155
157
  end
156
158
  end
@@ -115,7 +115,6 @@ describe 'IFrame' do
115
115
  not_compliant_on :safari do
116
116
  it 'handles nested iframes' do
117
117
  browser.goto(WatirSpec.url_for('nested_iframes.html'))
118
-
119
118
  browser.iframe(id: 'two').iframe(id: 'three').link(id: 'four').click
120
119
 
121
120
  Watir::Wait.until { browser.title == 'definition_lists' }
@@ -151,7 +150,7 @@ describe 'IFrame' do
151
150
 
152
151
  it 'switches when the frame is created by subtype' do
153
152
  subtype = browser.iframe.to_subtype
154
- expect { subtype.iframe.exist? }.to_not raise_exception
153
+ expect { subtype.element.locate }.to_not raise_exception
155
154
  end
156
155
 
157
156
  it 'switches back to top level browsing context' do
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.16.1
4
+ version: 6.16.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Rodionov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-12-23 00:00:00.000000000 Z
13
+ date: 2018-12-24 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: selenium-webdriver