watir 7.0.0.beta3 → 7.1.0

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/chrome.yml +34 -0
  3. data/.github/workflows/edge.yml +28 -0
  4. data/.github/workflows/firefox.yml +35 -0
  5. data/.github/workflows/ie.yml +24 -0
  6. data/.github/workflows/safari.yml +27 -0
  7. data/.github/workflows/unit.yml +52 -0
  8. data/.rubocop.yml +1 -1
  9. data/CHANGES.md +26 -0
  10. data/lib/watir/attribute_helper.rb +1 -1
  11. data/lib/watir/browser.rb +3 -3
  12. data/lib/watir/capabilities.rb +14 -0
  13. data/lib/watir/elements/date_field.rb +4 -1
  14. data/lib/watir/elements/date_time_field.rb +4 -1
  15. data/lib/watir/elements/element.rb +39 -13
  16. data/lib/watir/elements/table.rb +1 -1
  17. data/lib/watir/js_snippets/isElementInViewport.js +20 -0
  18. data/lib/watir/locators/element/selector_builder/xpath.rb +3 -2
  19. data/lib/watir/scroll.rb +2 -1
  20. data/lib/watir/version.rb +1 -1
  21. data/lib/watir/window.rb +22 -0
  22. data/lib/watirspec/remote_server.rb +2 -6
  23. data/spec/unit/capabilities_spec.rb +99 -5
  24. data/spec/watirspec/after_hooks_spec.rb +0 -2
  25. data/spec/watirspec/drag_and_drop_spec.rb +12 -0
  26. data/spec/watirspec/elements/date_time_field_spec.rb +3 -6
  27. data/spec/watirspec/elements/div_spec.rb +12 -1
  28. data/spec/watirspec/elements/element_spec.rb +91 -18
  29. data/spec/watirspec/html/scroll.html +8 -25
  30. data/spec/watirspec/html/sticky_elements.html +10 -0
  31. data/spec/watirspec/scroll_spec.rb +72 -42
  32. data/spec/watirspec/window_switching_spec.rb +40 -14
  33. data/spec/watirspec_helper.rb +2 -0
  34. data/watir.gemspec +3 -3
  35. metadata +24 -18
  36. data/.github/workflows/tests.yml +0 -104
  37. data/spec/watirspec/html/hover.html +0 -12
@@ -39,11 +39,12 @@ describe Watir::Capabilities do
39
39
  # :listener
40
40
  # :service (Built from Hash)
41
41
  # :http_client (Generated or Built from Hash)
42
+ # :proxy (Built from Hash and added to :options)
42
43
  # :options (Generated or Built from Hash)
43
44
  # :capabilities (incompatible with options)
44
45
 
45
46
  supported_browsers.each do |browser_symbol|
46
- it 'just browser has client & capabilities not service' do
47
+ it 'just browser has client & options not service' do
47
48
  capabilities = Watir::Capabilities.new(browser_symbol)
48
49
 
49
50
  args = capabilities.to_args
@@ -74,7 +75,7 @@ describe Watir::Capabilities do
74
75
  expect(args.last).not_to include(:service)
75
76
  end
76
77
 
77
- context 'service' do
78
+ describe 'service' do
78
79
  it 'uses provided service' do
79
80
  halt_service(browser_symbol)
80
81
 
@@ -106,7 +107,7 @@ describe Watir::Capabilities do
106
107
  end
107
108
  end
108
109
 
109
- context 'http_client' do
110
+ describe 'http_client' do
110
111
  it 'uses default HTTP Client' do
111
112
  capabilities = Watir::Capabilities.new(browser_symbol)
112
113
  args = capabilities.to_args
@@ -153,7 +154,7 @@ describe Watir::Capabilities do
153
154
  }.to raise_exception(ArgumentError, ':capabilities and :options are not both allowed')
154
155
  end
155
156
 
156
- context 'timeout options' do
157
+ describe 'timeout options' do
157
158
  it 'accepts page load and script timeouts in seconds' do
158
159
  options = {page_load_timeout: 11,
159
160
  script_timeout: 12}
