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.
- checksums.yaml +4 -4
- data/.github/workflows/chrome.yml +34 -0
- data/.github/workflows/edge.yml +28 -0
- data/.github/workflows/firefox.yml +35 -0
- data/.github/workflows/ie.yml +24 -0
- data/.github/workflows/safari.yml +27 -0
- data/.github/workflows/unit.yml +52 -0
- data/.rubocop.yml +1 -1
- data/CHANGES.md +26 -0
- data/lib/watir/attribute_helper.rb +1 -1
- data/lib/watir/browser.rb +3 -3
- data/lib/watir/capabilities.rb +14 -0
- data/lib/watir/elements/date_field.rb +4 -1
- data/lib/watir/elements/date_time_field.rb +4 -1
- data/lib/watir/elements/element.rb +39 -13
- data/lib/watir/elements/table.rb +1 -1
- data/lib/watir/js_snippets/isElementInViewport.js +20 -0
- data/lib/watir/locators/element/selector_builder/xpath.rb +3 -2
- data/lib/watir/scroll.rb +2 -1
- data/lib/watir/version.rb +1 -1
- data/lib/watir/window.rb +22 -0
- data/lib/watirspec/remote_server.rb +2 -6
- data/spec/unit/capabilities_spec.rb +99 -5
- data/spec/watirspec/after_hooks_spec.rb +0 -2
- data/spec/watirspec/drag_and_drop_spec.rb +12 -0
- data/spec/watirspec/elements/date_time_field_spec.rb +3 -6
- data/spec/watirspec/elements/div_spec.rb +12 -1
- data/spec/watirspec/elements/element_spec.rb +91 -18
- data/spec/watirspec/html/scroll.html +8 -25
- data/spec/watirspec/html/sticky_elements.html +10 -0
- data/spec/watirspec/scroll_spec.rb +72 -42
- data/spec/watirspec/window_switching_spec.rb +40 -14
- data/spec/watirspec_helper.rb +2 -0
- data/watir.gemspec +3 -3
- metadata +24 -18
- data/.github/workflows/tests.yml +0 -104
- 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 &
|
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
|
-
|
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
|
-
|
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
|
-
|
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:
|
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:
|
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:
|
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
|
-
|
627
|
-
|
628
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
942
|
-
|
943
|
-
|
944
|
-
|
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
|
-
<
|
4
|
-
|
5
|
-
|
6
|
-
|
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:
|
27
|
-
<
|
28
|
-
<
|
29
|
-
<
|
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
|
9
|
-
browser.execute_script('return
|
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(
|
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
|
-
|
25
|
-
|
26
|
-
expect(
|
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(
|
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
|
-
|
38
|
-
|
39
|
-
|
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
|
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
|
-
|
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
|
-
|
68
|
+
scroll_by = top_centered_viewport
|
69
|
+
browser.scroll.by(0, scroll_by)
|
51
70
|
|
52
|
-
expect(
|
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.
|
63
|
-
|
64
|
-
|
65
|
-
|
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.
|
70
|
-
|
71
|
-
|
72
|
-
|
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.
|
77
|
-
|
78
|
-
|
79
|
-
|
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.
|
85
|
-
|
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
|
90
|
-
expect { browser.
|
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
|
-
|
98
|
-
|
127
|
+
scroll_by = top_centered_viewport
|
128
|
+
|
129
|
+
element = browser.div(id: 'bottom')
|
130
|
+
element.scroll.by(0, scroll_by)
|
99
131
|
|
100
|
-
expect(
|
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
|