# frozen_string_literal: true require 'watirspec_helper' module Watir describe Scrolling do before do browser.goto(WatirSpec.url_for('scroll.html')) pause end def top_centered_viewport browser.execute_script('return (window.innerHeight - document.body.scrollHeight)/2;') end def current_top browser.execute_script('return document.body.getBoundingClientRect().top;') end context 'when scrolling Browser' do describe '#to' do it 'scrolls to the top of the page' do browser.scroll.to :bottom expect(browser.div(id: 'top')).not_to be_in_viewport browser.scroll.to :top expect(browser.div(id: 'top')).to be_in_viewport end it 'scrolls to the center of the page' do browser.scroll.to :center viewport_top = browser.execute_script('return document.body.getBoundingClientRect().top;') expect(viewport_top).to be_within(1).of(top_centered_viewport) end it 'scrolls to the bottom of the page' do expect(browser.div(id: 'bottom')).not_to be_in_viewport browser.scroll.to :bottom expect(browser.div(id: 'bottom')).to be_in_viewport end it 'scrolls to coordinates' do element = browser.div(id: 'center') location = element.location browser.scroll.to [location.x, location.y] expect(element).to be_in_viewport end it 'raises error when scroll point is not valid' do expect { browser.scroll.to(:blah) }.to raise_error(ArgumentError) end end describe '#by' do before do browser.scroll.to :top pause end it 'offset from top' do initial_top = current_top scroll_by = top_centered_viewport.round browser.scroll.by(0, -scroll_by) pause puts "scroll by #{scroll_by}" puts "initial top #{initial_top}" puts "current top #{current_top}" expect(current_top).to be_within(1).of(scroll_by + initial_top) end it 'offset from bottom' do initial_top = current_top browser.scroll.to :bottom scroll_by = top_centered_viewport browser.scroll.by(0, scroll_by) pause expect(current_top).to be_within(1).of(scroll_by + initial_top) end end describe '#from' do it 'scrolls by given amount with offset', except: {browser: :ie, reason: 'Not implemented'} do browser.goto(WatirSpec.url_for('scroll_nested.html')) browser.scroll.from(10, 10).by(0, 225) expect(in_viewport?(browser.iframe.checkbox(name: 'scroll_checkbox'))).to be true end end end context 'when scrolling Element' do describe '#to' do it 'scrolls element into view (viewport)', except: [{browser: %i[firefox safari], reason: 'incorrect MoveTargetOutOfBoundsError'}, {browser: :ie, reason: 'Not implemented'}] do browser.goto(WatirSpec.url_for('scroll_nested_offscreen.html')) iframe = browser.iframe expect(in_viewport?(iframe)).to be false iframe.scroll.to(:viewport) expect(in_viewport?(iframe)).to be true end it 'scrolls to element (top) by default' do element = browser.div(id: 'center') element.scroll.to element_top = browser.execute_script('return arguments[0].getBoundingClientRect().top', element) expect(element_top).to be_within(1).of(0) end it 'scrolls to element (center)' do element = browser.div(id: 'center') element.scroll.to :center element_rect = browser.execute_script('return arguments[0].getBoundingClientRect()', element) expect(element_rect['top']).to eq(element_rect['bottom'] - element_rect['height']) end it 'scrolls to element (bottom)' do element = browser.div(id: 'center') element.scroll.to :bottom element_bottom = browser.execute_script('return arguments[0].getBoundingClientRect().bottom', element) window_height = browser.execute_script('return window.innerHeight') expect(element_bottom).to be_within(1).of(window_height) end it 'scrolls to element multiple times' do 2.times do element = browser.div(id: 'center') element.scroll.to(:center) element_rect = browser.execute_script('return arguments[0].getBoundingClientRect()', element) expect(element_rect['top']).to eq(element_rect['bottom'] - element_rect['height']) end end it 'raises error when scroll param is not valid' do expect { browser.div(id: 'top').scroll.to(:blah) }.to raise_error(ArgumentError) end end describe '#by' do it 'offset' do browser.scroll.to :top pause initial_top = current_top browser.scroll.to :bottom pause scroll_by = top_centered_viewport element = browser.div(id: 'bottom') element.scroll.by(0, scroll_by) pause expect(current_top).to be_within(1).of(scroll_by + initial_top) end end describe '#from', except: [{browser: %i[firefox safari], reason: 'incorrect MoveTargetOutOfBoundsError'}, {browser: :ie, reason: 'Not implemented'}] do it 'scrolls from element by given amount' do browser.goto(WatirSpec.url_for('scroll_nested_offscreen.html')) iframe = browser.iframe iframe.scroll.from.by(0, 200) checkbox = iframe.checkbox(name: 'scroll_checkbox') expect(in_viewport?(checkbox)).to be true end it 'scrolls from an element with an offset' do browser.goto(WatirSpec.url_for('scroll_nested_offscreen.html')) move_left = browser.execute_script('return arguments[0].getBoundingClientRect().width/2', browser.footer) - browser.execute_script('return arguments[0].getBoundingClientRect().right/2', browser.iframe.we) browser.footer.scroll.from(-move_left.round, -50).by(0, 200) checkbox = browser.iframe.checkbox(name: 'scroll_checkbox') expect(in_viewport?(checkbox)).to be true end end end def in_viewport?(element) in_viewport = <<~IN_VIEWPORT for(var e=arguments[0],f=e.offsetTop,t=e.offsetLeft,o=e.offsetWidth,n=e.offsetHeight; e.offsetParent;)f+=(e=e.offsetParent).offsetTop,t+=e.offsetLeft; return f window.pageYOffset&&t+o>window.pageXOffset IN_VIEWPORT element.browser.execute_script(in_viewport, element.we) end def pause sleep 0.2 end end end