@@ -203,6 +204,63 @@ describe Watir::Capabilities do
203
204
  actual_options = args.last[:capabilities].first
204
205
  expect(actual_options.unhandled_prompt_behavior).to eq :accept_and_notify
205
206
  end
207
+
208
+ describe 'proxy' do
209
+ it 'adds Selenium Proxy to empty Options' do
210
+ proxy = Selenium::WebDriver::Proxy.new(http: '127.0.0.1:8080', ssl: '127.0.0.1:443')
211
+ capabilities = Watir::Capabilities.new(browser_symbol, proxy: proxy)
212
+ args = capabilities.to_args
213
+ proxy = args.last[:capabilities].first.proxy
214
+
215
+ expect(proxy).to be_a Selenium::WebDriver::Proxy
216
+ expect(proxy.type).to eq(:manual)
217
+ expect(proxy.http).to eq('127.0.0.1:8080')
218
+ expect(proxy.ssl).to eq('127.0.0.1:443')
219
+ end
220
+
221
+ it 'builds a Proxy from Hash for Options' do
222
+ proxy = {http: '127.0.0.1:8080', ssl: '127.0.0.1:443'}
223
+ capabilities = Watir::Capabilities.new(browser_symbol, proxy: proxy)
224
+ args = capabilities.to_args
225
+ proxy = args.last[:capabilities].first.proxy
226
+
227
+ expect(proxy).to be_a Selenium::WebDriver::Proxy
228
+ expect(proxy.type).to eq(:manual)
229
+ expect(proxy.http).to eq('127.0.0.1:8080')
230
+ expect(proxy.ssl).to eq('127.0.0.1:443')
231
+ end
232
+
233
+ it 'builds a Proxy from Hash and adds to Options' do
234
+ proxy = {http: '127.0.0.1:8080', ssl: '127.0.0.1:443'}
235
+ options = {unhandled_prompt_behavior: :accept,
236
+ page_load_strategy: :eager}
237
+
238
+ capabilities = Watir::Capabilities.new(browser_symbol, options: options, proxy: proxy)
239
+ args = capabilities.to_args
240
+ actual_options = args.last[:capabilities].first
241
+
242
+ expect(actual_options.proxy).to be_a Selenium::WebDriver::Proxy
243
+ expect(actual_options.proxy.type).to eq(:manual)
244
+ expect(actual_options.proxy.http).to eq('127.0.0.1:8080')
245
+ expect(actual_options.proxy.ssl).to eq('127.0.0.1:443')
246
+ expect(actual_options.unhandled_prompt_behavior).to eq :accept
247
+ expect(actual_options.page_load_strategy).to eq :eager
248
+ end
249
+ end
250
+
251
+ it 'errors on bad proxy key' do
252
+ proxy = {bad_key: 'foo'}
253
+ capabilities = Watir::Capabilities.new(browser_symbol, proxy: proxy)
254
+
255
+ expect { capabilities.to_args }.to raise_error(ArgumentError, /unknown option/)
256
+ end
257
+
258
+ it 'errors on bad proxy object' do
259
+ capabilities = Watir::Capabilities.new(browser_symbol, proxy: 7)
260
+ expect {
261
+ capabilities.to_args
262
+ }.to raise_exception(TypeError, '7 needs to be Selenium Proxy or Hash instance')
263
+ end
206
264
  end
207
265
 
208
266
  # Options:
@@ -210,6 +268,7 @@ describe Watir::Capabilities do
210
268
  # :service (Errors)
211
269
  # :listener
212
270
  # :http_client (Generated or Built from Hash)
271
+ # :proxy (Built from Hash and added to :options)
213
272
  # :options (Generated or Built from Hash)
214
273
  # :capabilities (incompatible with options)
215
274
 
@@ -266,6 +325,34 @@ describe Watir::Capabilities do
266
325
  expect(actual_options.browser_name).to eq 'chrome'
267
326
  end
268
327
 
