watir 6.16.1 → 6.16.2

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