328
+ it 'accepts proxy object' do
329
+ proxy = Selenium::WebDriver::Proxy.new(http: '127.0.0.1:8080', ssl: '127.0.0.1:443')
330
+ capabilities = Watir::Capabilities.new(:chrome,
331
+ url: 'https://example.com/wd/hub',
332
+ proxy: proxy)
333
+ args = capabilities.to_args
334
+ expect(args.first).to eq :remote
335
+ proxy = args.last[:capabilities].first.proxy
336
+ expect(proxy).to be_a Selenium::WebDriver::Proxy
337
+ expect(proxy.type).to eq(:manual)
338
+ expect(proxy.http).to eq('127.0.0.1:8080')
339
+ expect(proxy.ssl).to eq('127.0.0.1:443')
340
+ end
341
+
342
+ it 'accepts proxy Hash' do
343
+ proxy = {http: '127.0.0.1:8080', ssl: '127.0.0.1:443'}
344
+ capabilities = Watir::Capabilities.new(:chrome,
345
+ url: 'https://example.com/wd/hub',
346
+ proxy: proxy)
347
+ args = capabilities.to_args
348
+ expect(args.first).to eq :remote
349
+ proxy = args.last[:capabilities].first.proxy
350
+ expect(proxy).to be_a Selenium::WebDriver::Proxy
351
+ expect(proxy.type).to eq(:manual)
352
+ expect(proxy.http).to eq('127.0.0.1:8080')
353
+ expect(proxy.ssl).to eq('127.0.0.1:443')
354
+ end
355
+
269
356
  it 'accepts options object' do
270
357
  capabilities = Watir::Capabilities.new(:chrome,
271
358
  url: 'https://example.com/wd/hub',
@@ -316,11 +403,13 @@ describe Watir::Capabilities do
316
403
  expect(actual_capabilities.browser_name).to eq 'chrome'
317
404
  end
318
405
 
319
- it 'accepts http client & options objects' do
406
+ it 'accepts http client & proxy & options objects' do
320
407
  client = Watir::HttpClient.new
408
+ proxy = {http: '127.0.0.1:8080', ssl: '127.0.0.1:443'}
321
409
  options = Selenium::WebDriver::Chrome::Options.new(prefs: {foo: 'bar'})
322
410
  caps = Watir::Capabilities.new(:chrome,
323
411
  url: 'https://example.com/wd/hub',
412
+ proxy: proxy,
324
413
  options: options,
325
414
  http_client: client)
326
415
 
@@ -330,6 +419,11 @@ describe Watir::Capabilities do
330
419
  actual_options = args.last[:capabilities].first
331
420
  expect(actual_options).to be_a(Selenium::WebDriver::Chrome::Options)
332
421
  expect(actual_options.prefs).to eq(foo: 'bar')
422
+ proxy = args.last[:capabilities].first.proxy
423
+ expect(proxy).to be_a Selenium::WebDriver::Proxy
424
+ expect(proxy.type).to eq(:manual)
425
+ expect(proxy.http).to eq('127.0.0.1:8080')
426
+ expect(proxy.ssl).to eq('127.0.0.1:443')
333
427
  end
334
428
 
335
429
  it 'raises exception when both options & capabilities defined' do
@@ -98,7 +98,6 @@ describe 'Browser::AfterHooks' do
98
98
  @page_after_hook = proc { @yield = browser.title == 'Non-control elements' }
99
99
  browser.after_hooks.add @page_after_hook
100
100
  div = browser.div(id: 'html_test')
101
- div.scroll.to
102
101
  div.double_click
103
102
  expect(@yield).to be true
104
103
  end
@@ -108,7 +107,6 @@ describe 'Browser::AfterHooks' do
108
107
  @page_after_hook = proc { @yield = browser.title == 'Right Click Test' }
109
108
  browser.after_hooks.add @page_after_hook
110
109
  div = browser.div(id: 'click')
111
- div.scroll.to
112
110
  div.right_click
113
111
  expect(@yield).to be true
114
112
  end
@@ -13,10 +13,22 @@ describe 'Element' do
13
13
  expect(droppable.text).to include 'Dropped!'
14
14
  end
15
15
 
16
+ it 'can drag and drop an element onto another with specified scroll position' do
17
+ expect(droppable.text).to include 'Drop here'
18
+ draggable.drag_and_drop_on droppable, scroll_to: :center
19
+ expect(droppable.text).to include 'Dropped!'
20
+ end
21
+
16
22
  it 'can drag an element by the given offset' do
17
23
  expect(droppable.text).to include 'Drop here'
18
24
  draggable.drag_and_drop_by 200, 50
19
25
  expect(droppable.text).to include 'Dropped!'
20
26
  end
27
+
28
+ it 'can drag an element by the given offset with specified scroll position' do
29
+ expect(droppable.text).to include 'Drop here'
30
+ draggable.drag_and_drop_by 200, 50, scroll_to: :center
31
+ expect(droppable.text).to include 'Dropped!'
32
+ end
21
33
  end
22
34
  end
@@ -20,8 +20,7 @@ describe 'DateTimeField' do
20
20
  end
21
21
 
22
22
  it 'returns true if the datetime-local element exists',
23
- except: [{browser: :firefox, reason: 'https://github.com/mozilla/geckodriver/issues/1469'},
24
- {browser: :ie, reason: 'Date type not recognized'}] do
23
+ except: {browser: :ie, reason: 'Date type not recognized'} do
25
24
  expect(browser.date_time_field(xpath: "//input[@id='html5_datetime-local']")).to exist
26
25
  end
27
26
 
@@ -30,8 +29,7 @@ describe 'DateTimeField' do
30
29
  end
31
30
 
32
31
  it 'respects date-time fields types',
33
- except: [{browser: :firefox, reason: 'https://github.com/mozilla/geckodriver/issues/1469'},
34
- {browser: :ie, reason: 'Date type not recognized'}] do
32
+ except: {browser: :ie, reason: 'Date type not recognized'} do
35
33
  expect(browser.date_time_field.type).to eq('datetime-local')
36
34
  end
37
35
 
@@ -80,8 +78,7 @@ describe 'DateTimeField' do
80
78
 
81
79
  describe '#type' do
82
80
  it 'returns the type attribute if the date-time field exists',
83
- except: [{browser: :firefox, reason: 'https://github.com/mozilla/geckodriver/issues/1469'},
84
- {browser: :ie, reason: 'Date type not recognized'}] do
81
+ except: {browser: :ie, reason: 'Date type not recognized'} do
85
82
  expect(browser.date_time_field(id: 'html5_datetime-local').type).to eq 'datetime-local'
86
83
  end
87
84
 
@@ -170,10 +170,15 @@ describe 'Div' do
170
170
  except: {browser: :safari, reason: 'command correctly received, but action not taken'} do
171
171
  it 'fires the ondblclick event' do
172
172
  div = browser.div(id: 'html_test')
173
- div.scroll.to
174
173
  div.double_click
175
174
  expect(messages).to include('double clicked')
176
175
  end
176
+
177
+ it 'fires the ondblclick event with specified scroll position' do
178
+ div = browser.div(id: 'html_test')
179
+ div.double_click(scroll_to: :center)
180
+ expect(messages).to include('double clicked')
181
+ end
177
182
  end
178
183
 
179
184
  describe '#double_click!' do
@@ -196,6 +201,12 @@ describe 'Div' do
196
201
  expect(event_log.first).to eq('control=true alt=true')
197
202
  end
198
203
 
204
+ it 'accepts modifiers with scroll position', except: {browser: :ie} do
205
+ browser.goto(WatirSpec.url_for('right_click.html'))
206
+ browser.div(id: 'click-logger').right_click(:control, :alt, scroll_to: :center)
207
+ expect(event_log.first).to eq('control=true alt=true')
208
+ end
209
+
199
210
  it 'scrolls' do
200
211
  browser.del(class: 'footer').double_click
201
212
  puts 'yes?'
@@ -623,15 +623,65 @@ describe 'Element' do
623
623
  end
624
624
 
625
625
  describe '#hover' do
626
- it 'should hover over the element', except: {browser: :ie} do
627
- browser.goto WatirSpec.url_for('hover.html')
628
- link = browser.a
626
+ def element_color(element)
627
+ case element.style('color')
628
+ when 'rgba(0, 0, 255, 1)'
629
+ :blue
630
+ when 'rgba(255, 165, 0, 1)', 'rgb(255, 165, 0)'
631
+ :orange
632
+ else
633
+ raise rgba
634
+ end
635
+ end
636
+
637
+ it 'allows scrolling to top', except: {browser: :ie,
638
+ reason: 'needs require_window_focus'} do
639
+ browser.goto(WatirSpec.url_for('scroll.html'))
640
+ element = browser.div(id: 'center')
641
+
642
+ element.hover(scroll_to: :top)
643
+ expect(element_color(element)).to eq :orange
644
+
645
+ element_top = browser.execute_script('return arguments[0].getBoundingClientRect().top', element)
646
+ expect(element_top).to be_within(1).of(0)
647
+ end
648
+
649
+ it 'scrolls to center by default', except: {browser: :ie,
650
+ reason: 'needs require_window_focus'} do
651
+ browser.goto(WatirSpec.url_for('scroll.html'))
652
+ element = browser.div(id: 'center')
653
+
654
+ element.hover
655
+ expect(element_color(element)).to eq :orange
656
+
657
+ element_rect = browser.execute_script('return arguments[0].getBoundingClientRect()', element)
658
+
659
+ expect(element_rect['top']).to eq(element_rect['bottom'] - element_rect['height'])
660
+ end
661
+
662
+ it 'allows scrolling to bottom', except: {browser: :ie,
663
+ reason: 'needs require_window_focus'} do
664
+ browser.goto(WatirSpec.url_for('scroll.html'))
665
+ element = browser.div(id: 'center')
666
+
667
+ element.hover(scroll_to: :bottom)
668
+ expect(element_color(element)).to eq :orange
669
+
670
+ element_bottom = browser.execute_script('return arguments[0].getBoundingClientRect().bottom', element)
671
+ window_height = browser.execute_script('return window.innerHeight')
672
+
673
+ expect(element_bottom).to be_within(1).of(window_height)
674
+ end
675
+
676
+ it 'allows not scrolling', except: {browser: %i[chrome edge],
677
+ reason: 'https://bugs.chromium.org/p/chromedriver/issues/detail?id=3955'} do
678
+ browser.goto(WatirSpec.url_for('scroll.html'))
679
+ element = browser.div(id: 'center')
680
+
681
+ browser.execute_script('return window.pageYOffset;')
682
+ browser.execute_script('return window.innerHeight;')
629
683
 
630
- expect(link.style('font-size')).to eq '10px'
631
- link.scroll.to
632
- link.hover
633
- link.wait_until { |l| l.style('font-size') == '20px' }
634
- expect(link.style('font-size')).to eq '20px'
684
+ expect { element.hover(scroll_to: nil) }.to raise_exception Selenium::WebDriver::Error::MoveTargetOutOfBoundsError
635
685
  end
636
686
  end
637
687
 
@@ -914,40 +964,63 @@ describe 'Element' do
914
964
 
915
965
  it 'returns false if element center is not covered' do
916
966
  btn = browser.button(id: 'not_obscured')
917
- expect(btn).not_to be_obscured
967
+ btn.scroll.to :center
918
968
  expect { btn.click }.not_to raise_exception
969
+ expect(btn).not_to be_obscured
919
970
  end
920
971
 
921
972
  it 'returns false if element center is covered by its descendant' do
922
973
  btn = browser.button(id: 'has_descendant')
923
- expect(btn).not_to be_obscured
974
+ btn.scroll.to :center
924
975
  expect { btn.click }.not_to raise_exception
976
+ expect(btn).not_to be_obscured
925
977
  end
926
978
 
927
979
  it 'returns true if element center is covered by a non-descendant',
928
980
  except: {browser: :safari, reason: 'not getting element click intercepted'} do
929
981
  btn = browser.button(id: 'obscured')
930
- expect(btn).to be_obscured
931
-
982
+ btn.scroll.to :center
932
983
  expect { btn.click }.to raise_exception(Selenium::WebDriver::Error::ElementClickInterceptedError)
984
+ expect(btn).to be_obscured
933
985
  end
934
986
 
935
987
  it 'returns false if element center is surrounded by non-descendants' do
936
988
  btn = browser.button(id: 'surrounded')
937
- expect(btn).not_to be_obscured
989
+ btn.scroll.to :center
938
990
  expect { btn.click }.not_to raise_exception
991
+ expect(btn).not_to be_obscured
939
992
  end
940
993
 
941
- it 'scrolls interactive element into view before checking if obscured' do
942
- btn = browser.button(id: 'requires_scrolling')
943
- expect(btn).not_to be_obscured
944
- expect { btn.click }.not_to raise_exception
994
+ it 'correctly scrolls element below viewport' do
995
+ browser.goto WatirSpec.url_for('sticky_elements.html')
996
+
997
+ element = browser.div(id: 'center')
998
+
999
+ browser.scroll.to :top
1000
+ expect { element.click }.not_to raise_exception
1001
+
1002
+ browser.scroll.to :top
1003
+ expect(element).not_to be_obscured
1004
+ end
1005
+
1006
+ it 'correctly scrolls element above viewport',
1007
+ except: {browser: %i[chrome edge],
1008
+ reason: 'https://bugs.chromium.org/p/chromedriver/issues/detail?id=3954'} do
1009
+ browser.goto WatirSpec.url_for('sticky_elements.html')
1010
+ element = browser.div(id: 'center')
1011
+
1012
+ browser.scroll.to :bottom
1013
+ expect { element.click }.not_to raise_exception
1014
+
1015
+ browser.scroll.to :bottom
1016
+ expect(element).not_to be_obscured
945
1017
  end
946
1018
 
947
1019
  it 'scrolls non-interactive element into view before checking if obscured' do
948
1020
  div = browser.div(id: 'requires_scrolling_container')
949
- expect(div).not_to be_obscured
950
1021
  expect { div.click }.not_to raise_exception
1022
+ browser.scroll.to :top
1023
+ expect(div).not_to be_obscured
951
1024
  end
952
1025
 
953
1026
  it 'returns true if element cannot be scrolled into view' do
@@ -1,32 +1,15 @@
1
1
  <html>
2
2
  <head>
3
- <script>
4
- function isElementInViewport(el) {
5
- var top = el.offsetTop;
6
- var left = el.offsetLeft;
7
- var width = el.offsetWidth;
8
- var height = el.offsetHeight;
9
-
10
- while (el.offsetParent) {
11
- el = el.offsetParent;
12
- top += el.offsetTop;
13
- left += el.offsetLeft;
14
- }
15
-
16
- return (
17
- top < (window.pageYOffset + window.innerHeight) &&
18
- left < (window.pageXOffset + window.innerWidth) &&
19
- (top + height) > window.pageYOffset &&
20
- (left + width) > window.pageXOffset
21
- );
22
- }
23
- </script>
3
+ <style media="screen">
4
+ div { color: blue; }
5
+ div:hover { color: orange; }
6
+ </style>
24
7
  </head>
25
8
  <body>
26
- <div style="height: 180%; position: relative;">
27
- <button style="position: absolute;">Top</button>
28
- <button style="position: absolute; top: 50%;">Center</button>
29
- <button style="position: absolute; bottom: 0;">Bottom</button>
9
+ <div style="height: 300%; position: relative;">
10
+ <div id="top" style="position: absolute; top: 0;">top</div>
11
+ <div id="center" style="position: absolute; top: 50%;">Center</div>
12
+ <div id="bottom" style="position: absolute; top: 100%;">bottom</div>
30
13
  </div>
31
14
  </body>
32
15
  </html>
@@ -0,0 +1,10 @@
1
+ <html>
2
+ <body>
3
+ <div style="height: 300%; position: relative;">
4
+ <header style="position: sticky; z-index: 10; top: 0;"><h1>Sticky Header</h1></header>
5
+ <div id="top" style="position: absolute; top: 0;">top</div>
6
+ <div id="center" style="position: absolute; top: 50%;">Center</div>
7
+ <div id="bottom" style="position: absolute; top: 100%;">bottom</div>
8
+ </div>
9
+ </body>
10
+ </html>
@@ -5,101 +5,131 @@ describe Watir::Scrolling do
5
5
  browser.goto(WatirSpec.url_for('scroll.html'))
6
6
  end
7
7
 
8
- def visible?(element)
9
- browser.execute_script('return isElementInViewport(arguments[0]);', element)
8
+ def top_centered_viewport
9
+ browser.execute_script('return (window.innerHeight - document.body.scrollHeight)/2;')
10
+ end
11
+
12
+ def current_top
13
+ browser.execute_script('return document.body.getBoundingClientRect().top;')
10
14
  end
11
15
 
12
16
  context 'when scrolling Browser' do
13
17
  describe '#to' do
14
18
  it 'scrolls to the top of the page' do
15
19
  browser.scroll.to :bottom
20
+ expect(browser.div(id: 'top')).not_to be_in_viewport
16
21
  browser.scroll.to :top
17
- expect(visible?(browser.button(text: 'Top'))).to eq(true)
18
- expect(visible?(browser.button(text: 'Center'))).to eq(true)
19
- expect(visible?(browser.button(text: 'Bottom'))).to eq(false)
22
+ expect(browser.div(id: 'top')).to be_in_viewport
20
23
  end
21
24
 
22
25
  it 'scrolls to the center of the page' do
23
26
  browser.scroll.to :center
24
- expect(visible?(browser.button(text: 'Top'))).to eq(false)
25
- expect(visible?(browser.button(text: 'Center'))).to eq(true)
26
- expect(visible?(browser.button(text: 'Bottom'))).to eq(false)
27
+ viewport_top = browser.execute_script('return document.body.getBoundingClientRect().top;')
28
+
29
+ expect(viewport_top).to be_within(1).of(top_centered_viewport)
27
30
  end
28
31
 
29
32
  it 'scrolls to the bottom of the page' do
33
+ expect(browser.div(id: 'bottom')).not_to be_in_viewport
30
34
  browser.scroll.to :bottom
31
- expect(visible?(browser.button(text: 'Top'))).to eq(false)
32
- expect(visible?(browser.button(text: 'Center'))).to eq(true)
33
- expect(visible?(browser.button(text: 'Bottom'))).to eq(true)
35
+ expect(browser.div(id: 'bottom')).to be_in_viewport
34
36
  end
35
37
 
36
38
  it 'scrolls to coordinates' do
37
- button = browser.button(text: 'Bottom')
38
- browser.scroll.to [button.wd.location.x, button.wd.location.y]
39
- expect(visible?(button)).to eq(true)
39
+ element = browser.div(id: 'center')
40
+ location = element.location
41
+ browser.scroll.to [location.x, location.y]
42
+ expect(element).to be_in_viewport
40
43
  end
41
44
 
42
- it 'raises error when scroll point is not vaild' do
45
+ it 'raises error when scroll point is not valid' do
43
46
  expect { browser.scroll.to(:blah) }.to raise_error(ArgumentError)
44
47
  end
45
48
  end
46
49
 
47
50
  describe '#by' do
48
- it 'offset' do
51
+ before do
52
+ sleep(0.1)
53
+ browser.scroll.to :top
54
+ end
55
+
56
+ it 'offset from top' do
57
+ initial_top = current_top
58
+ scroll_by = top_centered_viewport
59
+ browser.scroll.by(0, -scroll_by)
60
+
61
+ expect(current_top).to be_within(1).of(scroll_by + initial_top)
62
+ end
63
+
64
+ it 'offset from bottom' do
65
+ browser.scroll.to :top
66
+ initial_top = current_top
49
67
  browser.scroll.to :bottom
50
- browser.scroll.by(-10_000, -10_000)
68
+ scroll_by = top_centered_viewport
69
+ browser.scroll.by(0, scroll_by)
51
70
 
52
- expect(visible?(browser.button(text: 'Top'))).to eq(true)
53
- expect(visible?(browser.button(text: 'Center'))).to eq(true)
54
- expect(visible?(browser.button(text: 'Bottom'))).to eq(false)
71
+ expect(current_top).to be_within(1).of(scroll_by + initial_top)
55
72
  end
56
73
  end
57
74
  end
58
75
 
59
76
  context 'when scrolling Element' do
60
77
  describe '#to' do
61
- it 'scrolls to element (top)' do
62
- browser.button(text: 'Center').scroll.to
63
- expect(visible?(browser.button(text: 'Top'))).to eq(false)
64
- expect(visible?(browser.button(text: 'Center'))).to eq(true)
65
- expect(visible?(browser.button(text: 'Bottom'))).to eq(true)
78
+ it 'scrolls to element (top) by default' do
79
+ element = browser.div(id: 'center')
80
+ element.scroll.to
81
+
82
+ element_top = browser.execute_script('return arguments[0].getBoundingClientRect().top', element)
83
+ expect(element_top).to be_within(1).of(0)
66
84
  end
67
85
 
68
86
  it 'scrolls to element (center)' do
69
- browser.button(text: 'Center').scroll.to :center
70
- expect(visible?(browser.button(text: 'Top'))).to eq(false)
71
- expect(visible?(browser.button(text: 'Center'))).to eq(true)
72
- expect(visible?(browser.button(text: 'Bottom'))).to eq(false)
87
+ element = browser.div(id: 'center')
88
+ element.scroll.to :center
89
+
90
+ element_rect = browser.execute_script('return arguments[0].getBoundingClientRect()', element)
91
+
92
+ expect(element_rect['top']).to eq(element_rect['bottom'] - element_rect['height'])
73
93
  end
74
94
 
75
95
  it 'scrolls to element (bottom)' do
76
- browser.button(text: 'Center').scroll.to :bottom
77
- expect(visible?(browser.button(text: 'Top'))).to eq(true)
78
- expect(visible?(browser.button(text: 'Center'))).to eq(true)
79
- expect(visible?(browser.button(text: 'Bottom'))).to eq(false)
96
+ element = browser.div(id: 'center')
97
+ element.scroll.to :bottom
98
+
99
+ element_bottom = browser.execute_script('return arguments[0].getBoundingClientRect().bottom', element)
100
+ window_height = browser.execute_script('return window.innerHeight')
101
+
102
+ expect(element_bottom).to be_within(1).of(window_height)
80
103
  end
81
104
 
82
105
  it 'scrolls to element multiple times' do
83
106
  2.times do
84
- browser.button(text: 'Center').scroll.to(:center)
85
- expect(visible?(browser.button(text: 'Top'))).to eq(false)
107
+ element = browser.div(id: 'center')
108
+ element.scroll.to(:center)
109
+
110
+ element_rect = browser.execute_script('return arguments[0].getBoundingClientRect()', element)
111
+
112
+ expect(element_rect['top']).to eq(element_rect['bottom'] - element_rect['height'])
86
113
  end
87
114
  end
88
115
 
89
- it 'raises error when scroll param is not vaild' do
90
- expect { browser.button(text: 'Top').scroll.to(:blah) }.to raise_error(ArgumentError)
116
+ it 'raises error when scroll param is not valid' do
117
+ expect { browser.div(id: 'top').scroll.to(:blah) }.to raise_error(ArgumentError)
91
118
  end
92
119
  end
93
120
 
94
121
  describe '#by' do
95
122
  it 'offset' do
123
+ sleep 0.1
124
+ browser.scroll.to :top
125
+ initial_top = current_top
96
126
  browser.scroll.to :bottom
97
- button = browser.button(text: 'Bottom')
98
- button.scroll.by(-10_000, -10_000) # simulate scrolling to top
127
+ scroll_by = top_centered_viewport
128
+
129
+ element = browser.div(id: 'bottom')
130
+ element.scroll.by(0, scroll_by)
99
131
 
100
- expect(visible?(browser.button(text: 'Top'))).to eq(true)
101
- expect(visible?(browser.button(text: 'Center'))).to eq(true)
102
- expect(visible?(browser.button(text: 'Bottom'))).to eq(false)
132
+ expect(current_top).to be_within(1).of(scroll_by + initial_top)
103
133
  end
104
134
  end
105
135
  end